genesis-compiler 1.2.9 → 1.2.11
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.
- package/README.md +1 -1
- package/docs/stack-components.md +14 -0
- package/package.json +1 -1
- package/plugins/genesis/.codex-plugin/plugin.json +1 -1
- package/src/index/code-index.js +13 -0
- package/src/index/codex-hooks.js +10 -1
- package/src/index/contracts.js +2 -1
- package/src/index/deployment.js +1 -0
- package/src/index/stack-deployment.js +59 -4
- package/src/index.js +10 -2
package/README.md
CHANGED
|
@@ -510,7 +510,7 @@ executing or provisioning it.
|
|
|
510
510
|
|
|
511
511
|
Normalized operational results identify their stable public contract in the
|
|
512
512
|
`contract` field: `genesis.workspace-setup.v1`, `genesis.environment.v1`,
|
|
513
|
-
`genesis.launch.v1`, `genesis.deployment.
|
|
513
|
+
`genesis.launch.v1`, `genesis.deployment.v2`, or
|
|
514
514
|
`genesis.verification.v1`. Hosts validate that identity instead of
|
|
515
515
|
feature-detecting individual fields.
|
|
516
516
|
|
package/docs/stack-components.md
CHANGED
|
@@ -257,6 +257,7 @@ complete form is:
|
|
|
257
257
|
|
|
258
258
|
- Workdir: `.`
|
|
259
259
|
- Runtimes: `nodejs`
|
|
260
|
+
- Recreate on restore: `node_modules`
|
|
260
261
|
- Ready when: `GET` `/api/health` returns `200`
|
|
261
262
|
- Prepare `Install production dependencies`: `npm` `install` `--omit=dev`
|
|
262
263
|
- Build `Build`: `npm` `run` `build`
|
|
@@ -270,6 +271,19 @@ Prepare, Build, and Migrate steps are optional and retain their declared order.
|
|
|
270
271
|
There is exactly one final Serve step and one exact HTTP readiness predicate
|
|
271
272
|
whose successful status is from 200 through 399. Runtime ids remain abstract.
|
|
272
273
|
|
|
274
|
+
`Recreate on restore` lists project-relative paths that a host may remove when
|
|
275
|
+
retaining an inactive release. Every listed path must be completely recreated
|
|
276
|
+
by the Deployment Prepare steps, which a host runs after restoring the release
|
|
277
|
+
and before Serve. Declaring these paths without a Prepare step is invalid.
|
|
278
|
+
An entry without `/` matches that path segment at every depth, so
|
|
279
|
+
`node_modules` covers root and nested workspace dependency trees. `*` stays
|
|
280
|
+
within one segment and `**` may cross path separators. A matched directory
|
|
281
|
+
includes its complete subtree.
|
|
282
|
+
This is application and Stack knowledge: for example, JSKIT declares
|
|
283
|
+
`node_modules`, while compiled output such as `dist` remains part of the
|
|
284
|
+
artifact because Prepare does not rebuild it. Genesis normalizes the paths but
|
|
285
|
+
does not remove, archive, restore, or reconstruct anything itself.
|
|
286
|
+
|
|
273
287
|
A project `## Deployment` section replaces every component recipe as one unit,
|
|
274
288
|
including with `- Nothing.`. Without a project section, exactly one selected
|
|
275
289
|
component recipe may apply; several are blocked as ambiguous and never merged.
|
package/package.json
CHANGED
package/src/index/code-index.js
CHANGED
|
@@ -15,6 +15,19 @@ import { sha256, stableJson, writeFileAtomic } from './utils.js';
|
|
|
15
15
|
export const MACHINE_CITY_PATH = '.genesis/machine-city.json';
|
|
16
16
|
export const PROGRAM_CITY_PATH = '.genesis/program-city.json';
|
|
17
17
|
|
|
18
|
+
export const GENESIS_DERIVED_ARTIFACTS = Object.freeze([
|
|
19
|
+
Object.freeze({
|
|
20
|
+
id: 'machine-city',
|
|
21
|
+
path: MACHINE_CITY_PATH,
|
|
22
|
+
recreator: 'index-codebase',
|
|
23
|
+
}),
|
|
24
|
+
Object.freeze({
|
|
25
|
+
id: 'program-city',
|
|
26
|
+
path: PROGRAM_CITY_PATH,
|
|
27
|
+
recreator: 'index-codebase',
|
|
28
|
+
}),
|
|
29
|
+
]);
|
|
30
|
+
|
|
18
31
|
const INDEXERS = astGrepCodeIndexers;
|
|
19
32
|
|
|
20
33
|
function directoryId(value) {
|
package/src/index/codex-hooks.js
CHANGED
|
@@ -250,10 +250,19 @@ async function changedProjectPaths(projectRoot, before, after) {
|
|
|
250
250
|
const dirtyChanges = [...new Set([...previous.keys(), ...current.keys()])].filter((file) => (
|
|
251
251
|
stableJson(previous.get(file)) !== stableJson(current.get(file))
|
|
252
252
|
));
|
|
253
|
-
|
|
253
|
+
const candidates = [...new Set([
|
|
254
254
|
...dirtyChanges,
|
|
255
255
|
...await committedPaths(projectRoot, before.head, after.head),
|
|
256
256
|
])].sort();
|
|
257
|
+
const changed = await Promise.all(candidates.map(async (file) => {
|
|
258
|
+
if (!previous.has(file)) return file;
|
|
259
|
+
// Moving pre-turn file bytes into HEAD is a save operation, not new implementation.
|
|
260
|
+
const finalState = current.has(file)
|
|
261
|
+
? current.get(file)
|
|
262
|
+
: await pathState(path.join(projectRoot, file));
|
|
263
|
+
return stableJson(previous.get(file)) === stableJson(finalState) ? null : file;
|
|
264
|
+
}));
|
|
265
|
+
return changed.filter(Boolean);
|
|
257
266
|
}
|
|
258
267
|
|
|
259
268
|
function changedPathLines(changedPaths) {
|
package/src/index/contracts.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const GENESIS_CONTRACTS = Object.freeze({
|
|
2
|
-
deployment: 'genesis.deployment.
|
|
2
|
+
deployment: 'genesis.deployment.v2',
|
|
3
|
+
derivedArtifacts: 'genesis.derived-artifacts.v1',
|
|
3
4
|
environment: 'genesis.environment.v1',
|
|
4
5
|
launch: 'genesis.launch.v1',
|
|
5
6
|
verification: 'genesis.verification.v1',
|
package/src/index/deployment.js
CHANGED
|
@@ -13,6 +13,7 @@ export async function inspectProjectDeployment({ projectRoot, stackPackages = []
|
|
|
13
13
|
else if (stack.deployment.steps.length > 0) status = 'ready';
|
|
14
14
|
const recipe = {
|
|
15
15
|
version: stack.deployment.version,
|
|
16
|
+
artifact: stack.deployment.artifact,
|
|
16
17
|
workdir: stack.deployment.workdir,
|
|
17
18
|
runtimeRequirements: stack.deployment.runtimeRequirements,
|
|
18
19
|
readiness: stack.deployment.readiness,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
const RUNTIME_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
|
|
9
9
|
const STEP_LINE = /^- (Prepare|Build|Migrate|Serve) `([^`\r\n]+)`:[ \t]+(.+)$/u;
|
|
10
|
+
const RESTORE_PATHS_PREFIX = '- Recreate on restore: ';
|
|
10
11
|
const STEP_ROLE_ORDER = Object.freeze({
|
|
11
12
|
prepare: 0,
|
|
12
13
|
build: 1,
|
|
@@ -45,6 +46,36 @@ function parseRuntimes(source, deploymentPath, line) {
|
|
|
45
46
|
return values;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
function parseDisposablePaths(source, deploymentPath, line) {
|
|
50
|
+
const values = parseBacktickedArguments(source.slice(RESTORE_PATHS_PREFIX.length));
|
|
51
|
+
if (!values || values.length === 0) {
|
|
52
|
+
invalid(
|
|
53
|
+
deploymentPath,
|
|
54
|
+
'Deployment Recreate on restore paths must be separate non-empty backticked values.',
|
|
55
|
+
line,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
const normalized = values.map((value) => String(value || '').trim());
|
|
59
|
+
if (normalized.some((value) => (
|
|
60
|
+
!value
|
|
61
|
+
|| value.startsWith('/')
|
|
62
|
+
|| value.includes('\\')
|
|
63
|
+
|| value.includes('***')
|
|
64
|
+
|| /[?\[\]{}!]/u.test(value)
|
|
65
|
+
|| value.split('/').some((segment) => !segment || ['.', '..'].includes(segment))
|
|
66
|
+
))) {
|
|
67
|
+
invalid(
|
|
68
|
+
deploymentPath,
|
|
69
|
+
'Deployment Recreate on restore paths must be canonical project-relative globs using only * and ** wildcards.',
|
|
70
|
+
line,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (new Set(normalized).size !== normalized.length) {
|
|
74
|
+
invalid(deploymentPath, 'Deployment contains a duplicate Recreate on restore path.', line);
|
|
75
|
+
}
|
|
76
|
+
return normalized;
|
|
77
|
+
}
|
|
78
|
+
|
|
48
79
|
function parseUrlPath(value, deploymentPath, line) {
|
|
49
80
|
const normalized = String(value || '').trim();
|
|
50
81
|
if (!normalized.startsWith('/') || normalized.startsWith('//') || /[\\?#]/u.test(normalized)) {
|
|
@@ -103,10 +134,15 @@ export function parseStackDeploymentLines(lines, {
|
|
|
103
134
|
} = {}) {
|
|
104
135
|
if (lines === undefined) return null;
|
|
105
136
|
const entries = lines.map((line) => line.trim()).filter(Boolean);
|
|
106
|
-
if (entries.length === 1 && entries[0] === '- Nothing.')
|
|
137
|
+
if (entries.length === 1 && entries[0] === '- Nothing.') {
|
|
138
|
+
return { version: 2, artifact: { disposablePaths: [] }, steps: [] };
|
|
139
|
+
}
|
|
107
140
|
|
|
108
141
|
const result = {
|
|
109
|
-
version:
|
|
142
|
+
version: 2,
|
|
143
|
+
artifact: {
|
|
144
|
+
disposablePaths: [],
|
|
145
|
+
},
|
|
110
146
|
workdir: '.',
|
|
111
147
|
runtimeRequirements: [],
|
|
112
148
|
readiness: null,
|
|
@@ -133,6 +169,14 @@ export function parseStackDeploymentLines(lines, {
|
|
|
133
169
|
result.runtimeRequirements = parseRuntimes(source, deploymentPath, line);
|
|
134
170
|
continue;
|
|
135
171
|
}
|
|
172
|
+
if (source.startsWith(RESTORE_PATHS_PREFIX)) {
|
|
173
|
+
if (seen.has('restore-paths')) {
|
|
174
|
+
invalid(deploymentPath, 'Duplicate Deployment Recreate on restore entry.', line);
|
|
175
|
+
}
|
|
176
|
+
seen.add('restore-paths');
|
|
177
|
+
result.artifact.disposablePaths = parseDisposablePaths(source, deploymentPath, line);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
136
180
|
if (source.startsWith('- Ready when: ')) {
|
|
137
181
|
if (seen.has('readiness')) invalid(deploymentPath, 'Duplicate Deployment Ready when.', line);
|
|
138
182
|
seen.add('readiness');
|
|
@@ -164,6 +208,15 @@ export function parseStackDeploymentLines(lines, {
|
|
|
164
208
|
if (!result.readiness) {
|
|
165
209
|
invalid(deploymentPath, 'Deployment needs one Ready when entry.');
|
|
166
210
|
}
|
|
211
|
+
if (
|
|
212
|
+
result.artifact.disposablePaths.length > 0
|
|
213
|
+
&& !result.steps.some(({ role }) => role === 'prepare')
|
|
214
|
+
) {
|
|
215
|
+
invalid(
|
|
216
|
+
deploymentPath,
|
|
217
|
+
'Deployment may recreate paths on restore only when it declares a Prepare step.',
|
|
218
|
+
);
|
|
219
|
+
}
|
|
167
220
|
return result;
|
|
168
221
|
}
|
|
169
222
|
|
|
@@ -177,7 +230,8 @@ export function composeStackDeployment(components, projectDeployment) {
|
|
|
177
230
|
}));
|
|
178
231
|
if (declarations.length === 0) {
|
|
179
232
|
return {
|
|
180
|
-
version:
|
|
233
|
+
version: 2,
|
|
234
|
+
artifact: { disposablePaths: [] },
|
|
181
235
|
workdir: '.',
|
|
182
236
|
runtimeRequirements: [],
|
|
183
237
|
readiness: null,
|
|
@@ -189,7 +243,8 @@ export function composeStackDeployment(components, projectDeployment) {
|
|
|
189
243
|
if (declarations.length === 1) return { ...declarations[0], diagnostics: [] };
|
|
190
244
|
const sources = declarations.map(({ source }) => source).sort();
|
|
191
245
|
return {
|
|
192
|
-
version:
|
|
246
|
+
version: 2,
|
|
247
|
+
artifact: { disposablePaths: [] },
|
|
193
248
|
workdir: '.',
|
|
194
249
|
runtimeRequirements: [],
|
|
195
250
|
readiness: null,
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
|
|
3
3
|
import { checkProject } from './index/check.js';
|
|
4
|
-
import { buildProjectIndex } from './index/code-index.js';
|
|
4
|
+
import { buildProjectIndex, GENESIS_DERIVED_ARTIFACTS } from './index/code-index.js';
|
|
5
|
+
import { GENESIS_CONTRACTS } from './index/contracts.js';
|
|
5
6
|
import { contextForProjectPaths } from './index/context.js';
|
|
6
7
|
import { generateProjectPrompt } from './index/prompt.js';
|
|
7
8
|
import { initializeProject } from './index/init.js';
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
prepareProjectWorkspace,
|
|
18
19
|
} from './index/workspace-setup.js';
|
|
19
20
|
|
|
20
|
-
export { GENESIS_CONTRACTS }
|
|
21
|
+
export { GENESIS_CONTRACTS };
|
|
21
22
|
|
|
22
23
|
function withIndexResult(result, index) {
|
|
23
24
|
const changedFiles = [...new Set([...result.changedFiles, ...index.changedFiles])].sort();
|
|
@@ -131,6 +132,13 @@ export function indexCodebase({
|
|
|
131
132
|
return buildProjectIndex({ projectRoot, queries, stackPackages, write });
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
export function inspectDerivedArtifacts() {
|
|
136
|
+
return {
|
|
137
|
+
contract: GENESIS_CONTRACTS.derivedArtifacts,
|
|
138
|
+
artifacts: GENESIS_DERIVED_ARTIFACTS.map((artifact) => ({ ...artifact })),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
134
142
|
export function verify(options) {
|
|
135
143
|
return verifyProject(options);
|
|
136
144
|
}
|