@owlmeans/viable-sdk 0.1.18-rc.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.
Files changed (166) hide show
  1. package/README.md +128 -0
  2. package/build/api/index.d.ts +2 -0
  3. package/build/api/index.d.ts.map +1 -0
  4. package/build/api/index.js +2 -0
  5. package/build/api/index.js.map +1 -0
  6. package/build/api/remote.d.ts +14 -0
  7. package/build/api/remote.d.ts.map +1 -0
  8. package/build/api/remote.js +123 -0
  9. package/build/api/remote.js.map +1 -0
  10. package/build/consts.d.ts +47 -0
  11. package/build/consts.d.ts.map +1 -0
  12. package/build/consts.js +47 -0
  13. package/build/consts.js.map +1 -0
  14. package/build/context/index.d.ts +22 -0
  15. package/build/context/index.d.ts.map +1 -0
  16. package/build/context/index.js +92 -0
  17. package/build/context/index.js.map +1 -0
  18. package/build/errors.d.ts +21 -0
  19. package/build/errors.d.ts.map +1 -0
  20. package/build/errors.js +36 -0
  21. package/build/errors.js.map +1 -0
  22. package/build/executor/boot-check.d.ts +73 -0
  23. package/build/executor/boot-check.d.ts.map +1 -0
  24. package/build/executor/boot-check.js +155 -0
  25. package/build/executor/boot-check.js.map +1 -0
  26. package/build/executor/env.d.ts +25 -0
  27. package/build/executor/env.d.ts.map +1 -0
  28. package/build/executor/env.js +77 -0
  29. package/build/executor/env.js.map +1 -0
  30. package/build/executor/errors.d.ts +69 -0
  31. package/build/executor/errors.d.ts.map +1 -0
  32. package/build/executor/errors.js +80 -0
  33. package/build/executor/errors.js.map +1 -0
  34. package/build/executor/files.d.ts +124 -0
  35. package/build/executor/files.d.ts.map +1 -0
  36. package/build/executor/files.js +529 -0
  37. package/build/executor/files.js.map +1 -0
  38. package/build/executor/git.d.ts +52 -0
  39. package/build/executor/git.d.ts.map +1 -0
  40. package/build/executor/git.js +353 -0
  41. package/build/executor/git.js.map +1 -0
  42. package/build/executor/health.d.ts +92 -0
  43. package/build/executor/health.d.ts.map +1 -0
  44. package/build/executor/health.js +98 -0
  45. package/build/executor/health.js.map +1 -0
  46. package/build/executor/index.d.ts +39 -0
  47. package/build/executor/index.d.ts.map +1 -0
  48. package/build/executor/index.js +173 -0
  49. package/build/executor/index.js.map +1 -0
  50. package/build/executor/integrity.d.ts +17 -0
  51. package/build/executor/integrity.d.ts.map +1 -0
  52. package/build/executor/integrity.js +59 -0
  53. package/build/executor/integrity.js.map +1 -0
  54. package/build/executor/layout.d.ts +61 -0
  55. package/build/executor/layout.d.ts.map +1 -0
  56. package/build/executor/layout.js +98 -0
  57. package/build/executor/layout.js.map +1 -0
  58. package/build/executor/shell.d.ts +89 -0
  59. package/build/executor/shell.d.ts.map +1 -0
  60. package/build/executor/shell.js +280 -0
  61. package/build/executor/shell.js.map +1 -0
  62. package/build/executor/spawn.d.ts +111 -0
  63. package/build/executor/spawn.d.ts.map +1 -0
  64. package/build/executor/spawn.js +314 -0
  65. package/build/executor/spawn.js.map +1 -0
  66. package/build/harness/index.d.ts +28 -0
  67. package/build/harness/index.d.ts.map +1 -0
  68. package/build/harness/index.js +83 -0
  69. package/build/harness/index.js.map +1 -0
  70. package/build/harness/templates.d.ts +30 -0
  71. package/build/harness/templates.d.ts.map +1 -0
  72. package/build/harness/templates.js +162 -0
  73. package/build/harness/templates.js.map +1 -0
  74. package/build/index.d.ts +13 -0
  75. package/build/index.d.ts.map +1 -0
  76. package/build/index.js +12 -0
  77. package/build/index.js.map +1 -0
  78. package/build/project/env.d.ts +108 -0
  79. package/build/project/env.d.ts.map +1 -0
  80. package/build/project/env.js +233 -0
  81. package/build/project/env.js.map +1 -0
  82. package/build/project/marker.d.ts +34 -0
  83. package/build/project/marker.d.ts.map +1 -0
  84. package/build/project/marker.js +54 -0
  85. package/build/project/marker.js.map +1 -0
  86. package/build/project/setup.d.ts +62 -0
  87. package/build/project/setup.d.ts.map +1 -0
  88. package/build/project/setup.js +190 -0
  89. package/build/project/setup.js.map +1 -0
  90. package/build/run/index.d.ts +75 -0
  91. package/build/run/index.d.ts.map +1 -0
  92. package/build/run/index.js +150 -0
  93. package/build/run/index.js.map +1 -0
  94. package/build/run/serve.d.ts +18 -0
  95. package/build/run/serve.d.ts.map +1 -0
  96. package/build/run/serve.js +148 -0
  97. package/build/run/serve.js.map +1 -0
  98. package/build/run/state.d.ts +75 -0
  99. package/build/run/state.d.ts.map +1 -0
  100. package/build/run/state.js +136 -0
  101. package/build/run/state.js.map +1 -0
  102. package/build/session/index.d.ts +17 -0
  103. package/build/session/index.d.ts.map +1 -0
  104. package/build/session/index.js +226 -0
  105. package/build/session/index.js.map +1 -0
  106. package/build/session/questions.d.ts +16 -0
  107. package/build/session/questions.d.ts.map +1 -0
  108. package/build/session/questions.js +17 -0
  109. package/build/session/questions.js.map +1 -0
  110. package/build/session/queue.d.ts +54 -0
  111. package/build/session/queue.d.ts.map +1 -0
  112. package/build/session/queue.js +102 -0
  113. package/build/session/queue.js.map +1 -0
  114. package/build/session/tasks.d.ts +15 -0
  115. package/build/session/tasks.d.ts.map +1 -0
  116. package/build/session/tasks.js +16 -0
  117. package/build/session/tasks.js.map +1 -0
  118. package/build/task/driver.d.ts +30 -0
  119. package/build/task/driver.d.ts.map +1 -0
  120. package/build/task/driver.js +120 -0
  121. package/build/task/driver.js.map +1 -0
  122. package/build/task/envelope.d.ts +35 -0
  123. package/build/task/envelope.d.ts.map +1 -0
  124. package/build/task/envelope.js +230 -0
  125. package/build/task/envelope.js.map +1 -0
  126. package/build/task/index.d.ts +4 -0
  127. package/build/task/index.d.ts.map +1 -0
  128. package/build/task/index.js +4 -0
  129. package/build/task/index.js.map +1 -0
  130. package/build/task/inquiry.d.ts +53 -0
  131. package/build/task/inquiry.d.ts.map +1 -0
  132. package/build/task/inquiry.js +232 -0
  133. package/build/task/inquiry.js.map +1 -0
  134. package/build/tools/catalogue.d.ts +17 -0
  135. package/build/tools/catalogue.d.ts.map +1 -0
  136. package/build/tools/catalogue.js +1169 -0
  137. package/build/tools/catalogue.js.map +1 -0
  138. package/build/tools/index.d.ts +7 -0
  139. package/build/tools/index.d.ts.map +1 -0
  140. package/build/tools/index.js +7 -0
  141. package/build/tools/index.js.map +1 -0
  142. package/build/tools/jobs.d.ts +12 -0
  143. package/build/tools/jobs.d.ts.map +1 -0
  144. package/build/tools/jobs.js +60 -0
  145. package/build/tools/jobs.js.map +1 -0
  146. package/build/tools/mcp.d.ts +43 -0
  147. package/build/tools/mcp.d.ts.map +1 -0
  148. package/build/tools/mcp.js +131 -0
  149. package/build/tools/mcp.js.map +1 -0
  150. package/build/tools/platform.d.ts +77 -0
  151. package/build/tools/platform.d.ts.map +1 -0
  152. package/build/tools/platform.js +316 -0
  153. package/build/tools/platform.js.map +1 -0
  154. package/build/tools/refusal.d.ts +66 -0
  155. package/build/tools/refusal.d.ts.map +1 -0
  156. package/build/tools/refusal.js +377 -0
  157. package/build/tools/refusal.js.map +1 -0
  158. package/build/tools/types.d.ts +83 -0
  159. package/build/tools/types.d.ts.map +1 -0
  160. package/build/tools/types.js +38 -0
  161. package/build/tools/types.js.map +1 -0
  162. package/build/types.d.ts +174 -0
  163. package/build/types.d.ts.map +1 -0
  164. package/build/types.js +2 -0
  165. package/build/types.js.map +1 -0
  166. package/package.json +105 -0
@@ -0,0 +1,73 @@
1
+ import { spawn as nodeSpawn } from 'node:child_process';
2
+ import type { TargetHealthReading } from './health.js';
3
+ /**
4
+ * Boot the generated backend for real, in isolation, and report what happened.
5
+ *
6
+ * `tsc` cannot see a foreign key that names a resource nothing registers: the reference is a
7
+ * string in an AJV schema, and it is resolved while the OwlMeans context initializes. So a story
8
+ * can type-check, be stamped complete, and leave a backend that dies at boot — which is exactly
9
+ * what happened, because the only real boot in the pipeline ran AFTER the story was accepted.
10
+ *
11
+ * It runs the real thing, but never the live one: a second process, on its own port, against a
12
+ * scratch schema, killed on every exit path.
13
+ */
14
+ /** How far the boot got. `ready` is the only success. */
15
+ export type BootCheckPhase = 'build' | 'schema' | 'boot' | 'ready';
16
+ export interface BootCheckReport {
17
+ ok: boolean;
18
+ phase: BootCheckPhase;
19
+ /** The classifier's reason plus the captured startup log, or null when the boot succeeded. */
20
+ error: string | null;
21
+ dbOk?: boolean;
22
+ }
23
+ export interface BootCheckDeps {
24
+ port: number;
25
+ /** Argv marker that tells this instance apart from the live one for process matching. */
26
+ marker: string;
27
+ cwd: string;
28
+ env: Record<string, string>;
29
+ bootId: string;
30
+ /** Omitted to reuse the artifacts already on disk. */
31
+ build?: () => Promise<string | null>;
32
+ readHealth?: (port: number, bootId: string, timeoutMs: number) => Promise<TargetHealthReading>;
33
+ spawn?: typeof nodeSpawn;
34
+ ddlWindowMs?: number;
35
+ readyWindowMs?: number;
36
+ readyPollMs?: number;
37
+ /** Whole-run cap, so a wedged boot cannot outlive the caller's deadline. */
38
+ timeoutMs?: number;
39
+ }
40
+ /**
41
+ * DELIBERATE DIFFERENCE from the publisher: no `resetSchema` step, and therefore no `schema`
42
+ * failure of its own.
43
+ *
44
+ * A slot's check drops and recreates its scratch schema as the application role, which owns it. On
45
+ * a developer's machine the database is the DEVELOPER'S — the connector was handed a `DATABASE_URL`
46
+ * and nothing above it, it has no credential that may drop anything, and a platform that silently
47
+ * dropped a schema in a database it does not own would be destroying work it cannot restore. The
48
+ * check still runs under `DATABASE_SCHEMA=bootcheck`, so it never touches the app's namespace; it
49
+ * simply leaves what it created behind, and the next run reconciles into it.
50
+ */
51
+ export declare const runBootCheck: (deps: BootCheckDeps) => Promise<BootCheckReport>;
52
+ export interface BootCheckStatus {
53
+ running: boolean;
54
+ startedAt: number | null;
55
+ report: BootCheckReport | null;
56
+ }
57
+ export interface BootCheckJob {
58
+ /** Start a check, or join the one already running. `true` when this call started it. */
59
+ start: (run: () => Promise<BootCheckReport>) => boolean;
60
+ status: () => BootCheckStatus;
61
+ /** The running check, for the legacy blocking caller. */
62
+ pending: () => Promise<BootCheckReport> | null;
63
+ }
64
+ /**
65
+ * The job behind `BootCheck` / `BootCheckStatus`.
66
+ *
67
+ * The command STARTS a check and returns; the verdict is read separately. A boot is minutes of
68
+ * build and startup, and holding one request open for it made a fault indistinguishable from a
69
+ * hung agent for the whole of the caller's timeout. A second start joins the running check rather
70
+ * than spawning another instance onto the same port.
71
+ */
72
+ export declare const createBootCheckJob: (watchdogMs?: number) => BootCheckJob;
73
+ //# sourceMappingURL=boot-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot-check.d.ts","sourceRoot":"","sources":["../../src/executor/boot-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAIvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAGtD;;;;;;;;;;GAUG;AAEH,yDAAyD;AACzD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;AAElE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAA;IACX,KAAK,EAAE,cAAc,CAAA;IACrB,8FAA8F;IAC9F,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,yFAAyF;IACzF,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACpC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAC9F,KAAK,CAAC,EAAE,OAAO,SAAS,CAAA;IACxB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAID;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,SAAgB,aAAa,KAAG,OAAO,CAAC,eAAe,CA6F/E,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,MAAM,EAAE,eAAe,GAAG,IAAI,CAAA;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,wFAAwF;IACxF,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,KAAK,OAAO,CAAA;IACvD,MAAM,EAAE,MAAM,eAAe,CAAA;IAC7B,yDAAyD;IACzD,OAAO,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAA;CAC/C;AAWD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,2BAA+B,YA2C7D,CAAA"}
@@ -0,0 +1,155 @@
1
+ import { spawn as nodeSpawn } from 'node:child_process';
2
+ import { readTargetHealth } from './health.js';
3
+ import { delay, killGroupAndWait, reclaimPort, waitForPortFree } from './spawn.js';
4
+ const STARTUP_LOG_CAP = 16_384;
5
+ /**
6
+ * DELIBERATE DIFFERENCE from the publisher: no `resetSchema` step, and therefore no `schema`
7
+ * failure of its own.
8
+ *
9
+ * A slot's check drops and recreates its scratch schema as the application role, which owns it. On
10
+ * a developer's machine the database is the DEVELOPER'S — the connector was handed a `DATABASE_URL`
11
+ * and nothing above it, it has no credential that may drop anything, and a platform that silently
12
+ * dropped a schema in a database it does not own would be destroying work it cannot restore. The
13
+ * check still runs under `DATABASE_SCHEMA=bootcheck`, so it never touches the app's namespace; it
14
+ * simply leaves what it created behind, and the next run reconciles into it.
15
+ */
16
+ export const runBootCheck = async (deps) => {
17
+ const { port, marker, cwd, env, bootId, build, readHealth = readTargetHealth, spawn = nodeSpawn, ddlWindowMs = 10_000, readyWindowMs = 90_000, readyPollMs = 2_000, timeoutMs = 480_000, } = deps;
18
+ const deadline = Date.now() + timeoutMs;
19
+ let child = null;
20
+ let log = '';
21
+ const record = (chunk) => {
22
+ log = (log + chunk).slice(-STARTUP_LOG_CAP);
23
+ };
24
+ try {
25
+ if (build != null) {
26
+ const buildError = await build();
27
+ if (buildError != null)
28
+ return { ok: false, phase: 'build', error: buildError };
29
+ }
30
+ // Before the spawn, not only after it. The leftover this reclaims belongs to a run that never
31
+ // finished, so it is already holding the port by the time anything asks for a fresh check —
32
+ // and the target refuses to start on a taken port rather than stealing it, correctly.
33
+ if (!await waitForPortFree(port, 2_000))
34
+ await reclaimPort(port, marker);
35
+ child = spawn('bun', ['dist/index.js', marker], {
36
+ cwd,
37
+ detached: true,
38
+ shell: true,
39
+ stdio: ['ignore', 'pipe', 'pipe'],
40
+ env: { ...process.env, ...env, BACKEND_BOOT_ID: bootId },
41
+ });
42
+ child.stdout?.on('data', chunk => record(chunk.toString()));
43
+ child.stderr?.on('data', chunk => record(chunk.toString()));
44
+ let exited = false;
45
+ child.on('exit', () => { exited = true; });
46
+ child.on('error', error => record(`\n${String(error)}`));
47
+ // A structure or reference error takes the target down during init; that is what this window
48
+ // is for. A target that survives it may still be degraded, which is what the poll asks about.
49
+ const ddlDeadline = Date.now() + ddlWindowMs;
50
+ while (Date.now() < ddlDeadline && !exited) {
51
+ await delay(200);
52
+ }
53
+ if (exited) {
54
+ return { ok: false, phase: 'boot', error: `The target backend exited while initializing:\n${log}` };
55
+ }
56
+ const readyDeadline = Math.min(Date.now() + readyWindowMs, deadline);
57
+ let reason = 'The target backend did not become ready';
58
+ while (Date.now() < readyDeadline) {
59
+ if (exited) {
60
+ return { ok: false, phase: 'boot', error: `The target backend exited while initializing:\n${log}` };
61
+ }
62
+ const health = await readHealth(port, bootId, 2_000);
63
+ if (health.ready)
64
+ return { ok: true, phase: 'ready', error: null, dbOk: health.dbOk };
65
+ reason = health.reason;
66
+ // A self-reported failure is terminal — no point waiting out the window for a target that
67
+ // has already said it will not come up.
68
+ if (health.terminal) {
69
+ return { ok: false, phase: 'boot', error: `${reason}\n${log}`.trim(), dbOk: health.dbOk };
70
+ }
71
+ await delay(readyPollMs);
72
+ }
73
+ return { ok: false, phase: 'boot', error: `${reason}\n${log}`.trim() };
74
+ }
75
+ catch (e) {
76
+ return { ok: false, phase: 'boot', error: `Boot check failed to run: ${String(e)}\n${log}`.trim() };
77
+ }
78
+ finally {
79
+ // Unconditional: a validation instance left holding its port would fail every later check,
80
+ // and one left holding the database would be indistinguishable from the live backend.
81
+ if (child != null) {
82
+ try {
83
+ await killGroupAndWait(child);
84
+ }
85
+ catch {
86
+ // Already gone.
87
+ }
88
+ }
89
+ try {
90
+ // Reclaimed by MARKER when waiting is not enough: a connector killed mid-check leaves its
91
+ // detached child alive, and every later check then fails with the target's own "the api port
92
+ // is already in use" — which reads as a defect in the generated app rather than as a stray
93
+ // process from a run that never finished.
94
+ if (!await waitForPortFree(port))
95
+ await reclaimPort(port, marker);
96
+ }
97
+ catch {
98
+ // Nothing else to do — the next check reclaims by marker anyway.
99
+ }
100
+ }
101
+ };
102
+ /**
103
+ * Outer bound on one boot-check job.
104
+ *
105
+ * `runBootCheck` caps its own ready poll but not the build in front of it, so this is the only
106
+ * thing that guarantees a poller eventually reads `running: false` — a check that outlives it is
107
+ * abandoned, not awaited.
108
+ */
109
+ const WATCHDOG_MS = 600_000;
110
+ /**
111
+ * The job behind `BootCheck` / `BootCheckStatus`.
112
+ *
113
+ * The command STARTS a check and returns; the verdict is read separately. A boot is minutes of
114
+ * build and startup, and holding one request open for it made a fault indistinguishable from a
115
+ * hung agent for the whole of the caller's timeout. A second start joins the running check rather
116
+ * than spawning another instance onto the same port.
117
+ */
118
+ export const createBootCheckJob = (watchdogMs = WATCHDOG_MS) => {
119
+ let promise = null;
120
+ let startedAt = null;
121
+ let last = null;
122
+ return {
123
+ start: run => {
124
+ if (promise != null)
125
+ return false;
126
+ startedAt = Date.now();
127
+ const job = run();
128
+ promise = job;
129
+ // The job owns its own completion: the starting request is already gone by then, so the
130
+ // report has to be parked where a status read can find it. A throw is a report too — a
131
+ // poller that never sees `running: false` waits out its whole deadline for nothing.
132
+ void job.then(report => { last = report; }, e => {
133
+ last = { ok: false, phase: 'boot', error: `Boot check failed to run: ${String(e)}` };
134
+ }).finally(() => {
135
+ if (promise === job)
136
+ promise = null;
137
+ });
138
+ const watchdog = setTimeout(() => {
139
+ if (promise !== job)
140
+ return;
141
+ promise = null;
142
+ last = {
143
+ ok: false, phase: 'boot',
144
+ error: `Boot check exceeded ${watchdogMs}ms and was abandoned`,
145
+ };
146
+ }, watchdogMs);
147
+ watchdog.unref?.();
148
+ void job.finally(() => clearTimeout(watchdog));
149
+ return true;
150
+ },
151
+ status: () => ({ running: promise != null, startedAt, report: last }),
152
+ pending: () => promise,
153
+ };
154
+ };
155
+ //# sourceMappingURL=boot-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot-check.js","sourceRoot":"","sources":["../../src/executor/boot-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Runtime environment for the target's api and worker processes.
3
+ *
4
+ * Read at runtime, never baked into the bundle — the api resolves `DATABASE_URL`, `VALKEY_URL`
5
+ * and the OIDC triple when it boots, which is why a configure push that lands after a build still
6
+ * reaches it with nothing more than a restart.
7
+ */
8
+ export declare const backendEnv: (dir: string) => Promise<Record<string, string>>;
9
+ /**
10
+ * Build-time environment for the target's browser bundle.
11
+ *
12
+ * DELIBERATE DIFFERENCE from the publisher: `BACKEND_PORT` names the WEB port, not the api's.
13
+ * A slot serves the app and its `/api` from one hostname behind one TLS front door, so the
14
+ * publisher can leave the port blank and let the scheme imply it. A local run has two processes
15
+ * on two loopback ports, and the local server proxies `/api` precisely so the browser stays
16
+ * same-origin — pointing the bundle at 3000 instead would make every call cross-origin and put
17
+ * the target's CORS configuration in the path of a developer's first page load.
18
+ *
19
+ * Composed from the WEB package's own `.env` and never from the root one. The publisher has the
20
+ * same boundary as an allow-list (`frontendEnvVars` / `frontendSecrets`); here it is the file
21
+ * split, and it is what keeps `DATABASE_URL` and `OIDC_SECRET` out of a bundle every visitor
22
+ * downloads.
23
+ */
24
+ export declare const frontendEnv: (dir: string) => Promise<Record<string, string>>;
25
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/executor/env.ts"],"names":[],"mappings":"AA0BA;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,QAAe,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiB5E,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,QAAe,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmB7E,CAAA"}
@@ -0,0 +1,77 @@
1
+ import { TARGET_API_BASE, TARGET_API_PORT, TARGET_WEB_PORT, TARGET_WORKER_PORT } from '@owlmeans/viable-common';
2
+ import { readEnvFile, ROOT_ENV_FILE, webEnvFile } from '../project/env.js';
3
+ /**
4
+ * The environment a locally-run target sees.
5
+ *
6
+ * Same tables the publisher composes for a pod, with two differences that follow from where this
7
+ * runs. The hosts are `localhost` — a loopback address, not a claimed preview hostname — and the
8
+ * VALUES come from the target's own `.env` files rather than from slot metadata, because on a
9
+ * developer's machine the platform provisions nothing: the database URL, the queue URL and the
10
+ * OIDC identity are lines in a file the developer and the configure push both write.
11
+ *
12
+ * The defaults are laid down first and the `.env` is overlaid on top, so a user who set a value
13
+ * gets the value they set. Callers that own a port — the boot check, the worker — spread their
14
+ * override over the result, exactly as the publisher does.
15
+ */
16
+ /** Keys the frontend build injects on its own, so they are never announced as extras. */
17
+ const FRONTEND_STANDARD_KEYS = new Set([
18
+ 'FRONTEND_PORT', 'FRONTEND_HOST', 'BACKEND_HOST', 'BACKEND_PORT', 'BACKEND_BASE_URL',
19
+ 'BASE_URL', 'FRONTEND_ENV_KEYS', 'SOURCEMAP',
20
+ ]);
21
+ /**
22
+ * Runtime environment for the target's api and worker processes.
23
+ *
24
+ * Read at runtime, never baked into the bundle — the api resolves `DATABASE_URL`, `VALKEY_URL`
25
+ * and the OIDC triple when it boots, which is why a configure push that lands after a build still
26
+ * reaches it with nothing more than a restart.
27
+ */
28
+ export const backendEnv = async (dir) => {
29
+ // The ROOT `.env` alone. The web package's file is compiled into a bundle anybody can read, so
30
+ // the two are never merged in either direction.
31
+ const values = await readEnvFile(dir, ROOT_ENV_FILE);
32
+ return {
33
+ BACKEND_PORT: `${TARGET_API_PORT}`,
34
+ BACKEND_HOST: 'localhost',
35
+ BACKEND_BASE_URL: TARGET_API_BASE,
36
+ FRONTEND_HOST: 'localhost',
37
+ FRONTEND_PORT: `${TARGET_WEB_PORT}`,
38
+ BASE_URL: '',
39
+ WORKER_PORT: `${TARGET_WORKER_PORT}`,
40
+ // The target's own values last: everything above is a default this machine can state without
41
+ // asking, and everything the user or a configure push wrote outranks it.
42
+ ...values,
43
+ };
44
+ };
45
+ /**
46
+ * Build-time environment for the target's browser bundle.
47
+ *
48
+ * DELIBERATE DIFFERENCE from the publisher: `BACKEND_PORT` names the WEB port, not the api's.
49
+ * A slot serves the app and its `/api` from one hostname behind one TLS front door, so the
50
+ * publisher can leave the port blank and let the scheme imply it. A local run has two processes
51
+ * on two loopback ports, and the local server proxies `/api` precisely so the browser stays
52
+ * same-origin — pointing the bundle at 3000 instead would make every call cross-origin and put
53
+ * the target's CORS configuration in the path of a developer's first page load.
54
+ *
55
+ * Composed from the WEB package's own `.env` and never from the root one. The publisher has the
56
+ * same boundary as an allow-list (`frontendEnvVars` / `frontendSecrets`); here it is the file
57
+ * split, and it is what keeps `DATABASE_URL` and `OIDC_SECRET` out of a bundle every visitor
58
+ * downloads.
59
+ */
60
+ export const frontendEnv = async (dir) => {
61
+ const values = await readEnvFile(dir, webEnvFile(dir));
62
+ const env = {
63
+ FRONTEND_PORT: `${TARGET_WEB_PORT}`,
64
+ BACKEND_HOST: 'localhost',
65
+ BACKEND_PORT: `${TARGET_WEB_PORT}`,
66
+ BACKEND_BASE_URL: TARGET_API_BASE,
67
+ BASE_URL: '/',
68
+ ...values,
69
+ };
70
+ // What the target's bundler substitutes. A key absent from this list is not replaced at build
71
+ // time and reaches the browser as `process.env.X` against an object that does not exist there.
72
+ env.FRONTEND_ENV_KEYS = Object.keys(env)
73
+ .filter(key => !FRONTEND_STANDARD_KEYS.has(key))
74
+ .join(',');
75
+ return env;
76
+ };
77
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/executor/env.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,kBAAkB,EACtE,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE1E;;;;;;;;;;;;GAYG;AAEH,yFAAyF;AACzF,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB;IACpF,UAAU,EAAE,mBAAmB,EAAE,WAAW;CAC7C,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,GAAW,EAAmC,EAAE;IAC/E,+FAA+F;IAC/F,gDAAgD;IAChD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,aAAa,CAAC,CAAA;IAEpD,OAAO;QACL,YAAY,EAAE,GAAG,eAAe,EAAE;QAClC,YAAY,EAAE,WAAW;QACzB,gBAAgB,EAAE,eAAe;QACjC,aAAa,EAAE,WAAW;QAC1B,aAAa,EAAE,GAAG,eAAe,EAAE;QACnC,QAAQ,EAAE,EAAE;QACZ,WAAW,EAAE,GAAG,kBAAkB,EAAE;QACpC,6FAA6F;QAC7F,yEAAyE;QACzE,GAAG,MAAM;KACV,CAAA;AACH,CAAC,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,GAAW,EAAmC,EAAE;IAChF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;IAEtD,MAAM,GAAG,GAA2B;QAClC,aAAa,EAAE,GAAG,eAAe,EAAE;QACnC,YAAY,EAAE,WAAW;QACzB,YAAY,EAAE,GAAG,eAAe,EAAE;QAClC,gBAAgB,EAAE,eAAe;QACjC,QAAQ,EAAE,GAAG;QACb,GAAG,MAAM;KACV,CAAA;IAED,8FAA8F;IAC9F,+FAA+F;IAC/F,GAAG,CAAC,iBAAiB,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;SACrC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAC/C,IAAI,CAAC,GAAG,CAAC,CAAA;IAEZ,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
@@ -0,0 +1,69 @@
1
+ import type { TargetIntegrityReport } from '@owlmeans/viable-common';
2
+ /**
3
+ * What the local executor throws, and why so little of it does.
4
+ *
5
+ * The publisher answers an ordinary command failure with a VALUE — error text in
6
+ * `SlotShellResult.result`, a report in the git answer — because the platform's remote helpers
7
+ * parse those shapes and a throw arrives as a transport failure with the diagnostics lost. The
8
+ * connector executes the same commands and is read by the same helpers, so it keeps that rule:
9
+ * everything here is for a condition the publisher ALSO throws on.
10
+ *
11
+ * Plain `Error` subclasses rather than `ResilientError` ones, for the same reason: these travel
12
+ * as an operation result the session marshals, and the publisher's equivalents are plain errors
13
+ * too — a class the platform has never seen would only widen what its catch has to know.
14
+ */
15
+ /**
16
+ * A path that resolved outside the project directory.
17
+ *
18
+ * Never a user's fault — always a caller's bug. On a developer's machine the blast radius is
19
+ * their whole home directory rather than a pod's volume, which is the one thing about this guard
20
+ * that is stricter here than in the publisher.
21
+ */
22
+ export declare class SandboxPathError extends Error {
23
+ readonly name = "SandboxPathError";
24
+ constructor(file: string);
25
+ }
26
+ /**
27
+ * A file command was asked for something it must refuse whatever the caller intended.
28
+ *
29
+ * Two conditions today, and both are about not destroying what is already there: a relocation into
30
+ * a directory that already holds files (the move would interleave two trees, and nothing
31
+ * afterwards could tell them apart), and a removal of the project root (which is `deleteProject`,
32
+ * a command with its own name and its own keep list).
33
+ *
34
+ * Thrown rather than answered, unlike the git refusals: those are policies a caller can plan
35
+ * around, and these two mean the caller's own arguments were wrong.
36
+ */
37
+ export declare class FileCommandRefused extends Error {
38
+ readonly name = "FileCommandRefused";
39
+ constructor(message: string);
40
+ }
41
+ /**
42
+ * A revert was asked for on a tree with uncommitted work in it.
43
+ *
44
+ * Thrown rather than answered, exactly as the platform's git service does: `RevertTo` answers a
45
+ * commit, so there is no field in its shape that could carry a refusal, and silently reverting
46
+ * over a person's uncommitted edits is the one outcome this operation must never have.
47
+ */
48
+ export declare class GitDirtyTree extends Error {
49
+ readonly name = "GitDirtyTree";
50
+ constructor(dir: string);
51
+ }
52
+ /** A git command failed in a way no answer shape can carry — an unresolvable hash, say. */
53
+ export declare class LocalGitError extends Error {
54
+ readonly name = "LocalGitError";
55
+ constructor(message: string);
56
+ }
57
+ /**
58
+ * The tree is not the generated application.
59
+ *
60
+ * Raised only where a caller asked for a verdict it cannot express as text; every build and shell
61
+ * path returns {@link integrityRefusal} instead, because that is the channel a failed build
62
+ * already travels on.
63
+ */
64
+ export declare class TargetIntegrityError extends Error {
65
+ readonly report: TargetIntegrityReport;
66
+ readonly name = "TargetIntegrityError";
67
+ constructor(report: TargetIntegrityReport);
68
+ }
69
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/executor/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAGpE;;;;;;;;;;;;GAYG;AAEH;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAyB,IAAI,sBAAqB;IAElD,YAAY,IAAI,EAAE,MAAM,EAEvB;CACF;AAED;;;;;;;;;;GAUG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,SAAyB,IAAI,wBAAuB;IAEpD,YAAY,OAAO,EAAE,MAAM,EAE1B;CACF;AAED;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAyB,IAAI,kBAAiB;IAE9C,YAAY,GAAG,EAAE,MAAM,EAEtB;CACF;AAED,2FAA2F;AAC3F,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAyB,IAAI,mBAAkB;IAE/C,YAAY,OAAO,EAAE,MAAM,EAE1B;CACF;AAED;;;;;;GAMG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;aAGjB,MAAM,EAAE,qBAAqB;IAFzD,SAAyB,IAAI,0BAAyB;IAEtD,YAA4B,MAAM,EAAE,qBAAqB,EAExD;CACF"}
@@ -0,0 +1,80 @@
1
+ import { formatIntegrityReport } from '@owlmeans/viable-common';
2
+ /**
3
+ * What the local executor throws, and why so little of it does.
4
+ *
5
+ * The publisher answers an ordinary command failure with a VALUE — error text in
6
+ * `SlotShellResult.result`, a report in the git answer — because the platform's remote helpers
7
+ * parse those shapes and a throw arrives as a transport failure with the diagnostics lost. The
8
+ * connector executes the same commands and is read by the same helpers, so it keeps that rule:
9
+ * everything here is for a condition the publisher ALSO throws on.
10
+ *
11
+ * Plain `Error` subclasses rather than `ResilientError` ones, for the same reason: these travel
12
+ * as an operation result the session marshals, and the publisher's equivalents are plain errors
13
+ * too — a class the platform has never seen would only widen what its catch has to know.
14
+ */
15
+ /**
16
+ * A path that resolved outside the project directory.
17
+ *
18
+ * Never a user's fault — always a caller's bug. On a developer's machine the blast radius is
19
+ * their whole home directory rather than a pod's volume, which is the one thing about this guard
20
+ * that is stricter here than in the publisher.
21
+ */
22
+ export class SandboxPathError extends Error {
23
+ name = 'SandboxPathError';
24
+ constructor(file) {
25
+ super(`Path escapes the sandbox: ${file}`);
26
+ }
27
+ }
28
+ /**
29
+ * A file command was asked for something it must refuse whatever the caller intended.
30
+ *
31
+ * Two conditions today, and both are about not destroying what is already there: a relocation into
32
+ * a directory that already holds files (the move would interleave two trees, and nothing
33
+ * afterwards could tell them apart), and a removal of the project root (which is `deleteProject`,
34
+ * a command with its own name and its own keep list).
35
+ *
36
+ * Thrown rather than answered, unlike the git refusals: those are policies a caller can plan
37
+ * around, and these two mean the caller's own arguments were wrong.
38
+ */
39
+ export class FileCommandRefused extends Error {
40
+ name = 'FileCommandRefused';
41
+ constructor(message) {
42
+ super(message);
43
+ }
44
+ }
45
+ /**
46
+ * A revert was asked for on a tree with uncommitted work in it.
47
+ *
48
+ * Thrown rather than answered, exactly as the platform's git service does: `RevertTo` answers a
49
+ * commit, so there is no field in its shape that could carry a refusal, and silently reverting
50
+ * over a person's uncommitted edits is the one outcome this operation must never have.
51
+ */
52
+ export class GitDirtyTree extends Error {
53
+ name = 'GitDirtyTree';
54
+ constructor(dir) {
55
+ super(`Working tree has uncommitted changes: ${dir}`);
56
+ }
57
+ }
58
+ /** A git command failed in a way no answer shape can carry — an unresolvable hash, say. */
59
+ export class LocalGitError extends Error {
60
+ name = 'LocalGitError';
61
+ constructor(message) {
62
+ super(message);
63
+ }
64
+ }
65
+ /**
66
+ * The tree is not the generated application.
67
+ *
68
+ * Raised only where a caller asked for a verdict it cannot express as text; every build and shell
69
+ * path returns {@link integrityRefusal} instead, because that is the channel a failed build
70
+ * already travels on.
71
+ */
72
+ export class TargetIntegrityError extends Error {
73
+ report;
74
+ name = 'TargetIntegrityError';
75
+ constructor(report) {
76
+ super(`The project in this directory is not a Viable application:\n${formatIntegrityReport(report)}`);
77
+ this.report = report;
78
+ }
79
+ }
80
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/executor/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAE/D;;;;;;;;;;;;GAYG;AAEH;;;;;;GAMG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChB,IAAI,GAAG,kBAAkB,CAAA;IAElD,YAAY,IAAY;QACtB,KAAK,CAAC,6BAA6B,IAAI,EAAE,CAAC,CAAA;IAC5C,CAAC;CACF;AAED;;;;;;;;;;GAUG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClB,IAAI,GAAG,oBAAoB,CAAA;IAEpD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;IAChB,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,YAAa,SAAQ,KAAK;IACZ,IAAI,GAAG,cAAc,CAAA;IAE9C,YAAY,GAAW;QACrB,KAAK,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAA;IACvD,CAAC;CACF;AAED,2FAA2F;AAC3F,MAAM,OAAO,aAAc,SAAQ,KAAK;IACb,IAAI,GAAG,eAAe,CAAA;IAE/C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;IAChB,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAGjB,MAAM;IAFT,IAAI,GAAG,sBAAsB,CAAA;IAEtD,YAA4B,MAA6B;QACvD,KAAK,CAAC,+DAA+D,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;sBAD3E,MAAM;IAElC,CAAC;CACF"}
@@ -0,0 +1,124 @@
1
+ import { SubProject } from '@owlmeans/viable-common';
2
+ import type { StatTreeResult } from '@owlmeans/viable-common';
3
+ /** What `readSource` and friends answer with — the shape the platform's file helpers parse. */
4
+ export interface LocalSourceFile {
5
+ path: string;
6
+ code?: string;
7
+ }
8
+ export interface SourceListOptions {
9
+ skipUIElements?: boolean;
10
+ excludes?: string[];
11
+ }
12
+ /**
13
+ * The target's files, as the platform asks for them.
14
+ *
15
+ * Shaped exactly like the publisher's `createFileHelper`, because the caller is the same code:
16
+ * the agent's remote helper sends a `SlotFileCommand` and parses one of these answers, and it has
17
+ * no way to know whether a pod or a laptop produced it.
18
+ */
19
+ export declare const createLocalFileHelper: (projectPath: string) => {
20
+ /**
21
+ * Wipe the project, keeping what the caller names and what is never ours to delete.
22
+ *
23
+ * The kept paths are project-relative and may be NESTED — `.agents/memory/history.md` is one
24
+ * the reinit pipeline passes, and `sources/web/.env` is one this helper adds itself. Matching
25
+ * them against top-level `readdir` names alone is what deleted the first: `.agents` matched
26
+ * nothing in the ignore set, so the whole harness tree went along with the one file the
27
+ * caller had explicitly asked to preserve — and nothing failed.
28
+ *
29
+ * So a directory is removed whole only when nothing kept lives under it; otherwise it is
30
+ * walked and pruned entry by entry.
31
+ */
32
+ emptyProject: (ignore?: string[]) => Promise<void>;
33
+ deleteProject: () => Promise<void>;
34
+ /**
35
+ * Finish an installed template: make sure the root manifest declares its workspaces.
36
+ *
37
+ * The agent pushes every template file itself, so this is only the finalizer. The workspace
38
+ * list is written only when the manifest does not already declare one — the template ships
39
+ * `["sources/*"]`, and injecting the explicit list beside it produced a manifest carrying the
40
+ * key TWICE, valid only because JSON keeps the last one.
41
+ */
42
+ initializeProject: () => Promise<void>;
43
+ getSourceList: (pattern?: string, options?: SourceListOptions) => Promise<string[]>;
44
+ getStructuredList: (patterns: string[]) => Promise<string[]>;
45
+ readFile: (path: string, notThrow?: boolean) => Promise<string>;
46
+ readSource: (filePath: string) => Promise<LocalSourceFile>;
47
+ readPossibleSource: (filePath: string) => Promise<LocalSourceFile>;
48
+ readSources: (files: string | string[]) => Promise<LocalSourceFile[]>;
49
+ writeFile: (filePath: string, content: string) => Promise<void>;
50
+ writeSource: (file: {
51
+ path: string;
52
+ code: string;
53
+ }) => Promise<void>;
54
+ deleteFile: (filePath: string, noThrow?: boolean) => Promise<void>;
55
+ /**
56
+ * The tree, one line per file, bounded.
57
+ *
58
+ * One command rather than a listing plus a read per entry: the caller is a census over a
59
+ * repository somebody else wrote, which may hold a hundred thousand files, and one round trip
60
+ * each — over a connector, on somebody's laptop — is not a slower walk but a walk that never
61
+ * finishes.
62
+ *
63
+ * `total` counts what the walk SAW and `entries` what it returned. They differ once the limit
64
+ * is reached, and that difference is the only thing that tells a caller its picture of the
65
+ * tree is partial: a listing that reported only its own length would be indistinguishable
66
+ * from a small repository.
67
+ *
68
+ * Every entry's `path` is relative to the directory ASKED FOR, not to the project root. That
69
+ * is the contract the in-process helper and the publisher answer, and one executor answering
70
+ * a different relativity is worse than either choice: the caller is a census that follows a
71
+ * listing with a `readHead` of what it listed, and nothing downstream knows which of the
72
+ * three produced the path it is holding.
73
+ */
74
+ statTree: (dir?: string, limit?: number) => Promise<StatTreeResult>;
75
+ /**
76
+ * The first bytes of one file, decoded as text.
77
+ *
78
+ * A classification reads a head; reading whole files to do it would hold a megabyte export in
79
+ * memory to look at its first line. Whatever the decoding produces for a binary head is the
80
+ * answer — that IS the signal an entropy classification wants, and cleaning it up would hide
81
+ * the one thing the caller is asking about.
82
+ */
83
+ readHead: (filePath: string, bytes: number) => Promise<string>;
84
+ /**
85
+ * Move everything in the project root under one directory, leaving a named few where they are.
86
+ *
87
+ * What makes a converted project possible: the origin's own tree goes below, a Viable target
88
+ * is grown above it, and the two never share a path. It is the same walk `emptyProject` does —
89
+ * kept paths may be nested, a directory holding one is walked rather than moved, and a
90
+ * directory left empty by that walk does not survive as a shell.
91
+ *
92
+ * The always-keep set applies here too and for the same reason: `.git` is the developer's
93
+ * history and moving it under the origin would take the project's whole history with it,
94
+ * `.viable` is how a later session recognizes the project, and the two `.env` files hold what
95
+ * the platform cannot re-derive.
96
+ *
97
+ * Refuses a destination that already holds something. A relocation into an occupied directory
98
+ * interleaves two trees, and nothing afterwards can tell which files came from where.
99
+ */
100
+ relocate: (dir: string, keep?: string[]) => Promise<{
101
+ moved: number;
102
+ kept: string[];
103
+ }>;
104
+ /**
105
+ * Delete a directory and everything under it — the purge of a relocated origin.
106
+ *
107
+ * Refuses the project root: emptying the project is `emptyProject`, which has a keep list this
108
+ * does not, and a purge that resolved to `.` would take the developer's `.git` and `.env` with
109
+ * the origin it was asked to remove.
110
+ */
111
+ removeTree: (dir: string) => Promise<void>;
112
+ getRootPath: (subproject?: SubProject) => string;
113
+ findFilesWithEnvVars: (frontend?: boolean) => Promise<string[]>;
114
+ };
115
+ export type LocalFileHelper = ReturnType<typeof createLocalFileHelper>;
116
+ /**
117
+ * The same confinement, for callers outside this helper.
118
+ *
119
+ * Exported because the configure push writes `.env` files by name and a path is a path: a guard
120
+ * that only the file commands apply is a guard on the file commands, and the connector holds the
121
+ * developer's home directory rather than a pod's volume.
122
+ */
123
+ export declare const confineToProject: (dir: string, file: string) => string;
124
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/executor/files.ts"],"names":[],"mappings":"AAKA,OAAO,EAE4E,UAAU,EAC5F,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAKvE,+FAA+F;AAC/F,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AA4CD;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,gBAAiB,MAAM;IAsDrD;;;;;;;;;;;OAWG;4BAC2B,MAAM,EAAE;;IAsCtC;;;;;;;OAOG;;gDA6BQ,iBAAiB,KACzB,OAAO,CAAC,MAAM,EAAE,CAAC;kCA6CgB,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,EAAE,CAAC;qBASzC,MAAM,yBAAqB,OAAO,CAAC,MAAM,CAAC;2BAWpC,MAAM,KAAG,OAAO,CAAC,eAAe,CAAC;mCAOzB,MAAM,KAAG,OAAO,CAAC,eAAe,CAAC;yBAQ3C,MAAM,GAAG,MAAM,EAAE,KAAG,OAAO,CAAC,eAAe,EAAE,CAAC;0BAY7C,MAAM,WAAW,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;wBAMzC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAG,OAAO,CAAC,IAAI,CAAC;2BAM3C,MAAM,wBAAmB,OAAO,CAAC,IAAI,CAAC;IAWnE;;;;;;;;;;;;;;;;;;OAkBG;qBACoB,MAAM,UAAU,MAAM,KAAG,OAAO,CAAC,cAAc,CAAC;IAyCvE;;;;;;;OAOG;yBACwB,MAAM,SAAS,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;IA2BlE;;;;;;;;;;;;;;;OAeG;oBACmB,MAAM,SAAS,MAAM,EAAE,KAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA6D1F;;;;;;OAMG;sBACqB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;+BAQnB,UAAU,KAAG,MAAM;sCAIN,OAAO,KAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CA+BtE,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAoCtE;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,QAAS,MAAM,QAAQ,MAAM,KAAG,MACU,CAAA"}