genesis-compiler 1.2.27 → 1.2.29
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 +338 -59
- package/docs/prompt-integration.md +50 -21
- package/docs/stack-components.md +65 -23
- package/package.json +4 -1
- package/plugins/genesis/.codex-plugin/plugin.json +1 -1
- package/prompts/adopt.txt +5 -4
- package/prompts/deslop.txt +3 -1
- package/prompts/start-existing-uninitialized.txt +8 -0
- package/prompts/start-existing.txt +23 -0
- package/prompts/start-new.txt +27 -0
- package/prompts/start.txt +3 -55
- package/prompts/work.txt +11 -3
- package/skills/genesis-deslop/SKILL.md +17 -0
- package/skills/genesis-project/SKILL.md +48 -9
- package/src/cli.js +19 -2
- package/src/index/assets.js +3 -0
- package/src/index/codex-hooks.js +8 -12
- package/src/index/context.js +20 -5
- package/src/index/migration.js +12 -3
- package/src/index/opencode-plugin.js +1 -1
- package/src/index/paths.js +1 -0
- package/src/index/project-files.js +12 -0
- package/src/index/project-format.js +1 -1
- package/src/index/prompt.js +46 -24
- package/src/index/session-context.js +18 -0
- package/src/index/stack-catalog.js +11 -0
- package/src/index/stack-project-contracts.js +205 -0
- package/src/index/stack-section.js +2 -2
- package/src/index/stack.js +93 -59
package/src/index/stack.js
CHANGED
|
@@ -10,18 +10,21 @@ import {
|
|
|
10
10
|
import { composeStackCityPresentation } from './stack-city-presentation.js';
|
|
11
11
|
import { resolveStackPieces } from './stack-composition.js';
|
|
12
12
|
import {
|
|
13
|
-
composeStackEnvironmentDefaults,
|
|
14
13
|
parseStackEnvironmentDefaultLines,
|
|
15
14
|
} from './stack-environment-defaults.js';
|
|
16
15
|
import {
|
|
17
|
-
composeStackEnvironmentFiles,
|
|
18
16
|
parseStackEnvironmentFileLines,
|
|
19
17
|
} from './stack-environment-files.js';
|
|
20
18
|
import {
|
|
21
|
-
composeStackSections,
|
|
22
19
|
opaqueStackSections,
|
|
23
20
|
trimStackSectionLines,
|
|
24
21
|
} from './stack-section.js';
|
|
22
|
+
import {
|
|
23
|
+
materializeStackProjectContracts,
|
|
24
|
+
renderStackPreparationPrompt,
|
|
25
|
+
requireMaterializedStackProjectContracts,
|
|
26
|
+
stackPieceContractNames,
|
|
27
|
+
} from './stack-project-contracts.js';
|
|
25
28
|
import { parseStackVerificationLines } from './stack-verification.js';
|
|
26
29
|
import {
|
|
27
30
|
applyStackPieceCustomization,
|
|
@@ -129,7 +132,7 @@ function renderStack({
|
|
|
129
132
|
resourceLines = null,
|
|
130
133
|
extensionSections = [],
|
|
131
134
|
stackPackages = [],
|
|
132
|
-
verificationLines =
|
|
135
|
+
verificationLines = null,
|
|
133
136
|
}) {
|
|
134
137
|
return [
|
|
135
138
|
'# Stack',
|
|
@@ -148,7 +151,9 @@ function renderStack({
|
|
|
148
151
|
...(environmentFileLines === null
|
|
149
152
|
? []
|
|
150
153
|
: ['', '## Environment files', '', ...trimStackSectionLines(environmentFileLines)]),
|
|
151
|
-
...(verificationLines
|
|
154
|
+
...(verificationLines === null
|
|
155
|
+
? []
|
|
156
|
+
: ['', '## Verification', '', ...trimStackSectionLines(verificationLines)]),
|
|
152
157
|
...extensionSections.flatMap(({ name, lines }) => (
|
|
153
158
|
['', `## ${name}`, '', ...trimStackSectionLines(lines)]
|
|
154
159
|
)),
|
|
@@ -185,46 +190,48 @@ export async function addStackPieces({ pieces, projectRoot, stackPackages = [] }
|
|
|
185
190
|
.map((piece) => customizePiece(projectRoot, piece)),
|
|
186
191
|
);
|
|
187
192
|
const selected = selectedPieces.map(({ id }) => id);
|
|
193
|
+
const newlySelectedPieces = selectedPieces.filter(({ id }) => !existing.includes(id));
|
|
188
194
|
const selectedPackages = [...new Set([
|
|
189
195
|
...declaredPackages,
|
|
190
196
|
...selectedPieces.map(({ stackPackage }) => stackPackage).filter(Boolean),
|
|
191
197
|
])].sort();
|
|
192
|
-
const
|
|
193
|
-
|
|
198
|
+
const projectContracts = materializeStackProjectContracts({
|
|
199
|
+
components: selectedPieces,
|
|
200
|
+
knownSectionNames: STACK_SECTIONS,
|
|
201
|
+
sections,
|
|
202
|
+
});
|
|
203
|
+
const verificationLines = projectContracts.verificationLines === null ? null : parseStackVerificationLines(
|
|
204
|
+
projectContracts.verificationLines,
|
|
194
205
|
{ path: STACK_PATH },
|
|
195
206
|
)
|
|
196
207
|
.map(({ label, argv }) => `- Verify \`${label}\`: ${argv.map((value) => `\`${value}\``).join(' ')}`);
|
|
197
|
-
const resourceLines =
|
|
208
|
+
const resourceLines = projectContracts.resourceLines;
|
|
198
209
|
parseStackResourceLines(resourceLines === null ? undefined : resourceLines, { path: STACK_PATH });
|
|
199
|
-
const environmentDefaultLines =
|
|
200
|
-
? sections.get('Environment defaults')
|
|
201
|
-
: null;
|
|
210
|
+
const environmentDefaultLines = projectContracts.environmentDefaultLines;
|
|
202
211
|
parseStackEnvironmentDefaultLines(
|
|
203
212
|
environmentDefaultLines === null ? undefined : environmentDefaultLines,
|
|
204
213
|
{ path: STACK_PATH },
|
|
205
214
|
);
|
|
206
|
-
const environmentFileLines =
|
|
207
|
-
? sections.get('Environment files')
|
|
208
|
-
: null;
|
|
215
|
+
const environmentFileLines = projectContracts.environmentFileLines;
|
|
209
216
|
parseStackEnvironmentFileLines(
|
|
210
217
|
environmentFileLines === null ? undefined : environmentFileLines,
|
|
211
218
|
{ path: STACK_PATH },
|
|
212
219
|
);
|
|
213
|
-
const extensionSections = opaqueStackSections(sections, STACK_SECTIONS);
|
|
214
220
|
const rendered = renderStack({
|
|
215
221
|
componentIds: selected,
|
|
216
222
|
environmentDefaultLines,
|
|
217
223
|
environmentFileLines,
|
|
218
224
|
resourceLines,
|
|
219
|
-
extensionSections,
|
|
225
|
+
extensionSections: projectContracts.extensionSections,
|
|
220
226
|
stackPackages: selectedPackages,
|
|
221
227
|
verificationLines,
|
|
222
228
|
});
|
|
223
229
|
const stackChanged = rendered !== source;
|
|
224
230
|
if (stackChanged) await writeFileAtomic(location, rendered);
|
|
231
|
+
const stack = await readStack(projectRoot, { stackPackages: availablePackages });
|
|
225
232
|
const skills = await syncProjectSkills({
|
|
226
233
|
projectRoot,
|
|
227
|
-
stack
|
|
234
|
+
stack,
|
|
228
235
|
});
|
|
229
236
|
const changedFiles = [
|
|
230
237
|
...(stackChanged ? [STACK_PATH] : []),
|
|
@@ -238,30 +245,34 @@ export async function addStackPieces({ pieces, projectRoot, stackPackages = [] }
|
|
|
238
245
|
components: selected,
|
|
239
246
|
changedFiles,
|
|
240
247
|
diagnostics: skills.diagnostics,
|
|
248
|
+
prompt: renderStackPreparationPrompt({
|
|
249
|
+
components: stack.components,
|
|
250
|
+
materializedSections: projectContracts.materializedSections,
|
|
251
|
+
newlySelected: newlySelectedPieces.map(({ id }) => id),
|
|
252
|
+
projectContracts: stack.projectContracts,
|
|
253
|
+
reviewSections: [...new Set(newlySelectedPieces.flatMap(stackPieceContractNames))]
|
|
254
|
+
.filter((name) => sections.has(name)),
|
|
255
|
+
}),
|
|
241
256
|
};
|
|
242
257
|
}
|
|
243
258
|
|
|
244
|
-
function
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return components.flatMap((piece) => piece.resources.map((resource) => ({
|
|
256
|
-
component: piece.id,
|
|
257
|
-
resource,
|
|
258
|
-
})));
|
|
259
|
+
export async function materializeProjectStackContracts({ projectRoot, stackPackages = [] }) {
|
|
260
|
+
const source = await readFile(path.join(projectRoot, STACK_PATH), 'utf8');
|
|
261
|
+
const selected = componentIds(parseSections(source));
|
|
262
|
+
if (selected.length === 0) {
|
|
263
|
+
return { changedFiles: [], diagnostics: [], materializedSections: [] };
|
|
264
|
+
}
|
|
265
|
+
const result = await addStackPieces({ pieces: selected, projectRoot, stackPackages });
|
|
266
|
+
return {
|
|
267
|
+
changedFiles: result.changedFiles,
|
|
268
|
+
diagnostics: result.diagnostics,
|
|
269
|
+
};
|
|
259
270
|
}
|
|
260
271
|
|
|
261
272
|
function composedProse(components, field) {
|
|
262
273
|
return components
|
|
263
|
-
.
|
|
264
|
-
.
|
|
274
|
+
.filter((piece) => piece[field])
|
|
275
|
+
.map((piece) => `### \`${piece.id}\`\n\n${piece[field]}`)
|
|
265
276
|
.join('\n\n');
|
|
266
277
|
}
|
|
267
278
|
|
|
@@ -280,7 +291,10 @@ async function customizePiece(projectRoot, piece) {
|
|
|
280
291
|
}));
|
|
281
292
|
}
|
|
282
293
|
|
|
283
|
-
|
|
294
|
+
async function readStackWithContractMode(projectRoot, {
|
|
295
|
+
allowComponentContracts,
|
|
296
|
+
stackPackages = [],
|
|
297
|
+
}) {
|
|
284
298
|
const location = path.join(projectRoot, STACK_PATH);
|
|
285
299
|
let source;
|
|
286
300
|
try {
|
|
@@ -305,39 +319,45 @@ export async function readStack(projectRoot, { stackPackages = [] } = {}) {
|
|
|
305
319
|
catalog,
|
|
306
320
|
requested: componentIds(sections),
|
|
307
321
|
})).map((piece) => customizePiece(projectRoot, piece)));
|
|
322
|
+
const projectContracts = (allowComponentContracts
|
|
323
|
+
? materializeStackProjectContracts
|
|
324
|
+
: requireMaterializedStackProjectContracts)({
|
|
325
|
+
components,
|
|
326
|
+
knownSectionNames: STACK_SECTIONS,
|
|
327
|
+
sections,
|
|
328
|
+
});
|
|
308
329
|
const projectVerificationCommands = parseStackVerificationLines(
|
|
309
|
-
|
|
330
|
+
projectContracts.verificationLines || [],
|
|
310
331
|
{ path: STACK_PATH },
|
|
311
332
|
).map(({ line: _line, ...command }) => command);
|
|
312
|
-
const
|
|
313
|
-
const verificationCommands = distinctVerificationCommands(
|
|
314
|
-
projectVerificationCommands.length > 0
|
|
315
|
-
? projectVerificationCommands
|
|
316
|
-
: componentVerificationCommands,
|
|
317
|
-
);
|
|
333
|
+
const verificationCommands = projectVerificationCommands;
|
|
318
334
|
const cityPresentation = composeStackCityPresentation(components);
|
|
319
|
-
const
|
|
320
|
-
?
|
|
321
|
-
:
|
|
322
|
-
|
|
323
|
-
? resourceDeclarations(components)
|
|
324
|
-
: projectResources.map((resource) => ({ component: 'project', resource }));
|
|
335
|
+
const resources = parseStackResourceLines(
|
|
336
|
+
projectContracts.resourceLines === null ? undefined : projectContracts.resourceLines,
|
|
337
|
+
{ path: STACK_PATH },
|
|
338
|
+
).map((resource) => ({ component: 'project', resource }));
|
|
325
339
|
const projectEnvironmentDefaults = parseStackEnvironmentDefaultLines(
|
|
326
|
-
|
|
340
|
+
projectContracts.environmentDefaultLines === null
|
|
341
|
+
? undefined
|
|
342
|
+
: projectContracts.environmentDefaultLines,
|
|
327
343
|
{ path: STACK_PATH },
|
|
328
344
|
);
|
|
329
|
-
const environmentDefaults =
|
|
330
|
-
|
|
331
|
-
: composeStackEnvironmentDefaults(components);
|
|
345
|
+
const environmentDefaults = projectEnvironmentDefaults
|
|
346
|
+
.map((entry) => ({ ...entry, sources: ['project'] }));
|
|
332
347
|
const projectEnvironmentFiles = parseStackEnvironmentFileLines(
|
|
333
|
-
|
|
348
|
+
projectContracts.environmentFileLines === null
|
|
349
|
+
? undefined
|
|
350
|
+
: projectContracts.environmentFileLines,
|
|
334
351
|
{ path: STACK_PATH },
|
|
335
352
|
);
|
|
336
|
-
const environmentFiles =
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
353
|
+
const environmentFiles = (projectEnvironmentFiles || [])
|
|
354
|
+
.map((file) => ({ ...file, source: 'project' }));
|
|
355
|
+
const extensions = projectContracts.extensionSections.map(({ name, lines }) => ({
|
|
356
|
+
name,
|
|
357
|
+
lines,
|
|
358
|
+
source: 'project',
|
|
359
|
+
diagnostics: [],
|
|
360
|
+
}));
|
|
341
361
|
return {
|
|
342
362
|
path: STACK_PATH,
|
|
343
363
|
identityHash: sha256(stableJson({
|
|
@@ -359,6 +379,7 @@ export async function readStack(projectRoot, { stackPackages = [] } = {}) {
|
|
|
359
379
|
environmentDefaults,
|
|
360
380
|
environmentFiles,
|
|
361
381
|
extensions,
|
|
382
|
+
projectContracts: projectContracts.projectContracts,
|
|
362
383
|
resources,
|
|
363
384
|
guidance: composedProse(components, 'guidance'),
|
|
364
385
|
adoption: composedProse(components, 'adoption'),
|
|
@@ -367,9 +388,22 @@ export async function readStack(projectRoot, { stackPackages = [] } = {}) {
|
|
|
367
388
|
};
|
|
368
389
|
}
|
|
369
390
|
|
|
391
|
+
export function readStack(projectRoot, { stackPackages = [] } = {}) {
|
|
392
|
+
return readStackWithContractMode(projectRoot, {
|
|
393
|
+
allowComponentContracts: false,
|
|
394
|
+
stackPackages,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export function readLegacyStack(projectRoot, { stackPackages = [] } = {}) {
|
|
399
|
+
return readStackWithContractMode(projectRoot, {
|
|
400
|
+
allowComponentContracts: true,
|
|
401
|
+
stackPackages,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
370
405
|
export function stackPromptContext(stack) {
|
|
371
406
|
return {
|
|
372
|
-
stackPackages: stack.stackPackages,
|
|
373
407
|
components: stack.components.map((piece) => ({
|
|
374
408
|
id: piece.id,
|
|
375
409
|
description: piece.description,
|