genesis-compiler 1.2.24 → 1.2.25
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 +31 -36
- package/docs/assurance-model.md +1 -2
- package/docs/prompt-integration.md +16 -20
- package/package.json +1 -2
- package/plugins/genesis/.codex-plugin/plugin.json +1 -1
- package/prompts/deslop.txt +11 -26
- package/prompts/work.txt +11 -8
- package/skills/genesis-deslop/SKILL.md +44 -16
- package/skills/genesis-deslop/agents/openai.yaml +2 -2
- package/skills/genesis-project/SKILL.md +10 -4
- package/src/cli.js +3 -36
- package/src/index/assets.js +0 -1
- package/src/index/codex-hooks.js +57 -594
- package/src/index/init.js +3 -3
- package/src/index/prompt.js +4 -1
- package/prompts/reconcile.txt +0 -13
package/README.md
CHANGED
|
@@ -108,10 +108,10 @@ empty or already-adopted project.
|
|
|
108
108
|
|
|
109
109
|
`genesis init` creates an empty Blueprint, a focused engineering approach, an
|
|
110
110
|
empty optional Stack, the current `genesis/version`, three project Agent Skills,
|
|
111
|
-
and project-local Codex
|
|
111
|
+
and one project-local Codex guidance hook. The skills are ordinary
|
|
112
112
|
[Agent Skills](https://agentskills.io): `genesis-project`, `genesis-program`,
|
|
113
113
|
and `genesis-deslop`, each with standard `SKILL.md` and `agents/openai.yaml`
|
|
114
|
-
metadata. Open `/hooks` once in Codex to review and trust the
|
|
114
|
+
metadata. Open `/hooks` once in Codex to review and trust the guidance hook. After
|
|
115
115
|
that, use Codex normally. No technology is assumed until you explicitly select
|
|
116
116
|
Stack components:
|
|
117
117
|
|
|
@@ -182,7 +182,7 @@ People may edit `## Project requirements` to name obligations the presets do
|
|
|
182
182
|
not capture, including a specific organizational, compliance, cryptographic,
|
|
183
183
|
or scale constraint. `genesis engineering set` changes only the profile and
|
|
184
184
|
preserves those requirements. Generated prompts, path-focused context, Codex
|
|
185
|
-
session guidance, Post-change work, and Deslop all receive the effective
|
|
185
|
+
session guidance, implementation Post-change work, and Deslop all receive the effective
|
|
186
186
|
approach. A project upgraded from an older Genesis release safely uses
|
|
187
187
|
`focused.v1` until `genesis init` or `genesis engineering set focused.v1`
|
|
188
188
|
records the file.
|
|
@@ -263,27 +263,19 @@ Python, Java, C#, C/C++, PHP, Go, Rust, Ruby, Kotlin, and Shell. A future techno
|
|
|
263
263
|
adds its adapter through its Stack piece rather than teaching Genesis prompts
|
|
264
264
|
to parse that language.
|
|
265
265
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
Stack components
|
|
278
|
-
|
|
279
|
-
guidance.
|
|
280
|
-
|
|
281
|
-
The hook never starts another Codex process. Its small per-session phase is
|
|
282
|
-
limited to `implementation -> optional post-change -> reconcile -> deslop ->
|
|
283
|
-
done`, so it cannot keep continuing recursively. The Stop after Deslop clears
|
|
284
|
-
the sequence rather than scheduling another model turn. Empty Post-change
|
|
285
|
-
content is skipped rather than producing an empty turn. Question, explanation,
|
|
286
|
-
review, diagnosis-only, and unchanged turns finish normally.
|
|
266
|
+
The project Codex hook injects a short operating guide at startup, resume,
|
|
267
|
+
clear, and compaction. It records no turn state, blocks no Stop, and requests no
|
|
268
|
+
follow-up turn. Implementation prompts compose selected Stack `Post-change`
|
|
269
|
+
guidance into the original implementation turn, and the project skill keeps
|
|
270
|
+
intentional Blueprint and affected Program changes aligned there.
|
|
271
|
+
|
|
272
|
+
Deslop runs only when explicitly requested. With no stated scope it reviews the
|
|
273
|
+
latest commit; “the last N commits” reviews the net surviving first-parent
|
|
274
|
+
range, and a named commit or range is honored exactly. It requires a clean
|
|
275
|
+
worktree and leaves ordinary uncommitted cleanup for review rather than
|
|
276
|
+
amending history. Genesis supplies the behavior-preserving boundary and Git
|
|
277
|
+
scope rules. Selected Stack components add technology-specific Deslop guidance
|
|
278
|
+
without weakening or broadening that contract.
|
|
287
279
|
|
|
288
280
|
Projects can customize a selected technology through its matching file, such
|
|
289
281
|
as `genesis/stack/jskit.md`:
|
|
@@ -303,7 +295,7 @@ Additional project-specific context about how JSKIT is used here.
|
|
|
303
295
|
|
|
304
296
|
### Post-change
|
|
305
297
|
|
|
306
|
-
- Additional project-specific work to perform
|
|
298
|
+
- Additional project-specific work to perform before the implementation turn completes.
|
|
307
299
|
|
|
308
300
|
### Deslop
|
|
309
301
|
|
|
@@ -321,7 +313,7 @@ A replacement for the installed JSKIT description.
|
|
|
321
313
|
|
|
322
314
|
### Post-change
|
|
323
315
|
|
|
324
|
-
- Replacement installed post-change work.
|
|
316
|
+
- Replacement installed post-change work for the implementation turn.
|
|
325
317
|
|
|
326
318
|
### Deslop
|
|
327
319
|
|
|
@@ -357,8 +349,9 @@ genesis prompt # implementation work
|
|
|
357
349
|
genesis prompt --task start # open a new or existing project conversation
|
|
358
350
|
genesis prompt --task adopt # import an existing project's complete contract
|
|
359
351
|
genesis prompt "Add filtering by note title"
|
|
360
|
-
genesis prompt --task deslop #
|
|
361
|
-
genesis prompt --task deslop "
|
|
352
|
+
genesis prompt --task deslop # clean up the latest commit
|
|
353
|
+
genesis prompt --task deslop "Deslop the last 5 commits"
|
|
354
|
+
genesis prompt --task deslop "Deslop commit a1b2c3d"
|
|
362
355
|
genesis prompt --task program # refresh explanation
|
|
363
356
|
genesis prompt --task blueprint "Start on notes" # update product intent
|
|
364
357
|
genesis prompt --task describe # create/refresh Blueprint and complete Program
|
|
@@ -377,8 +370,9 @@ The eight task types are deliberately explicit:
|
|
|
377
370
|
- `work` implements the Blueprint and optional request using current code,
|
|
378
371
|
Program, the selected engineering approach, selected Stack context, and
|
|
379
372
|
progressively loaded Agent Skills.
|
|
380
|
-
- `deslop` requests cleanup
|
|
381
|
-
|
|
373
|
+
- `deslop` requests behavior-preserving cleanup of committed work explicitly.
|
|
374
|
+
It defaults to the latest commit, accepts a first-parent commit count or exact
|
|
375
|
+
commit/range, requires a clean worktree, and leaves its result uncommitted.
|
|
382
376
|
- `program` edits only `genesis/program/` to explain the code that exists, with
|
|
383
377
|
selected Stack guidance available for technology-specific correctness.
|
|
384
378
|
- `blueprint` edits only `genesis/blueprint.md` from explicit user intent. It
|
|
@@ -418,19 +412,20 @@ Components may contribute:
|
|
|
418
412
|
|
|
419
413
|
- a concise description and supplemental Guidance used across relevant tasks;
|
|
420
414
|
- existing-project Adoption requirements used only while importing a codebase;
|
|
421
|
-
- optional Post-change work composed
|
|
415
|
+
- optional Post-change work composed into the original implementation turn;
|
|
422
416
|
- one authoritative Agent Skill directory when the component owns one;
|
|
423
417
|
- generic external-resource requirements;
|
|
424
|
-
- cleanup advice
|
|
418
|
+
- cleanup advice composed on top of the core explicit Deslop contract;
|
|
425
419
|
- structural code indexers used by Machine City and function lookup;
|
|
426
420
|
- default verification commands.
|
|
427
421
|
|
|
428
422
|
Technology-specific supplemental rules intentionally remain in Stack pieces.
|
|
429
423
|
General `Guidance` enriches implementation, review, Program, description, and
|
|
430
|
-
cleanup tasks; `Adoption` adds import-only requirements; `Post-change`
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
424
|
+
cleanup tasks; `Adoption` adds import-only requirements; `Post-change` adds
|
|
425
|
+
work to finish in the original implementation turn; `Deslop` adds
|
|
426
|
+
technology-specific cleanup rules to Genesis's invariant behavior-preserving
|
|
427
|
+
contract. None shadows an official generic technology skill or assumes that an
|
|
428
|
+
upstream skill contains every rule Genesis needs.
|
|
434
429
|
|
|
435
430
|
Genesis core contains no Stack pieces and no database, framework, language, or
|
|
436
431
|
platform dependency. See [Stack components](docs/stack-components.md).
|
package/docs/assurance-model.md
CHANGED
|
@@ -34,8 +34,7 @@ project. It creates ordinary project files with mode `0666`, directories and
|
|
|
34
34
|
executable skill files with mode `0777`, and lets the invoking process umask
|
|
35
35
|
and the destination directory's inherited ACL establish the effective mode and
|
|
36
36
|
group. Atomic replacements are created beside their destination so they inherit
|
|
37
|
-
the same filesystem policy before becoming visible.
|
|
38
|
-
state remains explicitly `0600`.
|
|
37
|
+
the same filesystem policy before becoming visible.
|
|
39
38
|
|
|
40
39
|
This keeps ordinary single-user projects conventional while allowing a managed
|
|
41
40
|
host to require shared-group writes and no access for other users. The host is
|
|
@@ -77,22 +77,19 @@ does not perform adoption automatically. If the user accepts, Codex runs the
|
|
|
77
77
|
command itself and follows its returned prompt in the same conversation. Other
|
|
78
78
|
hosts can call `adoptProject()` and send its `prompt` directly.
|
|
79
79
|
|
|
80
|
-
Codex can instead use the project-local
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
request
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
both City projections after reconciliation so Deslop sees the current
|
|
94
|
-
explanation and function inventory, then refreshes them again after Deslop in
|
|
95
|
-
case cleanup changed the implementation map.
|
|
80
|
+
Codex can instead use the project-local hook installed by `genesis init`.
|
|
81
|
+
That hook injects a short operating guide at startup, resume, clear, and
|
|
82
|
+
compaction. It does not record user turns, authorize edits, intercept Stop, or
|
|
83
|
+
request another model turn. Selected `Post-change` contributions are included
|
|
84
|
+
in the original implementation prompt, whose project skill also keeps
|
|
85
|
+
intentional Blueprint and affected Program changes aligned.
|
|
86
|
+
|
|
87
|
+
Deslop is an explicit prompt task available to any host or command-line user.
|
|
88
|
+
It resolves the latest commit by default, a requested first-parent count, or an
|
|
89
|
+
exact commit/range; requires a clean worktree; and leaves cleanup as ordinary
|
|
90
|
+
uncommitted work. Genesis owns that invariant contract. Selected Stack
|
|
91
|
+
`Deslop` prose and applicable technology skills enrich the cleanup without
|
|
92
|
+
changing its scope or behavior-preserving boundary.
|
|
96
93
|
|
|
97
94
|
Once Codex identifies relevant source, `genesis context <path...>` returns only
|
|
98
95
|
Program modules citing those paths plus the effective engineering approach and
|
|
@@ -113,7 +110,6 @@ user-installed generic technology skills independent.
|
|
|
113
110
|
Matching files under `genesis/stack/<component>.md` may add to or override that
|
|
114
111
|
selected component's Description, Guidance, Adoption, Post-change, and Deslop
|
|
115
112
|
fields. Effective Guidance is used by work, review, Program, describe, Deslop,
|
|
116
|
-
and path-context generation.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
guidance is included only in the adoption workflow.
|
|
113
|
+
and path-context generation. Effective Post-change work is composed into the
|
|
114
|
+
implementation prompt, while Deslop guidance remains cleanup-only. Effective
|
|
115
|
+
Adoption guidance is included only in the adoption workflow.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genesis-compiler",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.25",
|
|
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": {
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"prompts/describe.txt",
|
|
33
33
|
"prompts/deslop.txt",
|
|
34
34
|
"prompts/program.txt",
|
|
35
|
-
"prompts/reconcile.txt",
|
|
36
35
|
"prompts/review.txt",
|
|
37
36
|
"prompts/start.txt",
|
|
38
37
|
"prompts/work.txt",
|
package/prompts/deslop.txt
CHANGED
|
@@ -1,29 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
`.agents/skills/genesis-deslop/SKILL.md` completely. Review and clean every
|
|
3
|
-
listed repository before responding.
|
|
1
|
+
Read and follow `.agents/skills/genesis-deslop/SKILL.md` completely.
|
|
4
2
|
|
|
5
|
-
This is
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
language and framework context.
|
|
3
|
+
This is an explicitly requested behavior-preserving cleanup of committed work.
|
|
4
|
+
Resolve the commit or first-parent commit range from USER REQUEST exactly; when
|
|
5
|
+
no scope is stated, use the latest commit. Require a clean worktree before
|
|
6
|
+
editing and leave the cleanup as ordinary uncommitted work for review.
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
to
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
Apply the selected Stack cleanup guidance and applicable technology skills in
|
|
9
|
+
addition to the Genesis Deslop contract. Stack guidance may improve
|
|
10
|
+
technology-specific cleanup, but it cannot broaden the resolved Git scope,
|
|
11
|
+
weaken behavior preservation, or turn this into another implementation pass.
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
present; it may not complete, correct, or extend behavior. If review reveals a
|
|
19
|
-
defect, missing behavior, contract mismatch, or test gap, report it as a
|
|
20
|
-
follow-up finding and leave it unchanged in this pass, even when it is inside a
|
|
21
|
-
changed path or appears related to the preceding implementation.
|
|
22
|
-
|
|
23
|
-
Do not broaden the product change. Run focused checks when useful and summarize
|
|
24
|
-
what became simpler, files changed, and checks actually run.
|
|
25
|
-
|
|
26
|
-
Your response from this turn is the final user-facing answer for the original
|
|
27
|
-
request. Make it concise and self-contained. Lead with the outcome, include the
|
|
28
|
-
important implemented behavior and any genuine blocker or unfinished work, and
|
|
29
|
-
do not mention automatic phases, hooks, or these instructions.
|
|
13
|
+
Report the resolved range, what became simpler, files changed, checks actually
|
|
14
|
+
run, and any defect or gap deliberately left for follow-up.
|
package/prompts/work.txt
CHANGED
|
@@ -8,15 +8,18 @@ Before adding a helper or public operation, query the Genesis
|
|
|
8
8
|
`index <name-or-path>` operation and reuse an existing function when it already
|
|
9
9
|
owns the behavior.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
missing resource
|
|
11
|
+
Keep the Blueprint and affected Program modules aligned in this turn when the
|
|
12
|
+
implementation intentionally changes observable product behavior. Private
|
|
13
|
+
restructuring may require only corrected source citations or no explanatory
|
|
14
|
+
edit. Keep applicable consumer-owned Stack sections aligned when implementation
|
|
15
|
+
changes facts governed by those contracts. Follow the selected technology skill
|
|
16
|
+
and the section's own schema; Genesis only transports the section and does not
|
|
17
|
+
interpret or execute it. Never put an environment value or secret in Stack.
|
|
18
|
+
Never invent missing external-resource values. Preserve useful work and report
|
|
19
|
+
a genuinely missing resource instead of constructing a parallel fallback.
|
|
19
20
|
|
|
21
|
+
Apply any supplied Stack Post-change guidance before reporting completion. It
|
|
22
|
+
belongs to this implementation turn and does not request a follow-up agent turn.
|
|
20
23
|
Run focused checks when useful. Summarize files changed, checks actually run,
|
|
21
24
|
and anything still requiring attention.
|
|
22
25
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: genesis-deslop
|
|
3
|
-
description:
|
|
3
|
+
description: Deslop committed work through an explicit behavior-preserving cleanup pass. Use when asked to Deslop a commit or recent commits, simplify completed work, remove repeated helpers, clarify ownership, or align changed code with established project and technology patterns.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Genesis Deslop
|
|
7
7
|
|
|
8
|
-
Review and simplify
|
|
9
|
-
|
|
10
|
-
and the code immediately around it.
|
|
8
|
+
Review and simplify committed work without changing product behavior. Deslop is
|
|
9
|
+
explicit: never run it merely because implementation finished.
|
|
11
10
|
|
|
12
11
|
When this repository is Genesis itself or has `genesis-compiler` installed
|
|
13
12
|
locally, invoke every Genesis CLI operation through the project-pinned package:
|
|
@@ -16,6 +15,28 @@ package. Otherwise use `genesis <arguments>` only when that executable is
|
|
|
16
15
|
already available on `PATH`. Never install or update Genesis merely to satisfy
|
|
17
16
|
a workflow instruction.
|
|
18
17
|
|
|
18
|
+
## Resolve the committed scope
|
|
19
|
+
|
|
20
|
+
Before reading or editing the selected change, require a clean worktree and
|
|
21
|
+
index with `git status --short`. Stop and report the existing paths when it is
|
|
22
|
+
not clean; do not stash, commit, discard, or mix them into Deslop.
|
|
23
|
+
|
|
24
|
+
Resolve the user's scope as follows:
|
|
25
|
+
|
|
26
|
+
- With no stated scope, use the latest commit.
|
|
27
|
+
- “The last N commits” means the net surviving change from the first parent
|
|
28
|
+
before those N commits through `HEAD`.
|
|
29
|
+
- A named commit means that commit against its first parent.
|
|
30
|
+
- An explicit commit range means exactly that range.
|
|
31
|
+
- A root commit uses Git's root-diff form because it has no parent.
|
|
32
|
+
|
|
33
|
+
Inspect the resolved commit identities and changed paths before editing. Review
|
|
34
|
+
the committed diff, current source, direct call sites, relevant tests, and the
|
|
35
|
+
affected Program and Stack context. Do not substitute the ordinary working-tree
|
|
36
|
+
diff for the selected committed scope.
|
|
37
|
+
|
|
38
|
+
## Apply the cleanup contract
|
|
39
|
+
|
|
19
40
|
Apply the engineering approach supplied with the task. If this skill is invoked
|
|
20
41
|
directly, read `genesis/engineering.md` as well as the relevant project context.
|
|
21
42
|
Cleanup must reduce or preserve complexity, never introduce unapproved
|
|
@@ -26,7 +47,7 @@ operation to find existing public and internal functions before introducing or
|
|
|
26
47
|
consolidating an abstraction. Confirm every apparent duplicate in source and
|
|
27
48
|
its call sites.
|
|
28
49
|
|
|
29
|
-
Within the
|
|
50
|
+
Within the selected commits' intended behavior and scope, leave no
|
|
30
51
|
repeated helpers, no code that is unclear or hard to reason about, and no code
|
|
31
52
|
that goes against established patterns in the codebase. Remove unnecessary
|
|
32
53
|
wrappers, abandoned scaffolding, parallel framework plumbing, and speculative
|
|
@@ -34,7 +55,7 @@ abstractions. Consolidate ownership where one clear module is enough. Do not
|
|
|
34
55
|
optimize for tiny files or indirection; optimize for a small, obvious design
|
|
35
56
|
that a junior programmer can follow.
|
|
36
57
|
|
|
37
|
-
Cleanup is not a second implementation pass. A
|
|
58
|
+
Cleanup is not a second implementation pass. A committed path limits where cleanup
|
|
38
59
|
may occur; it does not authorize different behavior in that file. Deslop may
|
|
39
60
|
reorganize behavior already present; it may not complete, correct, or extend
|
|
40
61
|
behavior. If review reveals a defect, missing behavior, contract mismatch, or
|
|
@@ -43,15 +64,22 @@ is inside a changed path or appears related to the preceding implementation. Do
|
|
|
43
64
|
not implement the finding or alter tests to accommodate it during Deslop.
|
|
44
65
|
|
|
45
66
|
Apply every technology-specific Deslop instruction supplied by the selected
|
|
46
|
-
Stack
|
|
47
|
-
|
|
67
|
+
Stack and load applicable official technology skills for framework and language
|
|
68
|
+
context. Stack guidance enriches this contract; it cannot weaken the
|
|
69
|
+
behavior-preserving boundary, change the selected Git scope, or authorize
|
|
70
|
+
unrelated implementation.
|
|
48
71
|
|
|
49
72
|
You may edit or delete implementation and test files when that is the clearest
|
|
50
|
-
behavior-preserving cleanup.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
behavior-preserving cleanup. If moving or renaming selected source makes an
|
|
74
|
+
affected Program citation stale, update only that citation or informational
|
|
75
|
+
Implementation map. Do not change the Blueprint or a Program public contract to
|
|
76
|
+
excuse cleanup behavior. Do not edit `.genesis/`, Git metadata, dependency
|
|
77
|
+
directories, generated build output, retained migration history, or external
|
|
78
|
+
resources. Do not weaken tests, public behavior, or data guarantees. Do not
|
|
79
|
+
create a second architecture or perform unrelated rewrites.
|
|
80
|
+
|
|
81
|
+
Leave the cleanup as ordinary uncommitted work for review and a later normal
|
|
82
|
+
commit. Never amend or rewrite the selected commits. Run focused checks when
|
|
83
|
+
useful. Final declared checks remain available through the Genesis `verify`
|
|
84
|
+
operation. Summarize the resolved commit range, what became simpler, files
|
|
85
|
+
changed, checks actually run, and follow-up findings left unchanged.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Genesis Deslop"
|
|
3
|
-
short_description: "
|
|
4
|
-
default_prompt: "Use $genesis-deslop
|
|
3
|
+
short_description: "Clean up committed work without behavior drift"
|
|
4
|
+
default_prompt: "Use $genesis-deslop to Deslop the latest commit."
|
|
@@ -65,19 +65,25 @@ Neither is authority or proof; both may be regenerated with the Genesis
|
|
|
65
65
|
tradeoff. Never silently override the engineering approach.
|
|
66
66
|
- Work directly in the current Git tree and leave useful edits visible in the
|
|
67
67
|
ordinary diff.
|
|
68
|
-
-
|
|
69
|
-
|
|
68
|
+
- Keep the Blueprint and affected Program modules aligned in this same turn
|
|
69
|
+
when implementation intentionally changes observable product behavior.
|
|
70
|
+
Private restructuring may require only corrected Sources or an informational
|
|
71
|
+
Implementation map, and may require no explanatory edit. Keep exact
|
|
70
72
|
consumer-owned operation declarations, such as Vibe64 `## Outputs`, aligned
|
|
71
73
|
when implementation intentionally changes the corresponding commands or
|
|
72
74
|
capabilities. Record only capability metadata and environment-variable names
|
|
73
75
|
there, never values or secrets; do not infer or execute the section as
|
|
74
|
-
Genesis behavior.
|
|
76
|
+
Genesis behavior. Treat `.genesis/` as replaceable derived navigation data,
|
|
77
|
+
not authored product intent.
|
|
75
78
|
- Follow established project and technology seams instead of creating parallel
|
|
76
79
|
frameworks, persistence layers, transports, validators, or UI systems.
|
|
77
80
|
- Never invent unavailable external-resource values or pass literal
|
|
78
81
|
environment-variable names as data. Report the missing resource and preserve
|
|
79
82
|
useful work.
|
|
80
|
-
- Keep the implementation direct and cohesive.
|
|
83
|
+
- Keep the implementation direct and cohesive. Apply any supplied Stack
|
|
84
|
+
Post-change guidance before reporting completion; it is part of this
|
|
85
|
+
implementation turn, not a request for another agent turn. Run focused checks
|
|
86
|
+
when useful.
|
|
81
87
|
|
|
82
88
|
## Verify and report
|
|
83
89
|
|
package/src/cli.js
CHANGED
|
@@ -20,12 +20,8 @@ import {
|
|
|
20
20
|
verify,
|
|
21
21
|
} from './index.js';
|
|
22
22
|
import {
|
|
23
|
-
authorizeCodexTurn,
|
|
24
23
|
codexAdoptionRecommendation,
|
|
25
24
|
codexSessionContext,
|
|
26
|
-
completeCodexTurn,
|
|
27
|
-
discardCodexTurn,
|
|
28
|
-
recordCodexTurn,
|
|
29
25
|
} from './index/codex-hooks.js';
|
|
30
26
|
import { engineeringProfile, readEngineeringBaseline } from './index/engineering.js';
|
|
31
27
|
import { asDiagnostic, fail } from './index/errors.js';
|
|
@@ -138,8 +134,8 @@ function parseCommand(argv) {
|
|
|
138
134
|
'Command inspect requires environment or section <name>.',
|
|
139
135
|
);
|
|
140
136
|
}
|
|
141
|
-
} else if (command === 'hook' && (operands.length !== 1 || !['
|
|
142
|
-
fail('CLI_HOOK_ACTION_REQUIRED', 'Command hook requires exactly one of: discover, session
|
|
137
|
+
} else if (command === 'hook' && (operands.length !== 1 || !['discover', 'session'].includes(operands[0]))) {
|
|
138
|
+
fail('CLI_HOOK_ACTION_REQUIRED', 'Command hook requires exactly one of: discover, session.');
|
|
143
139
|
} else if (!['adopt', 'context', 'hook', 'index', 'inspect', 'prompt'].includes(command) && operands.length > 0) {
|
|
144
140
|
fail('CLI_EXTRA_ARGUMENT', `Command ${command} accepts no arguments.`);
|
|
145
141
|
}
|
|
@@ -266,8 +262,6 @@ function writeResult(command, result) {
|
|
|
266
262
|
}
|
|
267
263
|
if (command === 'hook') {
|
|
268
264
|
if (['discover', 'session'].includes(result.kind) && result.output) line(process.stdout, result.output);
|
|
269
|
-
else if (result.kind === 'authorize') line(process.stdout, `authorize: ${result.status}`);
|
|
270
|
-
else if (result.kind === 'stop') line(process.stdout, JSON.stringify(result.output));
|
|
271
265
|
return;
|
|
272
266
|
}
|
|
273
267
|
if (command === 'stack' && Array.isArray(result.pieces)) {
|
|
@@ -292,20 +286,6 @@ function writeResult(command, result) {
|
|
|
292
286
|
line(process.stdout, `${command}: ${result.status}`);
|
|
293
287
|
}
|
|
294
288
|
|
|
295
|
-
async function hookInput() {
|
|
296
|
-
if (process.stdin.isTTY) fail('CODEX_HOOK_INPUT_INVALID', 'Codex hook input must be supplied on stdin.');
|
|
297
|
-
const chunks = [];
|
|
298
|
-
let bytes = 0;
|
|
299
|
-
for await (const chunk of process.stdin) {
|
|
300
|
-
bytes += chunk.length;
|
|
301
|
-
if (bytes > 1024 * 1024) fail('CODEX_HOOK_INPUT_INVALID', 'Codex hook input exceeds 1 MiB.');
|
|
302
|
-
chunks.push(chunk);
|
|
303
|
-
}
|
|
304
|
-
try { return JSON.parse(Buffer.concat(chunks).toString('utf8')); } catch (error) {
|
|
305
|
-
fail('CODEX_HOOK_INPUT_INVALID', `Codex hook input is invalid JSON: ${error.message}.`);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
289
|
async function execute({ command, operands, options }, { signal } = {}) {
|
|
310
290
|
const projectRoot = options.projectRoot || process.cwd();
|
|
311
291
|
const stackPackages = options.stackPackages || [];
|
|
@@ -382,20 +362,7 @@ async function execute({ command, operands, options }, { signal } = {}) {
|
|
|
382
362
|
if (operands[0] === 'discover') {
|
|
383
363
|
return { kind: 'discover', ...await codexAdoptionRecommendation({ projectRoot }) };
|
|
384
364
|
}
|
|
385
|
-
|
|
386
|
-
return { kind: 'session', ...await codexSessionContext({ projectRoot }) };
|
|
387
|
-
}
|
|
388
|
-
if (operands[0] === 'authorize') {
|
|
389
|
-
return { kind: 'authorize', ...await authorizeCodexTurn({ projectRoot }) };
|
|
390
|
-
}
|
|
391
|
-
const input = await hookInput();
|
|
392
|
-
if (operands[0] === 'begin') {
|
|
393
|
-
return { kind: 'begin', ...await recordCodexTurn({ input, projectRoot }) };
|
|
394
|
-
}
|
|
395
|
-
if (operands[0] === 'end') {
|
|
396
|
-
return { kind: 'end', ...await discardCodexTurn({ input, projectRoot }) };
|
|
397
|
-
}
|
|
398
|
-
return { kind: 'stop', status: 'ready', output: await completeCodexTurn({ input, projectRoot }) };
|
|
365
|
+
return { kind: 'session', ...await codexSessionContext({ projectRoot }) };
|
|
399
366
|
}
|
|
400
367
|
if (command === 'verify') {
|
|
401
368
|
return verify({
|
package/src/index/assets.js
CHANGED
|
@@ -6,7 +6,6 @@ const assets = {
|
|
|
6
6
|
adopt: new URL('prompts/adopt.txt', root),
|
|
7
7
|
work: new URL('prompts/work.txt', root),
|
|
8
8
|
describe: new URL('prompts/describe.txt', root),
|
|
9
|
-
reconcile: new URL('prompts/reconcile.txt', root),
|
|
10
9
|
deslop: new URL('prompts/deslop.txt', root),
|
|
11
10
|
program: new URL('prompts/program.txt', root),
|
|
12
11
|
blueprint: new URL('prompts/blueprint.txt', root),
|
package/src/index/codex-hooks.js
CHANGED
|
@@ -1,82 +1,62 @@
|
|
|
1
|
-
import { readFile
|
|
2
|
-
import { tmpdir } from 'node:os';
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
3
2
|
import path from 'node:path';
|
|
4
3
|
|
|
5
|
-
import { readInstalledAsset } from './assets.js';
|
|
6
|
-
import { buildProjectIndex } from './code-index.js';
|
|
7
4
|
import { readEngineering, readEngineeringBaseline } from './engineering.js';
|
|
8
5
|
import { GenesisError } from './errors.js';
|
|
9
6
|
import { gitContext } from './git.js';
|
|
10
7
|
import { isProjectContentPath } from './paths.js';
|
|
11
|
-
import { runGit
|
|
8
|
+
import { runGit } from './process.js';
|
|
12
9
|
import { readStack } from './stack.js';
|
|
13
|
-
import { normalizeRelative, pathState,
|
|
10
|
+
import { normalizeRelative, pathState, writeFileAtomic } from './utils.js';
|
|
14
11
|
|
|
15
12
|
const HOOKS_PATH = '.codex/hooks.json';
|
|
16
|
-
const
|
|
17
|
-
|
|
13
|
+
const PROJECT_HOOK_ACTIONS = ['session', 'begin', 'stop', 'end'];
|
|
14
|
+
|
|
18
15
|
function hookCommand(action) {
|
|
19
16
|
const local = `const {runCli}=await import('genesis-compiler/cli');process.exitCode=await runCli(['hook','${action}'])`;
|
|
20
17
|
return `if command -v genesis >/dev/null 2>&1; then genesis hook ${action}; else node --input-type=module --eval "${local}"; fi`;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
additionalContextLimit: 4000,
|
|
36
|
-
}],
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
event: 'UserPromptSubmit',
|
|
41
|
-
command: hookCommand('begin'),
|
|
42
|
-
group: {
|
|
43
|
-
hooks: [{
|
|
44
|
-
type: 'command',
|
|
45
|
-
command: hookCommand('begin'),
|
|
46
|
-
commandWindows: 'genesis hook begin',
|
|
47
|
-
timeout: 10,
|
|
48
|
-
}],
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
event: 'Stop',
|
|
53
|
-
command: hookCommand('stop'),
|
|
54
|
-
group: {
|
|
55
|
-
hooks: [{
|
|
56
|
-
type: 'command',
|
|
57
|
-
command: hookCommand('stop'),
|
|
58
|
-
commandWindows: 'genesis hook stop',
|
|
59
|
-
timeout: 30,
|
|
60
|
-
statusMessage: 'Checking whether Genesis follow-up work is needed',
|
|
61
|
-
}],
|
|
62
|
-
},
|
|
20
|
+
const SESSION_HOOK = {
|
|
21
|
+
event: 'SessionStart',
|
|
22
|
+
group: {
|
|
23
|
+
matcher: '^(startup|resume|clear|compact)$',
|
|
24
|
+
hooks: [{
|
|
25
|
+
type: 'command',
|
|
26
|
+
command: hookCommand('session'),
|
|
27
|
+
commandWindows: 'genesis hook session',
|
|
28
|
+
timeout: 5,
|
|
29
|
+
statusMessage: 'Loading Genesis guidance',
|
|
30
|
+
additionalContextLimit: 4000,
|
|
31
|
+
}],
|
|
63
32
|
},
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
command: hookCommand('end'),
|
|
71
|
-
commandWindows: 'genesis hook end',
|
|
72
|
-
timeout: 3,
|
|
73
|
-
}],
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const OBSOLETE_PROJECT_HOOK_COMMANDS = new Set(PROJECT_HOOK_ACTIONS.flatMap((action) => [
|
|
36
|
+
hookCommand(action),
|
|
37
|
+
`genesis hook ${action}`,
|
|
38
|
+
]));
|
|
77
39
|
|
|
78
|
-
function
|
|
79
|
-
return
|
|
40
|
+
function genesisProjectHook(hook) {
|
|
41
|
+
return hook && (
|
|
42
|
+
OBSOLETE_PROJECT_HOOK_COMMANDS.has(hook.command)
|
|
43
|
+
|| OBSOLETE_PROJECT_HOOK_COMMANDS.has(hook.commandWindows)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function removeGenesisProjectHooks(hooks) {
|
|
48
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
49
|
+
if (!Array.isArray(groups)) {
|
|
50
|
+
throw new GenesisError('CODEX_HOOKS_INVALID', `${HOOKS_PATH} hooks.${event} must be an array.`);
|
|
51
|
+
}
|
|
52
|
+
const retained = groups.flatMap((group) => {
|
|
53
|
+
if (!Array.isArray(group?.hooks)) return [group];
|
|
54
|
+
const groupHooks = group.hooks.filter((hook) => !genesisProjectHook(hook));
|
|
55
|
+
return groupHooks.length > 0 ? [{ ...group, hooks: groupHooks }] : [];
|
|
56
|
+
});
|
|
57
|
+
if (retained.length > 0) hooks[event] = retained;
|
|
58
|
+
else delete hooks[event];
|
|
59
|
+
}
|
|
80
60
|
}
|
|
81
61
|
|
|
82
62
|
async function installedHooksSource(location) {
|
|
@@ -101,13 +81,9 @@ export async function installCodexHooks({ projectRoot } = {}) {
|
|
|
101
81
|
const location = path.join(root, HOOKS_PATH);
|
|
102
82
|
const { source, value } = await installedHooksSource(location);
|
|
103
83
|
value.hooks ||= {};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
throw new GenesisError('CODEX_HOOKS_INVALID', `${HOOKS_PATH} hooks.${spec.event} must be an array.`);
|
|
108
|
-
}
|
|
109
|
-
if (!genesisHookInstalled(groups, spec.command)) groups.push(spec.group);
|
|
110
|
-
}
|
|
84
|
+
removeGenesisProjectHooks(value.hooks);
|
|
85
|
+
const groups = value.hooks[SESSION_HOOK.event] ||= [];
|
|
86
|
+
groups.push(SESSION_HOOK.group);
|
|
111
87
|
const rendered = `${JSON.stringify(value, null, 2)}\n`;
|
|
112
88
|
if (source === rendered) return { status: 'unchanged', changedFiles: [] };
|
|
113
89
|
await writeFileAtomic(location, rendered);
|
|
@@ -131,7 +107,6 @@ async function optionalEngineering(projectRoot) {
|
|
|
131
107
|
'The project engineering profile is invalid. Do not infer a replacement; run the Genesis `check` operation and ask the user before implementation if the selected approach matters.',
|
|
132
108
|
].join('\n'),
|
|
133
109
|
profile: null,
|
|
134
|
-
status: 'invalid',
|
|
135
110
|
};
|
|
136
111
|
}
|
|
137
112
|
}
|
|
@@ -150,21 +125,14 @@ export async function codexSessionContext({ projectRoot } = {}) {
|
|
|
150
125
|
status: 'ready',
|
|
151
126
|
output: [
|
|
152
127
|
'This is a Genesis-enriched project.',
|
|
153
|
-
'- `genesis/blueprint.md`
|
|
154
|
-
'-
|
|
155
|
-
'- `genesis
|
|
156
|
-
'- `genesis/program/<subsystem>/` explains public operations and useful internal seams.',
|
|
157
|
-
'- Project Agent Skills live in `.agents/skills/`; load applicable skills progressively.',
|
|
158
|
-
'- When this repository is Genesis itself or has local `genesis-compiler`, run every Genesis CLI operation as `npm exec --no -- genesis <arguments>` so the project-pinned version is used without fetching another package. Otherwise use `genesis <arguments>` only when that executable is already available on `PATH`. Never install or update Genesis merely to run a workflow instruction.',
|
|
159
|
-
'- After locating relevant source files, run the Genesis `context <path...>` operation to load their Program and selected Stack material.',
|
|
160
|
-
'- Before creating a helper or public operation, run the Genesis `index <name-or-path>` operation and reuse an existing function when it already owns the behavior.',
|
|
161
|
-
'- `.genesis/machine-city.json` is the detailed code/function map; `.genesis/program-city.json` is the simpler subsystem/operation map.',
|
|
128
|
+
'- Read `genesis/blueprint.md`, `genesis/engineering.md`, and `genesis/stack.md` for product intent, engineering approach, and selected technology.',
|
|
129
|
+
'- Use the relevant project Agent Skills below `.agents/skills/`.',
|
|
130
|
+
'- After locating source, run `genesis context <path...>`; before adding a helper or public operation, run `genesis index <name-or-path...>` and reuse an existing owner.',
|
|
162
131
|
'- Program is fallible explanation; code, tests, and runtime behavior remain evidence.',
|
|
163
|
-
'-
|
|
164
|
-
'-
|
|
165
|
-
'-
|
|
166
|
-
|
|
167
|
-
`Engineering profile: ${engineering.profile?.id || 'invalid; run the Genesis \`check\` operation'}.`,
|
|
132
|
+
'- Keep Blueprint and affected Program explanations aligned with intentional observable product behavior in the same implementation turn. Private restructuring may need only source citations or no explanatory change.',
|
|
133
|
+
'- Deslop only when explicitly requested. Genesis defines its behavior-preserving committed scope; selected Stack components may add technology-specific cleanup guidance.',
|
|
134
|
+
'- This guidance refreshes after startup, resume, clear, and compaction. Continue the active request without restarting completed work.',
|
|
135
|
+
`Engineering profile: ${engineering.profile?.id || 'invalid; run the Genesis `check` operation'}.`,
|
|
168
136
|
`Selected Stack components: ${stackStatus}.`,
|
|
169
137
|
'',
|
|
170
138
|
'ENGINEERING APPROACH',
|
|
@@ -174,6 +142,10 @@ export async function codexSessionContext({ projectRoot } = {}) {
|
|
|
174
142
|
};
|
|
175
143
|
}
|
|
176
144
|
|
|
145
|
+
function zeroPaths(buffer) {
|
|
146
|
+
return [...new Set(buffer.toString('utf8').split('\0').map(normalizeRelative).filter(Boolean))];
|
|
147
|
+
}
|
|
148
|
+
|
|
177
149
|
export async function codexAdoptionRecommendation({ projectRoot = process.cwd() } = {}) {
|
|
178
150
|
let root;
|
|
179
151
|
try { root = (await gitContext(projectRoot)).repositoryRoot; } catch { return { status: 'not-applicable', output: '' }; }
|
|
@@ -197,512 +169,3 @@ export async function codexAdoptionRecommendation({ projectRoot = process.cwd()
|
|
|
197
169
|
].join('\n'),
|
|
198
170
|
};
|
|
199
171
|
}
|
|
200
|
-
|
|
201
|
-
function hookId(input, field) {
|
|
202
|
-
const value = input?.[field];
|
|
203
|
-
if (typeof value !== 'string' || !value || value.length > 512) {
|
|
204
|
-
throw new GenesisError('CODEX_HOOK_INPUT_INVALID', `Codex hook input requires ${field}.`);
|
|
205
|
-
}
|
|
206
|
-
return value;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function normalizedPaths(values = []) {
|
|
210
|
-
return [...new Set(values.map(normalizeRelative).filter(Boolean))];
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function zeroPaths(buffer) {
|
|
214
|
-
return normalizedPaths(buffer.toString('utf8').split('\0'));
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function projectPathStates(projectRoot, files) {
|
|
218
|
-
return Promise.all(files.map(async (file) => ({
|
|
219
|
-
path: file,
|
|
220
|
-
state: await pathState(path.join(projectRoot, file)),
|
|
221
|
-
})));
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
async function repositorySnapshot(projectRoot) {
|
|
225
|
-
const head = await runGitText(projectRoot, ['rev-parse', '--verify', 'HEAD']).catch(() => null);
|
|
226
|
-
const results = await Promise.all([
|
|
227
|
-
runGit(projectRoot, ['diff', '--no-ext-diff', '--no-renames', '--name-only', '-z']),
|
|
228
|
-
runGit(projectRoot, ['diff', '--cached', '--no-ext-diff', '--no-renames', '--name-only', '-z']),
|
|
229
|
-
runGit(projectRoot, ['ls-files', '-z', '--others', '--exclude-standard']),
|
|
230
|
-
runGit(projectRoot, ['ls-files', '-z', '--deleted']),
|
|
231
|
-
]);
|
|
232
|
-
const dirty = [...new Set(results.flatMap(({ stdout }) => zeroPaths(stdout)))]
|
|
233
|
-
.filter(isProjectContentPath)
|
|
234
|
-
.sort();
|
|
235
|
-
return {
|
|
236
|
-
head,
|
|
237
|
-
dirty: await projectPathStates(projectRoot, dirty),
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async function hookStatePath(projectRoot, input) {
|
|
242
|
-
const key = sha256(hookId(input, 'session_id')).slice('sha256:'.length);
|
|
243
|
-
const gitPath = await runGitText(projectRoot, ['rev-parse', '--git-path', `genesis/hooks/${key}.json`]);
|
|
244
|
-
return path.resolve(projectRoot, gitPath);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function hookLocatorPath(input) {
|
|
248
|
-
const key = sha256(hookId(input, 'session_id')).slice('sha256:'.length);
|
|
249
|
-
const user = typeof process.getuid === 'function' ? process.getuid() : 'user';
|
|
250
|
-
return path.join(tmpdir(), `genesis-codex-hook-${user}-${key}.json`);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function writeTurnState(statePath, state) {
|
|
254
|
-
return writeFileAtomic(statePath, stableJson(state), { mode: 0o600 });
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async function refreshProjectIndex(projectRoot) {
|
|
258
|
-
await buildProjectIndex({ projectRoot }).catch(() => null);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export async function recordCodexTurn({ input, projectRoot } = {}) {
|
|
262
|
-
const root = (await gitContext(projectRoot || input?.cwd)).repositoryRoot;
|
|
263
|
-
const statePath = await hookStatePath(root, input);
|
|
264
|
-
const turnId = hookId(input, 'turn_id');
|
|
265
|
-
const existing = await readTurnState(statePath);
|
|
266
|
-
if (existing?.schemaVersion === HOOK_STATE_SCHEMA_VERSION && existing.turnId === turnId) {
|
|
267
|
-
await writeHookLocator(input, root);
|
|
268
|
-
return { status: 'preserved' };
|
|
269
|
-
}
|
|
270
|
-
const repositories = registeredRepositories(existing || {}, root);
|
|
271
|
-
const state = {
|
|
272
|
-
schemaVersion: HOOK_STATE_SCHEMA_VERSION,
|
|
273
|
-
turnId,
|
|
274
|
-
phase: 'implementation',
|
|
275
|
-
implementationAuthorized: false,
|
|
276
|
-
repositories,
|
|
277
|
-
snapshot: repositories.length > 0 && existing?.snapshot
|
|
278
|
-
? existing.snapshot
|
|
279
|
-
: await repositorySnapshot(root),
|
|
280
|
-
};
|
|
281
|
-
await writeTurnState(statePath, state);
|
|
282
|
-
await writeHookLocator(input, root);
|
|
283
|
-
return { status: 'recorded' };
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
async function readTurnState(statePath) {
|
|
287
|
-
try { return JSON.parse(await readFile(statePath, 'utf8')); } catch (error) {
|
|
288
|
-
if (['ENOENT', 'ENOTDIR'].includes(error?.code)) return null;
|
|
289
|
-
throw error;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async function readHookLocator(input) {
|
|
294
|
-
try { return JSON.parse(await readFile(hookLocatorPath(input), 'utf8')); } catch (error) {
|
|
295
|
-
if (['ENOENT', 'ENOTDIR'].includes(error?.code)) return null;
|
|
296
|
-
throw error;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function writeHookLocator(input, coordinatorRoot) {
|
|
301
|
-
return writeFileAtomic(hookLocatorPath(input), stableJson({
|
|
302
|
-
schemaVersion: HOOK_LOCATOR_SCHEMA_VERSION,
|
|
303
|
-
coordinatorRoot,
|
|
304
|
-
}), { mode: 0o600 });
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
async function removeTurnState(statePath, input) {
|
|
308
|
-
await Promise.all([
|
|
309
|
-
rm(statePath, { force: true }),
|
|
310
|
-
rm(hookLocatorPath(input), { force: true }),
|
|
311
|
-
]);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function registeredRepositories(state, coordinatorRoot) {
|
|
315
|
-
if (Array.isArray(state.repositories) && state.repositories.length > 0) {
|
|
316
|
-
return state.repositories;
|
|
317
|
-
}
|
|
318
|
-
if (state.implementationAuthorized === true && state.snapshot) {
|
|
319
|
-
return [{
|
|
320
|
-
projectRoot: coordinatorRoot,
|
|
321
|
-
snapshot: state.snapshot,
|
|
322
|
-
changedPaths: normalizedPaths(state.changedPaths || []).sort(),
|
|
323
|
-
}];
|
|
324
|
-
}
|
|
325
|
-
return [];
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
export async function authorizeCodexTurn({
|
|
329
|
-
projectRoot = process.cwd(),
|
|
330
|
-
sessionId = process.env.CODEX_SESSION_ID,
|
|
331
|
-
} = {}) {
|
|
332
|
-
if (!sessionId) {
|
|
333
|
-
throw new GenesisError(
|
|
334
|
-
'CODEX_SESSION_ID_MISSING',
|
|
335
|
-
'genesis hook authorize requires the current Codex session.',
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
const input = { session_id: sessionId };
|
|
339
|
-
const root = (await gitContext(projectRoot)).repositoryRoot;
|
|
340
|
-
const locator = await readHookLocator(input);
|
|
341
|
-
if (locator && (
|
|
342
|
-
locator.schemaVersion !== HOOK_LOCATOR_SCHEMA_VERSION
|
|
343
|
-
|| typeof locator.coordinatorRoot !== 'string'
|
|
344
|
-
|| !locator.coordinatorRoot
|
|
345
|
-
)) {
|
|
346
|
-
throw new GenesisError(
|
|
347
|
-
'CODEX_HOOK_COORDINATOR_INVALID',
|
|
348
|
-
'The current Codex turn has invalid Genesis coordination state.',
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
|
-
const coordinatorRoot = locator
|
|
352
|
-
? (await gitContext(locator.coordinatorRoot)).repositoryRoot
|
|
353
|
-
: root;
|
|
354
|
-
const statePath = await hookStatePath(coordinatorRoot, input);
|
|
355
|
-
const state = await readTurnState(statePath);
|
|
356
|
-
if (!state || state.schemaVersion !== HOOK_STATE_SCHEMA_VERSION || state.phase !== 'implementation') {
|
|
357
|
-
throw new GenesisError(
|
|
358
|
-
'CODEX_HOOK_TURN_UNAVAILABLE',
|
|
359
|
-
'No active Genesis implementation turn is available. Start from the session repository and authorize before editing.',
|
|
360
|
-
);
|
|
361
|
-
}
|
|
362
|
-
const repositories = registeredRepositories(state, coordinatorRoot);
|
|
363
|
-
const registered = repositories.some((repository) => repository.projectRoot === root);
|
|
364
|
-
if (!registered) {
|
|
365
|
-
repositories.push({
|
|
366
|
-
projectRoot: root,
|
|
367
|
-
snapshot: root === coordinatorRoot && state.snapshot
|
|
368
|
-
? state.snapshot
|
|
369
|
-
: await repositorySnapshot(root),
|
|
370
|
-
changedPaths: [],
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
await writeTurnState(statePath, {
|
|
374
|
-
...state,
|
|
375
|
-
implementationAuthorized: true,
|
|
376
|
-
repositories,
|
|
377
|
-
});
|
|
378
|
-
await writeHookLocator(input, coordinatorRoot);
|
|
379
|
-
return {
|
|
380
|
-
status: registered && state.implementationAuthorized === true
|
|
381
|
-
? 'unchanged'
|
|
382
|
-
: 'authorized',
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
async function committedPaths(projectRoot, before, after) {
|
|
387
|
-
if (before === after) return [];
|
|
388
|
-
if (!after) return ['repository history changed'];
|
|
389
|
-
try {
|
|
390
|
-
const args = before
|
|
391
|
-
? ['diff', '--no-renames', '--name-only', '-z', before, after]
|
|
392
|
-
: ['diff-tree', '--root', '--no-commit-id', '--no-renames', '--name-only', '-r', '-z', after];
|
|
393
|
-
return zeroPaths((await runGit(projectRoot, args)).stdout).filter(isProjectContentPath);
|
|
394
|
-
} catch {
|
|
395
|
-
return ['repository history changed'];
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
async function changedProjectPaths(projectRoot, before, after) {
|
|
400
|
-
const previous = new Map(before.dirty.map(({ path: file, state }) => [file, state]));
|
|
401
|
-
const current = new Map(after.dirty.map(({ path: file, state }) => [file, state]));
|
|
402
|
-
const dirtyChanges = [...new Set([...previous.keys(), ...current.keys()])].filter((file) => (
|
|
403
|
-
stableJson(previous.get(file)) !== stableJson(current.get(file))
|
|
404
|
-
));
|
|
405
|
-
const candidates = [...new Set([
|
|
406
|
-
...dirtyChanges,
|
|
407
|
-
...await committedPaths(projectRoot, before.head, after.head),
|
|
408
|
-
])].sort();
|
|
409
|
-
const changed = await Promise.all(candidates.map(async (file) => {
|
|
410
|
-
if (!previous.has(file)) return file;
|
|
411
|
-
// Moving pre-turn file bytes into HEAD is a save operation, not new implementation.
|
|
412
|
-
const finalState = current.has(file)
|
|
413
|
-
? current.get(file)
|
|
414
|
-
: await pathState(path.join(projectRoot, file));
|
|
415
|
-
return stableJson(previous.get(file)) === stableJson(finalState) ? null : file;
|
|
416
|
-
}));
|
|
417
|
-
return changed.filter(Boolean);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function changedPathLines(changedPaths) {
|
|
421
|
-
const shown = changedPaths.slice(0, 50);
|
|
422
|
-
const omitted = changedPaths.length - shown.length;
|
|
423
|
-
return [
|
|
424
|
-
...shown.map((file) => `- ${file}`),
|
|
425
|
-
...(omitted > 0 ? [`- ... and ${omitted} more`] : []),
|
|
426
|
-
];
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
function changedRepositoryLines(repositories) {
|
|
430
|
-
return repositories.flatMap(({ projectRoot, changedPaths, driftedPaths = [] }) => [
|
|
431
|
-
`## Repository: \`${projectRoot}\``,
|
|
432
|
-
'',
|
|
433
|
-
...changedPathLines(changedPaths),
|
|
434
|
-
...(driftedPaths.length > 0 ? [
|
|
435
|
-
'',
|
|
436
|
-
'### Concurrent changes excluded from cleanup',
|
|
437
|
-
'',
|
|
438
|
-
'These paths changed after the implementation scope was frozen. Report them, but do not edit them:',
|
|
439
|
-
'',
|
|
440
|
-
...changedPathLines(driftedPaths),
|
|
441
|
-
] : []),
|
|
442
|
-
'',
|
|
443
|
-
]);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
async function changedRepositories(repositories, { snapshotField = 'snapshot' } = {}) {
|
|
447
|
-
return (await Promise.all(repositories.map(async (repository) => {
|
|
448
|
-
const currentPaths = await changedProjectPaths(
|
|
449
|
-
repository.projectRoot,
|
|
450
|
-
repository[snapshotField] || repository.snapshot,
|
|
451
|
-
await repositorySnapshot(repository.projectRoot),
|
|
452
|
-
);
|
|
453
|
-
const changedPaths = normalizedPaths([
|
|
454
|
-
...(repository.changedPaths || []),
|
|
455
|
-
...currentPaths,
|
|
456
|
-
]).sort();
|
|
457
|
-
return changedPaths.length > 0 ? { ...repository, changedPaths } : null;
|
|
458
|
-
}))).filter(Boolean);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
async function freezeChangedRepositories(repositories, { startPostChange = false } = {}) {
|
|
462
|
-
return Promise.all(repositories.map(async (repository) => {
|
|
463
|
-
const changedPaths = normalizedPaths(repository.changedPaths || []).sort();
|
|
464
|
-
const [pathStates, phaseSnapshot] = await Promise.all([
|
|
465
|
-
projectPathStates(repository.projectRoot, changedPaths),
|
|
466
|
-
startPostChange ? repositorySnapshot(repository.projectRoot) : null,
|
|
467
|
-
]);
|
|
468
|
-
const frozen = {
|
|
469
|
-
...repository,
|
|
470
|
-
changedPaths,
|
|
471
|
-
pathStates,
|
|
472
|
-
};
|
|
473
|
-
delete frozen.driftedPaths;
|
|
474
|
-
delete frozen.phaseSnapshot;
|
|
475
|
-
if (phaseSnapshot) frozen.phaseSnapshot = phaseSnapshot;
|
|
476
|
-
return frozen;
|
|
477
|
-
}));
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
async function cleanupScopeRepositories(repositories) {
|
|
481
|
-
return (await Promise.all(repositories.map(async (repository) => {
|
|
482
|
-
const ownedPaths = normalizedPaths(repository.changedPaths || []).sort();
|
|
483
|
-
if (ownedPaths.length === 0) return null;
|
|
484
|
-
const expected = new Map((repository.pathStates || [])
|
|
485
|
-
.map(({ path: file, state }) => [file, state]));
|
|
486
|
-
const changedPaths = [];
|
|
487
|
-
const driftedPaths = [];
|
|
488
|
-
for (const { path: file, state } of await projectPathStates(repository.projectRoot, ownedPaths)) {
|
|
489
|
-
const destination = expected.has(file) && stableJson(expected.get(file)) !== stableJson(state)
|
|
490
|
-
? driftedPaths
|
|
491
|
-
: changedPaths;
|
|
492
|
-
destination.push(file);
|
|
493
|
-
}
|
|
494
|
-
return {
|
|
495
|
-
...repository,
|
|
496
|
-
changedPaths,
|
|
497
|
-
driftedPaths,
|
|
498
|
-
};
|
|
499
|
-
}))).filter(Boolean);
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
async function repositoryContexts(repositories) {
|
|
503
|
-
return Promise.all(repositories.map(async (repository) => {
|
|
504
|
-
const [stack, engineering] = await Promise.all([
|
|
505
|
-
optionalStack(repository.projectRoot),
|
|
506
|
-
optionalEngineering(repository.projectRoot),
|
|
507
|
-
]);
|
|
508
|
-
return { ...repository, stack, engineering };
|
|
509
|
-
}));
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
function repositoryGuidanceLines({ projectRoot, stack, engineering }, {
|
|
513
|
-
deslop = false,
|
|
514
|
-
postChange = false,
|
|
515
|
-
} = {}) {
|
|
516
|
-
return [
|
|
517
|
-
`## Repository: \`${projectRoot}\``,
|
|
518
|
-
'',
|
|
519
|
-
'ENGINEERING APPROACH',
|
|
520
|
-
'',
|
|
521
|
-
engineering.guidance,
|
|
522
|
-
...(stack?.guidance ? ['', 'SELECTED STACK GUIDANCE', '', stack.guidance] : []),
|
|
523
|
-
...(postChange && stack?.postChange
|
|
524
|
-
? ['', 'COMPOSED STACK POST-CHANGE WORK', '', stack.postChange]
|
|
525
|
-
: []),
|
|
526
|
-
...(deslop && stack?.deslop
|
|
527
|
-
? ['', 'SELECTED STACK CLEANUP GUIDANCE', '', stack.deslop]
|
|
528
|
-
: []),
|
|
529
|
-
'',
|
|
530
|
-
];
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
async function reconciliationContinuation(repositories, knownContexts) {
|
|
534
|
-
const [instructions, contexts] = await Promise.all([
|
|
535
|
-
readInstalledAsset('reconcile'),
|
|
536
|
-
knownContexts || repositoryContexts(repositories),
|
|
537
|
-
]);
|
|
538
|
-
return [
|
|
539
|
-
'This is the automatic Genesis explanation turn for the preceding implementation turn.',
|
|
540
|
-
'Use the same conversation context and the Git-visible changes below in every listed repository. Do not perform Deslop yet.',
|
|
541
|
-
'',
|
|
542
|
-
'REPOSITORIES AND CHANGED PROJECT PATHS',
|
|
543
|
-
'',
|
|
544
|
-
...changedRepositoryLines(repositories),
|
|
545
|
-
'',
|
|
546
|
-
instructions.trim(),
|
|
547
|
-
'',
|
|
548
|
-
'REPOSITORY GUIDANCE',
|
|
549
|
-
'',
|
|
550
|
-
...contexts.flatMap((context) => repositoryGuidanceLines(context)),
|
|
551
|
-
].join('\n');
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
function postChangeContinuation(repositories, contexts) {
|
|
555
|
-
return [
|
|
556
|
-
'This is the one automatic Stack Post-change turn for the preceding implementation.',
|
|
557
|
-
'Use the same conversation context and the Git-visible changes below in every listed repository.',
|
|
558
|
-
'Perform only the composed Post-change work. Do not broaden the task, reconcile Genesis explanations, or perform Deslop yet.',
|
|
559
|
-
'Do not repeat or schedule another Post-change turn. If none of the configured work applies, make no changes and respond minimally.',
|
|
560
|
-
'',
|
|
561
|
-
'REPOSITORIES AND CHANGED PROJECT PATHS',
|
|
562
|
-
'',
|
|
563
|
-
...changedRepositoryLines(repositories),
|
|
564
|
-
'',
|
|
565
|
-
'REPOSITORY GUIDANCE AND POST-CHANGE WORK',
|
|
566
|
-
'',
|
|
567
|
-
...contexts.flatMap((context) => repositoryGuidanceLines(context, { postChange: true })),
|
|
568
|
-
].join('\n');
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
async function deslopContinuation(repositories) {
|
|
572
|
-
const [instructions, contexts] = await Promise.all([
|
|
573
|
-
readInstalledAsset('deslop'),
|
|
574
|
-
repositoryContexts(repositories),
|
|
575
|
-
]);
|
|
576
|
-
return [
|
|
577
|
-
'This is the final automatic Genesis Deslop turn for the preceding implementation.',
|
|
578
|
-
'Review every listed repository and only that work and the paths listed below. Do not broaden the task.',
|
|
579
|
-
'',
|
|
580
|
-
'REPOSITORIES AND CHANGED PROJECT PATHS',
|
|
581
|
-
'',
|
|
582
|
-
...changedRepositoryLines(repositories),
|
|
583
|
-
'',
|
|
584
|
-
instructions.trim(),
|
|
585
|
-
'',
|
|
586
|
-
'REPOSITORY GUIDANCE',
|
|
587
|
-
'',
|
|
588
|
-
...contexts.flatMap((context) => repositoryGuidanceLines(context, { deslop: true })),
|
|
589
|
-
'',
|
|
590
|
-
'PROGRAM CITATION MAINTENANCE',
|
|
591
|
-
'',
|
|
592
|
-
'If this cleanup renames or moves a source or helper cited by an affected Program module,',
|
|
593
|
-
'update only that module\'s Sources or informational Implementation map. This narrow',
|
|
594
|
-
'exception overrides the default prohibition on editing `genesis/`; never change the',
|
|
595
|
-
'Blueprint or a Program public contract to excuse cleanup behavior.',
|
|
596
|
-
].join('\n');
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
async function refreshProjectIndexes(repositories) {
|
|
600
|
-
await Promise.all(repositories.map(({ projectRoot }) => refreshProjectIndex(projectRoot)));
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
export async function completeCodexTurn({ input, projectRoot } = {}) {
|
|
604
|
-
const root = (await gitContext(projectRoot || input?.cwd)).repositoryRoot;
|
|
605
|
-
const statePath = await hookStatePath(root, input);
|
|
606
|
-
const state = await readTurnState(statePath);
|
|
607
|
-
if (!state || state.schemaVersion !== HOOK_STATE_SCHEMA_VERSION) return {};
|
|
608
|
-
|
|
609
|
-
if (state.implementationAuthorized !== true) {
|
|
610
|
-
const repositories = await changedRepositories(registeredRepositories(state, root));
|
|
611
|
-
if (repositories.length === 0) {
|
|
612
|
-
await removeTurnState(statePath, input);
|
|
613
|
-
return {};
|
|
614
|
-
}
|
|
615
|
-
await writeTurnState(statePath, {
|
|
616
|
-
...state,
|
|
617
|
-
phase: 'implementation',
|
|
618
|
-
repositories,
|
|
619
|
-
});
|
|
620
|
-
return {};
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
if (state.phase === 'implementation') {
|
|
624
|
-
if (input?.stop_hook_active === true || state.turnId !== hookId(input, 'turn_id')) {
|
|
625
|
-
await removeTurnState(statePath, input);
|
|
626
|
-
return {};
|
|
627
|
-
}
|
|
628
|
-
const changed = await changedRepositories(registeredRepositories(state, root));
|
|
629
|
-
if (changed.length === 0) {
|
|
630
|
-
await removeTurnState(statePath, input);
|
|
631
|
-
return {};
|
|
632
|
-
}
|
|
633
|
-
const contexts = await repositoryContexts(changed);
|
|
634
|
-
const postChange = contexts.some(({ stack }) => Boolean(stack?.postChange?.trim()));
|
|
635
|
-
const repositories = await freezeChangedRepositories(changed, { startPostChange: postChange });
|
|
636
|
-
await writeTurnState(statePath, {
|
|
637
|
-
...state,
|
|
638
|
-
phase: postChange ? 'post-change' : 'reconcile',
|
|
639
|
-
repositories,
|
|
640
|
-
});
|
|
641
|
-
return {
|
|
642
|
-
decision: 'block',
|
|
643
|
-
reason: postChange
|
|
644
|
-
? postChangeContinuation(repositories, contexts)
|
|
645
|
-
: await reconciliationContinuation(repositories, contexts),
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (input?.stop_hook_active !== true) {
|
|
650
|
-
await removeTurnState(statePath, input);
|
|
651
|
-
return {};
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
if (state.phase === 'post-change') {
|
|
655
|
-
const changed = await changedRepositories(registeredRepositories(state, root), {
|
|
656
|
-
snapshotField: 'phaseSnapshot',
|
|
657
|
-
});
|
|
658
|
-
if (changed.length === 0) {
|
|
659
|
-
await removeTurnState(statePath, input);
|
|
660
|
-
return {};
|
|
661
|
-
}
|
|
662
|
-
const repositories = await freezeChangedRepositories(changed);
|
|
663
|
-
await writeTurnState(statePath, {
|
|
664
|
-
...state,
|
|
665
|
-
phase: 'reconcile',
|
|
666
|
-
repositories,
|
|
667
|
-
});
|
|
668
|
-
return {
|
|
669
|
-
decision: 'block',
|
|
670
|
-
reason: await reconciliationContinuation(repositories),
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
if (state.phase === 'reconcile') {
|
|
675
|
-
const registered = registeredRepositories(state, root);
|
|
676
|
-
const repositories = await cleanupScopeRepositories(registered);
|
|
677
|
-
if (repositories.length === 0) {
|
|
678
|
-
await refreshProjectIndexes(registered);
|
|
679
|
-
await removeTurnState(statePath, input);
|
|
680
|
-
return {};
|
|
681
|
-
}
|
|
682
|
-
await refreshProjectIndexes(repositories);
|
|
683
|
-
await writeTurnState(statePath, {
|
|
684
|
-
...state,
|
|
685
|
-
phase: 'deslop',
|
|
686
|
-
repositories,
|
|
687
|
-
});
|
|
688
|
-
return {
|
|
689
|
-
decision: 'block',
|
|
690
|
-
reason: await deslopContinuation(repositories),
|
|
691
|
-
};
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
if (state.phase === 'deslop') {
|
|
695
|
-
await refreshProjectIndexes(registeredRepositories(state, root));
|
|
696
|
-
await removeTurnState(statePath, input);
|
|
697
|
-
return {};
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
await removeTurnState(statePath, input);
|
|
701
|
-
return {};
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
export async function discardCodexTurn({ input, projectRoot } = {}) {
|
|
705
|
-
const root = (await gitContext(projectRoot || input?.cwd)).repositoryRoot;
|
|
706
|
-
await removeTurnState(await hookStatePath(root, input), input);
|
|
707
|
-
return { status: 'discarded' };
|
|
708
|
-
}
|
package/src/index/init.js
CHANGED
|
@@ -54,12 +54,12 @@ export async function initializeProject({ projectRoot, stackPackages = [] } = {}
|
|
|
54
54
|
return {
|
|
55
55
|
status: changedFiles.length > 0 ? 'updated' : 'unchanged',
|
|
56
56
|
summary: changedFiles.length > 0
|
|
57
|
-
? 'Initialized Genesis, Agent Skills, and project Codex
|
|
58
|
-
: 'Genesis, its Agent Skills, and project Codex
|
|
57
|
+
? 'Initialized Genesis, Agent Skills, and the project Codex guidance hook.'
|
|
58
|
+
: 'Genesis, its Agent Skills, and the project Codex guidance hook are already initialized.',
|
|
59
59
|
changedFiles,
|
|
60
60
|
diagnostics: skills.diagnostics,
|
|
61
61
|
guidance: [
|
|
62
|
-
'Open Codex and use /hooks to review and trust the project
|
|
62
|
+
'Open Codex and use /hooks to review and trust the project guidance hook.',
|
|
63
63
|
'Genesis workflow skills are available in .agents/skills/.',
|
|
64
64
|
'Describe product intent in genesis/blueprint.md.',
|
|
65
65
|
'Choose the project engineering approach with genesis engineering set <profile>.',
|
package/src/index/prompt.js
CHANGED
|
@@ -25,7 +25,7 @@ const DEFAULT_REQUEST = {
|
|
|
25
25
|
start: 'Start a conversation about this project.',
|
|
26
26
|
adopt: 'Import the existing project into a truthful Genesis project contract.',
|
|
27
27
|
work: 'Implement the product intent expressed by the current Blueprint.',
|
|
28
|
-
deslop: '
|
|
28
|
+
deslop: 'Deslop the latest commit.',
|
|
29
29
|
program: 'Refresh the complete useful Program for the code that exists now.',
|
|
30
30
|
describe: 'Create or refresh the complete Blueprint and useful Program for the codebase that exists now.',
|
|
31
31
|
review: 'Review the complete useful relationship between Blueprint, code, Program, and tests.',
|
|
@@ -107,6 +107,7 @@ function renderPrompt({
|
|
|
107
107
|
skills = '',
|
|
108
108
|
guidance = '',
|
|
109
109
|
cleanup = '',
|
|
110
|
+
postChange = '',
|
|
110
111
|
adoption = '',
|
|
111
112
|
engineeringGuidance = '',
|
|
112
113
|
}) {
|
|
@@ -126,6 +127,7 @@ function renderPrompt({
|
|
|
126
127
|
...(guidance ? ['', 'SELECTED STACK GUIDANCE', '', guidance] : []),
|
|
127
128
|
...(adoption ? ['', 'SELECTED STACK ADOPTION GUIDANCE', '', adoption] : []),
|
|
128
129
|
...(skills ? ['', 'AVAILABLE AGENT SKILLS', '', skills] : []),
|
|
130
|
+
...(postChange ? ['', 'SELECTED STACK POST-CHANGE GUIDANCE', '', postChange] : []),
|
|
129
131
|
...(cleanup ? ['', 'SELECTED STACK CLEANUP GUIDANCE', '', cleanup] : []),
|
|
130
132
|
'',
|
|
131
133
|
].join('\n');
|
|
@@ -451,6 +453,7 @@ export async function generateProjectPrompt({
|
|
|
451
453
|
engineeringGuidance: engineering.guidance,
|
|
452
454
|
guidance: stack.guidance,
|
|
453
455
|
skills: renderAgentSkillCatalog(projectSkills.skills),
|
|
456
|
+
postChange: task === 'work' ? stack.postChange : '',
|
|
454
457
|
cleanup: task === 'deslop' ? stack.deslop : '',
|
|
455
458
|
});
|
|
456
459
|
return {
|
package/prompts/reconcile.txt
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
For every repository listed in the task, read and follow that repository's
|
|
2
|
-
`.agents/skills/genesis-program/SKILL.md` completely, operating in focused
|
|
3
|
-
post-change reconciliation mode.
|
|
4
|
-
|
|
5
|
-
Use the preceding implementation turn, listed changed paths, actual Git diff or
|
|
6
|
-
history, and relevant tests. Update Blueprint only for intentional observable
|
|
7
|
-
product behavior. Update only affected Program modules. Private restructuring
|
|
8
|
-
may require only Sources or an informational Implementation map, and may require
|
|
9
|
-
no explanatory edit at all.
|
|
10
|
-
|
|
11
|
-
Do not simplify or edit implementation, tests, configuration, dependencies,
|
|
12
|
-
Stack, or `.genesis/` during this turn. Do not run Deslop yet. Summarize every
|
|
13
|
-
explanatory change and genuine ambiguity.
|