genesis-compiler 1.8.5 → 1.8.6
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 +7 -0
- package/docs/prompt-integration.md +4 -0
- package/docs/stack-components.md +25 -0
- package/docs/templates.md +3 -0
- package/package.json +1 -1
- package/src/cli.js +21 -20
- package/src/index/project-inspection.js +4 -0
- package/src/index/stack-section-inspection.js +33 -17
- package/src/index.js +5 -1
package/README.md
CHANGED
|
@@ -1005,6 +1005,13 @@ repository. It retains the same Stack validation and performs no writes or
|
|
|
1005
1005
|
commands. Missing/invalid roots fail; this is never an automatic fallback from
|
|
1006
1006
|
Git ownership or discovery errors.
|
|
1007
1007
|
|
|
1008
|
+
`inspectStackSections({ names, projectRoot, rootMode, stackPackages })` returns
|
|
1009
|
+
an array of those same section results in the requested order. Names must be
|
|
1010
|
+
distinct and the array must be nonempty. It discovers the root once and reads
|
|
1011
|
+
the Stack once, so related sections share one Stack identity. Each call reads
|
|
1012
|
+
current files; results are not cached across calls. Missing sections retain
|
|
1013
|
+
their ordinary `unconfigured` result and repository/directory rules are unchanged.
|
|
1014
|
+
|
|
1008
1015
|
Hosts that already validate access to a shared worktree may wrap an operation
|
|
1009
1016
|
in `withTrustedGitRepository(absoluteWorktreeRoot, () => inspectEnvironment({
|
|
1010
1017
|
projectRoot: absoluteWorktreeRoot }))`. This explicitly trusts that one
|
|
@@ -99,6 +99,10 @@ The executable returns exactly one JSON result:
|
|
|
99
99
|
means the host already delivers through a native system field. This result
|
|
100
100
|
is valid only for session scope.
|
|
101
101
|
|
|
102
|
+
A validated complete host delivery is resolved before CLI project-format, Git
|
|
103
|
+
root, or Stack inspection. Unclaimed conversations and host contributions retain
|
|
104
|
+
the normal project diagnostics and composition. The resolver runs once per hook.
|
|
105
|
+
|
|
102
106
|
Malformed results and configured-resolver failures fail the hook. An unavailable
|
|
103
107
|
claimed owner must fail rather than returning `unclaimed`. Ownership belongs to
|
|
104
108
|
the native conversation: these results do not change project hook files, so
|
package/docs/stack-components.md
CHANGED
|
@@ -184,6 +184,13 @@ discovery. Default library and CLI inspection continue to use the enclosing
|
|
|
184
184
|
Git repository and its trust checks. Invalid modes or directory roots fail;
|
|
185
185
|
there is no automatic fallback.
|
|
186
186
|
|
|
187
|
+
When a consumer needs several related declarations, use
|
|
188
|
+
`inspectStackSections({ names: ['First operation', 'Second operation'], projectRoot })`.
|
|
189
|
+
It returns an array of the same `genesis.stack-section.v1` results in the requested
|
|
190
|
+
order, using one repository discovery and one fresh Stack read. All results have
|
|
191
|
+
the same Stack hash. The names array must be nonempty and contain no duplicates.
|
|
192
|
+
The explicit directory mode is also supported; no cross-call cache is retained.
|
|
193
|
+
|
|
187
194
|
## Selection and identity
|
|
188
195
|
|
|
189
196
|
`genesis stack add` records selected packages and component dependency closure,
|
|
@@ -265,3 +272,21 @@ previously effective declarations once and writing them into
|
|
|
265
272
|
`genesis/stack.md`. Existing project sections win exactly as they did before.
|
|
266
273
|
Current-format reads reject a selected component whose required contract was
|
|
267
274
|
not materialized, so a tool upgrade cannot quietly substitute a new proposal.
|
|
275
|
+
|
|
276
|
+
`genesis migrate` does not materialize newly added catalog proposals when the
|
|
277
|
+
project already uses the current format. Reconcile those explicitly with the
|
|
278
|
+
existing `genesis stack add` operation for an already-selected component. For
|
|
279
|
+
example, if `nodejs` is selected and the missing heading is
|
|
280
|
+
`## Connected development`, run `genesis stack add nodejs` and review its
|
|
281
|
+
preparation prompt. This adds the Node `npm` default without choosing connected
|
|
282
|
+
repositories or installing dependencies. Existing complete project sections
|
|
283
|
+
remain authoritative; reconcile any proposed operation against the real source.
|
|
284
|
+
Use the project's pinned compiler invocation when it declares `genesis-compiler`:
|
|
285
|
+
`npm exec --no -- genesis stack add nodejs`.
|
|
286
|
+
|
|
287
|
+
Before rolling out a catalog that adds operation proposals, operators should
|
|
288
|
+
run read-only project inspection against representative existing projects with
|
|
289
|
+
the candidate compiler and catalog. Arrange explicit reconciliation of affected
|
|
290
|
+
projects before rollout. A format marker alone does not establish compatibility
|
|
291
|
+
with new catalog proposals. Do not repair project contracts through opening,
|
|
292
|
+
status reads or another lazy write path.
|
package/docs/templates.md
CHANGED
|
@@ -14,6 +14,9 @@ application has been described or that an application has been created.
|
|
|
14
14
|
`genesis inspect project --json` is a read-only opening inspection shared by
|
|
15
15
|
the CLI, session guidance, and hosts such as Vibe64:
|
|
16
16
|
|
|
17
|
+
The diagnostics list reports each identical failure once, even when separate
|
|
18
|
+
inspectors encounter it. Distinct failures remain available for repair.
|
|
19
|
+
|
|
17
20
|
| State | Evidence | Next step |
|
|
18
21
|
| --- | --- | --- |
|
|
19
22
|
| `new` | No content beyond known bootstrap files | Choose a template or create through conversation |
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -471,7 +471,7 @@ async function cliStackPackages(projectRoot, supplied) {
|
|
|
471
471
|
return installedFirstPartyStackPackages({ projectRoot });
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
-
async function execute({ command, operands, options }, { signal } = {}) {
|
|
474
|
+
async function execute({ command, operands, options }, { signal, hostContext = null } = {}) {
|
|
475
475
|
if (command === 'parsers') {
|
|
476
476
|
const parserOptions = {
|
|
477
477
|
languages: operands.slice(1), all: options.all, directory: options.directory, signal,
|
|
@@ -576,23 +576,6 @@ async function execute({ command, operands, options }, { signal } = {}) {
|
|
|
576
576
|
return { kind: 'discover', ...await codexAdoptionRecommendation({ projectRoot }) };
|
|
577
577
|
}
|
|
578
578
|
const scope = operands[0];
|
|
579
|
-
if (scope === 'turn' && process.env.GENESIS_TURN_CONTEXT_ENABLED === '0') {
|
|
580
|
-
return { kind: 'turn', status: 'ready', output: '' };
|
|
581
|
-
}
|
|
582
|
-
if (scope === 'session' && process.env[SESSION_CONTEXT_INSTALLED_ENV] === '1') {
|
|
583
|
-
return { kind: 'session', status: 'ready', output: '' };
|
|
584
|
-
}
|
|
585
|
-
const nativeSession = await hookSessionInput();
|
|
586
|
-
const hostContext = await resolveConfiguredHostContext({
|
|
587
|
-
projectRoot,
|
|
588
|
-
...nativeSession,
|
|
589
|
-
scope,
|
|
590
|
-
});
|
|
591
|
-
// Ownership is resolved for this native conversation, not for the project.
|
|
592
|
-
// A host-owned delivery already contains everything its runtime requires.
|
|
593
|
-
if (hostContext?.kind === 'delivery') {
|
|
594
|
-
return { kind: 'session', status: 'ready', output: hostContext.text };
|
|
595
|
-
}
|
|
596
579
|
if (scope === 'turn') {
|
|
597
580
|
return hostContext === null
|
|
598
581
|
? { kind: 'turn', status: 'ready', output: '' }
|
|
@@ -669,7 +652,25 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
669
652
|
return 0;
|
|
670
653
|
}
|
|
671
654
|
options = parsed.options;
|
|
672
|
-
const
|
|
655
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
656
|
+
let hookResult = null;
|
|
657
|
+
let hostContext = null;
|
|
658
|
+
if (parsed.command === 'hook' && parsed.operands[0] !== 'discover') {
|
|
659
|
+
const scope = parsed.operands[0];
|
|
660
|
+
if ((scope === 'turn' && process.env.GENESIS_TURN_CONTEXT_ENABLED === '0') ||
|
|
661
|
+
(scope === 'session' && process.env[SESSION_CONTEXT_INSTALLED_ENV] === '1')) {
|
|
662
|
+
hookResult = { kind: scope, status: 'ready', output: '' };
|
|
663
|
+
} else {
|
|
664
|
+
const nativeSession = await hookSessionInput();
|
|
665
|
+
hostContext = await resolveConfiguredHostContext({ projectRoot, ...nativeSession, scope });
|
|
666
|
+
// A validated owner supplies the complete delivery; project composition is unused.
|
|
667
|
+
if (hostContext?.kind === 'delivery') {
|
|
668
|
+
hookResult = { kind: 'session', status: 'ready', output: hostContext.text };
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
const projectFormat = hookResult || parsed.command === 'parsers'
|
|
673
|
+
? null : await optionalProjectFormat(projectRoot);
|
|
673
674
|
const formatDiagnostic = projectFormatDiagnostic(projectFormat);
|
|
674
675
|
if (formatDiagnostic && !options.json) {
|
|
675
676
|
line(process.stderr, `WARNING: ${formatDiagnostic.message}`);
|
|
@@ -680,7 +681,7 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
680
681
|
process.once('SIGINT', abort);
|
|
681
682
|
process.once('SIGTERM', abort);
|
|
682
683
|
const result = withProjectFormatWarning(
|
|
683
|
-
await withParserCancellation(controller.signal, () => execute(parsed, { signal: controller.signal })),
|
|
684
|
+
hookResult ?? await withParserCancellation(controller.signal, () => execute(parsed, { signal: controller.signal, hostContext })),
|
|
684
685
|
projectFormat,
|
|
685
686
|
formatDiagnostic,
|
|
686
687
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
3
4
|
|
|
4
5
|
import { readBlueprint } from './blueprint.js';
|
|
5
6
|
import { readCollaboration } from './collaboration.js';
|
|
@@ -125,6 +126,9 @@ export async function inspectProject({ projectRoot, stackPackages = [] } = {}) {
|
|
|
125
126
|
try { await read(root); } catch (error) { result.diagnostics.push(asDiagnostic(error)); }
|
|
126
127
|
}
|
|
127
128
|
try { await inspectProgram(root); } catch (error) { result.diagnostics.push(asDiagnostic(error)); }
|
|
129
|
+
// Program resource validation can encounter the same Stack failure already reported above.
|
|
130
|
+
result.diagnostics = result.diagnostics.filter((diagnostic, index, diagnostics) =>
|
|
131
|
+
!diagnostics.slice(0, index).some((previous) => isDeepStrictEqual(previous, diagnostic)));
|
|
128
132
|
if (result.diagnostics.length) return result;
|
|
129
133
|
if (content.kind !== 'existing') {
|
|
130
134
|
return { ...result, state: 'new', templateEligible: true, nextAction: 'create' };
|
|
@@ -10,11 +10,25 @@ import { sha256, stableJson } from './utils.js';
|
|
|
10
10
|
/** Inspect one consumer-owned Stack section without interpreting its contents. */
|
|
11
11
|
export async function inspectProjectStackSection({
|
|
12
12
|
name,
|
|
13
|
+
...options
|
|
14
|
+
} = {}) {
|
|
15
|
+
return (await inspectProjectStackSections({ ...options, names: [name] }))[0];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Inspect several sections from one fresh Stack read, in the requested order. */
|
|
19
|
+
export async function inspectProjectStackSections({
|
|
20
|
+
names,
|
|
13
21
|
projectRoot,
|
|
14
22
|
rootMode = 'repository',
|
|
15
23
|
stackPackages = [],
|
|
16
24
|
} = {}) {
|
|
17
|
-
|
|
25
|
+
if (!Array.isArray(names) || names.length === 0) {
|
|
26
|
+
throw new TypeError('Stack section inspection requires a nonempty names array.');
|
|
27
|
+
}
|
|
28
|
+
const sectionNames = names.map(normalizeStackSectionName);
|
|
29
|
+
if (new Set(sectionNames).size !== sectionNames.length) {
|
|
30
|
+
throw new TypeError('Stack section inspection requires distinct names.');
|
|
31
|
+
}
|
|
18
32
|
let root;
|
|
19
33
|
if (rootMode === 'repository') {
|
|
20
34
|
root = (await gitContext(projectRoot)).repositoryRoot;
|
|
@@ -28,20 +42,22 @@ export async function inspectProjectStackSection({
|
|
|
28
42
|
throw new TypeError('Stack section rootMode must be repository or directory.');
|
|
29
43
|
}
|
|
30
44
|
const stack = await readStack(root, { stackPackages });
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
return sectionNames.map((sectionName) => {
|
|
46
|
+
const section = stack.extensions.find((candidate) => candidate.name === sectionName);
|
|
47
|
+
const diagnostics = [...(section?.diagnostics || [])];
|
|
48
|
+
const status = diagnostics.length > 0 ? 'blocked' : section ? 'ready' : 'unconfigured';
|
|
49
|
+
const lines = section ? [...section.lines] : [];
|
|
50
|
+
return {
|
|
51
|
+
contract: GENESIS_CONTRACTS.stackSection,
|
|
52
|
+
status,
|
|
53
|
+
stackHash: stack.identityHash,
|
|
54
|
+
sectionHash: status === 'ready' ? sha256(stableJson({ name: sectionName, lines })) : '',
|
|
55
|
+
components: stack.components.map(({ id }) => id),
|
|
56
|
+
name: sectionName,
|
|
57
|
+
source: section?.source || null,
|
|
58
|
+
content: lines.join('\n'),
|
|
59
|
+
lines,
|
|
60
|
+
diagnostics,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
47
63
|
}
|
package/src/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import { initializeProject } from './index/init.js';
|
|
|
21
21
|
import { migrateProject } from './index/migration.js';
|
|
22
22
|
import { installCodexPlugin } from './index/codex-plugin.js';
|
|
23
23
|
import { inspectProjectEnvironment } from './index/environment-files.js';
|
|
24
|
-
import { inspectProjectStackSection } from './index/stack-section-inspection.js';
|
|
24
|
+
import { inspectProjectStackSection, inspectProjectStackSections } from './index/stack-section-inspection.js';
|
|
25
25
|
import { listStackCatalogPieces } from './index/stack-catalog.js';
|
|
26
26
|
import { addStackPieces, readStack } from './index/stack.js';
|
|
27
27
|
import { uniqueSorted } from './index/utils.js';
|
|
@@ -161,6 +161,10 @@ export function inspectStackSection(options) {
|
|
|
161
161
|
return inspectProjectStackSection(options);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
export function inspectStackSections(options) {
|
|
165
|
+
return inspectProjectStackSections(options);
|
|
166
|
+
}
|
|
167
|
+
|
|
164
168
|
export function listEngineeringProfiles() {
|
|
165
169
|
return listEngineeringProfileCatalog();
|
|
166
170
|
}
|