genesis-compiler 1.2.5 → 1.2.7

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 (40) hide show
  1. package/README.md +45 -19
  2. package/docs/prompt-integration.md +1 -1
  3. package/docs/stack-components.md +19 -4
  4. package/package.json +2 -4
  5. package/plugins/genesis/.codex-plugin/plugin.json +1 -1
  6. package/prompts/adopt.txt +6 -0
  7. package/src/cli.js +38 -10
  8. package/src/index/agent-skills.js +11 -3
  9. package/src/index/check.js +30 -2
  10. package/src/index/code-index.js +7 -2
  11. package/src/index/context.js +2 -2
  12. package/src/index/contracts.js +7 -0
  13. package/src/index/deployment.js +4 -2
  14. package/src/index/environment-files.js +8 -2
  15. package/src/index/init.js +2 -2
  16. package/src/index/launch.js +4 -1
  17. package/src/index/process.js +119 -5
  18. package/src/index/prompt.js +24 -16
  19. package/src/index/stack-catalog.js +111 -26
  20. package/src/index/stack.js +60 -8
  21. package/src/index/verification.js +15 -1
  22. package/src/index/workspace-setup.js +12 -2
  23. package/src/index.js +29 -17
  24. package/stacks/pieces/cpp.md +0 -34
  25. package/stacks/pieces/csharp.md +0 -22
  26. package/stacks/pieces/go.md +0 -22
  27. package/stacks/pieces/java.md +0 -22
  28. package/stacks/pieces/jskit-mysql.md +0 -56
  29. package/stacks/pieces/jskit-postgresql.md +0 -56
  30. package/stacks/pieces/jskit.md +0 -114
  31. package/stacks/pieces/kotlin.md +0 -22
  32. package/stacks/pieces/mysql.md +0 -29
  33. package/stacks/pieces/nodejs.md +0 -36
  34. package/stacks/pieces/php.md +0 -23
  35. package/stacks/pieces/postgresql.md +0 -30
  36. package/stacks/pieces/python.md +0 -23
  37. package/stacks/pieces/ruby.md +0 -22
  38. package/stacks/pieces/rust.md +0 -22
  39. package/stacks/pieces/shell.md +0 -23
  40. package/stacks/pieces/vue.md +0 -28
package/README.md CHANGED
@@ -51,6 +51,18 @@ completely or correctly explains the implementation.
51
51
 
52
52
  Genesis requires Node.js 22 or newer and Git.
53
53
 
54
+ Install the framework-neutral compiler and the optional first-party technology
55
+ catalog as separate packages:
56
+
57
+ ```bash
58
+ npm install --global genesis-compiler genesis-stack
59
+ ```
60
+
61
+ `genesis-compiler` has no dependency on `genesis-stack` or on any framework.
62
+ The catalog is static Markdown and contains the complete curated set of
63
+ language, database, UI, and framework pieces. A host may supply another catalog
64
+ through the same contract.
65
+
54
66
  For an existing codebase, `adopt` is the direct entry point:
55
67
 
56
68
  ```bash
@@ -102,7 +114,8 @@ that, use Codex normally. No technology is assumed until you explicitly select
102
114
  Stack components:
103
115
 
104
116
  ```bash
105
- genesis stack add nodejs # or jskit jskit-mysql / jskit-postgresql
117
+ genesis stack add --stack-package genesis-stack nodejs
118
+ # or: genesis stack add --stack-package genesis-stack jskit jskit-mysql
106
119
  ```
107
120
 
108
121
  Genesis does not install substitute generic `nodejs`, `vue`, `php`, or similar
@@ -110,8 +123,9 @@ skills. Official, user, or host skills retain their normal names. A Stack piece
110
123
  may instead name one authoritative technology skill; Genesis copies that
111
124
  complete directory into `.agents/skills/`, including its `references/`,
112
125
  `scripts/`, `assets/`, and agent metadata. The agent loads those resources only
113
- when the skill requires them. For example, the JSKIT piece installs the JSKIT
114
- package's own `jskit` skill. A piece's optional `## Guidance` is concise
126
+ when the skill requires them. For example, the `genesis-stack` catalog's JSKIT
127
+ piece installs the JSKIT package's own `jskit` skill. A piece's optional
128
+ `## Guidance` is concise
115
129
  supplemental project-work guidance; it does not create or replace a generic
116
130
  technology skill.
117
131
 
@@ -130,8 +144,8 @@ execute the same normalized recipe themselves. A concrete Stack piece may declar
130
144
  ordered `## Workspace setup` recipe with labels, argument arrays expressed as
131
145
  backticked tokens, abstract runtimes, and optional project-relative working
132
146
  directories and readiness paths. A recipe whose declared project marker does
133
- not exist remains unconfigured until a later inspection. The built-in `jskit`
134
- piece waits for `package.json` and then declares `npm install`; generic
147
+ not exist remains unconfigured until a later inspection. The catalog's
148
+ `jskit` piece waits for `package.json` and then declares `npm install`; generic
135
149
  `nodejs` and `php` deliberately declare no installer. One project section in
136
150
  `genesis/stack.md` replaces all component defaults, including with
137
151
  `- Nothing.`. Without that override, exactly one component recipe is used;
@@ -143,7 +157,7 @@ resources such as database variables do not gate dependency installation.
143
157
  Hosts that manage project environments can call `inspectEnvironment()`.
144
158
  Concrete Stack integrations may declare public, non-secret Environment
145
159
  defaults such as the database driver selected by that integration. Explicit
146
- host or user values take precedence. The built-in JSKIT MySQL and PostgreSQL
160
+ host or user values take precedence. The catalog's JSKIT MySQL and PostgreSQL
147
161
  pieces respectively declare `DB_CLIENT=mysql2` and `DB_CLIENT=pg`, so users
148
162
  provide connection values rather than restating a deterministic technology
149
163
  choice.
@@ -164,7 +178,8 @@ optional readable `## Launch` section in `genesis/stack.md` declares labeled
164
178
  targets, exact backticked argument tokens, relative working directories,
165
179
  abstract runtime requirements, `{host}`/`{port}` substitutions, and an optional
166
180
  application-owned Preview identity block. Concrete components may provide a
167
- default: `jskit` declares its app-owned `npm run develop` command; generic
181
+ default: the catalog's `jskit` piece declares its app-owned `npm run develop`
182
+ command; generic
168
183
  `nodejs` and `php` do not guess. Genesis starts nothing itself. It returns preview identity
169
184
  command metadata and environment variable names, never their values. The host
170
185
  continues to own pinned runtimes, ports, processes, readiness probing and
@@ -177,7 +192,7 @@ Hosts that publish applications can call the separate public
177
192
  `inspectDeployment()` API. An optional readable `## Deployment` section
178
193
  declares an ordered production recipe: project-relative workdir, abstract
179
194
  runtimes, exact Prepare/Build/Migrate/Serve argv, and one HTTP readiness
180
- predicate. A concrete component may provide the recipe; the built-in `jskit`
195
+ predicate. A concrete component may provide the recipe; the catalog's `jskit`
181
196
  piece declares production dependency installation, build, database preparation,
182
197
  `npm start`, and `/api/health`. Generic language pieces do not guess. A project
183
198
  section replaces component defaults wholesale, and `- Nothing.` explicitly
@@ -201,8 +216,9 @@ genesis inspect deployment --json
201
216
  ```
202
217
 
203
218
  Without `--json`, the commands print concise human-readable summaries. They
204
- never execute setup, start a process, probe a server, materialize environment
205
- files, or deploy.
219
+ never start the application, probe a server, materialize environment files, or
220
+ deploy. `genesis prepare` is the separate explicit command that executes only
221
+ the finite Workspace setup recipe.
206
222
 
207
223
  At session start, Codex receives only a short explanation of how Genesis is
208
224
  organized. After it locates the source involved in a request, it can load the
@@ -354,17 +370,19 @@ object.
354
370
 
355
371
  ## Stack
356
372
 
357
- List and select the built-in Stack components:
373
+ List and select pieces from the installed optional catalog:
358
374
 
359
375
  ```bash
360
- genesis stack list
361
- genesis stack add jskit jskit-mysql # or jskit-postgresql
376
+ genesis stack list --stack-package genesis-stack
377
+ genesis stack add --stack-package genesis-stack jskit jskit-mysql
362
378
  ```
363
379
 
364
- `genesis/stack.md` records component ids and optional project verification
365
- commands. Selecting no components is valid. Built-in components include the
366
- eleven common language families listed above, plus Vue, MySQL, PostgreSQL,
367
- JSKIT, and JSKIT database integrations. Components may contribute:
380
+ `genesis/stack.md` records the owning Stack package, component ids, and optional
381
+ project verification commands. After the first selection, ordinary commands
382
+ resolve the recorded package without another flag. Selecting no components is
383
+ valid. `genesis-stack` contains the eleven common language families listed
384
+ above, plus Vue, MySQL, PostgreSQL, JSKIT, and JSKIT database integrations.
385
+ Components may contribute:
368
386
 
369
387
  - a concise description and supplemental Guidance used across relevant tasks;
370
388
  - existing-project Adoption requirements used only while importing a codebase;
@@ -380,8 +398,8 @@ cleanup tasks; `Adoption` adds import-only requirements; `Deslop` adds
380
398
  cleanup-only rules. None shadows an official generic technology skill or
381
399
  assumes that an upstream skill contains every rule Genesis needs.
382
400
 
383
- Genesis core contains no database, framework, language, or platform-specific
384
- controller behavior. See [Stack components](docs/stack-components.md).
401
+ Genesis core contains no Stack pieces and no database, framework, language, or
402
+ platform dependency. See [Stack components](docs/stack-components.md).
385
403
 
386
404
  ## Verification
387
405
 
@@ -428,6 +446,8 @@ genesis check
428
446
  - Blueprint and Stack validity;
429
447
  - selected Agent Skill presence and structural validity;
430
448
  - Program presence and structural validity;
449
+ - Workspace setup, environment, Launch, and Deployment as `ready`, `blocked`,
450
+ or honestly `unconfigured`;
431
451
  - missing Stack-declared environment inputs (without claiming the service is
432
452
  reachable);
433
453
  - verification evidence as `current`, `stale`, `missing`, `invalid`, or
@@ -484,6 +504,12 @@ identity, secret, and browser policy.
484
504
  `inspectDeployment()` returns the separate normalized production recipe without
485
505
  executing or provisioning it.
486
506
 
507
+ Normalized operational results identify their stable public contract in the
508
+ `contract` field: `genesis.workspace-setup.v1`, `genesis.environment.v1`,
509
+ `genesis.launch.v1`, `genesis.deployment.v1`, or
510
+ `genesis.verification.v1`. Hosts validate that identity instead of
511
+ feature-detecting individual fields.
512
+
487
513
  A host such as Vibe64 can send the generated prompt to its existing agent:
488
514
 
489
515
  ```js
@@ -35,7 +35,7 @@ Genesis keeps each instruction at one useful level:
35
35
  project's `.agents/skills/` directory.
36
36
  - `prompts/<task>.txt` is a task launcher. It selects the relevant
37
37
  workflow skill and states only that turn's edit boundary.
38
- - `stacks/pieces/<component>.md` supplies concise Description, supplemental
38
+ - a declared Stack package's `stacks/pieces/<component>.md` supplies concise Description, supplemental
39
39
  Guidance, Adoption requirements, Resources, Deslop overlays, structural Indexers, verification
40
40
  Commands, and an optional authoritative Agent Skill source.
41
41
  - `genesis/blueprint.md`, `genesis/program/`, and `genesis/stack.md` are the
@@ -1,8 +1,23 @@
1
1
  # Stack components
2
2
 
3
3
  Genesis core knows no framework, language, database, package manager, or
4
- environment-variable name. A built-in component is one Markdown file at
5
- `stacks/pieces/<id>.md`.
4
+ environment-variable name, and it ships no technology pieces. A Stack package
5
+ is an ordinary npm package with one static manifest pointer:
6
+
7
+ ```json
8
+ {
9
+ "name": "example-stack",
10
+ "genesis": { "stackPieces": "stacks/pieces" }
11
+ }
12
+ ```
13
+
14
+ Each piece is one Markdown file in that declared directory. Genesis reads the
15
+ manifest and Markdown only; it never imports or executes package code. Catalog
16
+ names are explicit, collisions fail, and the selected package is recorded in
17
+ the project's `## Stack packages` section. The first-party optional
18
+ `genesis-stack` package contains the complete curated catalog; Genesis core does
19
+ not depend on it. A framework contributes to that catalog rather than requiring
20
+ a compiler release or a separate catalog package.
6
21
 
7
22
  ````markdown
8
23
  # Stack piece: example
@@ -169,7 +184,7 @@ environment name and value. Selected
169
184
  component defaults compose by name; identical declarations collapse and
170
185
  different values fail rather than silently choosing one. Defaults participate
171
186
  in Stack identity, resource preflight, prompt context, Launch inspection, and
172
- verification execution. The JSKIT database integrations use this contract for
187
+ verification execution. The `genesis-stack` JSKIT database integrations use this contract for
173
188
  their deterministic `DB_CLIENT` driver ids; generic database pieces do not.
174
189
  Secrets and deployment-specific connection values remain host inputs and must
175
190
  never be declared as defaults.
@@ -288,7 +303,7 @@ district to a region and a campus while generating
288
303
  must not reclassify or filter paths. Under a matched prefix, the first directory
289
304
  is a campus, while files directly below the prefix belong to the prefix campus.
290
305
  Under the fallback, each top-level directory is a campus and project-root files
291
- belong to the project-root campus. The built-in JSKIT piece excludes exact
306
+ belong to the project-root campus. The `genesis-stack` JSKIT piece excludes exact
292
307
  `test`, `tests`, and `__tests__` path segments plus `*.test.*` and `*.spec.*`
293
308
  files, then declares `Packages`, `Source`, and `Everything else`.
294
309
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genesis-compiler",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "type": "module",
5
5
  "description": "An agent-independent prompt, multi-language code-index, cleanup, and verification companion with optional Codex hooks.",
6
6
  "repository": {
@@ -39,8 +39,7 @@
39
39
  "prompts/work.txt",
40
40
  "plugins/genesis",
41
41
  "skills",
42
- "src",
43
- "stacks/pieces"
42
+ "src"
44
43
  ],
45
44
  "scripts": {
46
45
  "test": "node --test test/*.test.js"
@@ -58,7 +57,6 @@
58
57
  "@ast-grep/lang-ruby": "^0.0.7",
59
58
  "@ast-grep/lang-rust": "^0.0.7",
60
59
  "@ast-grep/napi": "^0.45.1",
61
- "@jskit-ai/agent-docs": "0.1.134",
62
60
  "yaml": "^2.9.0"
63
61
  }
64
62
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genesis",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "Makes Codex aware of optional Genesis adoption for existing projects.",
5
5
  "author": {
6
6
  "name": "Mobily Enterprises"
package/prompts/adopt.txt CHANGED
@@ -50,6 +50,12 @@ or tool-specific manifests as evidence and carry every still-valid fact into
50
50
  Genesis; never add a permanent legacy reader or shim. Do not delete an old
51
51
  manifest until all of its live facts have been accounted for.
52
52
 
53
+ The resulting project contract may therefore own complete `## Resources`,
54
+ `## Environment defaults`, `## Environment files`, `## Workspace setup`,
55
+ `## Commands`, `## Launch`, and `## Deployment` sections. Treat these as one
56
+ operational inventory: do not preserve setup while silently dropping its
57
+ resource, launch, readiness, identity, verification, or deployment counterpart.
58
+
53
59
  Create the non-technical Blueprint and useful subsystem-oriented Program from
54
60
  current source and tests. Do not cite archive internals or Git object storage as
55
61
  implementation source; Program sources must be current Git-visible files.
package/src/cli.js CHANGED
@@ -44,6 +44,7 @@ const USAGE = `Usage:
44
44
 
45
45
  Options:
46
46
  --project-root <path> Set the project root (default: current directory)
47
+ --stack-package <name> Add an installed external Stack package (repeatable)
47
48
  --task <task> Select the prompt task (default: work)
48
49
  --json Emit one machine-readable result
49
50
  -h, --help Show this help
@@ -70,6 +71,7 @@ function parseCommand(argv) {
70
71
  options: {
71
72
  json: { type: 'boolean', default: false },
72
73
  'project-root': { type: 'string' },
74
+ 'stack-package': { type: 'string', multiple: true, default: [] },
73
75
  task: { type: 'string' },
74
76
  },
75
77
  });
@@ -79,6 +81,7 @@ function parseCommand(argv) {
79
81
  const options = {
80
82
  json: parsed.values.json,
81
83
  projectRoot: parsed.values['project-root'],
84
+ stackPackages: parsed.values['stack-package'],
82
85
  task: parsed.values.task,
83
86
  };
84
87
  const operands = parsed.positionals;
@@ -131,6 +134,10 @@ function writeCheck(result) {
131
134
  line(process.stdout, `Stack: ${result.stack}`);
132
135
  line(process.stdout, `Agent Skills: ${result.skills}`);
133
136
  line(process.stdout, `Program: ${result.program}`);
137
+ line(process.stdout, `Workspace setup: ${result.workspaceSetup}`);
138
+ line(process.stdout, `Environment: ${result.environment}`);
139
+ line(process.stdout, `Launch: ${result.launch}`);
140
+ line(process.stdout, `Deployment: ${result.deployment}`);
134
141
  line(process.stdout, `Resource inputs: ${result.resources}`);
135
142
  line(process.stdout, `Verification: ${result.verification}`);
136
143
  namedItems('Program files', result.programFiles);
@@ -262,26 +269,30 @@ async function hookInput() {
262
269
  }
263
270
  }
264
271
 
265
- async function execute({ command, operands, options }) {
272
+ async function execute({ command, operands, options }, { signal } = {}) {
266
273
  const projectRoot = options.projectRoot || process.cwd();
267
- if (command === 'init') return initialize({ projectRoot });
274
+ const stackPackages = options.stackPackages || [];
275
+ if (command === 'init') return initialize({ projectRoot, stackPackages });
268
276
  if (command === 'adopt') {
269
- return adoptProject({ projectRoot, request: operands.join(' ') });
277
+ return adoptProject({ projectRoot, request: operands.join(' '), stackPackages });
270
278
  }
271
279
  if (command === 'codex') return installCodex();
272
280
  if (command === 'stack') {
273
- if (operands[0] === 'list') return { status: 'ok', pieces: await listStackPieces() };
274
- return addStack({ pieces: operands.slice(1), projectRoot });
281
+ if (operands[0] === 'list') {
282
+ return { status: 'ok', pieces: await listStackPieces({ projectRoot, stackPackages }) };
283
+ }
284
+ return addStack({ pieces: operands.slice(1), projectRoot, stackPackages });
275
285
  }
276
286
  if (command === 'prompt') {
277
287
  return generatePrompt({
278
288
  projectRoot,
279
289
  task: options.task || 'work',
280
290
  request: operands.join(' '),
291
+ stackPackages,
281
292
  });
282
293
  }
283
- if (command === 'context') return getContext({ paths: operands, projectRoot });
284
- if (command === 'index') return indexCodebase({ projectRoot, queries: operands });
294
+ if (command === 'context') return getContext({ paths: operands, projectRoot, stackPackages });
295
+ if (command === 'index') return indexCodebase({ projectRoot, queries: operands, stackPackages });
285
296
  if (command === 'inspect') {
286
297
  const inspections = {
287
298
  workspace: inspectWorkspaceSetup,
@@ -289,11 +300,16 @@ async function execute({ command, operands, options }) {
289
300
  launch: inspectLaunch,
290
301
  deployment: inspectDeployment,
291
302
  };
292
- return { inspection: operands[0], ...await inspections[operands[0]]({ projectRoot }) };
303
+ return {
304
+ inspection: operands[0],
305
+ ...await inspections[operands[0]]({ projectRoot, stackPackages }),
306
+ };
293
307
  }
294
308
  if (command === 'prepare') {
295
309
  return prepareWorkspace({
296
310
  projectRoot,
311
+ signal,
312
+ stackPackages,
297
313
  onEvent: (event) => {
298
314
  if (!options.json) line(process.stderr, event.message);
299
315
  },
@@ -318,17 +334,21 @@ async function execute({ command, operands, options }) {
318
334
  if (command === 'verify') {
319
335
  return verify({
320
336
  projectRoot,
337
+ signal,
338
+ stackPackages,
321
339
  onEvent: (event) => {
322
340
  if (!options.json) line(process.stderr, event.message);
323
341
  },
324
342
  });
325
343
  }
326
- if (command === 'check') return check({ projectRoot });
344
+ if (command === 'check') return check({ projectRoot, stackPackages });
327
345
  fail('CLI_UNKNOWN_COMMAND', `Unknown command: ${command}`);
328
346
  }
329
347
 
330
348
  export async function runCli(argv = process.argv.slice(2)) {
331
349
  let options = {};
350
+ const controller = new AbortController();
351
+ const abort = () => controller.abort();
332
352
  try {
333
353
  const parsed = parseCommand(argv);
334
354
  if (parsed.command === 'help') {
@@ -336,7 +356,12 @@ export async function runCli(argv = process.argv.slice(2)) {
336
356
  return 0;
337
357
  }
338
358
  options = parsed.options;
339
- const result = await execute(parsed);
359
+ const finiteCommand = ['prepare', 'verify'].includes(parsed.command);
360
+ if (finiteCommand) {
361
+ process.once('SIGINT', abort);
362
+ process.once('SIGTERM', abort);
363
+ }
364
+ const result = await execute(parsed, { signal: controller.signal });
340
365
  if (options.json) line(process.stdout, JSON.stringify(result));
341
366
  else writeResult(parsed.command, result);
342
367
  return ['blocked', 'failed', 'invalid'].includes(result?.status) ? 2 : 0;
@@ -345,5 +370,8 @@ export async function runCli(argv = process.argv.slice(2)) {
345
370
  if (options.json) line(process.stderr, JSON.stringify(diagnostic));
346
371
  else line(process.stderr, `${diagnostic.code}: ${diagnostic.message}`);
347
372
  return 1;
373
+ } finally {
374
+ process.removeListener('SIGINT', abort);
375
+ process.removeListener('SIGTERM', abort);
348
376
  }
349
377
  }
@@ -156,8 +156,14 @@ async function describeSkill(directory, source) {
156
156
  };
157
157
  }
158
158
 
159
- async function packageDirectory(packageName) {
160
- for (const modulesRoot of require.resolve.paths(packageName) || []) {
159
+ async function packageDirectory(packageName, resolveFrom = null) {
160
+ const roots = [
161
+ ...(resolveFrom
162
+ ? createRequire(path.join(resolveFrom, 'package.json')).resolve.paths(packageName) || []
163
+ : []),
164
+ ...(require.resolve.paths(packageName) || []),
165
+ ];
166
+ for (const modulesRoot of [...new Set(roots)]) {
161
167
  const manifest = path.join(modulesRoot, packageName, 'package.json');
162
168
  try {
163
169
  const value = JSON.parse(await readFile(manifest, 'utf8'));
@@ -180,7 +186,9 @@ async function packageDirectory(packageName) {
180
186
  }
181
187
 
182
188
  async function resolveLocator(locator) {
183
- const root = locator.package ? await packageDirectory(locator.package) : packageRoot;
189
+ const root = locator.package
190
+ ? await packageDirectory(locator.package, locator.resolveFrom)
191
+ : packageRoot;
184
192
  const directory = path.join(root, locator.path);
185
193
  const source = locator.source || (
186
194
  locator.package
@@ -7,6 +7,10 @@ import { inspectProgram } from './program.js';
7
7
  import { inspectVerification } from './project-state.js';
8
8
  import { missingStackResources } from './stack-preflight.js';
9
9
  import { withStackEnvironmentDefaults } from './stack-environment-defaults.js';
10
+ import { inspectProjectEnvironment } from './environment-files.js';
11
+ import { inspectProjectLaunch } from './launch.js';
12
+ import { inspectProjectDeployment } from './deployment.js';
13
+ import { inspectWorkspaceSetupForStack } from './workspace-setup.js';
10
14
 
11
15
  function invalidResult(area, error) {
12
16
  return {
@@ -15,6 +19,10 @@ function invalidResult(area, error) {
15
19
  stack: area === 'stack' ? 'invalid' : 'unknown',
16
20
  skills: area === 'skills' ? 'invalid' : 'unknown',
17
21
  program: 'unknown',
22
+ workspaceSetup: 'unknown',
23
+ environment: 'unknown',
24
+ launch: 'unknown',
25
+ deployment: 'unknown',
18
26
  resources: 'unknown',
19
27
  verification: 'unknown',
20
28
  programFiles: [],
@@ -24,7 +32,11 @@ function invalidResult(area, error) {
24
32
  };
25
33
  }
26
34
 
27
- export async function checkProject({ environment = process.env, projectRoot } = {}) {
35
+ export async function checkProject({
36
+ environment = process.env,
37
+ projectRoot,
38
+ stackPackages = [],
39
+ } = {}) {
28
40
  const root = (await gitContext(projectRoot)).repositoryRoot;
29
41
  try {
30
42
  await readBlueprint(root, { required: true, requireDescription: true });
@@ -34,7 +46,7 @@ export async function checkProject({ environment = process.env, projectRoot } =
34
46
 
35
47
  let stack;
36
48
  try {
37
- stack = await readStack(root);
49
+ stack = await readStack(root, { stackPackages });
38
50
  } catch (error) {
39
51
  return invalidResult('stack', error);
40
52
  }
@@ -61,10 +73,18 @@ export async function checkProject({ environment = process.env, projectRoot } =
61
73
  resources: stack.resources,
62
74
  });
63
75
  const verification = await inspectVerification({ projectRoot: root, stack });
76
+ const [workspaceSetup, projectEnvironment, launch, deployment] = await Promise.all([
77
+ inspectWorkspaceSetupForStack({ projectRoot: root, stack }),
78
+ inspectProjectEnvironment({ environment, projectRoot: root, stackPackages }),
79
+ inspectProjectLaunch({ environment, projectRoot: root, stackPackages }),
80
+ inspectProjectDeployment({ projectRoot: root, stackPackages }),
81
+ ]);
64
82
  const diagnostics = [
65
83
  ...(program.diagnostic ? [program.diagnostic] : []),
66
84
  ...skills.diagnostics,
67
85
  ...missingResources,
86
+ ...workspaceSetup.diagnostics.filter(({ code }) => code !== 'STACK_WORKSPACE_SETUP_WAITING'),
87
+ ...deployment.diagnostics,
68
88
  ...(verification.status === 'invalid' ? [{
69
89
  code: 'VERIFICATION_EVIDENCE_INVALID',
70
90
  message: 'Saved verification evidence is malformed.',
@@ -79,6 +99,8 @@ export async function checkProject({ environment = process.env, projectRoot } =
79
99
  if (missingResources.length > 0) {
80
100
  guidance.push(`${missingResources.map(({ message }) => message).join(' ')} Prompt generation remains available.`);
81
101
  }
102
+ if (workspaceSetup.status === 'blocked') guidance.push('Repair the project Workspace setup declaration.');
103
+ if (deployment.status === 'blocked') guidance.push('Repair the project Deployment declaration.');
82
104
  if (['missing', 'stale'].includes(verification.status)) guidance.push('Run genesis verify to refresh concrete evidence.');
83
105
  if (verification.status === 'unconfigured') guidance.push('Add project verification commands to genesis/stack.md.');
84
106
  guidance.push('Use genesis prompt --task review for a semantic, evidence-based comparison.');
@@ -86,6 +108,8 @@ export async function checkProject({ environment = process.env, projectRoot } =
86
108
  const needsAttention = program.status === 'missing'
87
109
  || skills.status === 'missing'
88
110
  || missingResources.length > 0
111
+ || workspaceSetup.status === 'blocked'
112
+ || deployment.status === 'blocked'
89
113
  || ['missing', 'stale', 'unconfigured'].includes(verification.status);
90
114
 
91
115
  return {
@@ -96,6 +120,10 @@ export async function checkProject({ environment = process.env, projectRoot } =
96
120
  stack: 'valid',
97
121
  skills: skills.status,
98
122
  program: program.status,
123
+ workspaceSetup: workspaceSetup.status,
124
+ environment: projectEnvironment.status,
125
+ launch: launch.status,
126
+ deployment: deployment.status,
99
127
  resources: missingResources.length > 0 ? 'missing' : 'inputs-present',
100
128
  verification: verification.status,
101
129
  programFiles: program.files,
@@ -238,9 +238,14 @@ function formatCount(value, singular) {
238
238
  return `${value} ${singular}${value === 1 ? '' : 's'}`;
239
239
  }
240
240
 
241
- export async function buildProjectIndex({ projectRoot, queries = [], write = true } = {}) {
241
+ export async function buildProjectIndex({
242
+ projectRoot,
243
+ queries = [],
244
+ stackPackages = [],
245
+ write = true,
246
+ } = {}) {
242
247
  const root = (await gitContext(projectRoot)).repositoryRoot;
243
- const stack = await readStack(root);
248
+ const stack = await readStack(root, { stackPackages });
244
249
  const states = await gitVisibleFileStates(root, { includePath: isProjectContentPath });
245
250
  const files = [...states]
246
251
  .filter(([filePath, state]) => (
@@ -49,7 +49,7 @@ function pathMatchesTarget(filePath, target) {
49
49
  return !target || filePath === target || filePath.startsWith(`${target}/`);
50
50
  }
51
51
 
52
- export async function contextForProjectPaths({ paths, projectRoot } = {}) {
52
+ export async function contextForProjectPaths({ paths, projectRoot, stackPackages = [] } = {}) {
53
53
  if (!Array.isArray(paths) || paths.length === 0) {
54
54
  throw new GenesisError('CONTEXT_PATH_REQUIRED', 'Genesis context requires at least one project path.');
55
55
  }
@@ -62,7 +62,7 @@ export async function contextForProjectPaths({ paths, projectRoot } = {}) {
62
62
  modules: [],
63
63
  diagnostic: asDiagnostic(error),
64
64
  })),
65
- readStack(root),
65
+ readStack(root, { stackPackages }),
66
66
  ]);
67
67
  const modules = program.modules.filter((module) => targets.some((target) => citesTarget(module, target)));
68
68
  const moduleSources = await Promise.all(modules.map(async (module) => ({
@@ -0,0 +1,7 @@
1
+ export const GENESIS_CONTRACTS = Object.freeze({
2
+ deployment: 'genesis.deployment.v1',
3
+ environment: 'genesis.environment.v1',
4
+ launch: 'genesis.launch.v1',
5
+ verification: 'genesis.verification.v1',
6
+ workspaceSetup: 'genesis.workspace-setup.v1',
7
+ });
@@ -1,11 +1,12 @@
1
1
  import { gitContext } from './git.js';
2
2
  import { readStack } from './stack.js';
3
3
  import { sha256, stableJson, uniqueSorted } from './utils.js';
4
+ import { GENESIS_CONTRACTS } from './contracts.js';
4
5
 
5
6
  /** Read the Stack's production recipe without provisioning or publishing anything. */
6
- export async function inspectProjectDeployment({ projectRoot } = {}) {
7
+ export async function inspectProjectDeployment({ projectRoot, stackPackages = [] } = {}) {
7
8
  const root = (await gitContext(projectRoot)).repositoryRoot;
8
- const stack = await readStack(root);
9
+ const stack = await readStack(root, { stackPackages });
9
10
  const diagnostics = [...stack.deployment.diagnostics];
10
11
  let status = 'unconfigured';
11
12
  if (diagnostics.length > 0) status = 'blocked';
@@ -18,6 +19,7 @@ export async function inspectProjectDeployment({ projectRoot } = {}) {
18
19
  steps: stack.deployment.steps,
19
20
  };
20
21
  return {
22
+ contract: GENESIS_CONTRACTS.deployment,
21
23
  status,
22
24
  stackHash: stack.identityHash,
23
25
  recipeHash: status === 'ready' ? sha256(stableJson(recipe)) : '',
@@ -2,11 +2,16 @@ import { gitContext } from './git.js';
2
2
  import { readStack } from './stack.js';
3
3
  import { withStackEnvironmentDefaults } from './stack-environment-defaults.js';
4
4
  import { missingStackResources } from './stack-preflight.js';
5
+ import { GENESIS_CONTRACTS } from './contracts.js';
5
6
 
6
7
  /** Inspect Stack environment requirements without returning supplied host values. */
7
- export async function inspectProjectEnvironment({ environment = process.env, projectRoot } = {}) {
8
+ export async function inspectProjectEnvironment({
9
+ environment = process.env,
10
+ projectRoot,
11
+ stackPackages = [],
12
+ } = {}) {
8
13
  const root = (await gitContext(projectRoot)).repositoryRoot;
9
- const stack = await readStack(root);
14
+ const stack = await readStack(root, { stackPackages });
10
15
  const diagnostics = missingStackResources({
11
16
  environment: withStackEnvironmentDefaults(environment, stack.environmentDefaults),
12
17
  resources: stack.resources,
@@ -15,6 +20,7 @@ export async function inspectProjectEnvironment({ environment = process.env, pro
15
20
  || stack.environmentFiles.length > 0
16
21
  || stack.resources.length > 0;
17
22
  return {
23
+ contract: GENESIS_CONTRACTS.environment,
18
24
  status: !configured ? 'unconfigured' : diagnostics.length > 0 ? 'missing-inputs' : 'ready',
19
25
  stackHash: stack.identityHash,
20
26
  components: stack.components.map(({ id }) => id),
package/src/index/init.js CHANGED
@@ -20,14 +20,14 @@ async function createIfMissing(projectRoot, relativePath, source) {
20
20
  }
21
21
  }
22
22
 
23
- export async function initializeProject({ projectRoot } = {}) {
23
+ export async function initializeProject({ projectRoot, stackPackages = [] } = {}) {
24
24
  const root = (await gitContext(projectRoot)).repositoryRoot;
25
25
  const created = (await Promise.all([
26
26
  createIfMissing(root, BLUEPRINT_PATH, BLUEPRINT_SKELETON_SOURCE),
27
27
  createIfMissing(root, STACK_PATH, EMPTY_STACK_SOURCE),
28
28
  ])).filter(Boolean);
29
29
  await mkdir(path.join(root, PROGRAM_ROOT), { recursive: true });
30
- const stack = await readStack(root);
30
+ const stack = await readStack(root, { stackPackages });
31
31
  const skills = await syncProjectSkills({ projectRoot: root, stack });
32
32
  const hooks = await installCodexHooks({ projectRoot: root });
33
33
  const changedFiles = [...created, ...hooks.changedFiles, ...skills.changedFiles].sort();
@@ -3,14 +3,16 @@ import { missingStackResources } from './stack-preflight.js';
3
3
  import { withStackEnvironmentDefaults } from './stack-environment-defaults.js';
4
4
  import { readStack } from './stack.js';
5
5
  import { uniqueSorted } from './utils.js';
6
+ import { GENESIS_CONTRACTS } from './contracts.js';
6
7
 
7
8
  /** Read the Stack's launch declaration without choosing or starting a runtime. */
8
9
  export async function inspectProjectLaunch({
9
10
  environment = process.env,
10
11
  projectRoot,
12
+ stackPackages = [],
11
13
  } = {}) {
12
14
  const root = (await gitContext(projectRoot)).repositoryRoot;
13
- const stack = await readStack(root);
15
+ const stack = await readStack(root, { stackPackages });
14
16
  const diagnostics = missingStackResources({
15
17
  environment: withStackEnvironmentDefaults(environment, stack.environmentDefaults),
16
18
  resources: stack.resources,
@@ -27,6 +29,7 @@ export async function inspectProjectLaunch({
27
29
  if (targets.length === 0) status = 'unconfigured';
28
30
  else if (diagnostics.length > 0) status = 'blocked';
29
31
  return {
32
+ contract: GENESIS_CONTRACTS.launch,
30
33
  status,
31
34
  stackHash: stack.identityHash,
32
35
  components: stack.components.map(({ id }) => id),