genesis-compiler 1.2.28 → 1.3.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.
- package/README.md +84 -9
- package/docs/prompt-integration.md +108 -6
- package/package.json +4 -1
- package/plugins/genesis/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/project-guidance.js +41 -5
- 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 -85
- package/src/cli.js +124 -7
- package/src/index/assets.js +3 -0
- package/src/index/check.js +10 -0
- package/src/index/codex-hooks.js +21 -12
- package/src/index/collaboration.js +371 -0
- package/src/index/context.js +3 -8
- package/src/index/contracts.js +3 -0
- package/src/index/host-context-resolver.js +73 -0
- package/src/index/init.js +4 -0
- package/src/index/migration.js +2 -0
- package/src/index/opencode-plugin.js +1 -1
- package/src/index/paths.js +2 -0
- package/src/index/project-files.js +12 -0
- package/src/index/project-format.js +3 -1
- package/src/index/prompt.js +120 -45
- package/src/index/session-context.js +115 -25
- package/src/index/stack.js +2 -2
- package/src/index.js +27 -2
package/src/index/prompt.js
CHANGED
|
@@ -2,6 +2,7 @@ import { readInstalledAsset } from './assets.js';
|
|
|
2
2
|
import { inspectProjectSkills, renderAgentSkillCatalog } from './agent-skills.js';
|
|
3
3
|
import { buildProjectIndex, MACHINE_CITY_PATH, PROGRAM_CITY_PATH } from './code-index.js';
|
|
4
4
|
import { BLUEPRINT_SKELETON_SOURCE, readBlueprint } from './blueprint.js';
|
|
5
|
+
import { defaultCollaboration, readCollaboration } from './collaboration.js';
|
|
5
6
|
import {
|
|
6
7
|
engineeringPromptContext,
|
|
7
8
|
listEngineeringProfileCatalog,
|
|
@@ -17,8 +18,8 @@ import { inspectVerification } from './project-state.js';
|
|
|
17
18
|
import { missingStackResources } from './stack-preflight.js';
|
|
18
19
|
import { withStackEnvironmentDefaults } from './stack-environment-defaults.js';
|
|
19
20
|
import { stableJson } from './utils.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
21
|
+
import { classifyProjectKind } from './project-files.js';
|
|
22
|
+
import { inspectProjectFormatAtRoot } from './project-format.js';
|
|
22
23
|
|
|
23
24
|
const TASKS = new Set(['start', 'adopt', 'work', 'deslop', 'program', 'blueprint', 'describe', 'review']);
|
|
24
25
|
const DEFAULT_REQUEST = {
|
|
@@ -83,6 +84,26 @@ function programContext(program) {
|
|
|
83
84
|
};
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
function startProgramContext(program) {
|
|
88
|
+
return {
|
|
89
|
+
status: program.status,
|
|
90
|
+
subsystems: program.subsystems,
|
|
91
|
+
moduleCount: program.modules.length,
|
|
92
|
+
...(program.diagnostic ? { diagnostic: program.diagnostic } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function startStackContext(stack) {
|
|
97
|
+
return {
|
|
98
|
+
components: stack.components.map(({ id, description }) => ({ id, description })),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function startInstructions(instructions, projectKind) {
|
|
103
|
+
const specific = await readInstalledAsset(`start-${projectKind}`);
|
|
104
|
+
return `${instructions.trim()}\n\n${specific.trim()}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
86
107
|
function codeIndexContext(index) {
|
|
87
108
|
return {
|
|
88
109
|
machineCity: {
|
|
@@ -109,6 +130,7 @@ function renderPrompt({
|
|
|
109
130
|
cleanup = '',
|
|
110
131
|
postChange = '',
|
|
111
132
|
adoption = '',
|
|
133
|
+
collaborationGuidance = '',
|
|
112
134
|
engineeringGuidance = '',
|
|
113
135
|
}) {
|
|
114
136
|
return [
|
|
@@ -124,6 +146,7 @@ function renderPrompt({
|
|
|
124
146
|
stableJson(context).trimEnd(),
|
|
125
147
|
'```',
|
|
126
148
|
...(engineeringGuidance ? ['', 'ENGINEERING APPROACH', '', engineeringGuidance] : []),
|
|
149
|
+
...(collaborationGuidance ? ['', 'COLLABORATION APPROACH', '', collaborationGuidance] : []),
|
|
127
150
|
...(guidance ? ['', 'SELECTED STACK GUIDANCE', '', guidance] : []),
|
|
128
151
|
...(adoption ? ['', 'SELECTED STACK ADOPTION GUIDANCE', '', adoption] : []),
|
|
129
152
|
...(skills ? ['', 'AVAILABLE AGENT SKILLS', '', skills] : []),
|
|
@@ -133,7 +156,43 @@ function renderPrompt({
|
|
|
133
156
|
].join('\n');
|
|
134
157
|
}
|
|
135
158
|
|
|
136
|
-
|
|
159
|
+
function collaborationPromptContext(collaboration) {
|
|
160
|
+
return {
|
|
161
|
+
path: collaboration.path,
|
|
162
|
+
status: collaboration.status,
|
|
163
|
+
tone: collaboration.tone,
|
|
164
|
+
responseLength: collaboration.responseLength,
|
|
165
|
+
experience: collaboration.experience,
|
|
166
|
+
explanationStyle: collaboration.explanationStyle,
|
|
167
|
+
requirements: collaboration.requirements || 'Nothing.',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function stableSessionPromptParts({ collaboration, engineering, installed }) {
|
|
172
|
+
return installed
|
|
173
|
+
? { context: {}, collaborationGuidance: '', engineeringGuidance: '' }
|
|
174
|
+
: {
|
|
175
|
+
context: {
|
|
176
|
+
collaboration: collaborationPromptContext(collaboration),
|
|
177
|
+
engineering: engineeringPromptContext(engineering),
|
|
178
|
+
},
|
|
179
|
+
collaborationGuidance: collaboration.guidance,
|
|
180
|
+
engineeringGuidance: engineering.guidance,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function collaborationForPrompt(projectRoot) {
|
|
185
|
+
try {
|
|
186
|
+
return await readCollaboration(projectRoot);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
if (error?.code !== 'COLLABORATION_REQUIRED') throw error;
|
|
189
|
+
const format = await inspectProjectFormatAtRoot(projectRoot);
|
|
190
|
+
if (format.status !== 'uninitialized') throw error;
|
|
191
|
+
return defaultCollaboration();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function generateAdoptionPrompt({ environment, instructions, program, request, root, sessionPrompt, stackPackages }) {
|
|
137
196
|
const blueprint = await readBlueprint(root, { required: true });
|
|
138
197
|
const stack = await readStack(root, { stackPackages });
|
|
139
198
|
const availableStackPackages = [...new Set([...stack.stackPackages, ...stackPackages])];
|
|
@@ -157,7 +216,7 @@ async function generateAdoptionPrompt({ engineering, environment, instructions,
|
|
|
157
216
|
projectRoot: root,
|
|
158
217
|
projectKind: 'existing',
|
|
159
218
|
blueprint: { path: blueprint.path, source: blueprint.source },
|
|
160
|
-
|
|
219
|
+
...sessionPrompt.context,
|
|
161
220
|
stack: stackPromptContext(stack),
|
|
162
221
|
availableStackPieces: stackCatalogContext(catalog),
|
|
163
222
|
program: programContext(program),
|
|
@@ -166,7 +225,8 @@ async function generateAdoptionPrompt({ engineering, environment, instructions,
|
|
|
166
225
|
: { status: 'present' },
|
|
167
226
|
codeIndex: codeIndexContext(index),
|
|
168
227
|
},
|
|
169
|
-
|
|
228
|
+
collaborationGuidance: sessionPrompt.collaborationGuidance,
|
|
229
|
+
engineeringGuidance: sessionPrompt.engineeringGuidance,
|
|
170
230
|
guidance: stack.guidance,
|
|
171
231
|
adoption: stack.adoption,
|
|
172
232
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
@@ -181,7 +241,7 @@ async function generateAdoptionPrompt({ engineering, environment, instructions,
|
|
|
181
241
|
};
|
|
182
242
|
}
|
|
183
243
|
|
|
184
|
-
async function generateExplanationPrompt({
|
|
244
|
+
async function generateExplanationPrompt({ instructions, program, request, root, sessionPrompt, stackPackages, task }) {
|
|
185
245
|
const blueprint = await readBlueprint(root, {
|
|
186
246
|
required: true,
|
|
187
247
|
requireDescription: task === 'program',
|
|
@@ -204,12 +264,13 @@ async function generateExplanationPrompt({ engineering, instructions, program, r
|
|
|
204
264
|
task,
|
|
205
265
|
projectRoot: root,
|
|
206
266
|
blueprint: blueprintContext,
|
|
207
|
-
|
|
267
|
+
...sessionPrompt.context,
|
|
208
268
|
stack: stackPromptContext(stack),
|
|
209
269
|
program: programContext(program),
|
|
210
270
|
codeIndex: codeIndexContext(index),
|
|
211
271
|
},
|
|
212
|
-
|
|
272
|
+
collaborationGuidance: sessionPrompt.collaborationGuidance,
|
|
273
|
+
engineeringGuidance: sessionPrompt.engineeringGuidance,
|
|
213
274
|
guidance: stack.guidance,
|
|
214
275
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
215
276
|
}),
|
|
@@ -224,81 +285,86 @@ async function generateExplanationPrompt({ engineering, instructions, program, r
|
|
|
224
285
|
|
|
225
286
|
async function generateStartPrompt({
|
|
226
287
|
hiddenStackPieces,
|
|
227
|
-
engineering,
|
|
228
288
|
instructions,
|
|
229
289
|
program,
|
|
230
290
|
request,
|
|
231
291
|
root,
|
|
292
|
+
sessionPrompt,
|
|
232
293
|
stackPackages,
|
|
233
294
|
}) {
|
|
234
|
-
const availableEngineeringProfiles = (await listEngineeringProfileCatalog())
|
|
235
|
-
.map(({ id, name, description }) => ({ id, name, description }));
|
|
236
295
|
let blueprint;
|
|
237
296
|
try {
|
|
238
297
|
blueprint = await readBlueprint(root, { required: true });
|
|
239
298
|
} catch (error) {
|
|
240
299
|
if (error?.code !== 'BLUEPRINT_REQUIRED') throw error;
|
|
241
|
-
|
|
242
|
-
const existing = [...files.values()].some((state) => state.exists);
|
|
243
|
-
if (!existing) throw error;
|
|
300
|
+
if (await classifyProjectKind({ projectRoot: root }) === 'new') throw error;
|
|
244
301
|
return {
|
|
245
302
|
status: 'ready',
|
|
246
303
|
task: 'start',
|
|
247
304
|
prompt: renderPrompt({
|
|
248
|
-
instructions,
|
|
305
|
+
instructions: await startInstructions(instructions, 'existing-uninitialized'),
|
|
249
306
|
request,
|
|
250
307
|
context: {
|
|
251
308
|
task: 'start',
|
|
252
309
|
projectRoot: root,
|
|
253
310
|
projectKind: 'existing-uninitialized',
|
|
254
311
|
genesis: { initialized: false },
|
|
255
|
-
|
|
256
|
-
availableEngineeringProfiles,
|
|
257
|
-
program: programContext(program),
|
|
312
|
+
...sessionPrompt.context,
|
|
258
313
|
},
|
|
259
|
-
|
|
314
|
+
collaborationGuidance: sessionPrompt.collaborationGuidance,
|
|
315
|
+
engineeringGuidance: sessionPrompt.engineeringGuidance,
|
|
260
316
|
}),
|
|
261
317
|
warnings: program.diagnostic ? [program.diagnostic] : [],
|
|
262
318
|
verificationCommands: [],
|
|
263
319
|
};
|
|
264
320
|
}
|
|
265
321
|
const stack = await readStack(root, { stackPackages });
|
|
322
|
+
const projectKind = await classifyProjectKind({
|
|
323
|
+
projectRoot: root,
|
|
324
|
+
stackComponents: stack.components,
|
|
325
|
+
});
|
|
266
326
|
const availableStackPackages = [...new Set([...stack.stackPackages, ...stackPackages])];
|
|
267
|
-
const [
|
|
268
|
-
|
|
269
|
-
|
|
327
|
+
const [catalog, availableEngineeringProfiles, projectSkills, renderedInstructions] = await Promise.all([
|
|
328
|
+
projectKind === 'new'
|
|
329
|
+
? listStackCatalogPieces({ projectRoot: root, stackPackages: availableStackPackages })
|
|
330
|
+
: Promise.resolve([]),
|
|
331
|
+
projectKind === 'new'
|
|
332
|
+
? listEngineeringProfileCatalog()
|
|
333
|
+
.then((profiles) => profiles.map(({ id, name, description }) => ({ id, name, description })))
|
|
334
|
+
: Promise.resolve([]),
|
|
335
|
+
inspectProjectSkills({ projectRoot: root, stack }),
|
|
336
|
+
startInstructions(instructions, projectKind),
|
|
270
337
|
]);
|
|
271
|
-
const projectSkills = await inspectProjectSkills({ projectRoot: root, stack });
|
|
272
|
-
const newProject = stack.components.length === 0 && index.fileCount === 0;
|
|
273
338
|
return {
|
|
274
339
|
status: 'ready',
|
|
275
340
|
task: 'start',
|
|
276
341
|
prompt: renderPrompt({
|
|
277
|
-
instructions,
|
|
342
|
+
instructions: renderedInstructions,
|
|
278
343
|
request,
|
|
279
344
|
context: {
|
|
280
345
|
task: 'start',
|
|
281
346
|
projectRoot: root,
|
|
282
|
-
projectKind
|
|
347
|
+
projectKind,
|
|
283
348
|
blueprint: {
|
|
284
349
|
path: blueprint.path,
|
|
285
350
|
description: blueprint.description,
|
|
286
351
|
},
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
352
|
+
...sessionPrompt.context,
|
|
353
|
+
stack: startStackContext(stack),
|
|
354
|
+
...(projectKind === 'new'
|
|
355
|
+
? {
|
|
356
|
+
availableEngineeringProfiles,
|
|
357
|
+
availableStackPieces: stackCatalogContext(catalog, hiddenStackPieces),
|
|
358
|
+
}
|
|
359
|
+
: { program: startProgramContext(program) }),
|
|
293
360
|
},
|
|
294
|
-
|
|
361
|
+
collaborationGuidance: sessionPrompt.collaborationGuidance,
|
|
362
|
+
engineeringGuidance: sessionPrompt.engineeringGuidance,
|
|
295
363
|
guidance: stack.guidance,
|
|
296
|
-
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
297
364
|
}),
|
|
298
365
|
warnings: [
|
|
299
366
|
...(program.diagnostic ? [program.diagnostic] : []),
|
|
300
367
|
...projectSkills.diagnostics,
|
|
301
|
-
...index.diagnostics,
|
|
302
368
|
],
|
|
303
369
|
verificationCommands: [],
|
|
304
370
|
};
|
|
@@ -309,6 +375,7 @@ export async function generateProjectPrompt({
|
|
|
309
375
|
hiddenStackPieces = [],
|
|
310
376
|
projectRoot,
|
|
311
377
|
request = '',
|
|
378
|
+
sessionContextInstalled = false,
|
|
312
379
|
stackPackages = [],
|
|
313
380
|
task = 'work',
|
|
314
381
|
} = {}) {
|
|
@@ -317,10 +384,16 @@ export async function generateProjectPrompt({
|
|
|
317
384
|
}
|
|
318
385
|
const root = (await gitContext(projectRoot)).repositoryRoot;
|
|
319
386
|
const userRequest = requestText(request, task);
|
|
320
|
-
const [instructions, engineering] = await Promise.all([
|
|
387
|
+
const [instructions, collaboration, engineering] = await Promise.all([
|
|
321
388
|
readInstalledAsset(task),
|
|
389
|
+
collaborationForPrompt(root),
|
|
322
390
|
readEngineering(root),
|
|
323
391
|
]);
|
|
392
|
+
const sessionPrompt = stableSessionPromptParts({
|
|
393
|
+
collaboration,
|
|
394
|
+
engineering,
|
|
395
|
+
installed: sessionContextInstalled === true,
|
|
396
|
+
});
|
|
324
397
|
|
|
325
398
|
if (task === 'blueprint') {
|
|
326
399
|
const blueprint = await readBlueprint(root);
|
|
@@ -335,9 +408,10 @@ export async function generateProjectPrompt({
|
|
|
335
408
|
path: 'genesis/blueprint.md',
|
|
336
409
|
source: blueprint?.source || BLUEPRINT_SKELETON_SOURCE,
|
|
337
410
|
},
|
|
338
|
-
|
|
411
|
+
...sessionPrompt.context,
|
|
339
412
|
},
|
|
340
|
-
|
|
413
|
+
collaborationGuidance: sessionPrompt.collaborationGuidance,
|
|
414
|
+
engineeringGuidance: sessionPrompt.engineeringGuidance,
|
|
341
415
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
342
416
|
});
|
|
343
417
|
return {
|
|
@@ -354,21 +428,21 @@ export async function generateProjectPrompt({
|
|
|
354
428
|
return generateStartPrompt({
|
|
355
429
|
instructions,
|
|
356
430
|
hiddenStackPieces,
|
|
357
|
-
engineering,
|
|
358
431
|
program,
|
|
359
432
|
request: userRequest,
|
|
360
433
|
root,
|
|
434
|
+
sessionPrompt,
|
|
361
435
|
stackPackages,
|
|
362
436
|
});
|
|
363
437
|
}
|
|
364
438
|
if (task === 'adopt') {
|
|
365
439
|
return generateAdoptionPrompt({
|
|
366
440
|
environment,
|
|
367
|
-
engineering,
|
|
368
441
|
instructions,
|
|
369
442
|
program,
|
|
370
443
|
request: userRequest,
|
|
371
444
|
root,
|
|
445
|
+
sessionPrompt,
|
|
372
446
|
stackPackages,
|
|
373
447
|
});
|
|
374
448
|
}
|
|
@@ -381,10 +455,10 @@ export async function generateProjectPrompt({
|
|
|
381
455
|
return generateStartPrompt({
|
|
382
456
|
instructions: await readInstalledAsset('start'),
|
|
383
457
|
hiddenStackPieces,
|
|
384
|
-
engineering,
|
|
385
458
|
program,
|
|
386
459
|
request: userRequest,
|
|
387
460
|
root,
|
|
461
|
+
sessionPrompt,
|
|
388
462
|
stackPackages,
|
|
389
463
|
});
|
|
390
464
|
}
|
|
@@ -392,10 +466,10 @@ export async function generateProjectPrompt({
|
|
|
392
466
|
return generateStartPrompt({
|
|
393
467
|
instructions: await readInstalledAsset('start'),
|
|
394
468
|
hiddenStackPieces,
|
|
395
|
-
engineering,
|
|
396
469
|
program,
|
|
397
470
|
request: userRequest,
|
|
398
471
|
root,
|
|
472
|
+
sessionPrompt,
|
|
399
473
|
stackPackages,
|
|
400
474
|
});
|
|
401
475
|
}
|
|
@@ -403,10 +477,10 @@ export async function generateProjectPrompt({
|
|
|
403
477
|
if (['describe', 'program'].includes(task)) {
|
|
404
478
|
return generateExplanationPrompt({
|
|
405
479
|
instructions,
|
|
406
|
-
engineering,
|
|
407
480
|
program,
|
|
408
481
|
request: userRequest,
|
|
409
482
|
root,
|
|
483
|
+
sessionPrompt,
|
|
410
484
|
stackPackages,
|
|
411
485
|
task,
|
|
412
486
|
});
|
|
@@ -432,7 +506,7 @@ export async function generateProjectPrompt({
|
|
|
432
506
|
task,
|
|
433
507
|
projectRoot: root,
|
|
434
508
|
blueprint: { path: blueprint.path, description: blueprint.description },
|
|
435
|
-
|
|
509
|
+
...sessionPrompt.context,
|
|
436
510
|
stack: stackPromptContext(stack),
|
|
437
511
|
program: programContext(program),
|
|
438
512
|
resourceInputs: missing.length > 0
|
|
@@ -450,7 +524,8 @@ export async function generateProjectPrompt({
|
|
|
450
524
|
instructions,
|
|
451
525
|
request: userRequest,
|
|
452
526
|
context,
|
|
453
|
-
|
|
527
|
+
collaborationGuidance: sessionPrompt.collaborationGuidance,
|
|
528
|
+
engineeringGuidance: sessionPrompt.engineeringGuidance,
|
|
454
529
|
guidance: stack.guidance,
|
|
455
530
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
456
531
|
postChange: task === 'work' ? stack.postChange : '',
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
import { readCollaboration } from './collaboration.js';
|
|
2
|
+
import { GENESIS_CONTRACTS } from './contracts.js';
|
|
1
3
|
import { readEngineering, readEngineeringBaseline } from './engineering.js';
|
|
4
|
+
import { GenesisError } from './errors.js';
|
|
2
5
|
import { gitContext } from './git.js';
|
|
3
6
|
import { readStack } from './stack.js';
|
|
4
7
|
import { listStackCatalogPieces } from './stack-catalog.js';
|
|
8
|
+
import { normalizeSource, sha256, stableJson } from './utils.js';
|
|
9
|
+
|
|
10
|
+
const HOST_CONTEXT_MAX_BYTES = Object.freeze({
|
|
11
|
+
session: 16 * 1024,
|
|
12
|
+
turn: 512,
|
|
13
|
+
});
|
|
5
14
|
|
|
6
15
|
async function optionalStack(projectRoot, stackPackages) {
|
|
7
16
|
try { return await readStack(projectRoot, { stackPackages }); } catch { return null; }
|
|
@@ -24,6 +33,65 @@ async function optionalEngineering(projectRoot) {
|
|
|
24
33
|
}
|
|
25
34
|
}
|
|
26
35
|
|
|
36
|
+
async function optionalCollaboration(projectRoot) {
|
|
37
|
+
try {
|
|
38
|
+
return await readCollaboration(projectRoot);
|
|
39
|
+
} catch {
|
|
40
|
+
return {
|
|
41
|
+
guidance: [
|
|
42
|
+
'The project collaboration approach is invalid. Do not infer replacement preferences; run the Genesis `check` operation.',
|
|
43
|
+
].join('\n'),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function hostContextContribution({ hostDriver, hostDriverInput, scope }) {
|
|
49
|
+
if (hostDriver === undefined || hostDriver === null) {
|
|
50
|
+
if (hostDriverInput !== undefined) {
|
|
51
|
+
throw new GenesisError(
|
|
52
|
+
'HOST_CONTEXT_INVALID',
|
|
53
|
+
'Host context input requires an explicitly registered host driver.',
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
if (typeof hostDriver !== 'function') {
|
|
59
|
+
throw new GenesisError('HOST_CONTEXT_INVALID', 'The registered host driver must be a function.');
|
|
60
|
+
}
|
|
61
|
+
if (
|
|
62
|
+
!hostDriverInput
|
|
63
|
+
|| typeof hostDriverInput !== 'object'
|
|
64
|
+
|| Array.isArray(hostDriverInput)
|
|
65
|
+
|| hostDriverInput.scope !== scope
|
|
66
|
+
) {
|
|
67
|
+
throw new GenesisError(
|
|
68
|
+
'HOST_CONTEXT_INVALID',
|
|
69
|
+
`The ${scope} context lane requires host input with scope \`${scope}\`.`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
const value = await hostDriver(hostDriverInput);
|
|
73
|
+
if (typeof value !== 'string') {
|
|
74
|
+
throw new GenesisError('HOST_CONTEXT_INVALID', 'The registered host driver must return plain text.');
|
|
75
|
+
}
|
|
76
|
+
const output = normalizeSource(value).trim();
|
|
77
|
+
if (Buffer.byteLength(output, 'utf8') > HOST_CONTEXT_MAX_BYTES[scope]) {
|
|
78
|
+
throw new GenesisError(
|
|
79
|
+
'HOST_CONTEXT_INVALID',
|
|
80
|
+
`The registered host driver's ${scope} contribution exceeds ${HOST_CONTEXT_MAX_BYTES[scope]} bytes.`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return output;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function composedContext(contract, output) {
|
|
87
|
+
return {
|
|
88
|
+
contract,
|
|
89
|
+
status: 'ready',
|
|
90
|
+
output,
|
|
91
|
+
identity: sha256(stableJson({ contract, output })),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
27
95
|
async function optionalStackComponentIds(projectRoot, stack, stackPackages) {
|
|
28
96
|
try {
|
|
29
97
|
const packages = [...new Set([...(stack?.stackPackages || []), ...stackPackages])];
|
|
@@ -34,40 +102,62 @@ async function optionalStackComponentIds(projectRoot, stack, stackPackages) {
|
|
|
34
102
|
}
|
|
35
103
|
}
|
|
36
104
|
|
|
37
|
-
export async function projectSessionContext({
|
|
105
|
+
export async function projectSessionContext({
|
|
106
|
+
hostDriver,
|
|
107
|
+
hostDriverInput,
|
|
108
|
+
projectRoot,
|
|
109
|
+
stackPackages = [],
|
|
110
|
+
} = {}) {
|
|
38
111
|
const root = (await gitContext(projectRoot)).repositoryRoot;
|
|
39
|
-
const [stack, engineering] = await Promise.all([
|
|
112
|
+
const [stack, collaboration, engineering, hostContext] = await Promise.all([
|
|
40
113
|
optionalStack(root, stackPackages),
|
|
114
|
+
optionalCollaboration(root),
|
|
41
115
|
optionalEngineering(root),
|
|
116
|
+
hostContextContribution({ hostDriver, hostDriverInput, scope: 'session' }),
|
|
42
117
|
]);
|
|
43
118
|
const availableComponents = await optionalStackComponentIds(root, stack, stackPackages);
|
|
44
119
|
const selected = stack?.components.map(({ id }) => id) || [];
|
|
45
120
|
const stackStatus = stack
|
|
46
121
|
? (selected.length > 0 ? selected.join(', ') : 'none')
|
|
47
122
|
: 'unavailable; run the Genesis `check` operation';
|
|
123
|
+
const output = [
|
|
124
|
+
'This is a Genesis-enriched project.',
|
|
125
|
+
'- Read `genesis/blueprint.md`, `genesis/collaboration.md`, `genesis/engineering.md`, and `genesis/stack.md` for product intent, collaboration approach, engineering approach, and selected technology.',
|
|
126
|
+
'- For a new project whose Blueprint does not yet establish product direction, do not research technology or create source until the user has made clear what is being built, who or what will use or invoke it, and the first observable useful outcome. Ask only unresolved high-impact questions. A reply confirms only what it explicitly answers; Stack confirmation is not product intent.',
|
|
127
|
+
'- Once product direction is clear, choose one smallest implementation path through selected technology guidance, or authoritative technology documentation when the catalog has no match, and read only what that path requires. Do not survey alternatives, clone whole technology repositories, inspect unrelated package internals, or delegate research unless one concrete failure requires one exact investigation.',
|
|
128
|
+
`- Available Stack components: ${availableComponents.length > 0 ? availableComponents.map((id) => `\`${id}\``).join(', ') : 'none'}.`,
|
|
129
|
+
'- When the user names an unselected technology that exactly matches this catalog, run `genesis stack list`, ask whether to add and prepare it, and wait for confirmation. If confirmed, run `genesis stack add <piece...>` and follow its returned preparation prompt in the same task; then use `genesis context` and any installed technology skill. Never infer dependency commands from a component id. If declined or unmatched, continue through authoritative technology documentation without inventing a component.',
|
|
130
|
+
'- Project-owned operation sections in `genesis/stack.md` are the durable application contract. Make the implementation satisfy them or update a complete section to match evidenced reality; Genesis executes only Verification.',
|
|
131
|
+
'- Use the relevant project Agent Skills below `.agents/skills/`.',
|
|
132
|
+
'- After locating source, run `genesis context <path...>`; before adding a helper or public operation, run `genesis index <name-or-path...>` and reuse an existing owner.',
|
|
133
|
+
'- Program is fallible explanation; code, tests, and runtime behavior remain evidence.',
|
|
134
|
+
'- Keep Blueprint and affected Program explanations aligned with intentional observable product behavior in the same implementation turn. Private restructuring may need only source citations or no explanatory change.',
|
|
135
|
+
'- Before reporting completion, compare the requested observable behavior, required inputs and resources, declared project operations, and focused evidence with what actually exists. State anything not proven.',
|
|
136
|
+
'- Deslop only when explicitly requested. Genesis defines its behavior-preserving committed scope; selected Stack components may add technology-specific cleanup guidance.',
|
|
137
|
+
'- This guidance is loaded for a new session and refreshed after compaction. Continue the active request without restarting completed work.',
|
|
138
|
+
`Engineering profile: ${engineering.profile?.id || 'invalid; run the Genesis `check` operation'}.`,
|
|
139
|
+
`Selected Stack components: ${stackStatus}.`,
|
|
140
|
+
'',
|
|
141
|
+
'ENGINEERING APPROACH',
|
|
142
|
+
'',
|
|
143
|
+
engineering.guidance,
|
|
144
|
+
'',
|
|
145
|
+
'COLLABORATION APPROACH',
|
|
146
|
+
'',
|
|
147
|
+
collaboration.guidance,
|
|
148
|
+
...(hostContext ? ['', 'HOST CONTEXT', '', hostContext] : []),
|
|
149
|
+
].join('\n');
|
|
150
|
+
return composedContext(GENESIS_CONTRACTS.sessionContext, output);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function projectTurnContext({ hostDriver, hostDriverInput } = {}) {
|
|
154
|
+
const output = await hostContextContribution({
|
|
155
|
+
hostDriver,
|
|
156
|
+
hostDriverInput,
|
|
157
|
+
scope: 'turn',
|
|
158
|
+
});
|
|
48
159
|
return {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
'This is a Genesis-enriched project.',
|
|
52
|
-
'- Read `genesis/blueprint.md`, `genesis/engineering.md`, and `genesis/stack.md` for product intent, engineering approach, and selected technology.',
|
|
53
|
-
'- For a new project whose Blueprint does not yet establish product direction, do not research technology or create source until the user has made clear what is being built, who or what will use or invoke it, and the first observable useful outcome. Ask only unresolved high-impact questions. A reply confirms only what it explicitly answers; Stack confirmation is not product intent.',
|
|
54
|
-
'- Once product direction is clear, choose one smallest implementation path through selected technology guidance, or authoritative technology documentation when the catalog has no match, and read only what that path requires. Do not survey alternatives, clone whole technology repositories, inspect unrelated package internals, or delegate research unless one concrete failure requires one exact investigation.',
|
|
55
|
-
`- Available Stack components: ${availableComponents.length > 0 ? availableComponents.map((id) => `\`${id}\``).join(', ') : 'none'}.`,
|
|
56
|
-
'- When the user names an unselected technology that exactly matches this catalog, run `genesis stack list`, ask whether to add and prepare it, and wait for confirmation. If confirmed, run `genesis stack add <piece...>` and follow its returned preparation prompt in the same task; then use `genesis context` and any installed technology skill. Never infer dependency commands from a component id. If declined or unmatched, continue through authoritative technology documentation without inventing a component.',
|
|
57
|
-
'- Project-owned operation sections in `genesis/stack.md` are the durable application contract. Make the implementation satisfy them or update a complete section to match evidenced reality; Genesis executes only Verification.',
|
|
58
|
-
'- Use the relevant project Agent Skills below `.agents/skills/`.',
|
|
59
|
-
'- After locating source, run `genesis context <path...>`; before adding a helper or public operation, run `genesis index <name-or-path...>` and reuse an existing owner.',
|
|
60
|
-
'- Program is fallible explanation; code, tests, and runtime behavior remain evidence.',
|
|
61
|
-
'- Keep Blueprint and affected Program explanations aligned with intentional observable product behavior in the same implementation turn. Private restructuring may need only source citations or no explanatory change.',
|
|
62
|
-
'- Before reporting completion, compare the requested observable behavior, required inputs and resources, declared project operations, and focused evidence with what actually exists. State anything not proven.',
|
|
63
|
-
'- Deslop only when explicitly requested. Genesis defines its behavior-preserving committed scope; selected Stack components may add technology-specific cleanup guidance.',
|
|
64
|
-
'- This guidance is loaded for a new session and refreshed after compaction. Continue the active request without restarting completed work.',
|
|
65
|
-
`Engineering profile: ${engineering.profile?.id || 'invalid; run the Genesis `check` operation'}.`,
|
|
66
|
-
`Selected Stack components: ${stackStatus}.`,
|
|
67
|
-
'',
|
|
68
|
-
'ENGINEERING APPROACH',
|
|
69
|
-
'',
|
|
70
|
-
engineering.guidance,
|
|
71
|
-
].join('\n'),
|
|
160
|
+
...composedContext(GENESIS_CONTRACTS.turnContext, output),
|
|
161
|
+
trust: 'untrusted',
|
|
72
162
|
};
|
|
73
163
|
}
|
package/src/index/stack.js
CHANGED
|
@@ -271,8 +271,8 @@ export async function materializeProjectStackContracts({ projectRoot, stackPacka
|
|
|
271
271
|
|
|
272
272
|
function composedProse(components, field) {
|
|
273
273
|
return components
|
|
274
|
-
.
|
|
275
|
-
.
|
|
274
|
+
.filter((piece) => piece[field])
|
|
275
|
+
.map((piece) => `### \`${piece.id}\`\n\n${piece[field]}`)
|
|
276
276
|
.join('\n\n');
|
|
277
277
|
}
|
|
278
278
|
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,10 @@ import path from 'node:path';
|
|
|
2
2
|
|
|
3
3
|
import { checkProject } from './index/check.js';
|
|
4
4
|
import { buildProjectIndex, GENESIS_DERIVED_ARTIFACTS } from './index/code-index.js';
|
|
5
|
+
import {
|
|
6
|
+
inspectProjectCollaboration,
|
|
7
|
+
setProjectCollaboration,
|
|
8
|
+
} from './index/collaboration.js';
|
|
5
9
|
import { GENESIS_CONTRACTS } from './index/contracts.js';
|
|
6
10
|
import { contextForProjectPaths } from './index/context.js';
|
|
7
11
|
import { generateProjectPrompt } from './index/prompt.js';
|
|
@@ -19,8 +23,21 @@ import { listStackCatalogPieces } from './index/stack-catalog.js';
|
|
|
19
23
|
import { addStackPieces, readStack } from './index/stack.js';
|
|
20
24
|
import { uniqueSorted } from './index/utils.js';
|
|
21
25
|
import { verifyProject } from './index/verification.js';
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
import { projectSessionContext, projectTurnContext } from './index/session-context.js';
|
|
27
|
+
import {
|
|
28
|
+
HOST_CONTEXT_RESOLVER_DATA_ENV,
|
|
29
|
+
HOST_CONTEXT_RESOLVER_ENV,
|
|
30
|
+
SESSION_CONTEXT_INSTALLED_ENV,
|
|
31
|
+
} from './index/host-context-resolver.js';
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
GENESIS_CONTRACTS,
|
|
35
|
+
HOST_CONTEXT_RESOLVER_DATA_ENV,
|
|
36
|
+
HOST_CONTEXT_RESOLVER_ENV,
|
|
37
|
+
SESSION_CONTEXT_INSTALLED_ENV,
|
|
38
|
+
projectSessionContext,
|
|
39
|
+
projectTurnContext,
|
|
40
|
+
};
|
|
24
41
|
|
|
25
42
|
function withIndexResult(result, index) {
|
|
26
43
|
const changedFiles = uniqueSorted([...result.changedFiles, ...index.changedFiles]);
|
|
@@ -115,6 +132,10 @@ export function inspectEnvironment(options) {
|
|
|
115
132
|
return inspectProjectEnvironment(options);
|
|
116
133
|
}
|
|
117
134
|
|
|
135
|
+
export function inspectCollaboration(options) {
|
|
136
|
+
return inspectProjectCollaboration(options);
|
|
137
|
+
}
|
|
138
|
+
|
|
118
139
|
export function inspectStackSection(options) {
|
|
119
140
|
return inspectProjectStackSection(options);
|
|
120
141
|
}
|
|
@@ -131,6 +152,10 @@ export function setEngineeringProfile(options) {
|
|
|
131
152
|
return selectEngineeringProfile(options);
|
|
132
153
|
}
|
|
133
154
|
|
|
155
|
+
export function setCollaboration(options) {
|
|
156
|
+
return setProjectCollaboration(options);
|
|
157
|
+
}
|
|
158
|
+
|
|
134
159
|
export function generatePrompt(options) {
|
|
135
160
|
return generateProjectPrompt(options);
|
|
136
161
|
}
|