genesis-compiler 1.2.17 → 1.2.18
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 +62 -5
- package/docs/assurance-model.md +5 -3
- package/docs/prompt-integration.md +6 -1
- package/package.json +2 -1
- package/plugins/genesis/.codex-plugin/plugin.json +1 -1
- package/profiles/engineering/baseline.md +6 -0
- package/profiles/engineering/durable.v1.md +11 -0
- package/profiles/engineering/focused.v1.md +11 -0
- package/profiles/engineering/high-assurance.v1.md +11 -0
- package/prompts/start.txt +8 -0
- package/skills/genesis-deslop/SKILL.md +5 -0
- package/skills/genesis-project/SKILL.md +17 -5
- package/src/cli.js +80 -1
- package/src/index/check.js +12 -0
- package/src/index/codex-hooks.js +52 -7
- package/src/index/context.js +10 -1
- package/src/index/contracts.js +1 -0
- package/src/index/engineering.js +274 -0
- package/src/index/init.js +4 -1
- package/src/index/paths.js +1 -0
- package/src/index/prompt.js +35 -3
- package/src/index.js +17 -0
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ interaction.
|
|
|
13
13
|
```text
|
|
14
14
|
genesis/
|
|
15
15
|
blueprint.md non-technical product intent
|
|
16
|
+
engineering.md selected engineering profile and project-specific requirements
|
|
16
17
|
stack.md selected technology guidance, verification, declarations, and opaque extensions
|
|
17
18
|
stack/ optional per-component Description, Guidance, Adoption, Post-change, and Deslop customization
|
|
18
19
|
program/ concise explanations grouped into conceptual subsystems
|
|
@@ -104,8 +105,8 @@ assistant runs `genesis adopt`; the person need not know Genesis terminology or
|
|
|
104
105
|
type a command. It never runs adoption without approval and does nothing in an
|
|
105
106
|
empty or already-adopted project.
|
|
106
107
|
|
|
107
|
-
`genesis init` creates an empty Blueprint,
|
|
108
|
-
project Agent Skills, and project-local Codex hooks. The skills are ordinary
|
|
108
|
+
`genesis init` creates an empty Blueprint, a focused engineering approach, an
|
|
109
|
+
empty optional Stack, three project Agent Skills, and project-local Codex hooks. The skills are ordinary
|
|
109
110
|
[Agent Skills](https://agentskills.io): `genesis-project`, `genesis-program`,
|
|
110
111
|
and `genesis-deslop`, each with standard `SKILL.md` and `agents/openai.yaml`
|
|
111
112
|
metadata. Open `/hooks` once in Codex to review and trust the hooks. After
|
|
@@ -136,6 +137,54 @@ Genesis never overwrites an unmanaged skill and preserves locally modified
|
|
|
136
137
|
managed skills. Run `genesis init` after manually editing `genesis/stack.md`,
|
|
137
138
|
or use `genesis stack add`, to synchronize selected skills.
|
|
138
139
|
|
|
140
|
+
## Engineering approach
|
|
141
|
+
|
|
142
|
+
Every profile inherits one universal rule: implementation must remain easy to
|
|
143
|
+
reason about and be the smallest targeted change that satisfies current
|
|
144
|
+
requirements. Speculative abstractions, infrastructure, compatibility paths,
|
|
145
|
+
distributed patterns, cryptography, and similarly advanced machinery are not
|
|
146
|
+
allowed. When a concrete requirement makes material complexity necessary, the
|
|
147
|
+
agent must explain why a direct design is insufficient and ask before writing
|
|
148
|
+
that complexity.
|
|
149
|
+
|
|
150
|
+
The installed, versioned profile descriptions live in
|
|
151
|
+
`profiles/engineering/*.md`. Straight Genesis users can inspect and select them
|
|
152
|
+
without editing Markdown grammar:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
genesis engineering list
|
|
156
|
+
genesis engineering show focused.v1
|
|
157
|
+
genesis engineering set durable.v1
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`focused.v1` is the default for small direct product work. `durable.v1` adds
|
|
161
|
+
explicit compatibility and operational care for long-lived products.
|
|
162
|
+
`high-assurance.v1` adds risk-driven security and reliability discipline. None
|
|
163
|
+
of them mandates complexity without a concrete need.
|
|
164
|
+
|
|
165
|
+
The selection and any explicit project overrides are portable source:
|
|
166
|
+
|
|
167
|
+
```markdown
|
|
168
|
+
# Engineering approach
|
|
169
|
+
|
|
170
|
+
## Profile
|
|
171
|
+
|
|
172
|
+
- `focused.v1`
|
|
173
|
+
|
|
174
|
+
## Project requirements
|
|
175
|
+
|
|
176
|
+
- Nothing.
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
People may edit `## Project requirements` to name obligations the presets do
|
|
180
|
+
not capture, including a specific organizational, compliance, cryptographic,
|
|
181
|
+
or scale constraint. `genesis engineering set` changes only the profile and
|
|
182
|
+
preserves those requirements. Generated prompts, path-focused context, Codex
|
|
183
|
+
session guidance, Post-change work, and Deslop all receive the effective
|
|
184
|
+
approach. A project upgraded from an older Genesis release safely uses
|
|
185
|
+
`focused.v1` until `genesis init` or `genesis engineering set focused.v1`
|
|
186
|
+
records the file.
|
|
187
|
+
|
|
139
188
|
Hosts that manage project environments can call `inspectEnvironment()`.
|
|
140
189
|
Concrete Stack integrations may declare public, non-secret Environment
|
|
141
190
|
defaults such as the database driver selected by that integration. Explicit
|
|
@@ -323,7 +372,8 @@ The eight task types are deliberately explicit:
|
|
|
323
372
|
contracts into Genesis metadata. It composes technology-specific Adoption
|
|
324
373
|
requirements from the selected Stack and does not change application code.
|
|
325
374
|
- `work` implements the Blueprint and optional request using current code,
|
|
326
|
-
Program, selected Stack context, and
|
|
375
|
+
Program, the selected engineering approach, selected Stack context, and
|
|
376
|
+
progressively loaded Agent Skills.
|
|
327
377
|
- `deslop` requests cleanup explicitly. Codex projects also receive a bounded
|
|
328
378
|
automatic Deslop turn after their separate explanatory reconciliation turn.
|
|
329
379
|
- `program` edits only `genesis/program/` to explain the code that exists, with
|
|
@@ -422,7 +472,7 @@ genesis check
|
|
|
422
472
|
|
|
423
473
|
`check` is read-only. It reports only structural or recorded facts:
|
|
424
474
|
|
|
425
|
-
- Blueprint and Stack validity;
|
|
475
|
+
- Blueprint, engineering approach, and Stack validity;
|
|
426
476
|
- selected Agent Skill presence and structural validity;
|
|
427
477
|
- Program presence and structural validity;
|
|
428
478
|
- environment declarations and consumer-owned Stack extensions as `ready`,
|
|
@@ -451,10 +501,13 @@ import {
|
|
|
451
501
|
getContext,
|
|
452
502
|
indexCodebase,
|
|
453
503
|
initialize,
|
|
504
|
+
inspectEngineering,
|
|
454
505
|
inspectEnvironment,
|
|
455
506
|
inspectStackSection,
|
|
456
507
|
installCodex,
|
|
508
|
+
listEngineeringProfiles,
|
|
457
509
|
listStackPieces,
|
|
510
|
+
setEngineeringProfile,
|
|
458
511
|
verify,
|
|
459
512
|
} from 'genesis-compiler';
|
|
460
513
|
```
|
|
@@ -463,6 +516,9 @@ import {
|
|
|
463
516
|
Stack skills, and local Codex hooks.
|
|
464
517
|
`adoptProject()` also returns the initial `adopt` prompt for an existing
|
|
465
518
|
codebase. `installCodex()` installs the optional global discovery plugin.
|
|
519
|
+
`listEngineeringProfiles()`, `inspectEngineering()`, and
|
|
520
|
+
`setEngineeringProfile()` expose the same built-in catalog and portable
|
|
521
|
+
project selection used by the CLI and hosts.
|
|
466
522
|
`getContext()` resolves source paths to the Program modules that cite them,
|
|
467
523
|
the functions already declared there, selected Stack guidance, available Agent
|
|
468
524
|
Skills, and verification commands. `indexCodebase()` regenerates or returns the
|
|
@@ -474,7 +530,8 @@ projection paths without returning any supplied environment value.
|
|
|
474
530
|
interpreting or executing its contents.
|
|
475
531
|
|
|
476
532
|
Normalized results identify their stable public contract in the `contract`
|
|
477
|
-
field: `genesis.
|
|
533
|
+
field: `genesis.engineering.v1`, `genesis.environment.v2`,
|
|
534
|
+
`genesis.stack-section.v1`, or
|
|
478
535
|
`genesis.verification.v1`. A consumer defines any schema embedded inside the
|
|
479
536
|
opaque section body.
|
|
480
537
|
|
package/docs/assurance-model.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Genesis reports only facts it can establish mechanically:
|
|
4
4
|
|
|
5
|
-
1. Blueprint, Stack, and Program files satisfy their
|
|
5
|
+
1. Blueprint, Engineering approach, Stack, and Program files satisfy their
|
|
6
|
+
small structural formats, and the selected engineering profile exists in
|
|
7
|
+
the installed versioned catalog.
|
|
6
8
|
2. Program operations live in conceptual subsystem directories and cite real
|
|
7
9
|
source files. Optional helper maps are not mechanically certified.
|
|
8
10
|
3. Stack-declared environment inputs are present and non-placeholder. This does
|
|
@@ -17,8 +19,8 @@ Genesis reports only facts it can establish mechanically:
|
|
|
17
19
|
City projects the Program modules and source citations that exist. Neither
|
|
18
20
|
proves semantic equivalence, complete dynamic dispatch, or true duplication.
|
|
19
21
|
|
|
20
|
-
Prompt text, Stack Description/Guidance/Adoption/Post-change/Deslop prose,
|
|
21
|
-
content, and agent output are not assurance evidence. Genesis does not claim
|
|
22
|
+
Prompt text, engineering guidance, Stack Description/Guidance/Adoption/Post-change/Deslop prose,
|
|
23
|
+
Program prose, Agent Skill content, and agent output are not assurance evidence. Genesis does not claim
|
|
22
24
|
that product intent and code have converged, that Program is complete or
|
|
23
25
|
semantically current, or that passing checks prove the whole product correct.
|
|
24
26
|
|
|
@@ -40,6 +40,10 @@ Genesis keeps each instruction at one useful level:
|
|
|
40
40
|
commands, opaque consumer sections, and an optional authoritative Agent Skill source.
|
|
41
41
|
- `genesis/blueprint.md`, `genesis/program/`, and `genesis/stack.md` are the
|
|
42
42
|
project's own intent, explanation, and selected technical composition.
|
|
43
|
+
- `profiles/engineering/*.md` owns the installed versioned engineering
|
|
44
|
+
profiles. `genesis/engineering.md` selects one profile and records explicit
|
|
45
|
+
project requirements. A universal complexity gate is composed ahead of the
|
|
46
|
+
selected profile in every implementation and cleanup path.
|
|
43
47
|
- The generated JSON block contains current structural facts and warnings.
|
|
44
48
|
|
|
45
49
|
Detailed technology manuals belong in the technology skill's `references/`
|
|
@@ -89,7 +93,8 @@ then refreshes them again after Deslop in case cleanup changed the
|
|
|
89
93
|
implementation map.
|
|
90
94
|
|
|
91
95
|
Once Codex identifies relevant source, `genesis context <path...>` returns only
|
|
92
|
-
Program modules citing those paths plus
|
|
96
|
+
Program modules citing those paths plus the effective engineering approach and
|
|
97
|
+
concise selected Stack context, the
|
|
93
98
|
functions structurally indexed in those paths, available Agent Skill catalog,
|
|
94
99
|
and verification commands. `genesis index <name-or-path>` searches the complete
|
|
95
100
|
current function inventory and refreshes `.genesis/machine-city.json` and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genesis-compiler",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.18",
|
|
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": {
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"prompts/start.txt",
|
|
39
39
|
"prompts/work.txt",
|
|
40
40
|
"plugins/genesis",
|
|
41
|
+
"profiles",
|
|
41
42
|
"skills",
|
|
42
43
|
"src"
|
|
43
44
|
],
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Engineering baseline
|
|
2
|
+
|
|
3
|
+
- Every implementation must be easy to reason about and be the smallest targeted change that fully satisfies the known requirements.
|
|
4
|
+
- Prefer direct control flow, existing ownership boundaries, and established project or technology seams.
|
|
5
|
+
- Do not overengineer or overcomplicate the solution. Do not add speculative abstractions, layers, dependencies, infrastructure, compatibility paths, distributed patterns, cryptography, enterprise patterns, or other advanced machinery unless an explicit requirement or a concrete constraint makes it necessary.
|
|
6
|
+
- If good software requires material complexity beyond these rules, stop before writing it. Explain the requirement, why the direct design is insufficient, and the smallest added complexity proposed, then ask the user to approve or clarify the tradeoff.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Durable product
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Long-lived product work with explicit compatibility and operational care.
|
|
6
|
+
|
|
7
|
+
## Guidance
|
|
8
|
+
|
|
9
|
+
- Treat affected public contracts, stored data, migrations, recovery, and operability as first-class requirements.
|
|
10
|
+
- Make ownership and failure handling explicit enough for multiple contributors to maintain safely.
|
|
11
|
+
- Add boundaries or supporting machinery only where a current longevity or operational requirement needs them; keep unaffected work as direct as the focused profile.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Focused
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Small, direct changes for ordinary product work.
|
|
6
|
+
|
|
7
|
+
## Guidance
|
|
8
|
+
|
|
9
|
+
- Optimize for the clearest complete implementation with the fewest moving parts.
|
|
10
|
+
- Keep single-use logic close to its caller and introduce a shared abstraction only when one real shared operation already exists.
|
|
11
|
+
- Do not pre-build extensibility, scale, migration, or organizational machinery for hypothetical future needs.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# High assurance
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Security- or reliability-critical work backed by explicit risks and evidence.
|
|
6
|
+
|
|
7
|
+
## Guidance
|
|
8
|
+
|
|
9
|
+
- Establish the relevant threat model, trust boundaries, data sensitivity, availability, compliance, and recovery requirements before making a design they could materially change.
|
|
10
|
+
- Use established, audited primitives; make critical failure paths and ownership explicit; verify the properties on which safety depends.
|
|
11
|
+
- Cryptography, distributed coordination, redundant controls, and similarly advanced machinery still require a concrete risk or obligation. Ask for missing constraints instead of inventing them.
|
package/prompts/start.txt
CHANGED
|
@@ -13,6 +13,14 @@ the non-technical Blueprint from the user's answers before implementation.
|
|
|
13
13
|
If the product direction becomes clear while Stack is still empty, do not end
|
|
14
14
|
the turn after only writing or summarizing the Blueprint: present the relevant
|
|
15
15
|
Stack choices in that same turn and ask the user to select one explicitly.
|
|
16
|
+
The default `focused.v1` engineering profile is already suitable for ordinary
|
|
17
|
+
work, so do not force a separate profile question. When the user asks for a
|
|
18
|
+
different engineering approach, or the product clearly has long-lived
|
|
19
|
+
compatibility, operational, security, reliability, or compliance constraints,
|
|
20
|
+
use `availableEngineeringProfiles` to explain only the relevant choices in
|
|
21
|
+
product language. After an explicit choice, run `genesis engineering set
|
|
22
|
+
<profile>`; do not invent or duplicate a built-in profile. Record additional
|
|
23
|
+
explicit obligations in `genesis/engineering.md` under Project requirements.
|
|
16
24
|
This opening turn owns product direction and Stack selection, not final
|
|
17
25
|
verification. Do not run `genesis verify` before implementation exists. If
|
|
18
26
|
structural validation is useful, run `genesis check`; consumer-owned operations
|
|
@@ -9,6 +9,11 @@ Review and simplify the current local codebase without changing product
|
|
|
9
9
|
behavior. Start with the requested scope, or otherwise the ordinary Git diff
|
|
10
10
|
and the code immediately around it.
|
|
11
11
|
|
|
12
|
+
Apply the engineering approach supplied with the task. If this skill is invoked
|
|
13
|
+
directly, read `genesis/engineering.md` as well as the relevant project context.
|
|
14
|
+
Cleanup must reduce or preserve complexity, never introduce unapproved
|
|
15
|
+
machinery that the selected profile or a concrete requirement does not need.
|
|
16
|
+
|
|
12
17
|
Consult `.genesis/machine-city.json` or run `genesis index <name-or-path>` to
|
|
13
18
|
find existing public and internal functions before introducing or consolidating
|
|
14
19
|
an abstraction. Confirm every apparent duplicate in source and its call sites.
|
|
@@ -11,14 +11,16 @@ codebase, tests, Git review, or the coding agent.
|
|
|
11
11
|
## Establish context
|
|
12
12
|
|
|
13
13
|
1. Read `genesis/blueprint.md` for non-technical product intent.
|
|
14
|
-
2. Read `genesis/
|
|
14
|
+
2. Read `genesis/engineering.md` for the selected engineering profile and any
|
|
15
|
+
project-specific requirements.
|
|
16
|
+
3. Read `genesis/stack.md` for the selected technical composition, resources,
|
|
15
17
|
and verification commands.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
4. Locate the source involved in the request.
|
|
19
|
+
5. Run `genesis index <name-or-path>` before adding a helper or public operation.
|
|
18
20
|
Reuse an existing function when it already owns the behavior.
|
|
19
|
-
|
|
21
|
+
6. Run `genesis context <path...>` for the relevant Program explanations and
|
|
20
22
|
selected Stack context.
|
|
21
|
-
|
|
23
|
+
7. Load applicable technology skills from `.agents/skills/` or from the
|
|
22
24
|
agent's own installed skill catalog.
|
|
23
25
|
|
|
24
26
|
For an existing application's first Stack selection, inspect its real setup,
|
|
@@ -40,6 +42,16 @@ Neither is authority or proof; both may be regenerated with `genesis index`.
|
|
|
40
42
|
|
|
41
43
|
## Implement ordinary local work
|
|
42
44
|
|
|
45
|
+
- Apply the effective engineering approach supplied by Genesis. Every change
|
|
46
|
+
must be easy to reason about and be the smallest targeted implementation that
|
|
47
|
+
fully meets known requirements. Do not overengineer or overcomplicate it, and
|
|
48
|
+
do not add speculative abstractions, layers,
|
|
49
|
+
dependencies, infrastructure, compatibility paths, distributed patterns,
|
|
50
|
+
cryptography, or other advanced machinery.
|
|
51
|
+
- When a concrete requirement makes material complexity necessary, stop before
|
|
52
|
+
writing it. Explain why the direct design is insufficient and the smallest
|
|
53
|
+
added complexity proposed, then ask the user to approve or clarify the
|
|
54
|
+
tradeoff. Never silently override the engineering approach.
|
|
43
55
|
- Work directly in the current Git tree and leave useful edits visible in the
|
|
44
56
|
ordinary diff.
|
|
45
57
|
- Do not edit the Blueprint, Program, or `.genesis/` during implementation; the
|
package/src/cli.js
CHANGED
|
@@ -9,10 +9,13 @@ import {
|
|
|
9
9
|
getContext,
|
|
10
10
|
indexCodebase,
|
|
11
11
|
initialize,
|
|
12
|
+
inspectEngineering,
|
|
12
13
|
inspectEnvironment,
|
|
13
14
|
inspectStackSection,
|
|
14
15
|
installCodex,
|
|
16
|
+
listEngineeringProfiles,
|
|
15
17
|
listStackPieces,
|
|
18
|
+
setEngineeringProfile,
|
|
16
19
|
verify,
|
|
17
20
|
} from './index.js';
|
|
18
21
|
import {
|
|
@@ -22,12 +25,16 @@ import {
|
|
|
22
25
|
discardCodexTurn,
|
|
23
26
|
recordCodexTurn,
|
|
24
27
|
} from './index/codex-hooks.js';
|
|
28
|
+
import { engineeringProfile, readEngineeringBaseline } from './index/engineering.js';
|
|
25
29
|
import { asDiagnostic, fail } from './index/errors.js';
|
|
26
30
|
|
|
27
31
|
const USAGE = `Usage:
|
|
28
32
|
genesis init
|
|
29
33
|
genesis adopt [product guidance...]
|
|
30
34
|
genesis codex install
|
|
35
|
+
genesis engineering list
|
|
36
|
+
genesis engineering show [profile]
|
|
37
|
+
genesis engineering set <profile>
|
|
31
38
|
genesis stack list
|
|
32
39
|
genesis stack add <piece...>
|
|
33
40
|
genesis context <path...>
|
|
@@ -51,7 +58,7 @@ prompt to the agent you already use. Review all edits through the ordinary Git
|
|
|
51
58
|
diff, then run genesis verify for the Stack's concrete checks.
|
|
52
59
|
`;
|
|
53
60
|
|
|
54
|
-
const COMMANDS = new Set(['adopt', 'check', 'codex', 'context', 'hook', 'index', 'init', 'inspect', 'prompt', 'stack', 'verify']);
|
|
61
|
+
const COMMANDS = new Set(['adopt', 'check', 'codex', 'context', 'engineering', 'hook', 'index', 'init', 'inspect', 'prompt', 'stack', 'verify']);
|
|
55
62
|
|
|
56
63
|
function parseCommand(argv) {
|
|
57
64
|
if (argv.length === 0 || argv.includes('--help') || argv.includes('-h') || argv[0] === 'help') {
|
|
@@ -95,6 +102,20 @@ function parseCommand(argv) {
|
|
|
95
102
|
if (operands[0] === 'list' && operands.length !== 1) {
|
|
96
103
|
fail('CLI_EXTRA_ARGUMENT', 'Command stack list accepts no extra arguments.');
|
|
97
104
|
}
|
|
105
|
+
} else if (command === 'engineering') {
|
|
106
|
+
const [action] = operands;
|
|
107
|
+
if (!['list', 'show', 'set'].includes(action)) {
|
|
108
|
+
fail('CLI_ENGINEERING_ACTION_REQUIRED', 'Command engineering requires list, show, or set.');
|
|
109
|
+
}
|
|
110
|
+
if (action === 'list' && operands.length !== 1) {
|
|
111
|
+
fail('CLI_EXTRA_ARGUMENT', 'Command engineering list accepts no extra arguments.');
|
|
112
|
+
}
|
|
113
|
+
if (action === 'show' && operands.length > 2) {
|
|
114
|
+
fail('CLI_EXTRA_ARGUMENT', 'Command engineering show accepts at most one profile.');
|
|
115
|
+
}
|
|
116
|
+
if (action === 'set' && operands.length !== 2) {
|
|
117
|
+
fail('CLI_ENGINEERING_PROFILE_REQUIRED', 'Command engineering set requires exactly one profile.');
|
|
118
|
+
}
|
|
98
119
|
} else if (command === 'codex') {
|
|
99
120
|
if (operands.length !== 1 || operands[0] !== 'install') {
|
|
100
121
|
fail('CLI_CODEX_ACTION_REQUIRED', 'Command codex requires exactly: install.');
|
|
@@ -130,6 +151,7 @@ function namedItems(label, values) {
|
|
|
130
151
|
|
|
131
152
|
function writeCheck(result) {
|
|
132
153
|
line(process.stdout, `Blueprint: ${result.blueprint}`);
|
|
154
|
+
line(process.stdout, `Engineering approach: ${result.engineering}`);
|
|
133
155
|
line(process.stdout, `Stack: ${result.stack}`);
|
|
134
156
|
line(process.stdout, `Agent Skills: ${result.skills}`);
|
|
135
157
|
line(process.stdout, `Program: ${result.program}`);
|
|
@@ -144,6 +166,29 @@ function writeCheck(result) {
|
|
|
144
166
|
line(process.stdout, `Check: ${result.status}`);
|
|
145
167
|
}
|
|
146
168
|
|
|
169
|
+
function writeEngineering(result) {
|
|
170
|
+
if (result.action === 'list') {
|
|
171
|
+
for (const profile of result.profiles) {
|
|
172
|
+
line(process.stdout, `${profile.id}: ${profile.name} — ${profile.description}`);
|
|
173
|
+
}
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (result.profile) {
|
|
177
|
+
line(process.stdout, `${result.profile.name} (${result.profile.id})`);
|
|
178
|
+
line(process.stdout, result.profile.description);
|
|
179
|
+
}
|
|
180
|
+
if (result.guidance) {
|
|
181
|
+
line(process.stdout, '');
|
|
182
|
+
line(process.stdout, result.guidance);
|
|
183
|
+
}
|
|
184
|
+
if (result.action === 'set') {
|
|
185
|
+
namedItems('Changed files', result.changedFiles);
|
|
186
|
+
line(process.stdout, `engineering: ${result.status}`);
|
|
187
|
+
} else if (result.status) {
|
|
188
|
+
line(process.stdout, `Engineering approach: ${result.status}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
147
192
|
function writeInspection(result) {
|
|
148
193
|
const title = result.inspection[0].toUpperCase() + result.inspection.slice(1);
|
|
149
194
|
line(process.stdout, `${title}: ${result.status}`);
|
|
@@ -179,6 +224,10 @@ function writeResult(command, result) {
|
|
|
179
224
|
writeCheck(result);
|
|
180
225
|
return;
|
|
181
226
|
}
|
|
227
|
+
if (command === 'engineering') {
|
|
228
|
+
writeEngineering(result);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
182
231
|
if (command === 'context') {
|
|
183
232
|
process.stdout.write(result.context.endsWith('\n') ? result.context : `${result.context}\n`);
|
|
184
233
|
return;
|
|
@@ -254,6 +303,36 @@ async function execute({ command, operands, options }, { signal } = {}) {
|
|
|
254
303
|
return adoptProject({ projectRoot, request: operands.join(' '), stackPackages });
|
|
255
304
|
}
|
|
256
305
|
if (command === 'codex') return installCodex();
|
|
306
|
+
if (command === 'engineering') {
|
|
307
|
+
if (operands[0] === 'list') {
|
|
308
|
+
return { action: 'list', status: 'ok', profiles: await listEngineeringProfiles() };
|
|
309
|
+
}
|
|
310
|
+
if (operands[0] === 'show') {
|
|
311
|
+
if (!operands[1]) return { action: 'show', ...await inspectEngineering({ projectRoot }) };
|
|
312
|
+
const [baseline, profile] = await Promise.all([
|
|
313
|
+
readEngineeringBaseline(),
|
|
314
|
+
engineeringProfile(operands[1]),
|
|
315
|
+
]);
|
|
316
|
+
return {
|
|
317
|
+
action: 'show',
|
|
318
|
+
status: 'ready',
|
|
319
|
+
profile,
|
|
320
|
+
guidance: [
|
|
321
|
+
'## Universal complexity gate',
|
|
322
|
+
'',
|
|
323
|
+
baseline,
|
|
324
|
+
'',
|
|
325
|
+
'## Profile guidance',
|
|
326
|
+
'',
|
|
327
|
+
profile.guidance,
|
|
328
|
+
].join('\n'),
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
action: 'set',
|
|
333
|
+
...await setEngineeringProfile({ profile: operands[1], projectRoot }),
|
|
334
|
+
};
|
|
335
|
+
}
|
|
257
336
|
if (command === 'stack') {
|
|
258
337
|
if (operands[0] === 'list') {
|
|
259
338
|
return { status: 'ok', pieces: await listStackPieces({ projectRoot, stackPackages }) };
|
package/src/index/check.js
CHANGED
|
@@ -8,11 +8,13 @@ import { inspectVerification } from './project-state.js';
|
|
|
8
8
|
import { missingStackResources } from './stack-preflight.js';
|
|
9
9
|
import { withStackEnvironmentDefaults } from './stack-environment-defaults.js';
|
|
10
10
|
import { inspectProjectEnvironment } from './environment-files.js';
|
|
11
|
+
import { readEngineering } from './engineering.js';
|
|
11
12
|
|
|
12
13
|
function invalidResult(area, error) {
|
|
13
14
|
return {
|
|
14
15
|
status: 'invalid',
|
|
15
16
|
blueprint: area === 'blueprint' ? 'invalid' : 'valid',
|
|
17
|
+
engineering: area === 'engineering' ? 'invalid' : 'unknown',
|
|
16
18
|
stack: area === 'stack' ? 'invalid' : 'unknown',
|
|
17
19
|
skills: area === 'skills' ? 'invalid' : 'unknown',
|
|
18
20
|
program: 'unknown',
|
|
@@ -40,6 +42,13 @@ export async function checkProject({
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
let stack;
|
|
45
|
+
let engineering;
|
|
46
|
+
try {
|
|
47
|
+
engineering = await readEngineering(root);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
return invalidResult('engineering', error);
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
try {
|
|
44
53
|
stack = await readStack(root, { stackPackages });
|
|
45
54
|
} catch (error) {
|
|
@@ -87,6 +96,7 @@ export async function checkProject({
|
|
|
87
96
|
|
|
88
97
|
const guidance = [];
|
|
89
98
|
if (program.status === 'missing') guidance.push('Generate an explanatory Program prompt with genesis prompt --task program.');
|
|
99
|
+
if (engineering.status === 'defaulted') guidance.push('Run genesis init or genesis engineering set focused.v1 to record the default engineering approach.');
|
|
90
100
|
if (program.status === 'invalid') guidance.push('Repair the Program with genesis prompt --task program.');
|
|
91
101
|
if (skills.status === 'missing') guidance.push('Run genesis init to install selected project Agent Skills.');
|
|
92
102
|
if (skills.status === 'invalid') guidance.push('Repair the reported Agent Skill or managed-skill manifest.');
|
|
@@ -99,6 +109,7 @@ export async function checkProject({
|
|
|
99
109
|
guidance.push('Use genesis prompt --task review for a semantic, evidence-based comparison.');
|
|
100
110
|
|
|
101
111
|
const needsAttention = program.status === 'missing'
|
|
112
|
+
|| engineering.status === 'defaulted'
|
|
102
113
|
|| skills.status === 'missing'
|
|
103
114
|
|| missingResources.length > 0
|
|
104
115
|
|| extensionDiagnostics.length > 0
|
|
@@ -109,6 +120,7 @@ export async function checkProject({
|
|
|
109
120
|
? 'invalid'
|
|
110
121
|
: needsAttention ? 'attention' : 'ok',
|
|
111
122
|
blueprint: 'valid',
|
|
123
|
+
engineering: engineering.status,
|
|
112
124
|
stack: 'valid',
|
|
113
125
|
skills: skills.status,
|
|
114
126
|
program: program.status,
|
package/src/index/codex-hooks.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
|
|
4
4
|
import { readInstalledAsset } from './assets.js';
|
|
5
5
|
import { buildProjectIndex } from './code-index.js';
|
|
6
|
+
import { readEngineering, readEngineeringBaseline } from './engineering.js';
|
|
6
7
|
import { GenesisError } from './errors.js';
|
|
7
8
|
import { gitContext } from './git.js';
|
|
8
9
|
import { isProjectContentPath } from './paths.js';
|
|
@@ -115,9 +116,30 @@ async function optionalStack(projectRoot) {
|
|
|
115
116
|
try { return await readStack(projectRoot); } catch { return null; }
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
async function optionalEngineering(projectRoot) {
|
|
120
|
+
try {
|
|
121
|
+
return await readEngineering(projectRoot);
|
|
122
|
+
} catch {
|
|
123
|
+
return {
|
|
124
|
+
guidance: [
|
|
125
|
+
'## Universal complexity gate',
|
|
126
|
+
'',
|
|
127
|
+
await readEngineeringBaseline(),
|
|
128
|
+
'',
|
|
129
|
+
'The project engineering profile is invalid. Do not infer a replacement; run `genesis check` and ask the user before implementation if the selected approach matters.',
|
|
130
|
+
].join('\n'),
|
|
131
|
+
profile: null,
|
|
132
|
+
status: 'invalid',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
118
137
|
export async function codexSessionContext({ projectRoot } = {}) {
|
|
119
138
|
const root = (await gitContext(projectRoot)).repositoryRoot;
|
|
120
|
-
const stack = await
|
|
139
|
+
const [stack, engineering] = await Promise.all([
|
|
140
|
+
optionalStack(root),
|
|
141
|
+
optionalEngineering(root),
|
|
142
|
+
]);
|
|
121
143
|
const selected = stack?.components.map(({ id }) => id) || [];
|
|
122
144
|
const stackStatus = stack
|
|
123
145
|
? (selected.length > 0 ? selected.join(', ') : 'none')
|
|
@@ -127,6 +149,7 @@ export async function codexSessionContext({ projectRoot } = {}) {
|
|
|
127
149
|
output: [
|
|
128
150
|
'This is a Genesis-enriched project.',
|
|
129
151
|
'- `genesis/blueprint.md` describes non-technical product intent.',
|
|
152
|
+
'- `genesis/engineering.md` selects the project engineering approach and any project-specific requirements.',
|
|
130
153
|
'- `genesis/stack.md` selects optional technology guidance and verification.',
|
|
131
154
|
'- `genesis/program/<subsystem>/` explains public operations and useful internal seams.',
|
|
132
155
|
'- Project Agent Skills live in `.agents/skills/`; load applicable skills progressively.',
|
|
@@ -134,9 +157,14 @@ export async function codexSessionContext({ projectRoot } = {}) {
|
|
|
134
157
|
'- Before creating a helper or public operation, run `genesis index <name-or-path>` and reuse an existing function when it already owns the behavior.',
|
|
135
158
|
'- `.genesis/machine-city.json` is the detailed code/function map; `.genesis/program-city.json` is the simpler subsystem/operation map.',
|
|
136
159
|
'- Program is fallible explanation; code, tests, and runtime behavior remain evidence.',
|
|
137
|
-
'-
|
|
160
|
+
'- Apply the engineering approach below to implementation and cleanup; the Stop hook owns optional Stack Post-change work, Blueprint/Program reconciliation, and Deslop turns.',
|
|
138
161
|
'- After a code-changing turn, Genesis may request separate post-change, explanation, cleanup, and final-summary turns.',
|
|
162
|
+
`Engineering profile: ${engineering.profile?.id || 'invalid; run \`genesis check\`'}.`,
|
|
139
163
|
`Selected Stack components: ${stackStatus}.`,
|
|
164
|
+
'',
|
|
165
|
+
'ENGINEERING APPROACH',
|
|
166
|
+
'',
|
|
167
|
+
engineering.guidance,
|
|
140
168
|
].join('\n'),
|
|
141
169
|
};
|
|
142
170
|
}
|
|
@@ -279,9 +307,10 @@ function changedPathLines(changedPaths) {
|
|
|
279
307
|
}
|
|
280
308
|
|
|
281
309
|
async function reconciliationContinuation(projectRoot, changedPaths) {
|
|
282
|
-
const [instructions, stack] = await Promise.all([
|
|
310
|
+
const [instructions, stack, engineering] = await Promise.all([
|
|
283
311
|
readInstalledAsset('reconcile'),
|
|
284
312
|
optionalStack(projectRoot),
|
|
313
|
+
optionalEngineering(projectRoot),
|
|
285
314
|
]);
|
|
286
315
|
return [
|
|
287
316
|
'This is the automatic Genesis explanation turn for the preceding implementation turn.',
|
|
@@ -292,11 +321,15 @@ async function reconciliationContinuation(projectRoot, changedPaths) {
|
|
|
292
321
|
...changedPathLines(changedPaths),
|
|
293
322
|
'',
|
|
294
323
|
instructions.trim(),
|
|
324
|
+
'',
|
|
325
|
+
'ENGINEERING APPROACH',
|
|
326
|
+
'',
|
|
327
|
+
engineering.guidance,
|
|
295
328
|
...(stack?.guidance ? ['', 'SELECTED STACK GUIDANCE', '', stack.guidance] : []),
|
|
296
329
|
].join('\n');
|
|
297
330
|
}
|
|
298
331
|
|
|
299
|
-
function postChangeContinuation(changedPaths, stack) {
|
|
332
|
+
function postChangeContinuation(changedPaths, stack, engineering) {
|
|
300
333
|
return [
|
|
301
334
|
'This is the one automatic Stack Post-change turn for the preceding implementation.',
|
|
302
335
|
'Use the same conversation context and the Git-visible changes below.',
|
|
@@ -310,14 +343,19 @@ function postChangeContinuation(changedPaths, stack) {
|
|
|
310
343
|
'COMPOSED STACK POST-CHANGE WORK',
|
|
311
344
|
'',
|
|
312
345
|
stack.postChange,
|
|
346
|
+
'',
|
|
347
|
+
'ENGINEERING APPROACH',
|
|
348
|
+
'',
|
|
349
|
+
engineering.guidance,
|
|
313
350
|
...(stack.guidance ? ['', 'SELECTED STACK GUIDANCE', '', stack.guidance] : []),
|
|
314
351
|
].join('\n');
|
|
315
352
|
}
|
|
316
353
|
|
|
317
354
|
async function deslopContinuation(projectRoot, changedPaths) {
|
|
318
|
-
const [instructions, stack] = await Promise.all([
|
|
355
|
+
const [instructions, stack, engineering] = await Promise.all([
|
|
319
356
|
readInstalledAsset('deslop'),
|
|
320
357
|
optionalStack(projectRoot),
|
|
358
|
+
optionalEngineering(projectRoot),
|
|
321
359
|
]);
|
|
322
360
|
return [
|
|
323
361
|
'This is the final automatic Genesis Deslop turn for the preceding implementation.',
|
|
@@ -328,6 +366,10 @@ async function deslopContinuation(projectRoot, changedPaths) {
|
|
|
328
366
|
...changedPathLines(changedPaths),
|
|
329
367
|
'',
|
|
330
368
|
instructions.trim(),
|
|
369
|
+
'',
|
|
370
|
+
'ENGINEERING APPROACH',
|
|
371
|
+
'',
|
|
372
|
+
engineering.guidance,
|
|
331
373
|
...(stack?.guidance ? ['', 'SELECTED STACK GUIDANCE', '', stack.guidance] : []),
|
|
332
374
|
...(stack?.deslop ? ['', 'SELECTED STACK CLEANUP GUIDANCE', '', stack.deslop] : []),
|
|
333
375
|
'',
|
|
@@ -360,7 +402,10 @@ export async function completeCodexTurn({ input, projectRoot } = {}) {
|
|
|
360
402
|
await rm(statePath, { force: true });
|
|
361
403
|
return {};
|
|
362
404
|
}
|
|
363
|
-
const stack = await
|
|
405
|
+
const [stack, engineering] = await Promise.all([
|
|
406
|
+
optionalStack(root),
|
|
407
|
+
optionalEngineering(root),
|
|
408
|
+
]);
|
|
364
409
|
const postChange = Boolean(stack?.postChange?.trim());
|
|
365
410
|
await writeTurnState(statePath, {
|
|
366
411
|
...state,
|
|
@@ -370,7 +415,7 @@ export async function completeCodexTurn({ input, projectRoot } = {}) {
|
|
|
370
415
|
return {
|
|
371
416
|
decision: 'block',
|
|
372
417
|
reason: postChange
|
|
373
|
-
? postChangeContinuation(changedPaths, stack)
|
|
418
|
+
? postChangeContinuation(changedPaths, stack, engineering)
|
|
374
419
|
: await reconciliationContinuation(root, changedPaths),
|
|
375
420
|
};
|
|
376
421
|
}
|
package/src/index/context.js
CHANGED
|
@@ -4,6 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { inspectProjectSkills, renderAgentSkillCatalog } from './agent-skills.js';
|
|
5
5
|
import { buildProjectIndex } from './code-index.js';
|
|
6
6
|
import { asDiagnostic, GenesisError } from './errors.js';
|
|
7
|
+
import { readEngineering } from './engineering.js';
|
|
7
8
|
import { gitContext } from './git.js';
|
|
8
9
|
import { inspectProgram } from './program.js';
|
|
9
10
|
import { readStack } from './stack.js';
|
|
@@ -56,13 +57,14 @@ export async function contextForProjectPaths({ paths, projectRoot, stackPackages
|
|
|
56
57
|
const location = await gitContext(projectRoot);
|
|
57
58
|
const root = location.repositoryRoot;
|
|
58
59
|
const targets = [...new Set(paths.map((value) => projectPath(root, location.workingDirectory, value)))];
|
|
59
|
-
const [program, stack] = await Promise.all([
|
|
60
|
+
const [program, stack, engineering] = await Promise.all([
|
|
60
61
|
inspectProgram(root).catch((error) => ({
|
|
61
62
|
status: 'invalid',
|
|
62
63
|
modules: [],
|
|
63
64
|
diagnostic: asDiagnostic(error),
|
|
64
65
|
})),
|
|
65
66
|
readStack(root, { stackPackages }),
|
|
67
|
+
readEngineering(root),
|
|
66
68
|
]);
|
|
67
69
|
const modules = program.modules.filter((module) => targets.some((target) => citesTarget(module, target)));
|
|
68
70
|
const moduleSources = await Promise.all(modules.map(async (module) => ({
|
|
@@ -98,6 +100,12 @@ export async function contextForProjectPaths({ paths, projectRoot, stackPackages
|
|
|
98
100
|
'## Relevant Program',
|
|
99
101
|
'',
|
|
100
102
|
...programDetails,
|
|
103
|
+
'## Engineering approach',
|
|
104
|
+
'',
|
|
105
|
+
`Profile: \`${engineering.profile.id}\` — ${engineering.profile.description}`,
|
|
106
|
+
'',
|
|
107
|
+
engineering.guidance,
|
|
108
|
+
'',
|
|
101
109
|
...stackSummary(stack),
|
|
102
110
|
...stackGuidance(stack),
|
|
103
111
|
'',
|
|
@@ -125,6 +133,7 @@ export async function contextForProjectPaths({ paths, projectRoot, stackPackages
|
|
|
125
133
|
paths: targets,
|
|
126
134
|
modules: moduleSources.map(({ source: _source, ...module }) => module),
|
|
127
135
|
components: stack.components.map(({ id }) => id),
|
|
136
|
+
engineeringProfile: engineering.profile.id,
|
|
128
137
|
verificationCommands: stack.verificationCommands.map(({ label, argv }) => ({ label, argv })),
|
|
129
138
|
warnings: [
|
|
130
139
|
...(program.diagnostic ? [program.diagnostic] : []),
|
package/src/index/contracts.js
CHANGED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { GENESIS_CONTRACTS } from './contracts.js';
|
|
5
|
+
import { GenesisError } from './errors.js';
|
|
6
|
+
import { gitContext } from './git.js';
|
|
7
|
+
import { ENGINEERING_PATH } from './paths.js';
|
|
8
|
+
import { normalizeSource, writeFileAtomic } from './utils.js';
|
|
9
|
+
|
|
10
|
+
const PROFILE_ID_PATTERN = /^[a-z][a-z0-9-]*\.v[1-9][0-9]*$/u;
|
|
11
|
+
const PROFILE_IDS = Object.freeze(['focused.v1', 'durable.v1', 'high-assurance.v1']);
|
|
12
|
+
const PROFILE_ASSETS = new Map(PROFILE_IDS.map((id) => [
|
|
13
|
+
id,
|
|
14
|
+
new URL(`../../profiles/engineering/${id}.md`, import.meta.url),
|
|
15
|
+
]));
|
|
16
|
+
const BASELINE_ASSET = new URL('../../profiles/engineering/baseline.md', import.meta.url);
|
|
17
|
+
|
|
18
|
+
export const DEFAULT_ENGINEERING_PROFILE_ID = 'focused.v1';
|
|
19
|
+
export const ENGINEERING_SKELETON_SOURCE = `# Engineering approach
|
|
20
|
+
|
|
21
|
+
## Profile
|
|
22
|
+
|
|
23
|
+
- \`${DEFAULT_ENGINEERING_PROFILE_ID}\`
|
|
24
|
+
|
|
25
|
+
## Project requirements
|
|
26
|
+
|
|
27
|
+
- Nothing.
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
function normalizeProfileId(value) {
|
|
31
|
+
const id = String(value ?? '').trim();
|
|
32
|
+
if (!PROFILE_ID_PATTERN.test(id)) {
|
|
33
|
+
throw new GenesisError(
|
|
34
|
+
'ENGINEERING_PROFILE_INVALID',
|
|
35
|
+
'Engineering profile ids use a lowercase name followed by a version, such as `focused.v1`.',
|
|
36
|
+
{ profile: value },
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return id;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function sections(source, { title, sourcePath }) {
|
|
43
|
+
const lines = normalizeSource(source).split('\n');
|
|
44
|
+
if (lines.filter((line) => line.trim() === title).length !== 1) {
|
|
45
|
+
throw new GenesisError('ENGINEERING_INVALID', `${sourcePath} needs exactly one \`${title}\` title.`);
|
|
46
|
+
}
|
|
47
|
+
const result = new Map();
|
|
48
|
+
let current = null;
|
|
49
|
+
for (const line of lines) {
|
|
50
|
+
const heading = line.match(/^##\s+(.+?)\s*$/u);
|
|
51
|
+
if (heading) {
|
|
52
|
+
if (result.has(heading[1])) {
|
|
53
|
+
throw new GenesisError('ENGINEERING_INVALID', `Duplicate engineering section: ${heading[1]}.`, {
|
|
54
|
+
path: sourcePath,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
current = [];
|
|
58
|
+
result.set(heading[1], current);
|
|
59
|
+
} else if (current) {
|
|
60
|
+
current.push(line);
|
|
61
|
+
} else if (line.trim() && line.trim() !== title) {
|
|
62
|
+
throw new GenesisError('ENGINEERING_INVALID', `${sourcePath} contains content outside an engineering section.`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function sectionText(all, name) {
|
|
69
|
+
return (all.get(name) || []).join('\n').trim();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function parseProfileSource(source, { id }) {
|
|
73
|
+
const normalized = normalizeSource(source);
|
|
74
|
+
const titleMatch = normalized.match(/^# ([^\r\n]+)[ \t]*$/mu);
|
|
75
|
+
if (!titleMatch || normalized.match(/^# [^\r\n]+[ \t]*$/gmu)?.length !== 1) {
|
|
76
|
+
throw new GenesisError('ENGINEERING_PROFILE_INVALID', `Engineering profile ${id} needs one title.`);
|
|
77
|
+
}
|
|
78
|
+
const all = sections(normalized, {
|
|
79
|
+
sourcePath: `profiles/engineering/${id}.md`,
|
|
80
|
+
title: titleMatch[0].trim(),
|
|
81
|
+
});
|
|
82
|
+
const unknown = [...all.keys()].filter((name) => !['Description', 'Guidance'].includes(name));
|
|
83
|
+
const description = sectionText(all, 'Description');
|
|
84
|
+
const guidance = sectionText(all, 'Guidance');
|
|
85
|
+
if (unknown.length > 0 || !description || !guidance) {
|
|
86
|
+
throw new GenesisError(
|
|
87
|
+
'ENGINEERING_PROFILE_INVALID',
|
|
88
|
+
`Engineering profile ${id} needs only non-empty Description and Guidance sections.`,
|
|
89
|
+
{ profile: id },
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return Object.freeze({ id, name: titleMatch[1].trim(), description, guidance });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function engineeringProfile(value) {
|
|
96
|
+
const id = normalizeProfileId(value);
|
|
97
|
+
const location = PROFILE_ASSETS.get(id);
|
|
98
|
+
if (!location) {
|
|
99
|
+
throw new GenesisError(
|
|
100
|
+
'ENGINEERING_PROFILE_UNKNOWN',
|
|
101
|
+
`No installed engineering profile exists for ${id}.`,
|
|
102
|
+
{ profile: id },
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
return parseProfileSource(await readFile(location, 'utf8'), { id });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function readEngineeringBaseline() {
|
|
109
|
+
const source = normalizeSource(await readFile(BASELINE_ASSET, 'utf8')).trim();
|
|
110
|
+
if (!/^# Engineering baseline[ \t]*$/mu.test(source)) {
|
|
111
|
+
throw new GenesisError('ENGINEERING_PROFILE_INVALID', 'The installed engineering baseline is invalid.');
|
|
112
|
+
}
|
|
113
|
+
return source.replace(/^# Engineering baseline[ \t]*\n?/mu, '').trim();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function parseEngineeringSource(source) {
|
|
117
|
+
const normalized = normalizeSource(source);
|
|
118
|
+
const all = sections(normalized, {
|
|
119
|
+
sourcePath: ENGINEERING_PATH,
|
|
120
|
+
title: '# Engineering approach',
|
|
121
|
+
});
|
|
122
|
+
const unknown = [...all.keys()].filter((name) => !['Profile', 'Project requirements'].includes(name));
|
|
123
|
+
if (unknown.length > 0 || !all.has('Profile') || !all.has('Project requirements')) {
|
|
124
|
+
throw new GenesisError(
|
|
125
|
+
'ENGINEERING_INVALID',
|
|
126
|
+
`${ENGINEERING_PATH} needs only Profile and Project requirements sections.`,
|
|
127
|
+
{ path: ENGINEERING_PATH },
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
const profileLines = (all.get('Profile') || []).filter((line) => line.trim());
|
|
131
|
+
const match = profileLines.length === 1
|
|
132
|
+
? profileLines[0].trim().match(/^- `([^`]+)`$/u)
|
|
133
|
+
: null;
|
|
134
|
+
if (!match) {
|
|
135
|
+
throw new GenesisError(
|
|
136
|
+
'ENGINEERING_INVALID',
|
|
137
|
+
'The engineering Profile must be exactly one bullet containing a backticked profile id.',
|
|
138
|
+
{ path: ENGINEERING_PATH },
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
const requirementsSource = sectionText(all, 'Project requirements');
|
|
142
|
+
if (!requirementsSource) {
|
|
143
|
+
throw new GenesisError(
|
|
144
|
+
'ENGINEERING_INVALID',
|
|
145
|
+
'Project requirements must contain requirements or `- Nothing.`.',
|
|
146
|
+
{ path: ENGINEERING_PATH },
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (Buffer.byteLength(requirementsSource, 'utf8') > 64 * 1024) {
|
|
150
|
+
throw new GenesisError('ENGINEERING_INVALID', 'Project engineering requirements exceed 64 KiB.', {
|
|
151
|
+
path: ENGINEERING_PATH,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
path: ENGINEERING_PATH,
|
|
156
|
+
profileId: normalizeProfileId(match[1]),
|
|
157
|
+
requirements: requirementsSource === '- Nothing.' ? '' : requirementsSource,
|
|
158
|
+
source: normalized,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function renderEngineering({ profileId, requirements = '' }) {
|
|
163
|
+
return [
|
|
164
|
+
'# Engineering approach',
|
|
165
|
+
'',
|
|
166
|
+
'## Profile',
|
|
167
|
+
'',
|
|
168
|
+
`- \`${profileId}\``,
|
|
169
|
+
'',
|
|
170
|
+
'## Project requirements',
|
|
171
|
+
'',
|
|
172
|
+
requirements.trim() || '- Nothing.',
|
|
173
|
+
'',
|
|
174
|
+
].join('\n');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function effectiveGuidance({ baseline, profile, requirements }) {
|
|
178
|
+
return [
|
|
179
|
+
'## Universal complexity gate',
|
|
180
|
+
'',
|
|
181
|
+
baseline,
|
|
182
|
+
'',
|
|
183
|
+
`## Selected profile: ${profile.name} (\`${profile.id}\`)`,
|
|
184
|
+
'',
|
|
185
|
+
profile.guidance,
|
|
186
|
+
...(requirements ? [
|
|
187
|
+
'',
|
|
188
|
+
'## Project requirements',
|
|
189
|
+
'',
|
|
190
|
+
requirements,
|
|
191
|
+
] : []),
|
|
192
|
+
].join('\n');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export async function readEngineering(projectRoot) {
|
|
196
|
+
const location = path.join(projectRoot, ENGINEERING_PATH);
|
|
197
|
+
let parsed;
|
|
198
|
+
let status = 'configured';
|
|
199
|
+
try {
|
|
200
|
+
parsed = parseEngineeringSource(await readFile(location, 'utf8'));
|
|
201
|
+
} catch (error) {
|
|
202
|
+
if (!['ENOENT', 'ENOTDIR'].includes(error?.code)) throw error;
|
|
203
|
+
parsed = parseEngineeringSource(ENGINEERING_SKELETON_SOURCE);
|
|
204
|
+
status = 'defaulted';
|
|
205
|
+
}
|
|
206
|
+
const [baseline, profile] = await Promise.all([
|
|
207
|
+
readEngineeringBaseline(),
|
|
208
|
+
engineeringProfile(parsed.profileId),
|
|
209
|
+
]);
|
|
210
|
+
return {
|
|
211
|
+
contract: GENESIS_CONTRACTS.engineering,
|
|
212
|
+
path: ENGINEERING_PATH,
|
|
213
|
+
status,
|
|
214
|
+
profile,
|
|
215
|
+
requirements: parsed.requirements,
|
|
216
|
+
source: status === 'configured' ? parsed.source : null,
|
|
217
|
+
guidance: effectiveGuidance({ baseline, profile, requirements: parsed.requirements }),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function engineeringPromptContext(engineering) {
|
|
222
|
+
return {
|
|
223
|
+
path: engineering.path,
|
|
224
|
+
status: engineering.status,
|
|
225
|
+
profile: {
|
|
226
|
+
id: engineering.profile.id,
|
|
227
|
+
name: engineering.profile.name,
|
|
228
|
+
description: engineering.profile.description,
|
|
229
|
+
},
|
|
230
|
+
requirements: engineering.requirements || 'Nothing.',
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function listEngineeringProfileCatalog() {
|
|
235
|
+
return Promise.all(PROFILE_IDS.map(engineeringProfile));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export async function inspectProjectEngineering({ projectRoot } = {}) {
|
|
239
|
+
const root = (await gitContext(projectRoot)).repositoryRoot;
|
|
240
|
+
const [engineering, profiles] = await Promise.all([
|
|
241
|
+
readEngineering(root),
|
|
242
|
+
listEngineeringProfileCatalog(),
|
|
243
|
+
]);
|
|
244
|
+
return {
|
|
245
|
+
contract: engineering.contract,
|
|
246
|
+
path: engineering.path,
|
|
247
|
+
status: engineering.status,
|
|
248
|
+
profile: engineering.profile,
|
|
249
|
+
profiles,
|
|
250
|
+
requirements: engineering.requirements,
|
|
251
|
+
guidance: engineering.guidance,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export async function selectEngineeringProfile({ profile, projectRoot } = {}) {
|
|
256
|
+
const root = (await gitContext(projectRoot)).repositoryRoot;
|
|
257
|
+
const selected = await engineeringProfile(profile);
|
|
258
|
+
const current = await readEngineering(root);
|
|
259
|
+
const rendered = renderEngineering({
|
|
260
|
+
profileId: selected.id,
|
|
261
|
+
requirements: current.requirements,
|
|
262
|
+
});
|
|
263
|
+
const changed = current.source !== rendered;
|
|
264
|
+
if (changed) await writeFileAtomic(path.join(root, ENGINEERING_PATH), rendered);
|
|
265
|
+
return {
|
|
266
|
+
contract: GENESIS_CONTRACTS.engineering,
|
|
267
|
+
status: changed ? 'updated' : 'unchanged',
|
|
268
|
+
summary: changed
|
|
269
|
+
? `Selected engineering profile: ${selected.id}.`
|
|
270
|
+
: `Engineering profile ${selected.id} is already selected.`,
|
|
271
|
+
profile: selected,
|
|
272
|
+
changedFiles: changed ? [ENGINEERING_PATH] : [],
|
|
273
|
+
};
|
|
274
|
+
}
|
package/src/index/init.js
CHANGED
|
@@ -4,8 +4,9 @@ import path from 'node:path';
|
|
|
4
4
|
import { syncProjectSkills } from './agent-skills.js';
|
|
5
5
|
import { BLUEPRINT_SKELETON_SOURCE } from './blueprint.js';
|
|
6
6
|
import { installCodexHooks } from './codex-hooks.js';
|
|
7
|
+
import { ENGINEERING_SKELETON_SOURCE } from './engineering.js';
|
|
7
8
|
import { gitContext } from './git.js';
|
|
8
|
-
import { BLUEPRINT_PATH, PROGRAM_ROOT, STACK_PATH } from './paths.js';
|
|
9
|
+
import { BLUEPRINT_PATH, ENGINEERING_PATH, PROGRAM_ROOT, STACK_PATH } from './paths.js';
|
|
9
10
|
import { EMPTY_STACK_SOURCE, readStack } from './stack.js';
|
|
10
11
|
|
|
11
12
|
async function createIfMissing(projectRoot, relativePath, source) {
|
|
@@ -24,6 +25,7 @@ export async function initializeProject({ projectRoot, stackPackages = [] } = {}
|
|
|
24
25
|
const root = (await gitContext(projectRoot)).repositoryRoot;
|
|
25
26
|
const created = (await Promise.all([
|
|
26
27
|
createIfMissing(root, BLUEPRINT_PATH, BLUEPRINT_SKELETON_SOURCE),
|
|
28
|
+
createIfMissing(root, ENGINEERING_PATH, ENGINEERING_SKELETON_SOURCE),
|
|
27
29
|
createIfMissing(root, STACK_PATH, EMPTY_STACK_SOURCE),
|
|
28
30
|
])).filter(Boolean);
|
|
29
31
|
await mkdir(path.join(root, PROGRAM_ROOT), { recursive: true });
|
|
@@ -42,6 +44,7 @@ export async function initializeProject({ projectRoot, stackPackages = [] } = {}
|
|
|
42
44
|
'Open Codex and use /hooks to review and trust the project hooks.',
|
|
43
45
|
'Genesis workflow skills are available in .agents/skills/.',
|
|
44
46
|
'Describe product intent in genesis/blueprint.md.',
|
|
47
|
+
'Choose the project engineering approach with genesis engineering set <profile>.',
|
|
45
48
|
'Stack components are optional; add them with genesis stack add <piece...>.',
|
|
46
49
|
].join(' '),
|
|
47
50
|
};
|
package/src/index/paths.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const BLUEPRINT_PATH = 'genesis/blueprint.md';
|
|
2
|
+
export const ENGINEERING_PATH = 'genesis/engineering.md';
|
|
2
3
|
export const STACK_PATH = 'genesis/stack.md';
|
|
3
4
|
export const PROGRAM_ROOT = 'genesis/program';
|
|
4
5
|
export const VERIFICATION_PATH = '.genesis/verification.json';
|
package/src/index/prompt.js
CHANGED
|
@@ -2,6 +2,11 @@ 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 {
|
|
6
|
+
engineeringPromptContext,
|
|
7
|
+
listEngineeringProfileCatalog,
|
|
8
|
+
readEngineering,
|
|
9
|
+
} from './engineering.js';
|
|
5
10
|
import { readStack, stackPromptContext } from './stack.js';
|
|
6
11
|
import { listStackCatalogPieces } from './stack-catalog.js';
|
|
7
12
|
import { normalizeStackPieceId } from './stack-piece.js';
|
|
@@ -103,6 +108,7 @@ function renderPrompt({
|
|
|
103
108
|
guidance = '',
|
|
104
109
|
cleanup = '',
|
|
105
110
|
adoption = '',
|
|
111
|
+
engineeringGuidance = '',
|
|
106
112
|
}) {
|
|
107
113
|
return [
|
|
108
114
|
instructions.trim(),
|
|
@@ -116,6 +122,7 @@ function renderPrompt({
|
|
|
116
122
|
'```json',
|
|
117
123
|
stableJson(context).trimEnd(),
|
|
118
124
|
'```',
|
|
125
|
+
...(engineeringGuidance ? ['', 'ENGINEERING APPROACH', '', engineeringGuidance] : []),
|
|
119
126
|
...(guidance ? ['', 'SELECTED STACK GUIDANCE', '', guidance] : []),
|
|
120
127
|
...(adoption ? ['', 'SELECTED STACK ADOPTION GUIDANCE', '', adoption] : []),
|
|
121
128
|
...(skills ? ['', 'AVAILABLE AGENT SKILLS', '', skills] : []),
|
|
@@ -124,7 +131,7 @@ function renderPrompt({
|
|
|
124
131
|
].join('\n');
|
|
125
132
|
}
|
|
126
133
|
|
|
127
|
-
async function generateAdoptionPrompt({ environment, instructions, program, request, root, stackPackages }) {
|
|
134
|
+
async function generateAdoptionPrompt({ engineering, environment, instructions, program, request, root, stackPackages }) {
|
|
128
135
|
const blueprint = await readBlueprint(root, { required: true });
|
|
129
136
|
const stack = await readStack(root, { stackPackages });
|
|
130
137
|
const availableStackPackages = [...new Set([...stack.stackPackages, ...stackPackages])];
|
|
@@ -148,6 +155,7 @@ async function generateAdoptionPrompt({ environment, instructions, program, requ
|
|
|
148
155
|
projectRoot: root,
|
|
149
156
|
projectKind: 'existing',
|
|
150
157
|
blueprint: { path: blueprint.path, source: blueprint.source },
|
|
158
|
+
engineering: engineeringPromptContext(engineering),
|
|
151
159
|
stack: stackPromptContext(stack),
|
|
152
160
|
availableStackPieces: stackCatalogContext(catalog),
|
|
153
161
|
program: programContext(program),
|
|
@@ -156,6 +164,7 @@ async function generateAdoptionPrompt({ environment, instructions, program, requ
|
|
|
156
164
|
: { status: 'present' },
|
|
157
165
|
codeIndex: codeIndexContext(index),
|
|
158
166
|
},
|
|
167
|
+
engineeringGuidance: engineering.guidance,
|
|
159
168
|
guidance: stack.guidance,
|
|
160
169
|
adoption: stack.adoption,
|
|
161
170
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
@@ -170,7 +179,7 @@ async function generateAdoptionPrompt({ environment, instructions, program, requ
|
|
|
170
179
|
};
|
|
171
180
|
}
|
|
172
181
|
|
|
173
|
-
async function generateExplanationPrompt({ instructions, program, request, root, stackPackages, task }) {
|
|
182
|
+
async function generateExplanationPrompt({ engineering, instructions, program, request, root, stackPackages, task }) {
|
|
174
183
|
const blueprint = await readBlueprint(root, {
|
|
175
184
|
required: true,
|
|
176
185
|
requireDescription: task === 'program',
|
|
@@ -193,10 +202,12 @@ async function generateExplanationPrompt({ instructions, program, request, root,
|
|
|
193
202
|
task,
|
|
194
203
|
projectRoot: root,
|
|
195
204
|
blueprint: blueprintContext,
|
|
205
|
+
engineering: engineeringPromptContext(engineering),
|
|
196
206
|
stack: stackPromptContext(stack),
|
|
197
207
|
program: programContext(program),
|
|
198
208
|
codeIndex: codeIndexContext(index),
|
|
199
209
|
},
|
|
210
|
+
engineeringGuidance: engineering.guidance,
|
|
200
211
|
guidance: stack.guidance,
|
|
201
212
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
202
213
|
}),
|
|
@@ -211,12 +222,15 @@ async function generateExplanationPrompt({ instructions, program, request, root,
|
|
|
211
222
|
|
|
212
223
|
async function generateStartPrompt({
|
|
213
224
|
hiddenStackPieces,
|
|
225
|
+
engineering,
|
|
214
226
|
instructions,
|
|
215
227
|
program,
|
|
216
228
|
request,
|
|
217
229
|
root,
|
|
218
230
|
stackPackages,
|
|
219
231
|
}) {
|
|
232
|
+
const availableEngineeringProfiles = (await listEngineeringProfileCatalog())
|
|
233
|
+
.map(({ id, name, description }) => ({ id, name, description }));
|
|
220
234
|
let blueprint;
|
|
221
235
|
try {
|
|
222
236
|
blueprint = await readBlueprint(root, { required: true });
|
|
@@ -236,8 +250,11 @@ async function generateStartPrompt({
|
|
|
236
250
|
projectRoot: root,
|
|
237
251
|
projectKind: 'existing-uninitialized',
|
|
238
252
|
genesis: { initialized: false },
|
|
253
|
+
engineering: engineeringPromptContext(engineering),
|
|
254
|
+
availableEngineeringProfiles,
|
|
239
255
|
program: programContext(program),
|
|
240
256
|
},
|
|
257
|
+
engineeringGuidance: engineering.guidance,
|
|
241
258
|
}),
|
|
242
259
|
warnings: program.diagnostic ? [program.diagnostic] : [],
|
|
243
260
|
verificationCommands: [],
|
|
@@ -265,11 +282,14 @@ async function generateStartPrompt({
|
|
|
265
282
|
path: blueprint.path,
|
|
266
283
|
description: blueprint.description,
|
|
267
284
|
},
|
|
285
|
+
engineering: engineeringPromptContext(engineering),
|
|
286
|
+
availableEngineeringProfiles,
|
|
268
287
|
stack: stackPromptContext(stack),
|
|
269
288
|
availableStackPieces: stackCatalogContext(catalog, hiddenStackPieces),
|
|
270
289
|
program: programContext(program),
|
|
271
290
|
codeIndex: codeIndexContext(index),
|
|
272
291
|
},
|
|
292
|
+
engineeringGuidance: engineering.guidance,
|
|
273
293
|
guidance: stack.guidance,
|
|
274
294
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
275
295
|
}),
|
|
@@ -295,7 +315,10 @@ export async function generateProjectPrompt({
|
|
|
295
315
|
}
|
|
296
316
|
const root = (await gitContext(projectRoot)).repositoryRoot;
|
|
297
317
|
const userRequest = requestText(request, task);
|
|
298
|
-
const instructions = await
|
|
318
|
+
const [instructions, engineering] = await Promise.all([
|
|
319
|
+
readInstalledAsset(task),
|
|
320
|
+
readEngineering(root),
|
|
321
|
+
]);
|
|
299
322
|
|
|
300
323
|
if (task === 'blueprint') {
|
|
301
324
|
const blueprint = await readBlueprint(root);
|
|
@@ -310,7 +333,9 @@ export async function generateProjectPrompt({
|
|
|
310
333
|
path: 'genesis/blueprint.md',
|
|
311
334
|
source: blueprint?.source || BLUEPRINT_SKELETON_SOURCE,
|
|
312
335
|
},
|
|
336
|
+
engineering: engineeringPromptContext(engineering),
|
|
313
337
|
},
|
|
338
|
+
engineeringGuidance: engineering.guidance,
|
|
314
339
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
315
340
|
});
|
|
316
341
|
return {
|
|
@@ -327,6 +352,7 @@ export async function generateProjectPrompt({
|
|
|
327
352
|
return generateStartPrompt({
|
|
328
353
|
instructions,
|
|
329
354
|
hiddenStackPieces,
|
|
355
|
+
engineering,
|
|
330
356
|
program,
|
|
331
357
|
request: userRequest,
|
|
332
358
|
root,
|
|
@@ -336,6 +362,7 @@ export async function generateProjectPrompt({
|
|
|
336
362
|
if (task === 'adopt') {
|
|
337
363
|
return generateAdoptionPrompt({
|
|
338
364
|
environment,
|
|
365
|
+
engineering,
|
|
339
366
|
instructions,
|
|
340
367
|
program,
|
|
341
368
|
request: userRequest,
|
|
@@ -352,6 +379,7 @@ export async function generateProjectPrompt({
|
|
|
352
379
|
return generateStartPrompt({
|
|
353
380
|
instructions: await readInstalledAsset('start'),
|
|
354
381
|
hiddenStackPieces,
|
|
382
|
+
engineering,
|
|
355
383
|
program,
|
|
356
384
|
request: userRequest,
|
|
357
385
|
root,
|
|
@@ -362,6 +390,7 @@ export async function generateProjectPrompt({
|
|
|
362
390
|
return generateStartPrompt({
|
|
363
391
|
instructions: await readInstalledAsset('start'),
|
|
364
392
|
hiddenStackPieces,
|
|
393
|
+
engineering,
|
|
365
394
|
program,
|
|
366
395
|
request: userRequest,
|
|
367
396
|
root,
|
|
@@ -372,6 +401,7 @@ export async function generateProjectPrompt({
|
|
|
372
401
|
if (['describe', 'program'].includes(task)) {
|
|
373
402
|
return generateExplanationPrompt({
|
|
374
403
|
instructions,
|
|
404
|
+
engineering,
|
|
375
405
|
program,
|
|
376
406
|
request: userRequest,
|
|
377
407
|
root,
|
|
@@ -400,6 +430,7 @@ export async function generateProjectPrompt({
|
|
|
400
430
|
task,
|
|
401
431
|
projectRoot: root,
|
|
402
432
|
blueprint: { path: blueprint.path, description: blueprint.description },
|
|
433
|
+
engineering: engineeringPromptContext(engineering),
|
|
403
434
|
stack: stackPromptContext(stack),
|
|
404
435
|
program: programContext(program),
|
|
405
436
|
resourceInputs: missing.length > 0
|
|
@@ -417,6 +448,7 @@ export async function generateProjectPrompt({
|
|
|
417
448
|
instructions,
|
|
418
449
|
request: userRequest,
|
|
419
450
|
context,
|
|
451
|
+
engineeringGuidance: engineering.guidance,
|
|
420
452
|
guidance: stack.guidance,
|
|
421
453
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
422
454
|
cleanup: task === 'deslop' ? stack.deslop : '',
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,11 @@ import { buildProjectIndex, GENESIS_DERIVED_ARTIFACTS } from './index/code-index
|
|
|
5
5
|
import { GENESIS_CONTRACTS } from './index/contracts.js';
|
|
6
6
|
import { contextForProjectPaths } from './index/context.js';
|
|
7
7
|
import { generateProjectPrompt } from './index/prompt.js';
|
|
8
|
+
import {
|
|
9
|
+
inspectProjectEngineering,
|
|
10
|
+
listEngineeringProfileCatalog,
|
|
11
|
+
selectEngineeringProfile,
|
|
12
|
+
} from './index/engineering.js';
|
|
8
13
|
import { initializeProject } from './index/init.js';
|
|
9
14
|
import { installCodexPlugin } from './index/codex-plugin.js';
|
|
10
15
|
import { inspectProjectEnvironment } from './index/environment-files.js';
|
|
@@ -98,6 +103,18 @@ export function inspectStackSection(options) {
|
|
|
98
103
|
return inspectProjectStackSection(options);
|
|
99
104
|
}
|
|
100
105
|
|
|
106
|
+
export function listEngineeringProfiles() {
|
|
107
|
+
return listEngineeringProfileCatalog();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function inspectEngineering(options) {
|
|
111
|
+
return inspectProjectEngineering(options);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function setEngineeringProfile(options) {
|
|
115
|
+
return selectEngineeringProfile(options);
|
|
116
|
+
}
|
|
117
|
+
|
|
101
118
|
export function generatePrompt(options) {
|
|
102
119
|
return generateProjectPrompt(options);
|
|
103
120
|
}
|