@lorepack/cli 0.0.0-stage → 0.1.0-alpha.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 (229) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/commands/activate.d.ts +20 -0
  3. package/dist/commands/activate.d.ts.map +1 -0
  4. package/dist/commands/activate.js +171 -0
  5. package/dist/commands/activate.js.map +1 -0
  6. package/dist/commands/build.d.ts +3 -0
  7. package/dist/commands/build.d.ts.map +1 -0
  8. package/dist/commands/build.js +53 -0
  9. package/dist/commands/build.js.map +1 -0
  10. package/dist/commands/config.d.ts +14 -0
  11. package/dist/commands/config.d.ts.map +1 -0
  12. package/dist/commands/config.js +109 -0
  13. package/dist/commands/config.js.map +1 -0
  14. package/dist/commands/connect.d.ts +5 -0
  15. package/dist/commands/connect.d.ts.map +1 -0
  16. package/dist/commands/connect.js +196 -0
  17. package/dist/commands/connect.js.map +1 -0
  18. package/dist/commands/deploy.d.ts +14 -0
  19. package/dist/commands/deploy.d.ts.map +1 -0
  20. package/dist/commands/deploy.js +248 -0
  21. package/dist/commands/deploy.js.map +1 -0
  22. package/dist/commands/dev.d.ts +25 -0
  23. package/dist/commands/dev.d.ts.map +1 -0
  24. package/dist/commands/dev.js +227 -0
  25. package/dist/commands/dev.js.map +1 -0
  26. package/dist/commands/diff.d.ts +3 -0
  27. package/dist/commands/diff.d.ts.map +1 -0
  28. package/dist/commands/diff.js +75 -0
  29. package/dist/commands/diff.js.map +1 -0
  30. package/dist/commands/doctor.d.ts +14 -0
  31. package/dist/commands/doctor.d.ts.map +1 -0
  32. package/dist/commands/doctor.js +96 -0
  33. package/dist/commands/doctor.js.map +1 -0
  34. package/dist/commands/export.d.ts +3 -0
  35. package/dist/commands/export.d.ts.map +1 -0
  36. package/dist/commands/export.js +126 -0
  37. package/dist/commands/export.js.map +1 -0
  38. package/dist/commands/index.d.ts +8 -0
  39. package/dist/commands/index.d.ts.map +1 -0
  40. package/dist/commands/index.js +51 -0
  41. package/dist/commands/index.js.map +1 -0
  42. package/dist/commands/init.d.ts +3 -0
  43. package/dist/commands/init.d.ts.map +1 -0
  44. package/dist/commands/init.js +95 -0
  45. package/dist/commands/init.js.map +1 -0
  46. package/dist/commands/inspect.d.ts +15 -0
  47. package/dist/commands/inspect.d.ts.map +1 -0
  48. package/dist/commands/inspect.js +527 -0
  49. package/dist/commands/inspect.js.map +1 -0
  50. package/dist/commands/mcp.d.ts +12 -0
  51. package/dist/commands/mcp.d.ts.map +1 -0
  52. package/dist/commands/mcp.js +219 -0
  53. package/dist/commands/mcp.js.map +1 -0
  54. package/dist/commands/pack.d.ts +9 -0
  55. package/dist/commands/pack.d.ts.map +1 -0
  56. package/dist/commands/pack.js +57 -0
  57. package/dist/commands/pack.js.map +1 -0
  58. package/dist/commands/plan.d.ts +3 -0
  59. package/dist/commands/plan.d.ts.map +1 -0
  60. package/dist/commands/plan.js +44 -0
  61. package/dist/commands/plan.js.map +1 -0
  62. package/dist/commands/prune.d.ts +7 -0
  63. package/dist/commands/prune.d.ts.map +1 -0
  64. package/dist/commands/prune.js +341 -0
  65. package/dist/commands/prune.js.map +1 -0
  66. package/dist/commands/search.d.ts +3 -0
  67. package/dist/commands/search.d.ts.map +1 -0
  68. package/dist/commands/search.js +84 -0
  69. package/dist/commands/search.js.map +1 -0
  70. package/dist/commands/serve.d.ts +20 -0
  71. package/dist/commands/serve.d.ts.map +1 -0
  72. package/dist/commands/serve.js +66 -0
  73. package/dist/commands/serve.js.map +1 -0
  74. package/dist/commands/status.d.ts +3 -0
  75. package/dist/commands/status.d.ts.map +1 -0
  76. package/dist/commands/status.js +27 -0
  77. package/dist/commands/status.js.map +1 -0
  78. package/dist/commands/target.d.ts +71 -0
  79. package/dist/commands/target.d.ts.map +1 -0
  80. package/dist/commands/target.js +945 -0
  81. package/dist/commands/target.js.map +1 -0
  82. package/dist/entry.d.ts +3 -0
  83. package/dist/entry.d.ts.map +1 -0
  84. package/dist/entry.js +19 -0
  85. package/dist/entry.js.map +1 -0
  86. package/dist/framework/context.d.ts +49 -0
  87. package/dist/framework/context.d.ts.map +1 -0
  88. package/dist/framework/context.js +47 -0
  89. package/dist/framework/context.js.map +1 -0
  90. package/dist/framework/exit.d.ts +36 -0
  91. package/dist/framework/exit.d.ts.map +1 -0
  92. package/dist/framework/exit.js +57 -0
  93. package/dist/framework/exit.js.map +1 -0
  94. package/dist/framework/metadata.d.ts +38 -0
  95. package/dist/framework/metadata.d.ts.map +1 -0
  96. package/dist/framework/metadata.js +47 -0
  97. package/dist/framework/metadata.js.map +1 -0
  98. package/dist/framework/program.d.ts +47 -0
  99. package/dist/framework/program.d.ts.map +1 -0
  100. package/dist/framework/program.js +189 -0
  101. package/dist/framework/program.js.map +1 -0
  102. package/dist/index.d.ts +7 -0
  103. package/dist/index.d.ts.map +1 -0
  104. package/dist/index.js +7 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/migrations/README.md +7 -0
  107. package/dist/migrations/build/0001_catalog.sql +85 -0
  108. package/dist/migrations/build/0002_tables.sql +43 -0
  109. package/dist/migrations/build/0003_table-cell-range.sql +13 -0
  110. package/dist/migrations/build/0004_chunk-page.sql +11 -0
  111. package/dist/migrations/state/0001_state.sql +40 -0
  112. package/dist/public-entry.js +38563 -0
  113. package/dist/public-entry.js.map +7 -0
  114. package/dist/public-index.js +36428 -0
  115. package/dist/public-index.js.map +7 -0
  116. package/dist/services/build.d.ts +48 -0
  117. package/dist/services/build.d.ts.map +1 -0
  118. package/dist/services/build.js +499 -0
  119. package/dist/services/build.js.map +1 -0
  120. package/dist/services/builds.d.ts +40 -0
  121. package/dist/services/builds.d.ts.map +1 -0
  122. package/dist/services/builds.js +184 -0
  123. package/dist/services/builds.js.map +1 -0
  124. package/dist/services/cancellation.d.ts +27 -0
  125. package/dist/services/cancellation.d.ts.map +1 -0
  126. package/dist/services/cancellation.js +41 -0
  127. package/dist/services/cancellation.js.map +1 -0
  128. package/dist/services/cloudflare-target.d.ts +38 -0
  129. package/dist/services/cloudflare-target.d.ts.map +1 -0
  130. package/dist/services/cloudflare-target.js +471 -0
  131. package/dist/services/cloudflare-target.js.map +1 -0
  132. package/dist/services/comparer.d.ts +15 -0
  133. package/dist/services/comparer.d.ts.map +1 -0
  134. package/dist/services/comparer.js +43 -0
  135. package/dist/services/comparer.js.map +1 -0
  136. package/dist/services/config-resolve.d.ts +60 -0
  137. package/dist/services/config-resolve.d.ts.map +1 -0
  138. package/dist/services/config-resolve.js +178 -0
  139. package/dist/services/config-resolve.js.map +1 -0
  140. package/dist/services/deploy.d.ts +70 -0
  141. package/dist/services/deploy.d.ts.map +1 -0
  142. package/dist/services/deploy.js +260 -0
  143. package/dist/services/deploy.js.map +1 -0
  144. package/dist/services/dev-session.d.ts +52 -0
  145. package/dist/services/dev-session.d.ts.map +1 -0
  146. package/dist/services/dev-session.js +102 -0
  147. package/dist/services/dev-session.js.map +1 -0
  148. package/dist/services/doctor.d.ts +35 -0
  149. package/dist/services/doctor.d.ts.map +1 -0
  150. package/dist/services/doctor.js +389 -0
  151. package/dist/services/doctor.js.map +1 -0
  152. package/dist/services/export.d.ts +20 -0
  153. package/dist/services/export.d.ts.map +1 -0
  154. package/dist/services/export.js +129 -0
  155. package/dist/services/export.js.map +1 -0
  156. package/dist/services/init.d.ts +46 -0
  157. package/dist/services/init.d.ts.map +1 -0
  158. package/dist/services/init.js +231 -0
  159. package/dist/services/init.js.map +1 -0
  160. package/dist/services/packing.d.ts +25 -0
  161. package/dist/services/packing.d.ts.map +1 -0
  162. package/dist/services/packing.js +69 -0
  163. package/dist/services/packing.js.map +1 -0
  164. package/dist/services/parse-cache.d.ts +47 -0
  165. package/dist/services/parse-cache.d.ts.map +1 -0
  166. package/dist/services/parse-cache.js +65 -0
  167. package/dist/services/parse-cache.js.map +1 -0
  168. package/dist/services/project.d.ts +49 -0
  169. package/dist/services/project.d.ts.map +1 -0
  170. package/dist/services/project.js +119 -0
  171. package/dist/services/project.js.map +1 -0
  172. package/dist/services/remote-prune.d.ts +7 -0
  173. package/dist/services/remote-prune.d.ts.map +1 -0
  174. package/dist/services/remote-prune.js +34 -0
  175. package/dist/services/remote-prune.js.map +1 -0
  176. package/dist/services/retention.d.ts +20 -0
  177. package/dist/services/retention.d.ts.map +1 -0
  178. package/dist/services/retention.js +106 -0
  179. package/dist/services/retention.js.map +1 -0
  180. package/dist/services/revalidate.d.ts +36 -0
  181. package/dist/services/revalidate.d.ts.map +1 -0
  182. package/dist/services/revalidate.js +73 -0
  183. package/dist/services/revalidate.js.map +1 -0
  184. package/dist/services/search.d.ts +25 -0
  185. package/dist/services/search.d.ts.map +1 -0
  186. package/dist/services/search.js +88 -0
  187. package/dist/services/search.js.map +1 -0
  188. package/dist/services/serving.d.ts +70 -0
  189. package/dist/services/serving.d.ts.map +1 -0
  190. package/dist/services/serving.js +240 -0
  191. package/dist/services/serving.js.map +1 -0
  192. package/dist/services/status.d.ts +54 -0
  193. package/dist/services/status.d.ts.map +1 -0
  194. package/dist/services/status.js +203 -0
  195. package/dist/services/status.js.map +1 -0
  196. package/dist/services/studio-assets.d.ts +13 -0
  197. package/dist/services/studio-assets.d.ts.map +1 -0
  198. package/dist/services/studio-assets.js +94 -0
  199. package/dist/services/studio-assets.js.map +1 -0
  200. package/dist/services/studio-diagnostics.d.ts +28 -0
  201. package/dist/services/studio-diagnostics.d.ts.map +1 -0
  202. package/dist/services/studio-diagnostics.js +88 -0
  203. package/dist/services/studio-diagnostics.js.map +1 -0
  204. package/dist/services/studio-endpoints.d.ts +61 -0
  205. package/dist/services/studio-endpoints.d.ts.map +1 -0
  206. package/dist/services/studio-endpoints.js +88 -0
  207. package/dist/services/studio-endpoints.js.map +1 -0
  208. package/dist/services/studio-mutations.d.ts +32 -0
  209. package/dist/services/studio-mutations.d.ts.map +1 -0
  210. package/dist/services/studio-mutations.js +149 -0
  211. package/dist/services/studio-mutations.js.map +1 -0
  212. package/dist/services/versions.d.ts +38 -0
  213. package/dist/services/versions.d.ts.map +1 -0
  214. package/dist/services/versions.js +46 -0
  215. package/dist/services/versions.js.map +1 -0
  216. package/dist/services/watch.d.ts +103 -0
  217. package/dist/services/watch.d.ts.map +1 -0
  218. package/dist/services/watch.js +420 -0
  219. package/dist/services/watch.js.map +1 -0
  220. package/package.json +73 -4
  221. package/studio-dist/assets/ibm-plex-mono-latin-400-normal-Dm_PoFIZ.woff2 +0 -0
  222. package/studio-dist/assets/ibm-plex-mono-latin-500-normal-C_OblDzq.woff2 +0 -0
  223. package/studio-dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  224. package/studio-dist/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  225. package/studio-dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  226. package/studio-dist/assets/index-BuAYbQVX.js +66 -0
  227. package/studio-dist/assets/index-C_3XEUt4.css +1 -0
  228. package/studio-dist/index.html +30 -0
  229. package/README.md +0 -3
@@ -0,0 +1,178 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { closestMatch, RUNTIME_LIMITS } from '@lorepack/core';
4
+ import { DEV_PORT } from './dev-session.js';
5
+ import { DEFAULT_REVALIDATE_INTERVAL_MS } from './revalidate.js';
6
+ /**
7
+ * Every resolved value, with the layer that supplied it and where that layer said it.
8
+ *
9
+ * Architecture 4.9 calls this transparent magic: defaults work, and nothing is hidden. The
10
+ * test of it is whether a user can find out what Lorepack decided without reading the
11
+ * source, which means a value is not enough. A number with no provenance still leaves them
12
+ * asking where it came from and what to edit.
13
+ *
14
+ * ## The distinction that matters most
15
+ *
16
+ * Some of these participate in the **build id** and some do not, and confusing the two is a
17
+ * expensive mistake in both directions. A value that decides what a build *contains*
18
+ * belongs in the hashed effective configuration; a value that decides how a build is
19
+ * *served* does not, and moving one in would change the identity of every build in
20
+ * existence for a number that decides nothing about what any of them hold.
21
+ *
22
+ * The Phase 3 audit on #4 called this out specifically for `RUNTIME_LIMITS`, ports and
23
+ * revalidation intervals. They are shown here, because a user asking "what did you decide"
24
+ * means all of it, and they are marked `buildId: false`.
25
+ */
26
+ /** Architecture 6.8, in precedence order, lowest first. */
27
+ export const LAYERS = ['defaults', 'project', 'targets', 'environment', 'flags'];
28
+ /** `LORE_`-prefixed, and deliberately a short list rather than a general override channel. */
29
+ export const ENVIRONMENT_KEYS = [
30
+ 'LORE_DEV_PORT',
31
+ 'LORE_REVALIDATE_INTERVAL_MS',
32
+ 'LORE_LOCK_WAIT_MS',
33
+ ];
34
+ /** Anything whose name looks like a credential is redacted rather than printed. */
35
+ const SECRET_PATTERN = /token|secret|password|key|credential/i;
36
+ export function resolveConfiguration(config, environment = process.env) {
37
+ const values = [];
38
+ const yamlText = existsSync(config.configPath) ? readFileSync(config.configPath, 'utf8') : '';
39
+ const declared = (path) => declaredIn(yamlText, path);
40
+ /**
41
+ * Which layer supplied a value, for a key the project file may or may not mention.
42
+ *
43
+ * Only two layers can supply these today: the built-in defaults and `lore.yaml`. The
44
+ * targets layer exists in the precedence order and has no content until Phase 6 adds
45
+ * deployment targets, which #57 says explicitly.
46
+ */
47
+ const fromProjectOrDefaults = (path, value, buildId) => declared(path)
48
+ ? { path, value, layer: 'project', source: config.configPath, buildId }
49
+ : { path, value, layer: 'defaults', source: 'built-in', buildId };
50
+ // Everything in the effective configuration participates in the build id, by construction:
51
+ // it *is* the hashed structure (architecture 11.4).
52
+ const effective = config.effective;
53
+ values.push({
54
+ path: 'name',
55
+ value: effective.name,
56
+ layer: 'project',
57
+ source: config.configPath,
58
+ buildId: true,
59
+ });
60
+ values.push(fromProjectOrDefaults('sources', effective.sources, true));
61
+ values.push(fromProjectOrDefaults('include', effective.include, true));
62
+ values.push(fromProjectOrDefaults('exclude', effective.exclude, true));
63
+ values.push(fromProjectOrDefaults('followSymlinks', effective.followSymlinks, true));
64
+ values.push(fromProjectOrDefaults('strictRules', effective.strictRules, true));
65
+ values.push(fromProjectOrDefaults('includeOriginals', effective.includeOriginals, true));
66
+ values.push(fromProjectOrDefaults('contextProfile', effective.contextProfile, true));
67
+ for (const [key, value] of Object.entries(effective.chunking)) {
68
+ values.push(fromProjectOrDefaults(`chunking.${key}`, value, true));
69
+ }
70
+ for (const [key, value] of Object.entries(effective.limits)) {
71
+ values.push(fromProjectOrDefaults(`limits.${key}`, value, true));
72
+ }
73
+ values.push({
74
+ path: 'defaultsVersion',
75
+ value: effective.defaultsVersion,
76
+ layer: 'defaults',
77
+ source: 'built-in',
78
+ buildId: true,
79
+ });
80
+ // Shown even when empty. It is part of the hashed structure whether or not anyone wrote a
81
+ // rule, and a display that claims to be complete cannot omit a value for being boring:
82
+ // "no rules" is exactly what a user checking why ranking looks wrong needs to see.
83
+ values.push({
84
+ path: 'rules',
85
+ value: effective.rules,
86
+ layer: effective.rules.length > 0 ? 'project' : 'defaults',
87
+ source: effective.rules.length > 0 ? config.configPath : 'built-in',
88
+ buildId: true,
89
+ });
90
+ // Serving bounds. Shown, because "what did you decide" means all of it, and marked as not
91
+ // participating, because a serving bound decides nothing about what a build contains.
92
+ for (const [key, value] of Object.entries(RUNTIME_LIMITS)) {
93
+ values.push(withEnvironment(`runtime.${key}`, value, environment, false));
94
+ }
95
+ values.push(withEnvironment('runtime.devPort', DEV_PORT, environment, false));
96
+ values.push(withEnvironment('runtime.revalidateIntervalMs', DEFAULT_REVALIDATE_INTERVAL_MS, environment, false));
97
+ return { projectRoot: config.projectRoot, values: values.sort(byPath) };
98
+ }
99
+ /** Applies the environment layer to one serving bound, when a `LORE_*` variable names it. */
100
+ function withEnvironment(path, fallback, environment, buildId) {
101
+ const variable = environmentKeyFor(path);
102
+ const raw = variable === null ? undefined : environment[variable];
103
+ if (variable === null || raw === undefined) {
104
+ return { path, value: fallback, layer: 'defaults', source: 'built-in', buildId };
105
+ }
106
+ const parsed = Number(raw);
107
+ return {
108
+ path,
109
+ value: Number.isFinite(parsed) ? parsed : raw,
110
+ layer: 'environment',
111
+ source: variable,
112
+ buildId,
113
+ ...(SECRET_PATTERN.test(variable) ? { secret: true } : {}),
114
+ };
115
+ }
116
+ function environmentKeyFor(path) {
117
+ if (path === 'runtime.devPort')
118
+ return 'LORE_DEV_PORT';
119
+ if (path === 'runtime.revalidateIntervalMs')
120
+ return 'LORE_REVALIDATE_INTERVAL_MS';
121
+ return null;
122
+ }
123
+ /**
124
+ * Whether `lore.yaml` mentions a key, without reimplementing YAML.
125
+ *
126
+ * A deliberately shallow test: it decides which *layer* to attribute a value to, and it is
127
+ * checked against the parsed configuration for the value itself. Being wrong here shows the
128
+ * wrong provenance, never the wrong number.
129
+ */
130
+ function declaredIn(yamlText, path) {
131
+ const [head, ...rest] = path.split('.');
132
+ if (head === undefined)
133
+ return false;
134
+ const topLevel = new RegExp(`^${escapeForRegExp(head)}\\s*:`, 'm');
135
+ if (!topLevel.test(yamlText))
136
+ return false;
137
+ if (rest.length === 0)
138
+ return true;
139
+ // A nested key, which in a project file is always indented under its parent.
140
+ const nested = new RegExp(`^\\s+${escapeForRegExp(rest.join('.'))}\\s*:`, 'm');
141
+ return nested.test(yamlText);
142
+ }
143
+ function escapeForRegExp(value) {
144
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
145
+ }
146
+ function byPath(left, right) {
147
+ return left.path < right.path ? -1 : left.path > right.path ? 1 : 0;
148
+ }
149
+ /** Redacted for display. Never the value, only the fact that there is one. */
150
+ export function displayValue(entry) {
151
+ if (entry.secret === true)
152
+ return '[redacted]';
153
+ if (Array.isArray(entry.value)) {
154
+ return entry.value.length === 0 ? '(none)' : entry.value.map((item) => String(item)).join(', ');
155
+ }
156
+ if (typeof entry.value === 'object' && entry.value !== null)
157
+ return JSON.stringify(entry.value);
158
+ return String(entry.value);
159
+ }
160
+ /**
161
+ * The closest known path to something a user typed.
162
+ *
163
+ * `closestMatch` lives in core because `lore.yaml` validation needs the same answer for an
164
+ * unrecognized key. Two implementations of "what did they probably mean" would give two
165
+ * different answers to the same typo.
166
+ *
167
+ * The threshold scales with the length here, because a configuration path is much longer
168
+ * than a top-level key and a fixed distance of three is nearly meaningless across
169
+ * `chunking.targetTokens`.
170
+ */
171
+ export function closestPath(wanted, known) {
172
+ return closestMatch(wanted, known, Math.max(2, Math.floor(wanted.length / 3)));
173
+ }
174
+ /** Where the targets layer will read from, once Phase 6 gives it something to say. */
175
+ export function targetsDirectory(projectRoot) {
176
+ return join(projectRoot, '.lore', 'targets');
177
+ }
178
+ //# sourceMappingURL=config-resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-resolve.js","sourceRoot":"","sources":["../../src/services/config-resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { type ActivationReceipt, type Capability, type DeploymentReceipt, type DeploymentTarget, type DeployPlan, type ProgressBus } from '@lorepack/core';
2
+ /**
3
+ * The deploy orchestration, shared by every target.
4
+ *
5
+ * Architecture section 16.3 lists the rules a target must obey, and this is where most of them
6
+ * are actually enforced. That split is deliberate: a rule a target has to remember is a rule
7
+ * some target will forget, and the one that forgets will be the one written last, by someone
8
+ * reading a different target as an example.
9
+ *
10
+ * So a target **reports** and this **decides**. A target says which capabilities it can serve;
11
+ * this refuses the deploy. A target says what its plan would do; this prints it and stops when
12
+ * asked. A target writes candidate data; this is what insists verification ran against the
13
+ * candidate before activation is even offered.
14
+ *
15
+ * Section 18.5 fixes the sequence:
16
+ *
17
+ * status -> plan -> build if dirty -> project candidate -> verify -> activate -> smoke -> receipt
18
+ *
19
+ * `build if dirty` belongs to the caller, because deploying is not the only thing that needs
20
+ * it and `--no-build` is a flag about the caller's intent rather than about the target.
21
+ */
22
+ export interface DeployOptions {
23
+ readonly target: DeploymentTarget;
24
+ readonly projectRoot: string;
25
+ readonly projectName: string;
26
+ readonly buildId: string;
27
+ readonly buildDirectory: string;
28
+ readonly buildCapabilities: readonly Capability[];
29
+ readonly progress: ProgressBus;
30
+ readonly plan?: DeployPlan;
31
+ /** Stop after printing the plan. Nothing remote is touched, which is the point. */
32
+ readonly dryRun?: boolean;
33
+ /**
34
+ * Capabilities the user has accepted losing, **by name**.
35
+ *
36
+ * Section 16.3 says a named override per capability, never a blanket `--force`. The
37
+ * difference matters: `--force` is a habit, and a habit that silently drops table queries
38
+ * from a deployment is exactly what capability negotiation exists to prevent.
39
+ */
40
+ readonly allowCapabilityLoss?: readonly Capability[];
41
+ /** A receipt to continue from, so a partial deploy resumes rather than restarts. */
42
+ readonly resume?: DeploymentReceipt;
43
+ /**
44
+ * Test-only hook for forcing a resumable failure after candidate projection completed.
45
+ *
46
+ * The hook lives at the orchestration boundary so acceptance can interrupt a real target
47
+ * after the projected receipt was written, while production callers omit it entirely.
48
+ */
49
+ readonly afterProject?: ((receipt: DeploymentReceipt) => Promise<void> | void) | undefined;
50
+ readonly now?: () => Date;
51
+ }
52
+ export interface DeployResult {
53
+ readonly receipt: DeploymentReceipt;
54
+ readonly plan: DeployPlan;
55
+ /** Absent on a dry run, which is how a caller knows nothing was activated. */
56
+ readonly activation?: ActivationReceipt;
57
+ readonly dryRun: boolean;
58
+ }
59
+ /** Where receipts live. Local, under `.lore/`, so a resume needs nothing remote to find. */
60
+ export declare function receiptsDirectory(projectRoot: string): string;
61
+ export declare function receiptPath(projectRoot: string, receiptId: string): string;
62
+ /**
63
+ * Reads a receipt to resume from, validated against the committed schema.
64
+ *
65
+ * Validated rather than trusted because a receipt is a file on disk that a person can edit,
66
+ * and a resume driven by a malformed one would replay the wrong steps against a live target.
67
+ */
68
+ export declare function readReceipt(projectRoot: string, receiptId: string): DeploymentReceipt;
69
+ export declare function runDeploy(options: DeployOptions): Promise<DeployResult>;
70
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/services/deploy.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAGf,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAKf,KAAK,WAAW,EAEjB,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,iBAAiB,EAAE,SAAS,UAAU,EAAE,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACrD,oFAAoF;IACpF,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3F,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,4FAA4F;AAC5F,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,iBAAiB,CAmBrF;AAeD,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CA0O7E"}
@@ -0,0 +1,260 @@
1
+ import { existsSync, mkdirSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { DEPLOY_STEPS, deploymentReceiptSchema, LORE_DIRECTORY, LoreError, writeFileAtomic, } from '@lorepack/core';
4
+ /** Where receipts live. Local, under `.lore/`, so a resume needs nothing remote to find. */
5
+ export function receiptsDirectory(projectRoot) {
6
+ return join(projectRoot, LORE_DIRECTORY, 'receipts');
7
+ }
8
+ export function receiptPath(projectRoot, receiptId) {
9
+ return join(receiptsDirectory(projectRoot), `${receiptId}.json`);
10
+ }
11
+ /**
12
+ * Reads a receipt to resume from, validated against the committed schema.
13
+ *
14
+ * Validated rather than trusted because a receipt is a file on disk that a person can edit,
15
+ * and a resume driven by a malformed one would replay the wrong steps against a live target.
16
+ */
17
+ export function readReceipt(projectRoot, receiptId) {
18
+ const path = receiptPath(projectRoot, receiptId);
19
+ if (!existsSync(path)) {
20
+ throw new LoreError('LORE_E_BUILD_NOT_FOUND', `No deployment receipt ${receiptId}.`, {
21
+ // Deliberately naming no command: `lorepack deploy` and `lorepack target` arrive with #91 and
22
+ // #85, and a remediation pointing at a command that does not exist is worse than one
23
+ // that describes the action. These become command names when those tickets land.
24
+ remediation: 'Check the receipt id, or deploy again from the start.',
25
+ subject: receiptId,
26
+ });
27
+ }
28
+ const parsed = deploymentReceiptSchema.safeParse(JSON.parse(readFileSync(path, 'utf8')));
29
+ if (!parsed.success) {
30
+ throw new LoreError('LORE_E_BUILD_VALIDATION', `Receipt ${receiptId} is not readable.`, {
31
+ remediation: 'Deploy again from the start. A receipt is a record, so losing one is safe.',
32
+ subject: receiptId,
33
+ });
34
+ }
35
+ return parsed.data;
36
+ }
37
+ function writeReceipt(projectRoot, receipt) {
38
+ mkdirSync(receiptsDirectory(projectRoot), { recursive: true });
39
+ writeFileAtomic(receiptPath(projectRoot, receipt.receiptId), `${JSON.stringify(receipt, null, 2)}\n`);
40
+ }
41
+ /** Steps already done, so a resume skips them rather than repeating a remote write. */
42
+ function done(receipt, step) {
43
+ return receipt?.completedSteps.includes(step) === true;
44
+ }
45
+ export async function runDeploy(options) {
46
+ const { target, progress } = options;
47
+ const now = options.now ?? (() => new Date());
48
+ const accepted = options.allowCapabilityLoss ?? [];
49
+ const detection = await target.detect();
50
+ if (!detection.installed) {
51
+ throw new LoreError('LORE_E_TARGET_NOT_CONFIGURED', `The ${target.id} target is not usable here: ${detection.reason ?? 'it reported no reason'}.`, {
52
+ remediation: `Set up the ${target.id} target before deploying to it.`,
53
+ subject: target.id,
54
+ });
55
+ }
56
+ // `validating` rather than a new stage name: the stage set is closed on purpose, and what
57
+ // planning does here is check a build against a target without changing either.
58
+ let plan = options.plan;
59
+ if (plan === undefined) {
60
+ progress.start('validating', 'Planning', 1);
61
+ plan = await target.plan({
62
+ projectName: options.projectName,
63
+ buildId: options.buildId,
64
+ buildDirectory: options.buildDirectory,
65
+ buildCapabilities: options.buildCapabilities,
66
+ });
67
+ progress.finish('validating', 1);
68
+ }
69
+ /**
70
+ * Capability loss fails by default, and the override is per capability.
71
+ *
72
+ * Checked here rather than in a target so it cannot be forgotten by one, and checked
73
+ * **before** anything is applied so the refusal costs nothing.
74
+ */
75
+ const unaccepted = plan.capabilityLoss.filter((capability) => !accepted.includes(capability));
76
+ if (unaccepted.length > 0) {
77
+ throw new LoreError('LORE_E_CAPABILITY_LOSS', `This build uses ${unaccepted.join(', ')}, which the ${target.id} target cannot serve.`, {
78
+ remediation: `Deploying would answer fewer questions than the local build does. Accept each one by name to continue: ${unaccepted
79
+ .map((capability) => `--allow-capability-loss ${capability}`)
80
+ .join(' ')}`,
81
+ details: { lost: unaccepted },
82
+ });
83
+ }
84
+ const receiptId = options.resume?.receiptId ?? `${target.id}-${options.buildId.slice(5, 17)}`;
85
+ let receipt = options.resume ?? {
86
+ formatVersion: 1,
87
+ receiptId,
88
+ target: target.id,
89
+ project: options.projectName,
90
+ buildId: options.buildId,
91
+ previousBuildId: null,
92
+ state: 'planned',
93
+ deployedAt: now().toISOString(),
94
+ endpoint: plan.endpoint,
95
+ capabilityLossAccepted: [...accepted],
96
+ completedSteps: ['plan'],
97
+ ...(plan.transfer === undefined ? {} : { transfer: plan.transfer }),
98
+ verification: { search: 'skipped', sourceRead: 'skipped', tableQuery: 'skipped' },
99
+ };
100
+ if (options.dryRun === true) {
101
+ // Deliberately not written to disk. A dry run that left a receipt behind would make
102
+ // `--resume` offer to continue something that never started.
103
+ return { receipt, plan, dryRun: true };
104
+ }
105
+ writeReceipt(options.projectRoot, receipt);
106
+ // Project the candidate. Build-scoped only, so nothing a reader can see changes yet.
107
+ if (!done(options.resume, 'project')) {
108
+ let projectionStarted = false;
109
+ let uploadStarted = false;
110
+ let projectionCompleted = 0;
111
+ let uploadCompleted = 0;
112
+ const reportApplyProgress = (update) => {
113
+ if (update.stage === 'projecting') {
114
+ if (!projectionStarted) {
115
+ progress.start('projecting', 'Projecting', update.total);
116
+ projectionStarted = true;
117
+ }
118
+ projectionCompleted = update.completed;
119
+ progress.progress('projecting', update.completed, {
120
+ ...(update.total === undefined ? {} : { total: update.total }),
121
+ ...(update.unit === undefined ? {} : { unit: update.unit }),
122
+ ...(update.detail === undefined ? {} : { detail: update.detail }),
123
+ });
124
+ return;
125
+ }
126
+ if (!uploadStarted) {
127
+ progress.start('uploading', 'Uploading', update.total);
128
+ uploadStarted = true;
129
+ }
130
+ uploadCompleted = update.completed;
131
+ progress.progress('uploading', update.completed, {
132
+ ...(update.total === undefined ? {} : { total: update.total }),
133
+ ...(update.unit === undefined ? {} : { unit: update.unit }),
134
+ ...(update.detail === undefined ? {} : { detail: update.detail }),
135
+ });
136
+ };
137
+ let applied;
138
+ try {
139
+ applied = await target.apply(plan, options.resume, reportApplyProgress);
140
+ }
141
+ catch (error) {
142
+ const partial = partialReceipt(error);
143
+ if (partial !== null)
144
+ writeReceipt(options.projectRoot, partial);
145
+ throw error;
146
+ }
147
+ /**
148
+ * Merged, not replaced. The orchestration owns what it decided.
149
+ *
150
+ * A target returns a receipt describing what it wrote, and taking it wholesale let it
151
+ * erase fields that are not its to set: the first version of this dropped
152
+ * `capabilityLossAccepted`, so a deploy that gave up a capability recorded that it had
153
+ * not. The same shape would let a target rewrite the build id or the accepted losses,
154
+ * which is precisely the "a target reports, this decides" split this file exists for.
155
+ */
156
+ receipt = {
157
+ ...applied,
158
+ buildId: receipt.buildId,
159
+ project: receipt.project,
160
+ target: receipt.target,
161
+ receiptId: receipt.receiptId,
162
+ capabilityLossAccepted: receipt.capabilityLossAccepted,
163
+ ...(applied.transfer === undefined && receipt.transfer !== undefined
164
+ ? { transfer: receipt.transfer }
165
+ : {}),
166
+ state: 'projected',
167
+ completedSteps: steps(applied, 'project'),
168
+ };
169
+ writeReceipt(options.projectRoot, receipt);
170
+ await options.afterProject?.(receipt);
171
+ progress.finish('projecting', projectionStarted ? projectionCompleted : plan.steps.length);
172
+ if (uploadStarted) {
173
+ progress.finish('uploading', uploadCompleted);
174
+ }
175
+ }
176
+ /**
177
+ * Verify the candidate, before activation is even offered.
178
+ *
179
+ * Section 16.3 says `verify` must query the candidate explicitly. The orchestration cannot
180
+ * check that a target did so, but it can guarantee the *order*: nothing is activated that
181
+ * was not verified first, and a verification that failed stops here with the previous build
182
+ * still serving.
183
+ */
184
+ if (!done(options.resume, 'verify')) {
185
+ progress.start('verifying', 'Verifying', 1);
186
+ const verification = await target.verify(receipt);
187
+ receipt = {
188
+ ...receipt,
189
+ state: 'verified',
190
+ ...(verification.capabilities === undefined
191
+ ? {}
192
+ : { verifiedCapabilities: [...verification.capabilities] }),
193
+ verification: {
194
+ search: verification.search,
195
+ sourceRead: verification.sourceRead,
196
+ tableQuery: verification.tableQuery,
197
+ },
198
+ completedSteps: steps(receipt, 'verify'),
199
+ };
200
+ writeReceipt(options.projectRoot, receipt);
201
+ progress.finish('verifying', 1);
202
+ const failed = Object.entries(receipt.verification)
203
+ .filter(([, outcome]) => outcome === 'failed')
204
+ .map(([what]) => what);
205
+ if (failed.length > 0) {
206
+ const failedReceipt = { ...receipt, state: 'failed' };
207
+ writeReceipt(options.projectRoot, failedReceipt);
208
+ throw new LoreError('LORE_E_REMOTE_DEPLOY', `The candidate failed verification: ${failed.join(', ')}.`, {
209
+ remediation: `Nothing was activated and the previous build is still serving. ${verification.failures?.join(' ') ?? ''}`.trim(),
210
+ details: { receiptId: receipt.receiptId, failed },
211
+ });
212
+ }
213
+ }
214
+ // The smallest possible pointer mutation, and the only step that changes what a reader sees.
215
+ progress.start('activating', 'Activating', 1);
216
+ const activation = await target.activate(receipt);
217
+ progress.finish('activating', 1);
218
+ const activatedReceipt = {
219
+ ...receipt,
220
+ previousBuildId: activation.previousBuildId,
221
+ endpoint: activation.endpoint,
222
+ completedSteps: steps(receipt, 'activate'),
223
+ };
224
+ /**
225
+ * The smoke check, which is the difference between "the write returned" and "it is serving".
226
+ *
227
+ * A target confirms by querying its own public endpoint, so a pointer that was written and
228
+ * not picked up is caught here rather than by a user. A target that cannot confirm returns
229
+ * null, and that is recorded rather than treated as success.
230
+ */
231
+ if (activation.confirmedBuildId !== null && activation.confirmedBuildId !== options.buildId) {
232
+ const failedReceipt = { ...activatedReceipt, state: 'failed' };
233
+ writeReceipt(options.projectRoot, failedReceipt);
234
+ throw new LoreError('LORE_E_REMOTE_DEPLOY', `The endpoint is serving ${activation.confirmedBuildId}, not the build that was just activated.`, {
235
+ remediation: 'The pointer was written but the endpoint did not pick it up. Check the target, then deploy again; the projected candidate is still there and will be reused.',
236
+ details: { expected: options.buildId, serving: activation.confirmedBuildId },
237
+ });
238
+ }
239
+ receipt = {
240
+ ...activatedReceipt,
241
+ state: 'active',
242
+ deployedAt: now().toISOString(),
243
+ completedSteps: steps(activatedReceipt, 'smoke'),
244
+ };
245
+ writeReceipt(options.projectRoot, receipt);
246
+ return { receipt, plan, activation, dryRun: false };
247
+ }
248
+ /** Appends a step once, in the order section 18.5 fixes, so a resume reads them back reliably. */
249
+ function steps(receipt, step) {
250
+ const present = new Set(receipt.completedSteps);
251
+ present.add(step);
252
+ return DEPLOY_STEPS.filter((known) => present.has(known));
253
+ }
254
+ function partialReceipt(error) {
255
+ if (typeof error !== 'object' || error === null || !('receipt' in error))
256
+ return null;
257
+ const parsed = deploymentReceiptSchema.safeParse(error.receipt);
258
+ return parsed.success ? parsed.data : null;
259
+ }
260
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/services/deploy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { type LoadedConfig } from '@lorepack/core';
2
+ /**
3
+ * The receipt a running `lorepack dev` leaves, so the session is discoverable rather than
4
+ * guessed at.
5
+ *
6
+ * Architecture 15.3 fixes the file and the preferred port. The reason it exists is that a
7
+ * dev server is the one long-lived thing Lorepack runs, and everything else that wants to
8
+ * talk to it (another command, a connector's generated config, the person who has forgotten
9
+ * which terminal it is in) otherwise has to scan ports and hope.
10
+ *
11
+ * A receipt is evidence, not a lock. The process it names may be gone, and a file left
12
+ * behind by a machine that lost power must not stop the next session from starting. So it
13
+ * carries a pid and is always checked against reality before it is believed.
14
+ */
15
+ export declare const DEV_PORT = 43110;
16
+ export declare const DEV_RECEIPT = "dev.json";
17
+ export interface DevReceipt {
18
+ readonly port: number;
19
+ readonly pid: number;
20
+ /** ISO 8601, for a person reading the file rather than for any comparison. */
21
+ readonly startedAt: string;
22
+ readonly buildId: string;
23
+ readonly host: string;
24
+ }
25
+ /**
26
+ * Written atomically, because a reader may arrive mid-write.
27
+ *
28
+ * A truncated receipt is worse than none: it names a port that is half a number, and the
29
+ * reader has no way to tell that from a session on a strange port. Rename is the one
30
+ * operation that is atomic on every filesystem this runs on.
31
+ */
32
+ export declare function writeReceipt(config: LoadedConfig, receipt: DevReceipt): void;
33
+ export declare function readReceipt(config: LoadedConfig): DevReceipt | null;
34
+ export declare function removeReceipt(config: LoadedConfig): void;
35
+ /**
36
+ * Whether the process a receipt names is still there.
37
+ *
38
+ * Signal `0` performs the permission and existence checks without delivering anything,
39
+ * which is the portable way to ask. `EPERM` means the process exists and belongs to someone
40
+ * else, which still counts as running.
41
+ */
42
+ export declare function isRunning(pid: number): boolean;
43
+ /**
44
+ * Refuses a second supervisor on the same project, and clears a receipt whose process died.
45
+ *
46
+ * Two supervisors on one project is not a race worth winning. They would both watch, both
47
+ * rebuild, and take turns failing to acquire the build lock, and the user would see a
48
+ * server that intermittently stalls for reasons nothing explains. Refusing with the port of
49
+ * the session that already exists is more useful than either of them starting.
50
+ */
51
+ export declare function assertNoLiveSession(config: LoadedConfig): void;
52
+ //# sourceMappingURL=dev-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-session.d.ts","sourceRoot":"","sources":["../../src/services/dev-session.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,gBAAgB,CAAC;AAE9D;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,WAAW,aAAa,CAAC;AAEtC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAMD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAM5E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,GAAG,IAAI,CAkBnE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ9C;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAmB9D"}