genesis-compiler 1.5.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -1
- package/docs/parsers.md +46 -0
- package/package.json +6 -13
- package/prompts/adopt.txt +15 -0
- package/prompts/describe.txt +16 -1
- package/prompts/program.txt +16 -1
- package/prompts/review.txt +2 -0
- package/prompts/work.txt +15 -0
- package/skills/genesis-program/SKILL.md +57 -1
- package/skills/genesis-project/SKILL.md +17 -0
- package/src/cli.js +51 -14
- package/src/index/code-index.js +10 -35
- package/src/index/code-indexers/ast-grep.js +40 -28
- package/src/index/code-indexers/parsers.js +231 -0
- package/src/index/code-indexers/worker.js +20 -0
- package/src/index/context.js +6 -0
- package/src/index/contracts.js +1 -0
- package/src/index/init.js +2 -0
- package/src/index/process.js +7 -1
- package/src/index/program.js +15 -9
- package/src/index/project-inspection.js +1 -0
- package/src/index/prompt.js +2 -0
- package/src/index/session-context.js +2 -0
- package/src/index/subsystems.js +109 -0
- package/src/index.js +3 -0
package/README.md
CHANGED
|
@@ -28,7 +28,8 @@ genesis/
|
|
|
28
28
|
engineering.md selected engineering profile and project-specific requirements
|
|
29
29
|
stack.md selected components, resources, verification, and project-owned operation contracts
|
|
30
30
|
stack/ optional per-component Description, Guidance, Adoption, Post-change, and Deslop customization
|
|
31
|
-
|
|
31
|
+
subsystems.md authored responsibilities, Program membership, and data ownership/use
|
|
32
|
+
program/ concise public-operation explanations
|
|
32
33
|
.agents/skills/
|
|
33
34
|
genesis-* Genesis workflow skills
|
|
34
35
|
<technology>/ authoritative skills installed by selected Stack pieces
|
|
@@ -897,6 +898,10 @@ import {
|
|
|
897
898
|
installCodex,
|
|
898
899
|
listEngineeringProfiles,
|
|
899
900
|
listStackPieces,
|
|
901
|
+
listParsers,
|
|
902
|
+
installParsers,
|
|
903
|
+
verifyParsers,
|
|
904
|
+
parserEnvironment,
|
|
900
905
|
migrate,
|
|
901
906
|
projectSessionContext,
|
|
902
907
|
projectTurnContext,
|
|
@@ -910,6 +915,9 @@ import {
|
|
|
910
915
|
|
|
911
916
|
`initialize()` installs the project files, Genesis workflow skills, selected
|
|
912
917
|
Stack skills, and local Codex hooks.
|
|
918
|
+
Extra language parsers install on first use, outside the project's dependencies.
|
|
919
|
+
The CLI can also prepare and verify parsers for an offline host; see
|
|
920
|
+
[language parser management](docs/parsers.md).
|
|
913
921
|
`migrate()` updates recognized older Genesis project-file formats and returns
|
|
914
922
|
the resulting structural check for hosts such as Vibe64.
|
|
915
923
|
`adoptProject()` also returns the initial `adopt` prompt for an existing
|
|
@@ -977,3 +985,60 @@ project operations, and records exact verification evidence. Code, tests, Git
|
|
|
977
985
|
review, and the user's chosen agent remain responsible for implementation. It
|
|
978
986
|
does not claim universal semantic convergence, exhaustive coverage, or
|
|
979
987
|
whole-product correctness.
|
|
988
|
+
|
|
989
|
+
## Authored subsystems (version zero)
|
|
990
|
+
|
|
991
|
+
`genesis/subsystems.md` is the single authored map connecting architectural
|
|
992
|
+
responsibilities to Program operations and data. Program directories are only
|
|
993
|
+
navigation; Genesis never infers subsystem membership from them. Blueprint
|
|
994
|
+
remains non-technical product intent. Source, migrations and runtime behavior
|
|
995
|
+
remain evidence; the map does not define application behavior or database DDL.
|
|
996
|
+
|
|
997
|
+
```markdown
|
|
998
|
+
# Subsystems
|
|
999
|
+
|
|
1000
|
+
## `forms` Forms
|
|
1001
|
+
|
|
1002
|
+
Owns reusable form authoring, rendering, and answer validation.
|
|
1003
|
+
|
|
1004
|
+
### Program
|
|
1005
|
+
- `genesis/program/forms/render.md`
|
|
1006
|
+
|
|
1007
|
+
### Data owned
|
|
1008
|
+
- Table `database` `default` `form_definitions`
|
|
1009
|
+
|
|
1010
|
+
### Data used
|
|
1011
|
+
- Nothing.
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
Each subsystem has a unique lowercase hyphenated id, title, responsibility
|
|
1015
|
+
prose, and exactly the three shown sections. Each Program module is assigned
|
|
1016
|
+
exactly once, by its complete project-relative path. Each table has at most one
|
|
1017
|
+
owner. Data used names a table owned by another declared subsystem. Empty
|
|
1018
|
+
sections explicitly say `- Nothing.`; an empty initialized map contains
|
|
1019
|
+
`# Subsystems` followed by `- Nothing.`. Data-only and code-only subsystems are
|
|
1020
|
+
valid. No subsystem hierarchy is inferred from paths.
|
|
1021
|
+
|
|
1022
|
+
Table references contain three distinct values: declared Stack resource **id**,
|
|
1023
|
+
schema, and table. `default` selects that resource's default schema; other schema
|
|
1024
|
+
names are literal. Never put host database names or environment values here.
|
|
1025
|
+
Genesis validates declarations and resource references without opening a database.
|
|
1026
|
+
Hosts resolve table references against their inspected schema and show missing
|
|
1027
|
+
references and unassigned tables explicitly; the map is not a complete schema
|
|
1028
|
+
inventory. Table/column descriptions and relationships remain database metadata.
|
|
1029
|
+
|
|
1030
|
+
`inspectSubsystems({ projectRoot })` and `genesis inspect subsystems --json`
|
|
1031
|
+
return `genesis.subsystems.v0`, normalized entries, status and a deterministic
|
|
1032
|
+
identity. Program inspection additionally validates membership and referenced
|
|
1033
|
+
modules. Context includes the relevant subsystem through its Program Sources;
|
|
1034
|
+
`context .` includes all subsystems. Program City uses authored titles and table
|
|
1035
|
+
associations, including data-only districts, and changes its hash when the map
|
|
1036
|
+
changes. Opening context stays concise; detailed associations load on demand.
|
|
1037
|
+
|
|
1038
|
+
Adoption, Program refresh, work prompts, session guidance and installed workflow
|
|
1039
|
+
skills maintain the map alongside Program in the same turn. Review checks it
|
|
1040
|
+
read-only; Blueprint-only work leaves it alone. Ordinary private helper edits
|
|
1041
|
+
need no map change. Existing projects do not need a bulk update: missing or empty maps preserve
|
|
1042
|
+
Program access and instruct the agent to author the map from source before its
|
|
1043
|
+
next implementation task. Until then, operations have no declared subsystem;
|
|
1044
|
+
there is no folder-based compatibility reader or automatic ownership inference. Initialization creates an empty map without replacing one.
|
package/docs/parsers.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Language parsers
|
|
2
|
+
|
|
3
|
+
Genesis installs extra language parsers automatically the first time it indexes
|
|
4
|
+
matching source. JavaScript, TypeScript and TSX use its built-in core parser.
|
|
5
|
+
No project dependency or lockfile is changed.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
genesis parsers list
|
|
9
|
+
genesis parsers install python cpp
|
|
10
|
+
genesis parsers install --all
|
|
11
|
+
genesis parsers verify --all
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
These commands work outside a Git repository and support `--json`. Downloads
|
|
15
|
+
and verification progress go to stderr. The language names come from `parsers
|
|
16
|
+
list`; C and C++ are separate parsers (`c` and `cpp`), and shell uses `bash`.
|
|
17
|
+
|
|
18
|
+
Use `--directory /absolute/path` or `GENESIS_PARSER_ROOT` to choose a cache.
|
|
19
|
+
Otherwise Genesis uses `$XDG_CACHE_HOME/genesis/parsers`, falling back to
|
|
20
|
+
`~/.cache/genesis/parsers`. Installations are pinned by language, package version,
|
|
21
|
+
OS and CPU. npm must be available for installation. Genesis uses the public npm
|
|
22
|
+
registry, disables package lifecycle scripts, verifies each native parser, and
|
|
23
|
+
retains only its current-platform binary and loader. Prebuilt native support is
|
|
24
|
+
required; Genesis does not compile a missing parser on the user's machine.
|
|
25
|
+
|
|
26
|
+
For a prepared host or release artifact:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
genesis parsers install --all --directory /absolute/release/parsers
|
|
30
|
+
genesis parsers verify --all --directory /absolute/release/parsers
|
|
31
|
+
export GENESIS_PARSER_ROOT=/absolute/release/parsers
|
|
32
|
+
export GENESIS_PARSER_AUTO_INSTALL=0
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The cache can be relocated on the same OS/CPU. Verify it again at its destination
|
|
36
|
+
before activation. Missing or broken parsers fail verification; indexing reports
|
|
37
|
+
an actionable diagnostic. A damaged installed version is preserved for inspection:
|
|
38
|
+
remove only that reported version directory deliberately, then rerun install.
|
|
39
|
+
Successful installations are reusable offline and require no runtime writes.
|
|
40
|
+
|
|
41
|
+
The library exports `listParsers`, `installParsers`, `verifyParsers`, and
|
|
42
|
+
`parserEnvironment`. The first three accept `directory`; install/verify accept
|
|
43
|
+
`languages` or `all` and an abort `signal`. Install accepts `onProgress`.
|
|
44
|
+
`parserEnvironment({ directory, autoInstall, environment })` returns the two
|
|
45
|
+
normalized environment values for a host and its commands. Preparing or verifying
|
|
46
|
+
all parsers uses short-lived children; native indexing runs in a finite child and releases parser memory on exit.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genesis-compiler",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An agent-independent prompt, multi-language code-index, cleanup, and verification companion with project agent guidance.",
|
|
6
6
|
"repository": {
|
|
@@ -43,25 +43,18 @@
|
|
|
43
43
|
"plugins/opencode",
|
|
44
44
|
"profiles",
|
|
45
45
|
"skills",
|
|
46
|
-
"src"
|
|
46
|
+
"src",
|
|
47
|
+
"docs/parsers.md"
|
|
47
48
|
],
|
|
48
49
|
"scripts": {
|
|
49
50
|
"test": "node --test test/*.test.js"
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {
|
|
52
|
-
"@ast-grep/lang-bash": "^0.0.8",
|
|
53
|
-
"@ast-grep/lang-c": "^0.0.6",
|
|
54
|
-
"@ast-grep/lang-cpp": "^0.0.6",
|
|
55
|
-
"@ast-grep/lang-csharp": "^0.0.6",
|
|
56
|
-
"@ast-grep/lang-go": "^0.0.6",
|
|
57
|
-
"@ast-grep/lang-java": "^0.0.7",
|
|
58
|
-
"@ast-grep/lang-kotlin": "^0.0.7",
|
|
59
|
-
"@ast-grep/lang-php": "^0.0.7",
|
|
60
|
-
"@ast-grep/lang-python": "^0.0.6",
|
|
61
|
-
"@ast-grep/lang-ruby": "^0.0.7",
|
|
62
|
-
"@ast-grep/lang-rust": "^0.0.7",
|
|
63
53
|
"@ast-grep/napi": "^0.45.1",
|
|
64
54
|
"mdast-util-from-markdown": "^2.0.3",
|
|
65
55
|
"yaml": "^2.9.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@ast-grep/lang-python": "0.0.6"
|
|
66
59
|
}
|
|
67
60
|
}
|
package/prompts/adopt.txt
CHANGED
|
@@ -60,3 +60,18 @@ execute them. Finish with a clear inventory of what was imported, what remains
|
|
|
60
60
|
unconfigured or blocked, and what would require a separately approved
|
|
61
61
|
implementation port. Never claim the project is ready merely because Stack
|
|
62
62
|
components were selected.
|
|
63
|
+
|
|
64
|
+
Maintain `genesis/subsystems.md` in the same implementation turn when a change
|
|
65
|
+
adds, removes, or changes a subsystem responsibility, Program membership, or
|
|
66
|
+
data ownership/use. Read the map before changing related code. Reuse existing
|
|
67
|
+
subsystems unless a distinct responsibility is evidenced. Declare each Program
|
|
68
|
+
module exactly once; folders do not determine membership. Keep table references
|
|
69
|
+
grounded in schema/migrations; Genesis does not inspect databases. Private
|
|
70
|
+
helper changes need no map edit when these associations remain unchanged.
|
|
71
|
+
|
|
72
|
+
If `genesis/subsystems.md` is missing, or is empty in an existing explained
|
|
73
|
+
application, create it from the actual source, schema, and existing Program
|
|
74
|
+
before implementation. This is ordinary explanatory adoption, not a blocker or
|
|
75
|
+
a reason to ask permission again. Preserve the existing Program and source;
|
|
76
|
+
inspect the relevant responsibilities and complete the smallest truthful map.
|
|
77
|
+
Initialization can create the empty file, but only the agent authors its meaning.
|
package/prompts/describe.txt
CHANGED
|
@@ -12,6 +12,21 @@ If the codebase is too large for one careful pass, use subagents as you judge
|
|
|
12
12
|
appropriate, reconcile their findings, and remain responsible for one coherent
|
|
13
13
|
result. Identify anything not inspected or genuinely uncertain.
|
|
14
14
|
|
|
15
|
-
Edit only `genesis/blueprint.md` and explanatory Markdown below
|
|
15
|
+
Edit only `genesis/blueprint.md`, `genesis/subsystems.md`, and explanatory Markdown below
|
|
16
16
|
`genesis/program/`. Summarize every explanatory file created, updated, or
|
|
17
17
|
removed.
|
|
18
|
+
|
|
19
|
+
Maintain `genesis/subsystems.md` in the same implementation turn when a change
|
|
20
|
+
adds, removes, or changes a subsystem responsibility, Program membership, or
|
|
21
|
+
data ownership/use. Read the map before changing related code. Reuse existing
|
|
22
|
+
subsystems unless a distinct responsibility is evidenced. Declare each Program
|
|
23
|
+
module exactly once; folders do not determine membership. Keep table references
|
|
24
|
+
grounded in schema/migrations; Genesis does not inspect databases. Private
|
|
25
|
+
helper changes need no map edit when these associations remain unchanged.
|
|
26
|
+
|
|
27
|
+
If `genesis/subsystems.md` is missing, or is empty in an existing explained
|
|
28
|
+
application, create it from the actual source, schema, and existing Program
|
|
29
|
+
before implementation. This is ordinary explanatory adoption, not a blocker or
|
|
30
|
+
a reason to ask permission again. Preserve the existing Program and source;
|
|
31
|
+
inspect the relevant responsibilities and complete the smallest truthful map.
|
|
32
|
+
Initialization can create the empty file, but only the agent authors its meaning.
|
package/prompts/program.txt
CHANGED
|
@@ -4,9 +4,24 @@ in complete Program-refresh mode.
|
|
|
4
4
|
Explain the code that currently exists using the smallest useful
|
|
5
5
|
subsystem-oriented Program. Read implementation, tests, Blueprint, and current
|
|
6
6
|
Program material. Use Machine City as a navigation aid, then verify relevant
|
|
7
|
-
source directly. Edit only explanatory Markdown below `genesis/program/`.
|
|
7
|
+
source directly. Edit only `genesis/subsystems.md` and explanatory Markdown below `genesis/program/`.
|
|
8
8
|
Delete stale or duplicate modules and do not edit code, tests, configuration,
|
|
9
9
|
Blueprint, Stack, or `.genesis/`.
|
|
10
10
|
|
|
11
11
|
When finished, summarize Program files created, updated, or removed and report
|
|
12
12
|
genuine ambiguity.
|
|
13
|
+
|
|
14
|
+
Maintain `genesis/subsystems.md` in the same implementation turn when a change
|
|
15
|
+
adds, removes, or changes a subsystem responsibility, Program membership, or
|
|
16
|
+
data ownership/use. Read the map before changing related code. Reuse existing
|
|
17
|
+
subsystems unless a distinct responsibility is evidenced. Declare each Program
|
|
18
|
+
module exactly once; folders do not determine membership. Keep table references
|
|
19
|
+
grounded in schema/migrations; Genesis does not inspect databases. Private
|
|
20
|
+
helper changes need no map edit when these associations remain unchanged.
|
|
21
|
+
|
|
22
|
+
If `genesis/subsystems.md` is missing, or is empty in an existing explained
|
|
23
|
+
application, create it from the actual source, schema, and existing Program
|
|
24
|
+
before implementation. This is ordinary explanatory adoption, not a blocker or
|
|
25
|
+
a reason to ask permission again. Preserve the existing Program and source;
|
|
26
|
+
inspect the relevant responsibilities and complete the smallest truthful map.
|
|
27
|
+
Initialization can create the empty file, but only the agent authors its meaning.
|
package/prompts/review.txt
CHANGED
|
@@ -10,3 +10,5 @@ evidence from inference and state questions that require human intent.
|
|
|
10
10
|
|
|
11
11
|
Do not edit any file. Return a concise report ordered by impact with exact file
|
|
12
12
|
references, the evidence inspected, and the smallest sensible correction.
|
|
13
|
+
|
|
14
|
+
Review `genesis/subsystems.md` responsibilities, Program membership, and data ownership/use against source and schema. Report missing, stale, or conflicting associations without editing them.
|
package/prompts/work.txt
CHANGED
|
@@ -38,3 +38,18 @@ explicit decision, and add the selection with the Genesis
|
|
|
38
38
|
`stack add <piece...>` operation before relying on technology-specific
|
|
39
39
|
operations. Do not end after only updating
|
|
40
40
|
or summarizing the Blueprint while the Stack remains empty.
|
|
41
|
+
|
|
42
|
+
Maintain `genesis/subsystems.md` in the same implementation turn when a change
|
|
43
|
+
adds, removes, or changes a subsystem responsibility, Program membership, or
|
|
44
|
+
data ownership/use. Read the map before changing related code. Reuse existing
|
|
45
|
+
subsystems unless a distinct responsibility is evidenced. Declare each Program
|
|
46
|
+
module exactly once; folders do not determine membership. Keep table references
|
|
47
|
+
grounded in schema/migrations; Genesis does not inspect databases. Private
|
|
48
|
+
helper changes need no map edit when these associations remain unchanged.
|
|
49
|
+
|
|
50
|
+
If `genesis/subsystems.md` is missing, or is empty in an existing explained
|
|
51
|
+
application, create it from the actual source, schema, and existing Program
|
|
52
|
+
before implementation. This is ordinary explanatory adoption, not a blocker or
|
|
53
|
+
a reason to ask permission again. Preserve the existing Program and source;
|
|
54
|
+
inspect the relevant responsibilities and complete the smallest truthful map.
|
|
55
|
+
Initialization can create the empty file, but only the agent authors its meaning.
|
|
@@ -21,7 +21,8 @@ private design choice, or ambiguity into product intent.
|
|
|
21
21
|
|
|
22
22
|
## Program
|
|
23
23
|
|
|
24
|
-
Organize Program
|
|
24
|
+
Organize Program in readable directories; membership is declared only in
|
|
25
|
+
`genesis/subsystems.md`, independently of directory names:
|
|
25
26
|
|
|
26
27
|
```text
|
|
27
28
|
genesis/program/billing/invoices.md
|
|
@@ -64,3 +65,58 @@ The caller determines whether this is initial description, complete Program
|
|
|
64
65
|
refresh, focused post-change reconciliation, Blueprint-only work, or read-only
|
|
65
66
|
review. Respect the caller's edit boundary. Report ambiguity rather than
|
|
66
67
|
inventing intent.
|
|
68
|
+
|
|
69
|
+
## Subsystems
|
|
70
|
+
|
|
71
|
+
Maintain `genesis/subsystems.md` alongside Program in description and refresh
|
|
72
|
+
work. Blueprint-only work does not change the map; review remains read-only.
|
|
73
|
+
The map is the authored association authority, but responsibilities and table
|
|
74
|
+
references remain fallible explanations of application source and schema.
|
|
75
|
+
|
|
76
|
+
Use this exact version-zero grammar:
|
|
77
|
+
|
|
78
|
+
```markdown
|
|
79
|
+
# Subsystems
|
|
80
|
+
|
|
81
|
+
## `forms` Forms
|
|
82
|
+
|
|
83
|
+
Owns reusable form rendering, validation, and submission capture.
|
|
84
|
+
|
|
85
|
+
### Program
|
|
86
|
+
- `genesis/program/forms/render.md`
|
|
87
|
+
|
|
88
|
+
### Data owned
|
|
89
|
+
- Table `database` `default` `form_definitions`
|
|
90
|
+
|
|
91
|
+
### Data used
|
|
92
|
+
- Nothing.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Use one stable lowercase hyphenated id and a human title per subsystem. Each
|
|
96
|
+
entry needs responsibility prose and exactly the three sections shown. Empty
|
|
97
|
+
sections say `- Nothing.`; a new empty map contains only `# Subsystems` and
|
|
98
|
+
`- Nothing.`. Every Program module belongs to exactly one subsystem. No folder
|
|
99
|
+
inference, globs, duplicated operations, or duplicated table owners.
|
|
100
|
+
|
|
101
|
+
A table identity is three separate exact backticked values: the declared Stack
|
|
102
|
+
resource id, schema, and table. `default` means the resource's default schema;
|
|
103
|
+
use an explicit schema where applicable. Never record a host database name,
|
|
104
|
+
credential, SQL expression, or environment value. Data used references a table
|
|
105
|
+
owned by another declared subsystem. A subsystem may own data without Program
|
|
106
|
+
operations, or operations without data. Read the real schema/migrations before
|
|
107
|
+
assigning ownership; report uncertainty instead of inventing associations.
|
|
108
|
+
|
|
109
|
+
Maintain `genesis/subsystems.md` in the same implementation turn when a change
|
|
110
|
+
adds, removes, or changes a subsystem responsibility, Program membership, or
|
|
111
|
+
data ownership/use. Read the map before changing related code. Reuse existing
|
|
112
|
+
subsystems unless a distinct responsibility is evidenced. Declare each Program
|
|
113
|
+
module exactly once; folders do not determine membership. Keep table references
|
|
114
|
+
grounded in schema/migrations; Genesis does not inspect databases. Private
|
|
115
|
+
helper changes need no map edit when these associations remain unchanged.
|
|
116
|
+
|
|
117
|
+
If `genesis/subsystems.md` is missing, or is empty in an existing explained
|
|
118
|
+
application, create it from the actual source, schema, and existing Program
|
|
119
|
+
before implementation. This is ordinary explanatory adoption, not a blocker or
|
|
120
|
+
a reason to ask permission again. Preserve the existing Program and source;
|
|
121
|
+
inspect the relevant responsibilities and complete the smallest truthful map.
|
|
122
|
+
Initialization can create the empty file, but only the agent authors its meaning.
|
|
@@ -152,3 +152,20 @@ required inputs and resources, declared project operations, and focused evidence
|
|
|
152
152
|
with what actually exists. Report files changed, checks actually run,
|
|
153
153
|
anything not proven, and anything still requiring attention. Never claim that
|
|
154
154
|
an unrun check passed or that passing checks prove the whole product.
|
|
155
|
+
|
|
156
|
+
## Subsystem maintenance
|
|
157
|
+
|
|
158
|
+
Maintain `genesis/subsystems.md` in the same implementation turn when a change
|
|
159
|
+
adds, removes, or changes a subsystem responsibility, Program membership, or
|
|
160
|
+
data ownership/use. Read the map before changing related code. Reuse existing
|
|
161
|
+
subsystems unless a distinct responsibility is evidenced. Declare each Program
|
|
162
|
+
module exactly once; folders do not determine membership. Keep table references
|
|
163
|
+
grounded in schema/migrations; Genesis does not inspect databases. Private
|
|
164
|
+
helper changes need no map edit when these associations remain unchanged.
|
|
165
|
+
|
|
166
|
+
If `genesis/subsystems.md` is missing, or is empty in an existing explained
|
|
167
|
+
application, create it from the actual source, schema, and existing Program
|
|
168
|
+
before implementation. This is ordinary explanatory adoption, not a blocker or
|
|
169
|
+
a reason to ask permission again. Preserve the existing Program and source;
|
|
170
|
+
inspect the relevant responsibilities and complete the smallest truthful map.
|
|
171
|
+
Initialization can create the empty file, but only the agent authors its meaning.
|
package/src/cli.js
CHANGED
|
@@ -14,12 +14,16 @@ import {
|
|
|
14
14
|
inspectEngineering,
|
|
15
15
|
inspectEnvironment,
|
|
16
16
|
inspectStackSection,
|
|
17
|
+
inspectSubsystems,
|
|
17
18
|
inspectProject,
|
|
18
19
|
inspectSkills,
|
|
19
20
|
installCodex,
|
|
20
21
|
listEngineeringProfiles,
|
|
21
22
|
listStackPieces,
|
|
22
23
|
listTemplates,
|
|
24
|
+
listParsers,
|
|
25
|
+
installParsers,
|
|
26
|
+
verifyParsers,
|
|
23
27
|
migrate,
|
|
24
28
|
setCollaboration,
|
|
25
29
|
setEngineeringProfile,
|
|
@@ -44,6 +48,7 @@ import {
|
|
|
44
48
|
import { projectSessionContext, projectTurnContext } from './index/session-context.js';
|
|
45
49
|
import { installedFirstPartyStackPackages } from './index/stack-catalog.js';
|
|
46
50
|
import { readStack } from './index/stack.js';
|
|
51
|
+
import { withParserCancellation } from './index/code-indexers/parsers.js';
|
|
47
52
|
|
|
48
53
|
const USAGE = `Usage:
|
|
49
54
|
genesis init
|
|
@@ -61,7 +66,11 @@ const USAGE = `Usage:
|
|
|
61
66
|
genesis templates apply <catalogue:technology/variant>
|
|
62
67
|
genesis context <path...>
|
|
63
68
|
genesis index [function-or-path...]
|
|
69
|
+
genesis parsers list
|
|
70
|
+
genesis parsers install <language...> | --all
|
|
71
|
+
genesis parsers verify <language...> | --all
|
|
64
72
|
genesis migrate
|
|
73
|
+
genesis inspect subsystems
|
|
65
74
|
genesis inspect environment
|
|
66
75
|
genesis inspect project
|
|
67
76
|
genesis inspect skills
|
|
@@ -76,6 +85,8 @@ Options:
|
|
|
76
85
|
--stack-package <name> Add an installed external Stack package (repeatable)
|
|
77
86
|
--template-source <namespace=repository[#branch]> Add a template catalogue (repeatable)
|
|
78
87
|
--task <task> Select the prompt task (default: work)
|
|
88
|
+
--directory <path> Parser cache directory (parsers commands only)
|
|
89
|
+
--all Select every parser (parsers install/verify only)
|
|
79
90
|
--json Emit one machine-readable result
|
|
80
91
|
-h, --help Show this help
|
|
81
92
|
|
|
@@ -84,7 +95,7 @@ prompt to the agent you already use. Review all edits through the ordinary Git
|
|
|
84
95
|
diff, then run genesis verify for the Stack's concrete checks.
|
|
85
96
|
`;
|
|
86
97
|
|
|
87
|
-
const COMMANDS = new Set(['adopt', 'check', 'codex', 'collaboration', 'context', 'engineering', 'hook', 'index', 'init', 'inspect', 'migrate', 'prompt', 'skills', 'stack', 'templates', 'verify']);
|
|
98
|
+
const COMMANDS = new Set(['adopt', 'check', 'codex', 'collaboration', 'context', 'engineering', 'hook', 'index', 'init', 'inspect', 'migrate', 'parsers', 'prompt', 'skills', 'stack', 'templates', 'verify']);
|
|
88
99
|
|
|
89
100
|
function parseCommand(argv) {
|
|
90
101
|
if (argv.length === 0 || argv.includes('--help') || argv.includes('-h') || argv[0] === 'help') {
|
|
@@ -100,6 +111,8 @@ function parseCommand(argv) {
|
|
|
100
111
|
strict: true,
|
|
101
112
|
options: {
|
|
102
113
|
json: { type: 'boolean', default: false },
|
|
114
|
+
all: { type: 'boolean', default: false },
|
|
115
|
+
directory: { type: 'string' },
|
|
103
116
|
'project-root': { type: 'string' },
|
|
104
117
|
'stack-package': { type: 'string', multiple: true, default: [] },
|
|
105
118
|
'template-source': { type: 'string', multiple: true, default: [] },
|
|
@@ -111,6 +124,8 @@ function parseCommand(argv) {
|
|
|
111
124
|
}
|
|
112
125
|
const options = {
|
|
113
126
|
json: parsed.values.json,
|
|
127
|
+
all: parsed.values.all,
|
|
128
|
+
directory: parsed.values.directory,
|
|
114
129
|
projectRoot: parsed.values['project-root'],
|
|
115
130
|
stackPackages: parsed.values['stack-package'],
|
|
116
131
|
templateSources: parsed.values['template-source'].map((source) => {
|
|
@@ -123,13 +138,23 @@ function parseCommand(argv) {
|
|
|
123
138
|
task: parsed.values.task,
|
|
124
139
|
};
|
|
125
140
|
const operands = parsed.positionals;
|
|
141
|
+
if (command !== 'parsers' && (options.all || options.directory !== undefined)) {
|
|
142
|
+
fail('CLI_OPTION_NOT_APPLICABLE', 'Options --all and --directory apply only to parsers commands.');
|
|
143
|
+
}
|
|
126
144
|
if (options.templateSources.length && command !== 'templates') {
|
|
127
145
|
fail('CLI_OPTION_NOT_APPLICABLE', `Option --template-source is not applicable to ${command}.`);
|
|
128
146
|
}
|
|
129
147
|
if (options.task !== undefined && command !== 'prompt') {
|
|
130
148
|
fail('CLI_OPTION_NOT_APPLICABLE', `Option --task is not applicable to ${command}.`);
|
|
131
149
|
}
|
|
132
|
-
if (command === '
|
|
150
|
+
if (command === 'parsers') {
|
|
151
|
+
const [action, ...languages] = operands;
|
|
152
|
+
if (!['list', 'install', 'verify'].includes(action)) fail('CLI_PARSER_ACTION_REQUIRED', 'Use parsers list, install, or verify.');
|
|
153
|
+
if (action === 'list' && (languages.length || options.all)) fail('CLI_EXTRA_ARGUMENT', 'parsers list accepts no languages or --all.');
|
|
154
|
+
if (action !== 'list' && (options.all ? languages.length : !languages.length)) {
|
|
155
|
+
fail('PARSER_SELECTION_INVALID', 'Choose parser names or --all.');
|
|
156
|
+
}
|
|
157
|
+
} else if (command === 'templates') {
|
|
133
158
|
if (!(operands[0] === 'list' && operands.length === 1) && !(operands[0] === 'apply' && operands.length === 2)) {
|
|
134
159
|
fail('CLI_TEMPLATE_ACTION_REQUIRED', 'Use templates list or templates apply <catalogue:technology/variant>.');
|
|
135
160
|
}
|
|
@@ -182,12 +207,12 @@ function parseCommand(argv) {
|
|
|
182
207
|
} else if (command === 'context' && operands.length === 0) {
|
|
183
208
|
fail('CONTEXT_PATH_REQUIRED', 'Command context requires at least one project path.');
|
|
184
209
|
} else if (command === 'inspect') {
|
|
185
|
-
const ordinaryInspection = operands.length === 1 && ['environment', 'project', 'skills'].includes(operands[0]);
|
|
210
|
+
const ordinaryInspection = operands.length === 1 && ['environment', 'project', 'skills', 'subsystems'].includes(operands[0]);
|
|
186
211
|
const sectionInspection = operands.length >= 2 && operands[0] === 'section';
|
|
187
212
|
if (!ordinaryInspection && !sectionInspection) {
|
|
188
213
|
fail(
|
|
189
214
|
'CLI_INSPECT_TARGET_REQUIRED',
|
|
190
|
-
'Command inspect requires project, environment, skills, or section <name>.',
|
|
215
|
+
'Command inspect requires project, environment, skills, subsystems, or section <name>.',
|
|
191
216
|
);
|
|
192
217
|
}
|
|
193
218
|
} else if (command === 'hook' && (operands.length !== 1 || !['discover', 'session', 'turn'].includes(operands[0]))) {
|
|
@@ -272,7 +297,9 @@ function writeInspection(result) {
|
|
|
272
297
|
line(process.stdout, `${title}: ${result.status}`);
|
|
273
298
|
namedItems('Components', result.components);
|
|
274
299
|
namedItems('Runtimes', result.runtimeRequirements);
|
|
275
|
-
if (result.inspection === '
|
|
300
|
+
if (result.inspection === 'subsystems') {
|
|
301
|
+
namedItems('Subsystems', result.subsystems.map(({ id, title }) => `${id}: ${title}`));
|
|
302
|
+
} else if (result.inspection === 'environment') {
|
|
276
303
|
namedItems('Public defaults', result.environmentDefaults.map(({ name, value }) => `${name}=${value}`));
|
|
277
304
|
namedItems('Environment files', result.files.map(({ format, path: filePath }) => `${format}: ${filePath}`));
|
|
278
305
|
} else if (result.inspection === 'section') {
|
|
@@ -286,6 +313,12 @@ function writeInspection(result) {
|
|
|
286
313
|
}
|
|
287
314
|
|
|
288
315
|
function writeResult(command, result) {
|
|
316
|
+
if (command === 'parsers') {
|
|
317
|
+
line(process.stdout, `Parser directory: ${result.directory}`);
|
|
318
|
+
if (result.parsers) for (const parser of result.parsers) line(process.stdout, `${parser.language}: ${parser.status}${parser.message ? ` — ${parser.message}` : ''}`);
|
|
319
|
+
else line(process.stdout, `Parsers verified: ${result.languages.join(', ')}`);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
289
322
|
if (command === 'inspect' && result.inspection === 'skills') {
|
|
290
323
|
line(process.stdout, `Agent Skills: ${result.status}`);
|
|
291
324
|
for (const skill of result.skills) line(process.stdout, ` - ${skill.name}: ${skill.status}`);
|
|
@@ -425,6 +458,13 @@ async function cliStackPackages(projectRoot, supplied) {
|
|
|
425
458
|
}
|
|
426
459
|
|
|
427
460
|
async function execute({ command, operands, options }, { signal } = {}) {
|
|
461
|
+
if (command === 'parsers') {
|
|
462
|
+
const parserOptions = {
|
|
463
|
+
languages: operands.slice(1), all: options.all, directory: options.directory, signal,
|
|
464
|
+
onProgress: (message) => line(process.stderr, message),
|
|
465
|
+
};
|
|
466
|
+
return { list: listParsers, install: installParsers, verify: verifyParsers }[operands[0]](parserOptions);
|
|
467
|
+
}
|
|
428
468
|
const projectRoot = options.projectRoot || process.cwd();
|
|
429
469
|
const stackPackages = await cliStackPackages(projectRoot, options.stackPackages || []);
|
|
430
470
|
if (command === 'init') return initialize({ projectRoot, stackPackages });
|
|
@@ -511,7 +551,7 @@ async function execute({ command, operands, options }, { signal } = {}) {
|
|
|
511
551
|
}),
|
|
512
552
|
};
|
|
513
553
|
}
|
|
514
|
-
const inspections = { environment: inspectEnvironment, project: inspectProject, skills: inspectSkills };
|
|
554
|
+
const inspections = { subsystems: inspectSubsystems, environment: inspectEnvironment, project: inspectProject, skills: inspectSkills };
|
|
515
555
|
return {
|
|
516
556
|
inspection: operands[0],
|
|
517
557
|
...await inspections[operands[0]]({ projectRoot, stackPackages }),
|
|
@@ -578,7 +618,7 @@ async function optionalProjectFormat(projectRoot) {
|
|
|
578
618
|
}
|
|
579
619
|
|
|
580
620
|
function requiresCurrentProjectFormat(command, operands) {
|
|
581
|
-
if (['check', 'codex', 'hook', 'migrate'].includes(command)) return false;
|
|
621
|
+
if (['check', 'codex', 'hook', 'migrate', 'parsers'].includes(command)) return false;
|
|
582
622
|
if (command === 'engineering') {
|
|
583
623
|
return operands[0] === 'set' || (operands[0] === 'show' && operands.length === 1);
|
|
584
624
|
}
|
|
@@ -607,7 +647,7 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
607
647
|
return 0;
|
|
608
648
|
}
|
|
609
649
|
options = parsed.options;
|
|
610
|
-
const projectFormat = await optionalProjectFormat(options.projectRoot || process.cwd());
|
|
650
|
+
const projectFormat = parsed.command === 'parsers' ? null : await optionalProjectFormat(options.projectRoot || process.cwd());
|
|
611
651
|
const formatDiagnostic = projectFormatDiagnostic(projectFormat);
|
|
612
652
|
if (formatDiagnostic && !options.json) {
|
|
613
653
|
line(process.stderr, `WARNING: ${formatDiagnostic.message}`);
|
|
@@ -615,13 +655,10 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
615
655
|
if (formatDiagnostic && requiresCurrentProjectFormat(parsed.command, parsed.operands)) {
|
|
616
656
|
fail(formatDiagnostic.code, formatDiagnostic.message, formatDiagnostic.details);
|
|
617
657
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
process.once('SIGINT', abort);
|
|
621
|
-
process.once('SIGTERM', abort);
|
|
622
|
-
}
|
|
658
|
+
process.once('SIGINT', abort);
|
|
659
|
+
process.once('SIGTERM', abort);
|
|
623
660
|
const result = withProjectFormatWarning(
|
|
624
|
-
await execute(parsed, { signal: controller.signal }),
|
|
661
|
+
await withParserCancellation(controller.signal, () => execute(parsed, { signal: controller.signal })),
|
|
625
662
|
projectFormat,
|
|
626
663
|
formatDiagnostic,
|
|
627
664
|
);
|
package/src/index/code-index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { extractCodeIndexes } from './code-indexers/ast-grep.js';
|
|
5
5
|
import { asDiagnostic } from './errors.js';
|
|
6
6
|
import { buildCityPresentation } from './city-presentation.js';
|
|
7
7
|
import { cityPathExcluded } from './stack-city-presentation.js';
|
|
@@ -28,8 +28,6 @@ export const GENESIS_DERIVED_ARTIFACTS = Object.freeze([
|
|
|
28
28
|
}),
|
|
29
29
|
]);
|
|
30
30
|
|
|
31
|
-
const INDEXERS = astGrepCodeIndexers;
|
|
32
|
-
|
|
33
31
|
function directoryId(value) {
|
|
34
32
|
return `directory:${value || '.'}`;
|
|
35
33
|
}
|
|
@@ -43,7 +41,7 @@ function subsystemId(value) {
|
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
function operationId(module) {
|
|
46
|
-
return `operation:${module.
|
|
44
|
+
return `operation:${module.path}`;
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
function parentDirectory(value) {
|
|
@@ -70,18 +68,10 @@ function directoryRecords(paths) {
|
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
function subsystemRecords(subsystems) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
paths.add(segments.slice(0, count).join('/'));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return [...paths].sort().map((subsystem) => ({
|
|
81
|
-
id: subsystemId(subsystem),
|
|
82
|
-
path: subsystem,
|
|
83
|
-
title: path.posix.basename(subsystem).replace(/-/gu, ' '),
|
|
84
|
-
parentId: subsystem.includes('/') ? subsystemId(parentDirectory(subsystem)) : null,
|
|
71
|
+
return subsystems.map((entry) => ({
|
|
72
|
+
id: subsystemId(entry.id), path: entry.id, title: entry.title,
|
|
73
|
+
description: entry.description, parentId: null,
|
|
74
|
+
dataOwned: entry.dataOwned, dataUsed: entry.dataUsed,
|
|
85
75
|
}));
|
|
86
76
|
}
|
|
87
77
|
|
|
@@ -195,7 +185,7 @@ async function programCity(projectRoot) {
|
|
|
195
185
|
implementationMap: module.implementationMap,
|
|
196
186
|
path: module.path,
|
|
197
187
|
subsystem: module.subsystem,
|
|
198
|
-
districtId: subsystemId(module.subsystem),
|
|
188
|
+
districtId: module.subsystem === null ? null : subsystemId(module.subsystem),
|
|
199
189
|
sources: module.sources,
|
|
200
190
|
sourceFileIds: module.sources.map(fileId),
|
|
201
191
|
}));
|
|
@@ -203,9 +193,9 @@ async function programCity(projectRoot) {
|
|
|
203
193
|
schema: 'genesis.program-city.v1',
|
|
204
194
|
schemaVersion: 1,
|
|
205
195
|
status: program.status,
|
|
206
|
-
programHash: sha256(stableJson(operations)),
|
|
196
|
+
programHash: sha256(stableJson({ operations, subsystems: program.subsystemMap })),
|
|
207
197
|
diagnostics: [],
|
|
208
|
-
districts: subsystemRecords(program.subsystems),
|
|
198
|
+
districts: subsystemRecords(program.subsystemMap.subsystems),
|
|
209
199
|
buildings: operations,
|
|
210
200
|
links: operations.flatMap((operation) => operation.sourceFileIds.map((targetId) => ({
|
|
211
201
|
kind: 'implemented-by',
|
|
@@ -270,22 +260,7 @@ export async function buildProjectIndex({
|
|
|
270
260
|
))
|
|
271
261
|
.map(([filePath, state]) => ({ path: filePath, hash: state.hash, mode: state.mode }));
|
|
272
262
|
const indexers = [...new Set(stack.components.flatMap((component) => component.indexers || []))].sort();
|
|
273
|
-
const contributions =
|
|
274
|
-
const diagnostics = [];
|
|
275
|
-
for (const id of indexers) {
|
|
276
|
-
const indexer = INDEXERS.get(id);
|
|
277
|
-
if (!indexer) {
|
|
278
|
-
diagnostics.push({ code: 'CODE_INDEXER_UNAVAILABLE', message: `No installed code indexer exists for ${id}.` });
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
try {
|
|
282
|
-
const contribution = await indexer.extract({ files, projectRoot: root });
|
|
283
|
-
contributions.push({ ...contribution, extractor: id });
|
|
284
|
-
diagnostics.push(...(contribution.diagnostics || []).map((diagnostic) => ({ ...diagnostic, extractor: id })));
|
|
285
|
-
} catch (error) {
|
|
286
|
-
diagnostics.push({ ...asDiagnostic(error), code: 'CODE_INDEXER_FAILED', extractor: id });
|
|
287
|
-
}
|
|
288
|
-
}
|
|
263
|
+
const { contributions, diagnostics } = await extractCodeIndexes({ indexers, files, projectRoot: root });
|
|
289
264
|
const machine = machineCity({
|
|
290
265
|
cityRegions: stack.cityRegions,
|
|
291
266
|
components: stack.components.map(({ id }) => id),
|