@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,173 @@
1
+ import p from 'node:path';
2
+ import { commandDeadline, SlotCommandType, SlotFileCommand, SlotGitCommand, SlotShellCommand } from '@owlmeans/viable-common';
3
+ import { createLocalFileHelper } from './files.js';
4
+ import { dispatchGitCommand } from './git.js';
5
+ import { forgetIntegrity, verifyTarget } from './integrity.js';
6
+ import { targetPaths } from './layout.js';
7
+ import { createLocalShellHelper } from './shell.js';
8
+ import { withDeadline } from './spawn.js';
9
+ export * from './errors.js';
10
+ export * from './layout.js';
11
+ export * from './integrity.js';
12
+ export * from './files.js';
13
+ export * from './env.js';
14
+ export * from './health.js';
15
+ export * from './boot-check.js';
16
+ export * from './shell.js';
17
+ export * from './git.js';
18
+ export { BUILD_TIMEOUT, MAX_OUTPUT_BUFFER, failureOutput, isAlive, killGroupAndWait, probeListening, runCommand, runScript, signalGroup, waitForPortFree, withDeadline } from './spawn.js';
19
+ /**
20
+ * Answer the platform's slot commands against a directory on this machine.
21
+ *
22
+ * The dispatcher is the publisher's, switch for switch, and that is the point: the platform's
23
+ * remote helpers parse the ANSWERS, and they have no way to know whether a pod or a laptop
24
+ * produced one. So an ordinary failure is never thrown here — it comes back in the same shape the
25
+ * publisher would have sent, error text and all — and only an unknown command, which is a
26
+ * protocol fault rather than a project fault, escapes as an exception.
27
+ *
28
+ * Everything is resolved per call rather than closed over: a re-initialization replaces the tree
29
+ * under a running connector, and a remembered layout would then resolve every path into a
30
+ * directory that no longer exists.
31
+ */
32
+ export const makeLocalSlotExecutor = (dir, opts = {}) => {
33
+ const root = p.resolve(dir);
34
+ const log = opts.log ?? (() => undefined);
35
+ const execute = async ({ type, command, args }) => {
36
+ const fileHelper = createLocalFileHelper(root);
37
+ const shellHelper = createLocalShellHelper(fileHelper, args?.subproject);
38
+ log(`Executing command [${type}]: ${command}`);
39
+ return await withDeadline(`${type}:${command}`, commandDeadline(type, command), async () => {
40
+ switch (type) {
41
+ case SlotCommandType.Files:
42
+ switch (command) {
43
+ case SlotFileCommand.EmptyProject:
44
+ await fileHelper.emptyProject(args?.ignore);
45
+ forgetIntegrity();
46
+ return {};
47
+ case SlotFileCommand.DeleteProject:
48
+ await fileHelper.deleteProject();
49
+ forgetIntegrity();
50
+ return {};
51
+ case SlotFileCommand.InitializeProject:
52
+ await fileHelper.initializeProject();
53
+ forgetIntegrity();
54
+ return {};
55
+ case SlotFileCommand.GetSourceList:
56
+ return await fileHelper.getSourceList(args?.pattern, args?.options);
57
+ case SlotFileCommand.GetStructuredList:
58
+ return await fileHelper.getStructuredList(args?.patterns);
59
+ case SlotFileCommand.ReadFile:
60
+ return { result: await fileHelper.readFile(args?.filePath, args?.noThrow) };
61
+ case SlotFileCommand.ReadSource:
62
+ return await fileHelper.readSource(args?.filePath);
63
+ case SlotFileCommand.ReadPossibleSource:
64
+ return await fileHelper.readPossibleSource(args?.filePath);
65
+ case SlotFileCommand.ReadSources:
66
+ return await fileHelper.readSources(args?.files);
67
+ case SlotFileCommand.WriteFile:
68
+ await fileHelper.writeFile(args?.filePath, args?.content);
69
+ forgetIntegrity();
70
+ return {};
71
+ case SlotFileCommand.WriteSource:
72
+ await fileHelper.writeSource(args?.file);
73
+ forgetIntegrity();
74
+ return {};
75
+ case SlotFileCommand.DeleteFile:
76
+ await fileHelper.deleteFile(args?.filePath, args?.noThrow);
77
+ forgetIntegrity();
78
+ return {};
79
+ case SlotFileCommand.StatTree:
80
+ return await fileHelper.statTree(args?.dir, args?.limit);
81
+ case SlotFileCommand.ReadHead:
82
+ // `{ result }`, exactly like ReadFile: the platform's remote helper reads one field
83
+ // for "the text of a file", and a second shape for the same thing would be a second
84
+ // parser to keep in step.
85
+ return { result: await fileHelper.readHead(args?.path, args?.bytes) };
86
+ case SlotFileCommand.Relocate: {
87
+ const result = await fileHelper.relocate(args?.dir, args?.keep);
88
+ forgetIntegrity();
89
+ return result;
90
+ }
91
+ case SlotFileCommand.RemoveTree:
92
+ await fileHelper.removeTree(args?.dir);
93
+ forgetIntegrity();
94
+ return {};
95
+ case SlotFileCommand.FindFilesWithEnvVars:
96
+ return await fileHelper.findFilesWithEnvVars(args?.frontend);
97
+ case SlotFileCommand.GetRootPath:
98
+ return { result: fileHelper.getRootPath(args?.subproject) };
99
+ default:
100
+ throw new Error(`Unknown command: ${command}`);
101
+ }
102
+ case SlotCommandType.Shell:
103
+ switch (command) {
104
+ case SlotShellCommand.Bun:
105
+ return { result: await shellHelper.bun(args?.args, args?.options) };
106
+ case SlotShellCommand.Reinstall:
107
+ // Lockfile cleared, then installed. A plain `bun install` here would reinstall
108
+ // exactly the versions already pinned on disk, which is the whole problem.
109
+ return { result: await shellHelper.reinstall() };
110
+ case SlotShellCommand.BuildCommon:
111
+ return { result: await shellHelper.buildCommon() };
112
+ case SlotShellCommand.Validate:
113
+ return { result: await shellHelper.validate(args?.subproject) };
114
+ case SlotShellCommand.ValidateWithRenderer:
115
+ return { result: await shellHelper.validateWithRenderer() };
116
+ case SlotShellCommand.Build: {
117
+ const result = await shellHelper.build();
118
+ // The tree changed, so the next spawn re-reads it rather than trusting the verdict
119
+ // this build was admitted on.
120
+ forgetIntegrity();
121
+ return { result };
122
+ }
123
+ case SlotShellCommand.ValidateBackend:
124
+ return { result: await shellHelper.validateBackend() };
125
+ case SlotShellCommand.DbSync:
126
+ return { result: await shellHelper.dbSync() };
127
+ case SlotShellCommand.BootCheck: {
128
+ const report = await shellHelper.bootCheck({
129
+ skipBuild: args?.skipBuild === true, wait: args?.wait === true,
130
+ });
131
+ // The shell contract is "error text or null", so a healthy boot reports null exactly
132
+ // like a clean build; `started` is what tells a caller to begin polling.
133
+ return report == null
134
+ ? { result: null, started: true }
135
+ : { result: report.ok ? null : report.error, phase: report.phase };
136
+ }
137
+ case SlotShellCommand.BootCheckStatus: {
138
+ const status = await shellHelper.bootCheckStatus();
139
+ return {
140
+ running: status.running,
141
+ startedAt: status.startedAt,
142
+ done: !status.running && status.report != null,
143
+ result: status.report == null || status.report.ok ? null : status.report.error,
144
+ phase: status.report?.phase ?? null,
145
+ };
146
+ }
147
+ case SlotShellCommand.Integrity:
148
+ return await shellHelper.integrity();
149
+ default:
150
+ throw new Error(`Unknown command: ${command}`);
151
+ }
152
+ case SlotCommandType.Git: {
153
+ const result = await dispatchGitCommand(root, command, args);
154
+ if (command === SlotGitCommand.Discard || command === SlotGitCommand.RevertTo) {
155
+ // Both rewrite the working tree wholesale, so the memoized verdict describes a tree
156
+ // that no longer exists.
157
+ forgetIntegrity();
158
+ }
159
+ return result;
160
+ }
161
+ default:
162
+ throw new Error(`Unknown command type: ${String(type)}`);
163
+ }
164
+ });
165
+ };
166
+ return {
167
+ execute,
168
+ layout: () => targetPaths(root),
169
+ integrity: async () => await verifyTarget(root),
170
+ dir: root,
171
+ };
172
+ };
173
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/executor/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { TargetFileMap, TargetIntegrityReport } from '@owlmeans/viable-common';
2
+ /** Read the manifest's files from a tree; a path that cannot be read comes back as `null`. */
3
+ export declare const readTargetFiles: (dir: string) => Promise<TargetFileMap>;
4
+ /** Verify the tree, reusing a verdict from the last couple of seconds. */
5
+ export declare const verifyTarget: (dir: string) => Promise<TargetIntegrityReport>;
6
+ /** Drop the memoized verdict — called wherever the connector itself changes the tree. */
7
+ export declare const forgetIntegrity: () => void;
8
+ /**
9
+ * The refusal text a build or shell command answers with, or `null` when the tree is fine.
10
+ *
11
+ * Text and not an exception, because "error text or null" is the contract every shell command
12
+ * already answers with — a caller needs no new branch to notice a refusal, and the diagnostics
13
+ * reach the person whose tree they belong to through the channel that already carries a failed
14
+ * build.
15
+ */
16
+ export declare const integrityRefusal: (dir: string, prefix?: string) => Promise<string | null>;
17
+ //# sourceMappingURL=integrity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.d.ts","sourceRoot":"","sources":["../../src/executor/integrity.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AA6BnF,8FAA8F;AAC9F,eAAO,MAAM,eAAe,QAAe,MAAM,KAAG,OAAO,CAAC,aAAa,CAKxE,CAAA;AAED,0EAA0E;AAC1E,eAAO,MAAM,YAAY,QAAe,MAAM,KAAG,OAAO,CAAC,qBAAqB,CAS7E,CAAA;AAED,yFAAyF;AACzF,eAAO,MAAM,eAAe,QAAO,IAA0B,CAAA;AAE7D;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,QAAe,MAAM,sBAAuB,OAAO,CAAC,MAAM,GAAG,IAAI,CAO7F,CAAA"}
@@ -0,0 +1,59 @@
1
+ import fs from 'fs-extra';
2
+ import p from 'node:path';
3
+ import { formatIntegrityReport, TARGET_INTEGRITY_FILES, verifyTargetShape } from '@owlmeans/viable-common';
4
+ /**
5
+ * Whether this directory still holds the generated application.
6
+ *
7
+ * The publisher is authoritative for a slot because it is the only process holding the volume at
8
+ * the moment of a spawn; on a developer's machine the connector is in exactly that position. What
9
+ * gets EXECUTED comes out of the tree — `bun run build` reads `scripts.build` from a
10
+ * `package.json` on disk, `bun install` runs whatever lifecycle hooks it declares, and
11
+ * `bun dist/index.js` runs whatever the build emitted — and here it runs as the developer, with
12
+ * their environment and their credentials in scope. So the check sits in front of every spawn,
13
+ * not in front of the callers somebody remembered to guard.
14
+ *
15
+ * Deliberately structural and model-free: thirty-odd file reads and a list of exact strings. The
16
+ * question is not whether a program is good; it is whether this tree is the one we generated.
17
+ */
18
+ /**
19
+ * How long a clean verdict is reused.
20
+ *
21
+ * Short on purpose. The check runs before every spawn — the build, the backend start, the boot
22
+ * check, every `bun` invocation — and several of those run back to back inside one operation. A
23
+ * longer window would let a write land between the check and the spawn it was meant to guard, so
24
+ * this is a de-duplication of one burst, not a cache.
25
+ */
26
+ const VERDICT_TTL_MS = 2_000;
27
+ let _cached = null;
28
+ /** Read the manifest's files from a tree; a path that cannot be read comes back as `null`. */
29
+ export const readTargetFiles = async (dir) => {
30
+ const entries = await Promise.all(TARGET_INTEGRITY_FILES.map(async (file) => [file, await fs.readFile(p.join(dir, file), 'utf-8').catch(() => null)]));
31
+ return Object.fromEntries(entries);
32
+ };
33
+ /** Verify the tree, reusing a verdict from the last couple of seconds. */
34
+ export const verifyTarget = async (dir) => {
35
+ if (_cached != null && _cached.root === dir && Date.now() - _cached.at < VERDICT_TTL_MS) {
36
+ return _cached.report;
37
+ }
38
+ const report = verifyTargetShape(await readTargetFiles(dir));
39
+ _cached = { at: Date.now(), root: dir, report };
40
+ return report;
41
+ };
42
+ /** Drop the memoized verdict — called wherever the connector itself changes the tree. */
43
+ export const forgetIntegrity = () => { _cached = null; };
44
+ /**
45
+ * The refusal text a build or shell command answers with, or `null` when the tree is fine.
46
+ *
47
+ * Text and not an exception, because "error text or null" is the contract every shell command
48
+ * already answers with — a caller needs no new branch to notice a refusal, and the diagnostics
49
+ * reach the person whose tree they belong to through the channel that already carries a failed
50
+ * build.
51
+ */
52
+ export const integrityRefusal = async (dir, prefix = 'Refused') => {
53
+ const report = await verifyTarget(dir);
54
+ return report.ok
55
+ ? null
56
+ : `${prefix}: the project in this directory is not a Viable application\n`
57
+ + formatIntegrityReport(report);
58
+ };
59
+ //# sourceMappingURL=integrity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.js","sourceRoot":"","sources":["../../src/executor/integrity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAA;AACzB,OAAO,CAAC,MAAM,WAAW,CAAA;AAEzB,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAG1G;;;;;;;;;;;;;GAaG;AAEH;;;;;;;GAOG;AACH,MAAM,cAAc,GAAG,KAAK,CAAA;AAE5B,IAAI,OAAO,GAAuE,IAAI,CAAA;AAEtF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,GAAW,EAA0B,EAAE;IAC3E,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,GAAG,CAAC,KAAK,EAAC,IAAI,EAAC,EAAE,CACxE,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAU,CAAC,CAAC,CAAA;IAEpF,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;AACpC,CAAC,CAAA;AAED,0EAA0E;AAC1E,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,GAAW,EAAkC,EAAE;IAChF,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,cAAc,EAAE,CAAC;QACxF,OAAO,OAAO,CAAC,MAAM,CAAA;IACvB,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC,CAAA;IAC5D,OAAO,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,CAAA;IAE/C,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED,yFAAyF;AACzF,MAAM,CAAC,MAAM,eAAe,GAAG,GAAS,EAAE,GAAG,OAAO,GAAG,IAAI,CAAA,CAAC,CAAC,CAAA;AAE7D;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,GAAW,EAAE,MAAM,GAAG,SAAS,EAA0B,EAAE;IAChG,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAA;IAEtC,OAAO,MAAM,CAAC,EAAE;QACd,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,GAAG,MAAM,+DAA+D;cACtE,qBAAqB,CAAC,MAAM,CAAC,CAAA;AACrC,CAAC,CAAA"}
@@ -0,0 +1,61 @@
1
+ import { TargetLayout } from '@owlmeans/viable-common';
2
+ import type { SubProject, TargetPaths } from '@owlmeans/viable-common';
3
+ /**
4
+ * Read the directory and say which layout its target project has.
5
+ *
6
+ * An empty or half-installed tree answers `V1`, matching the publisher: a project that has not
7
+ * been initialized yet resolves the paths it always did, and the answer flips by itself the
8
+ * moment a v2 tree lands.
9
+ *
10
+ * Deliberately un-memoized. It is two `stat`s against a page cache the process touches
11
+ * constantly, while a re-initialization replaces the tree wholesale under a running connector —
12
+ * a remembered verdict would then resolve every path into a directory that no longer exists,
13
+ * with a `posix_spawn` ENOENT as the only symptom.
14
+ */
15
+ export declare const detectLayout: (dir: string) => TargetLayout;
16
+ /** Where every role lives in this directory's target project. */
17
+ export declare const targetPaths: (dir: string) => TargetPaths;
18
+ /** Absolute path of the package that runs as the target's HTTP server. */
19
+ export declare const apiPath: (dir: string) => string;
20
+ /** Absolute path of the package whose `dist/` is served to a browser. */
21
+ export declare const webPath: (dir: string) => string;
22
+ /**
23
+ * Absolute path of the package that runs as the target's queue worker, or `null` when this
24
+ * layout has no such package at all.
25
+ *
26
+ * A path, not a verdict: it answers where a worker WOULD live and says nothing about whether one
27
+ * is there. {@link hasWorker} is the disk read.
28
+ */
29
+ export declare const workerPath: (dir: string) => string | null;
30
+ /**
31
+ * Whether this target project has a queue worker.
32
+ *
33
+ * Read from disk rather than from a record, for the same reason the layout is: what runs is
34
+ * whatever was generated, a re-initialization can replace it under a running connector, and a
35
+ * remembered answer would supervise a package that is no longer there — or miss one that has
36
+ * just arrived. The manifest and not the directory, because a half-finished install leaves the
37
+ * directory behind.
38
+ */
39
+ export declare const hasWorker: (dir: string) => boolean;
40
+ /**
41
+ * Resolve a wire-level subproject role to the directory it names in this tree.
42
+ *
43
+ * `SubProject` is a ROLE and stays one: the vocabulary on the wire is not rewritten, it is
44
+ * mapped, per layout. An unknown value — a role from a platform newer than this connector —
45
+ * falls back to the role's own name, which fails visibly rather than resolving to some other
46
+ * package's directory.
47
+ */
48
+ export declare const subprojectDir: (dir: string, role: SubProject) => string;
49
+ /**
50
+ * Absolute paths of the packages that must be built before anything that imports them, in
51
+ * dependency order — see `TargetPaths.libraries`.
52
+ *
53
+ * Every bundled package keeps its dependencies external, so `<slug>-common` and (on v2)
54
+ * `<slug>-backend` are resolved from `node_modules` at RUN time and followed to their `main`.
55
+ * Nothing else builds them: the api, web and worker builds each run inside their own directory.
56
+ * Missing directories are dropped — a build spawned into one that does not exist reports
57
+ * `ENOENT … posix_spawn '/bin/sh'`, which blames the toolchain for a tree that is simply
58
+ * incomplete.
59
+ */
60
+ export declare const libraryPaths: (dir: string) => string[];
61
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/executor/layout.ts"],"names":[],"mappings":"AAGA,OAAO,EAA4C,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAChG,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAkBtE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,QAAS,MAAM,KAAG,YAQ1C,CAAA;AAED,iEAAiE;AACjE,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,WAAyC,CAAA;AAEnF,0EAA0E;AAC1E,eAAO,MAAM,OAAO,QAAS,MAAM,KAAG,MAIrC,CAAA;AAED,yEAAyE;AACzE,eAAO,MAAM,OAAO,QAAS,MAAM,KAAG,MAIrC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,QAAS,MAAM,KAAG,MAAM,GAAG,IAIjD,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,QAAS,MAAM,KAAG,OAIvC,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,QAAS,MAAM,QAAQ,UAAU,KAAG,MACpB,CAAA;AAE1C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,QAAS,MAAM,KAAG,MAAM,EAMhD,CAAA"}
@@ -0,0 +1,98 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { LAYOUT_MARKERS, LAYOUTS, subprojectDirOf, TargetLayout } from '@owlmeans/viable-common';
4
+ /**
5
+ * Where a target project's packages live, in THIS directory.
6
+ *
7
+ * The tables — which role is which directory, what a full build runs, which packages must be
8
+ * built before anything imports them — belong to `@owlmeans/viable-common`, because the publisher
9
+ * answers the same questions over a pod volume. What lives here is the pair of filesystem probes
10
+ * that pick a layout and turn a package name into an absolute path.
11
+ *
12
+ * Platform vs target: this describes a TARGET project's directory shape. Nothing about the SDK's
13
+ * own repository is v1 or v2.
14
+ */
15
+ const MARKERS = LAYOUT_MARKERS.map(([layout, marker]) => [layout, path.join(...marker.split('/'))]);
16
+ /**
17
+ * Read the directory and say which layout its target project has.
18
+ *
19
+ * An empty or half-installed tree answers `V1`, matching the publisher: a project that has not
20
+ * been initialized yet resolves the paths it always did, and the answer flips by itself the
21
+ * moment a v2 tree lands.
22
+ *
23
+ * Deliberately un-memoized. It is two `stat`s against a page cache the process touches
24
+ * constantly, while a re-initialization replaces the tree wholesale under a running connector —
25
+ * a remembered verdict would then resolve every path into a directory that no longer exists,
26
+ * with a `posix_spawn` ENOENT as the only symptom.
27
+ */
28
+ export const detectLayout = (dir) => {
29
+ for (const [layout, marker] of MARKERS) {
30
+ if (fs.existsSync(path.join(dir, marker))) {
31
+ return layout;
32
+ }
33
+ }
34
+ return TargetLayout.V1;
35
+ };
36
+ /** Where every role lives in this directory's target project. */
37
+ export const targetPaths = (dir) => LAYOUTS[detectLayout(dir)];
38
+ /** Absolute path of the package that runs as the target's HTTP server. */
39
+ export const apiPath = (dir) => {
40
+ const paths = targetPaths(dir);
41
+ return path.resolve(dir, paths.dir, paths.api);
42
+ };
43
+ /** Absolute path of the package whose `dist/` is served to a browser. */
44
+ export const webPath = (dir) => {
45
+ const paths = targetPaths(dir);
46
+ return path.resolve(dir, paths.dir, paths.web);
47
+ };
48
+ /**
49
+ * Absolute path of the package that runs as the target's queue worker, or `null` when this
50
+ * layout has no such package at all.
51
+ *
52
+ * A path, not a verdict: it answers where a worker WOULD live and says nothing about whether one
53
+ * is there. {@link hasWorker} is the disk read.
54
+ */
55
+ export const workerPath = (dir) => {
56
+ const paths = targetPaths(dir);
57
+ return paths.worker == null ? null : path.resolve(dir, paths.dir, paths.worker);
58
+ };
59
+ /**
60
+ * Whether this target project has a queue worker.
61
+ *
62
+ * Read from disk rather than from a record, for the same reason the layout is: what runs is
63
+ * whatever was generated, a re-initialization can replace it under a running connector, and a
64
+ * remembered answer would supervise a package that is no longer there — or miss one that has
65
+ * just arrived. The manifest and not the directory, because a half-finished install leaves the
66
+ * directory behind.
67
+ */
68
+ export const hasWorker = (dir) => {
69
+ const worker = workerPath(dir);
70
+ return worker != null && fs.existsSync(path.join(worker, 'package.json'));
71
+ };
72
+ /**
73
+ * Resolve a wire-level subproject role to the directory it names in this tree.
74
+ *
75
+ * `SubProject` is a ROLE and stays one: the vocabulary on the wire is not rewritten, it is
76
+ * mapped, per layout. An unknown value — a role from a platform newer than this connector —
77
+ * falls back to the role's own name, which fails visibly rather than resolving to some other
78
+ * package's directory.
79
+ */
80
+ export const subprojectDir = (dir, role) => subprojectDirOf(detectLayout(dir), role);
81
+ /**
82
+ * Absolute paths of the packages that must be built before anything that imports them, in
83
+ * dependency order — see `TargetPaths.libraries`.
84
+ *
85
+ * Every bundled package keeps its dependencies external, so `<slug>-common` and (on v2)
86
+ * `<slug>-backend` are resolved from `node_modules` at RUN time and followed to their `main`.
87
+ * Nothing else builds them: the api, web and worker builds each run inside their own directory.
88
+ * Missing directories are dropped — a build spawned into one that does not exist reports
89
+ * `ENOENT … posix_spawn '/bin/sh'`, which blames the toolchain for a tree that is simply
90
+ * incomplete.
91
+ */
92
+ export const libraryPaths = (dir) => {
93
+ const paths = targetPaths(dir);
94
+ return paths.libraries
95
+ .map(pkg => path.resolve(dir, paths.dir, pkg))
96
+ .filter(library => fs.existsSync(library));
97
+ };
98
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/executor/layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import { SubProject } from '@owlmeans/viable-common';
2
+ import type { SlotShellResult } from '@owlmeans/viable-common';
3
+ import type { BootCheckReport, BootCheckStatus } from './boot-check.js';
4
+ import type { LocalFileHelper } from './files.js';
5
+ /**
6
+ * The shell half of the local executor — every `SlotShellCommand`, against a directory.
7
+ *
8
+ * The contract every method answers with is the publisher's: **error text, or `null` for
9
+ * success**. It is not a transcript — a command that fails returns the diagnostics a fixer or a
10
+ * person can act on, and a command that succeeds returns nothing at all.
11
+ */
12
+ /**
13
+ * The one reason a script refuses that is NOT a verdict about the code.
14
+ *
15
+ * A build with nothing to build on is an ordinary no-op that the next trigger repeats correctly —
16
+ * it happens between attaching to a fresh clone and the first install. It must not be reported as
17
+ * a failed build, or the connector announces broken code during a window in which nothing was
18
+ * even attempted.
19
+ */
20
+ export declare const NOT_INSTALLED_REASON = "cannot run: the target's dependencies are not installed yet";
21
+ /** Whether a refusal describes the code, or merely a window in which nothing ran. */
22
+ export declare const isBuildVerdict: (reason: string | null) => boolean;
23
+ export declare const createLocalShellHelper: (fileHelper: LocalFileHelper, subproject?: SubProject) => {
24
+ bun: (args?: string, options?: {
25
+ subproject?: SubProject;
26
+ }) => Promise<string | null>;
27
+ /**
28
+ * Throw the lockfile away and install again.
29
+ *
30
+ * The truncate is the point. `bun install` on its own reproduces whatever the lockfile says,
31
+ * and a target's lockfile was written the day the project was created — so a framework
32
+ * package republished afterwards is invisible to it no matter how often the target is
33
+ * rebuilt. Emptied rather than deleted, matching initialization: bun reads an empty file as
34
+ * "no lockfile", so a failed install leaves a state the next attempt resolves cleanly instead
35
+ * of one where a stale lock has come back.
36
+ */
37
+ reinstall: () => Promise<string | null>;
38
+ buildCommon: () => Promise<string | null>;
39
+ validate: (subprojectOverride?: SubProject) => Promise<string | null>;
40
+ /** The buildability check for the UI: the browser bundle really built, or the reason it did not. */
41
+ validateWithRenderer: () => Promise<string | null>;
42
+ /**
43
+ * Rebuild the whole target, in dependency order.
44
+ *
45
+ * The libraries first, because everything else resolves them from `node_modules` at RUN time
46
+ * and follows each to its `build/index.js` — a bundle built before them starts with
47
+ * `Cannot find package '<slug>-backend'`, a message about a dependency for a build that never
48
+ * happened. The remaining three are independent, so all of them run and their problems are
49
+ * reported together rather than one round trip at a time.
50
+ */
51
+ build: () => Promise<string | null>;
52
+ /** Build the api only — the type check the frontend renderer build cannot give it. */
53
+ validateBackend: () => Promise<string | null>;
54
+ /**
55
+ * Reconcile the target's database with its code.
56
+ *
57
+ * The target owns its own structure: every `@owlmeans/postgres` resource creates and updates
58
+ * its table while the context initializes. So a sync is not a command run against the source
59
+ * tree — it is *check that the database is there, then restart the backend* — and there is
60
+ * nothing to generate and no migration file to apply.
61
+ *
62
+ * A local target's database is the developer's. The platform provisions none, so an absent
63
+ * URL is reported by NAME rather than repaired: it is a line the person has to write, and
64
+ * "database unavailable" would send them looking at a server instead.
65
+ */
66
+ dbSync: () => Promise<string | null>;
67
+ /**
68
+ * Answering, not enforcing.
69
+ *
70
+ * The connector refuses on its own before every spawn regardless; this exists so a caller can
71
+ * ask BEFORE letting a merge reach a build, and report the violations to the person whose
72
+ * repository they belong to.
73
+ */
74
+ integrity: () => Promise<SlotShellResult>;
75
+ /**
76
+ * Start a real boot in isolation and return at once.
77
+ *
78
+ * A second start joins the running check rather than spawning another instance onto the port.
79
+ * The verdict is read with {@link bootCheckStatus}; `wait` is the legacy blocking path for a
80
+ * caller that predates the job.
81
+ */
82
+ bootCheck: (options?: {
83
+ skipBuild?: boolean;
84
+ wait?: boolean;
85
+ }) => Promise<BootCheckReport | null>;
86
+ bootCheckStatus: () => Promise<BootCheckStatus>;
87
+ };
88
+ export type LocalShellHelper = ReturnType<typeof createLocalShellHelper>;
89
+ //# sourceMappingURL=shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/executor/shell.ts"],"names":[],"mappings":"AAIA,OAAO,EACkB,UAAU,EAElC,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAK9D,OAAO,KAAK,EAAgB,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAErF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAKjD;;;;;;GAMG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,gEAAgE,CAAA;AAEjG,qFAAqF;AACrF,eAAO,MAAM,cAAc,WAAY,MAAM,GAAG,IAAI,KAAG,OACG,CAAA;AAqB1D,eAAO,MAAM,sBAAsB,eAAgB,eAAe,eAAe,UAAU;iBA+EpE,MAAM,YAAY;QAAE,UAAU,CAAC,EAAE,UAAU,CAAA;KAAE,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IASzF;;;;;;;;;OASG;qBACkB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;uBAapB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;oCAOP,UAAU,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAgBzE,oGAAoG;gCACpE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAGtD;;;;;;;;OAQG;iBACc,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAevC,sFAAsF;2BAC3D,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAGjD;;;;;;;;;;;OAWG;kBACe,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAoBxC;;;;;;OAMG;qBACkB,OAAO,CAAC,eAAe,CAAC;IAU7C;;;;;;OAMG;0BAEQ;QAAE,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KAC/C,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;2BA0CP,OAAO,CAAC,eAAe,CAAC;CAItD,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAA"}