@genvidtech/c3-domain-manager 0.0.1 → 0.6.2
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/LICENSE +18 -0
- package/README.md +195 -29
- package/dist/adapters/locations.d.ts +22 -0
- package/dist/adapters/locations.d.ts.map +1 -0
- package/dist/adapters/locations.js +42 -0
- package/dist/adapters/locations.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +99 -0
- package/dist/cli.js.map +1 -0
- package/dist/domain/classification.d.ts +8 -0
- package/dist/domain/classification.d.ts.map +1 -0
- package/dist/domain/classification.js +66 -0
- package/dist/domain/classification.js.map +1 -0
- package/dist/domain/contextMap.d.ts +8 -0
- package/dist/domain/contextMap.d.ts.map +1 -0
- package/dist/domain/contextMap.js +168 -0
- package/dist/domain/contextMap.js.map +1 -0
- package/dist/domain/domainAnalysis.d.ts +25 -0
- package/dist/domain/domainAnalysis.d.ts.map +1 -0
- package/dist/domain/domainAnalysis.js +136 -0
- package/dist/domain/domainAnalysis.js.map +1 -0
- package/dist/domain/domainGenerator.d.ts +33 -0
- package/dist/domain/domainGenerator.d.ts.map +1 -0
- package/dist/domain/domainGenerator.js +312 -0
- package/dist/domain/domainGenerator.js.map +1 -0
- package/dist/domain/editorValidation.d.ts +19 -0
- package/dist/domain/editorValidation.d.ts.map +1 -0
- package/dist/domain/editorValidation.js +40 -0
- package/dist/domain/editorValidation.js.map +1 -0
- package/dist/domain/formatting.d.ts +16 -0
- package/dist/domain/formatting.d.ts.map +1 -0
- package/dist/domain/formatting.js +414 -0
- package/dist/domain/formatting.js.map +1 -0
- package/dist/domain/glossary.d.ts +20 -0
- package/dist/domain/glossary.d.ts.map +1 -0
- package/dist/domain/glossary.js +62 -0
- package/dist/domain/glossary.js.map +1 -0
- package/dist/domain/health.d.ts +14 -0
- package/dist/domain/health.d.ts.map +1 -0
- package/dist/domain/health.js +21 -0
- package/dist/domain/health.js.map +1 -0
- package/dist/domain/relationships.d.ts +13 -0
- package/dist/domain/relationships.d.ts.map +1 -0
- package/dist/domain/relationships.js +74 -0
- package/dist/domain/relationships.js.map +1 -0
- package/dist/domain/types.d.ts +290 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +29 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +519 -0
- package/dist/mcp/server.js.map +1 -0
- package/docs/TOC.md +27 -0
- package/docs/decisions/0001-adopt-c3source-extractors.md +67 -0
- package/docs/decisions/0002-configurable-locations-adapters-seam.md +72 -0
- package/docs/decisions/0003-adopt-loadprojectconfig-schema-first.md +73 -0
- package/docs/decisions/0004-adopt-mcp-utils-0.4.0-helpers.md +74 -0
- package/docs/decisions/0005-validateforeditor-read-side-diagnostic.md +65 -0
- package/docs/decisions/0006-event-variable-reference-coupling.md +77 -0
- package/docs/decisions/0007-project-dir-resolverootfolder.md +72 -0
- package/docs/decisions/0008-adopt-openproject-option-a.md +77 -0
- package/docs/domain-architecture.md +242 -0
- package/docs/releasing.md +122 -0
- package/package.json +79 -8
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Domain Architecture
|
|
2
|
+
|
|
3
|
+
How to organize a Construct 3 project into domains, configure classification, and use the analysis tools.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
A domain in this context is a named grouping of source files (event sheets, layouts, scripts) that map to a coherent user-facing feature area. Grouping files this way makes it easier to:
|
|
8
|
+
|
|
9
|
+
- Find where a change should be made
|
|
10
|
+
- Measure coupling between features
|
|
11
|
+
- Enforce architectural boundaries
|
|
12
|
+
|
|
13
|
+
The groupings are declared in `domain-config.json` at the project root. The `c3-domain-manager` package reads this file to classify files, generate a browsable index, and run health and boundary checks.
|
|
14
|
+
|
|
15
|
+
## Primary domains vs shared subdomains
|
|
16
|
+
|
|
17
|
+
**Primary domains** represent distinct user experiences — each one owns a vertical slice of the product. Examples: Authentication, Gameplay, Shop & Economy.
|
|
18
|
+
|
|
19
|
+
**Shared subdomains** contain code that is genuinely reused across multiple primary domains. Examples: UI Components, Chat, Analytics.
|
|
20
|
+
|
|
21
|
+
A shared subdomain is worth defining only when both conditions hold:
|
|
22
|
+
|
|
23
|
+
1. Multiple domains include the same event sheets, layouts, or scripts
|
|
24
|
+
2. Knowing the subdomain actually narrows down where to look for a change
|
|
25
|
+
|
|
26
|
+
If different domains implement the same concept independently (e.g. each domain has its own reward screen), a shared subdomain would not help — the concept is not shared at the code level.
|
|
27
|
+
|
|
28
|
+
## domain-config.json structure
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"domains": {
|
|
33
|
+
"Authentication": {
|
|
34
|
+
"description": "Login, device binding, user profile",
|
|
35
|
+
"strategy": "supporting",
|
|
36
|
+
"eventSheetDirs": ["Login", "Profile"],
|
|
37
|
+
"layoutDirs": ["Login"],
|
|
38
|
+
"scriptDirs": ["Auth"],
|
|
39
|
+
"glossary": {
|
|
40
|
+
"session": "An authenticated user session with a backend token"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"sharedSubdomains": {
|
|
45
|
+
"UI Components": {
|
|
46
|
+
"description": "Reusable UI widgets used across domains",
|
|
47
|
+
"scriptDirs": ["UI"]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"overrides": {
|
|
51
|
+
"eventSheets/Shared/ChatEvents.json": "Watch Content"
|
|
52
|
+
},
|
|
53
|
+
"relationships": [
|
|
54
|
+
{
|
|
55
|
+
"from": "Gameplay",
|
|
56
|
+
"to": "Authentication",
|
|
57
|
+
"type": "conformist",
|
|
58
|
+
"description": "Gameplay reads the authenticated user ID without influencing Auth"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### domains
|
|
65
|
+
|
|
66
|
+
Each entry under `domains` is a primary domain. Fields:
|
|
67
|
+
|
|
68
|
+
| Field | Type | Description |
|
|
69
|
+
|-------|------|-------------|
|
|
70
|
+
| `description` | string | One-line summary of what this domain covers |
|
|
71
|
+
| `strategy` | `"core"` \| `"supporting"` \| `"generic"` | DDD strategic classification (optional) |
|
|
72
|
+
| `eventSheetDirs` | string[] | Subdirectories of `eventSheets/` owned by this domain |
|
|
73
|
+
| `layoutDirs` | string[] | Subdirectories of `layouts/` owned by this domain |
|
|
74
|
+
| `scriptDirs` | string[] | Subdirectories of `scripts/` owned by this domain |
|
|
75
|
+
| `glossary` | Record<string, string> | Domain-specific term definitions (optional) |
|
|
76
|
+
|
|
77
|
+
### sharedSubdomains
|
|
78
|
+
|
|
79
|
+
Same structure as `domains`. Entries here are flagged as shared in the generated index and health reports.
|
|
80
|
+
|
|
81
|
+
### overrides
|
|
82
|
+
|
|
83
|
+
A flat map of `relativePath → domainName`. Overrides take precedence over directory-based classification. Use them for files that live in a directory owned by one domain but logically belong to another.
|
|
84
|
+
|
|
85
|
+
Paths are relative to the project root, using forward slashes: `eventSheets/Shared/Chat.json`.
|
|
86
|
+
|
|
87
|
+
### relationships
|
|
88
|
+
|
|
89
|
+
Optional. Declares the expected integration patterns between domains using DDD relationship types:
|
|
90
|
+
|
|
91
|
+
| Type | Meaning |
|
|
92
|
+
|------|---------|
|
|
93
|
+
| `shared-kernel` | Both teams share a subset of code and coordinate changes |
|
|
94
|
+
| `customer-supplier` | Downstream team (customer) depends on upstream team (supplier) |
|
|
95
|
+
| `conformist` | Downstream conforms to upstream's model without influence |
|
|
96
|
+
| `anti-corruption-layer` | Downstream translates upstream's model through an adapter |
|
|
97
|
+
| `open-host-service` | Upstream publishes a stable protocol for any consumer |
|
|
98
|
+
|
|
99
|
+
Declared relationships are checked by `validate-boundaries`. Observed dependencies (found in event sheet includes and event-variable references) that are not declared produce warnings.
|
|
100
|
+
|
|
101
|
+
### Validation
|
|
102
|
+
|
|
103
|
+
The config is validated against a lenient zod schema (`DomainConfigSchema`) when loaded. "Lenient" means unknown keys are **tolerated and preserved** (so extra fields you add survive a load→edit→write round-trip through the MCP `set-overrides`/`remove-overrides` tools) and non-essential fields are optional; only `domains` and each domain's `description` are required. A missing file, malformed JSON, or a schema violation produces a clear error prefixed `loadProjectConfig(domain-config.json): …` — from the CLI it aborts the command, and from the MCP server it is returned as a structured tool error.
|
|
104
|
+
|
|
105
|
+
## File classification rules
|
|
106
|
+
|
|
107
|
+
Files are classified in two steps:
|
|
108
|
+
|
|
109
|
+
1. **Exact override** — if the file's relative path appears in `overrides`, that domain wins. This has highest priority.
|
|
110
|
+
2. **Directory prefix** — the file's path (stripped of the file-type root, e.g. `eventSheets/`) is matched against `eventSheetDirs` / `layoutDirs` / `scriptDirs`. The longest matching prefix wins, allowing nested directories to override parent directories.
|
|
111
|
+
|
|
112
|
+
File type roots:
|
|
113
|
+
|
|
114
|
+
| File type | Root directory |
|
|
115
|
+
|-----------|----------------|
|
|
116
|
+
| `eventSheet` | `eventSheets/` |
|
|
117
|
+
| `layout` | `layouts/` |
|
|
118
|
+
| `script` | `scripts/` |
|
|
119
|
+
|
|
120
|
+
Example: a file at `eventSheets/Battle/Skills/ActiveSkills.json` with config `eventSheetDirs: ["Battle"]` matches `Battle/` and is classified under that domain. If a second domain declares `eventSheetDirs: ["Battle/Skills"]`, the longer prefix wins and the file goes to the second domain.
|
|
121
|
+
|
|
122
|
+
Files that match no rule are "uncategorized". Run `c3-domain-manager list-uncategorized` to find them.
|
|
123
|
+
|
|
124
|
+
## Strategic classification
|
|
125
|
+
|
|
126
|
+
The optional `strategy` field on a domain or subdomain marks its DDD strategic role:
|
|
127
|
+
|
|
128
|
+
- **core** — competitive differentiator; invest heavily, do not outsource
|
|
129
|
+
- **supporting** — necessary but not differentiating; can be built with standard solutions
|
|
130
|
+
- **generic** — commodity capability; prefer off-the-shelf solutions
|
|
131
|
+
|
|
132
|
+
`validate-boundaries` uses this to enforce direction rules. For example, a `supporting` domain should not depend on a `core` domain (that would invert the dependency direction).
|
|
133
|
+
|
|
134
|
+
## Generated domain index
|
|
135
|
+
|
|
136
|
+
Running `c3-domain-manager generate` (or `regenerate` via MCP) writes files to `extracted/domain-index/`:
|
|
137
|
+
|
|
138
|
+
- `index.md` — master index listing all domains with file counts and descriptions
|
|
139
|
+
- `<DomainName>.md` — per-domain page with:
|
|
140
|
+
- File lists (event sheets, layouts, scripts)
|
|
141
|
+
- Exported function signatures extracted from event sheets
|
|
142
|
+
- Include graph (which sheets include which, within and across domains)
|
|
143
|
+
- Event-variable reference graph (cross-domain references to/from this domain, when present)
|
|
144
|
+
- Cross-domain dependency summary
|
|
145
|
+
|
|
146
|
+
Commit `extracted/domain-index/` to version control so the index is always available without regenerating.
|
|
147
|
+
|
|
148
|
+
## Paths and locations
|
|
149
|
+
|
|
150
|
+
By default the tool scans `eventSheets/`, `layouts/`, and `scripts/` under the auto-detected C3 project root, reads `domain-config.json` from that root, and writes generated output to `extracted/` there. All three locations can be overridden:
|
|
151
|
+
|
|
152
|
+
| Flag | Default | Effect |
|
|
153
|
+
|------|---------|--------|
|
|
154
|
+
| `--project-dir <path>` | auto-detected (see below) | Sets the C3 project source root — the directory whose `eventSheets/`, `layouts/`, and `scripts/` are scanned. Relative paths resolve against the **current working directory**; absolute paths are used as-is. |
|
|
155
|
+
| `--config <path>` | `<project-root>/domain-config.json` | Selects the domain-config file. |
|
|
156
|
+
| `--extracted <path>` | `<project-root>/extracted` | Selects the domain-index output directory. |
|
|
157
|
+
|
|
158
|
+
Relative paths for `--config` and `--extracted` resolve against the **project root** (as set by `--project-dir` or auto-detection), never the package install directory. Absolute paths are used as-is. Operator-supplied paths are trusted — paths outside the project root are intentionally allowed.
|
|
159
|
+
|
|
160
|
+
**`--project-dir` resolution precedence** (highest to lowest):
|
|
161
|
+
|
|
162
|
+
1. **`--project-dir <path>`** — explicit flag. Relative resolves against the current working directory; absolute used as-is. No containment restriction — `../sibling` is valid.
|
|
163
|
+
2. **`C3_PROJECT_DIR` environment variable** — same resolution rules as the flag.
|
|
164
|
+
3. **Discovery** — the current directory and its immediate children (depth 1) are searched for a directory or file named `project.c3proj` (the Construct 3 project manifest). Exactly one match becomes the project root. Two or more matches produce an ambiguity error: the command prints it and exits non-zero, requiring the user to pass `--project-dir` explicitly. This is the intended behavior for a repository hosting multiple C3 projects.
|
|
165
|
+
4. **Fallback** — the current working directory (preserves prior behavior when no project marker is found).
|
|
166
|
+
|
|
167
|
+
This resolution is implemented by `resolveProjectRoot` in `src/adapters/locations.ts`, a thin wrapper over `@genvidtech/mcp-utils`'s `resolveRootFolder` that passes `PROJECT_MANIFEST_FILE` (from `@genvidtech/c3source`) as the discovery marker.
|
|
168
|
+
|
|
169
|
+
**Ephemeral mode** — pass `none` as the `--extracted` value to route output into a temporary directory that is automatically deleted when the command finishes (or when the MCP server shuts down on SIGINT/SIGTERM). This is useful as a no-side-effect validation pass: generation runs but leaves no files behind in the project tree.
|
|
170
|
+
|
|
171
|
+
When using the MCP server, the resolved locations are forwarded from the CLI `server` command via `startServer(loc: ResolvedLocations)`. The MCP server itself does not re-run discovery — the root is fixed at startup.
|
|
172
|
+
|
|
173
|
+
## Cross-domain coupling sources
|
|
174
|
+
|
|
175
|
+
Two independent sources contribute to the observed coupling graph between domains:
|
|
176
|
+
|
|
177
|
+
### Include coupling
|
|
178
|
+
|
|
179
|
+
Event sheets can include other event sheets using include events. When a sheet in domain A includes a sheet in domain B, that creates an include edge from A to B. The include graph is stored in `DomainData` as `includesFrom` (outgoing: A → B, payload = included sheet names) and `includedBy` (incoming: B ← A, same payload).
|
|
180
|
+
|
|
181
|
+
### Event-variable reference coupling
|
|
182
|
+
|
|
183
|
+
C3 event sheets can also reference event variables declared in other sheets via System ACEs. When a sheet in domain A references a variable that is declared in domain B, that creates a reference edge from A to B. The reference graph is stored as two sibling maps alongside the include maps: `referencesFrom` (outgoing: A → B, payload = variable names) and `referencedBy` (incoming: B ← A, same payload).
|
|
184
|
+
|
|
185
|
+
**Resolution policy:**
|
|
186
|
+
|
|
187
|
+
- **Global-scope approximation** — only top-level (sheet-root) `variable` events are indexed as declarations. C3 cross-sheet variable references require global variables, and root-level declarations are the global-scope approximation. Local variables declared inside groups or functions are deliberately excluded.
|
|
188
|
+
- **Attribute-to-all on collision** — if the same variable name is declared at the top level of sheets in multiple domains, a reference to that name creates an edge to every declaring domain.
|
|
189
|
+
- **Unresolved references produce no edge** — if the referenced variable name has no indexed (root-level) declaration anywhere in the project, the reference is silently ignored. There is no diagnostics bucket for unresolved names.
|
|
190
|
+
- **Same-domain references produce no edge** — consistent with include coupling, references resolved to the same domain as the referencing sheet are not recorded.
|
|
191
|
+
|
|
192
|
+
**Limitation:** only top-level declarations are indexed. Variables scoped inside a group or function block are not visible across sheets in C3, so excluding them is correct behaviour. A variable declared inside a block but referenced from another sheet would be unresolvable and fall into the "unresolved → no edge" path above.
|
|
193
|
+
|
|
194
|
+
No `domain-config.json` schema change is required — reference coupling is derived entirely from event sheet content and does not need configuration.
|
|
195
|
+
|
|
196
|
+
### How coupling surfaces in analysis
|
|
197
|
+
|
|
198
|
+
Both coupling sources are aggregated with **union semantics** across all downstream consumers:
|
|
199
|
+
|
|
200
|
+
- **Health metrics** (`computeHealth`) — Ca and Ce count the union of include-coupled and reference-coupled distinct domains, with overlap deduped (a domain that is both include-coupled and reference-coupled is counted only once).
|
|
201
|
+
- **Boundary validation** (`validateBoundaries`) — the undeclared-dependency and forbidden-direction checks operate over the union of include and reference target domains. A reference edge to an undeclared domain produces an `undeclared` violation exactly as an include edge would.
|
|
202
|
+
- **Context map** (`generateContextMap`) — reference coupling surfaces as a distinct `observed-ref` edge kind. In text format it appears as `[observed-ref]`; in Mermaid it renders as `-.->|var|`. Edge precedence is: declared > observed (include) > observed-ref. An include and a reference to the same domain pair produce only the higher-precedence edge.
|
|
203
|
+
- **Domain pages** (`formatDomainPage`) — the "Cross-Domain Dependencies" section gains two subsections: "Event-variable references from this domain" and "Event-variable references into this domain", rendered only when the respective map is non-empty.
|
|
204
|
+
|
|
205
|
+
## Health metrics
|
|
206
|
+
|
|
207
|
+
`domain-health` (MCP tool or library `computeHealth`) computes per-domain:
|
|
208
|
+
|
|
209
|
+
- **Ca (afferent coupling)** — how many other domains depend on this domain (via includes or event-variable references)
|
|
210
|
+
- **Ce (efferent coupling)** — how many domains this domain depends on (via includes or event-variable references)
|
|
211
|
+
- **Instability** — `Ce / (Ca + Ce)`, range 0–1. 0 is maximally stable (nothing it depends on can break it); 1 is maximally unstable (many dependencies, no dependents)
|
|
212
|
+
|
|
213
|
+
High instability in a core domain is a warning sign.
|
|
214
|
+
|
|
215
|
+
## Boundary validation
|
|
216
|
+
|
|
217
|
+
`validate-boundaries` (MCP tool or library `validateBoundaries`) checks:
|
|
218
|
+
|
|
219
|
+
- **Undeclared dependencies** — domain A includes sheets from domain B, or references event-variables declared in domain B, but no relationship is declared from A to B
|
|
220
|
+
- **Stale declarations** — a declared relationship has no corresponding observed dependency
|
|
221
|
+
- **Forbidden directions** — e.g. a `supporting` domain depending on a `core` domain
|
|
222
|
+
|
|
223
|
+
Filter to a single domain by passing the `domain` parameter.
|
|
224
|
+
|
|
225
|
+
## Glossary collision detection
|
|
226
|
+
|
|
227
|
+
Each domain can define a `glossary` map of terms to definitions. `glossary-check` collects all definitions across domains and reports terms that appear with different definitions in different domains. These collisions indicate shared language that may need alignment.
|
|
228
|
+
|
|
229
|
+
## Editor-strictness validation
|
|
230
|
+
|
|
231
|
+
`validate-editor` (CLI subcommand or MCP `READ_ONLY` tool "Validate Editor Strictness") checks whether the target project's event sheets are structurally valid from the C3 editor's perspective. It re-walks `eventSheets/` fresh from disk, attributes each sheet to a domain via `classifyFile`, and runs `@genvidtech/c3source`'s `validateForEditor` per sheet. Issues are grouped by sheet; sheets that match no domain classification are reported under `"(unclassified)"`.
|
|
232
|
+
|
|
233
|
+
This is a read-side diagnostic only. `c3-domain-manager` never writes or modifies event sheets — the report surfaces sheets the C3 editor would refuse to import (e.g. a `variable` event missing its `comment` field, or a `group` event missing its `description`) so you can fix them in the C3 editor.
|
|
234
|
+
|
|
235
|
+
Because it reads sheets directly from disk, the MCP tool does not append the stale-index warning that other read tools emit — index freshness is irrelevant to its output.
|
|
236
|
+
|
|
237
|
+
## Maintenance
|
|
238
|
+
|
|
239
|
+
- After adding or renaming files, run `c3-domain-manager list-uncategorized` to confirm coverage
|
|
240
|
+
- After deleting files, run `c3-domain-manager list-stale-overrides` to clean up orphaned override entries
|
|
241
|
+
- Regenerate the domain index after any `domain-config.json` change: `c3-domain-manager generate`
|
|
242
|
+
- To check event sheets for C3 editor compatibility: `c3-domain-manager validate-editor`
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
How to cut a new release of `@genvidtech/c3-domain-manager`. Routine releases are
|
|
4
|
+
fully self-service — this repo is already wired for OIDC **trusted publishing**,
|
|
5
|
+
so there is no npm token to manage and nothing in the `publish-npm-package` skill
|
|
6
|
+
to re-run (that skill is one-time setup, not per-release).
|
|
7
|
+
|
|
8
|
+
## TL;DR
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# 1. Land all release content on main first (the tag publishes whatever main points at).
|
|
12
|
+
# 2. Bump the version (patch for fixes, minor for features) — updates all 3 spots, no commit/tag:
|
|
13
|
+
npm version X.Y.Z --no-git-tag-version
|
|
14
|
+
# 3. Commit + tag + push:
|
|
15
|
+
git add package.json package-lock.json
|
|
16
|
+
git commit -m "chore: Release X.Y.Z" # see message shape below
|
|
17
|
+
git tag vX.Y.Z # lightweight tag — matches recent convention
|
|
18
|
+
git push origin main
|
|
19
|
+
git push origin vX.Y.Z # this push triggers the publish workflow
|
|
20
|
+
# 4. After it publishes: file the downstream plugin update request (step 7).
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Step by step
|
|
24
|
+
|
|
25
|
+
1. **Bump the version.** Choose the bump per semver — patch (`0.1.2 → 0.1.3`) for a
|
|
26
|
+
bug fix, minor for a backward-compatible feature. **At `0.x`, a breaking change to
|
|
27
|
+
the public API takes a minor bump even when the work is a bug fix** — removing or
|
|
28
|
+
renaming an exported function/type (anything re-exported from `src/index.ts`) is
|
|
29
|
+
the pre-1.0 "breaking" signal. Example: `0.1.3 → 0.2.0` for issue #5, which fixed
|
|
30
|
+
the extraction by retiring the public `extractIncludes`/`extractFunctions` exports.
|
|
31
|
+
Run `npm version X.Y.Z --no-git-tag-version` — it updates all **three** spots and
|
|
32
|
+
makes **no commit and no tag**, so you keep control of the message and tag style
|
|
33
|
+
below:
|
|
34
|
+
- `package.json` → `"version"`
|
|
35
|
+
- `package-lock.json` → the top-level `"version"`
|
|
36
|
+
- `package-lock.json` → `packages."".version` (the root package entry, ~line 9)
|
|
37
|
+
|
|
38
|
+
(You can edit the three spots by hand instead, but that risks missing the second
|
|
39
|
+
`package-lock.json` spot; the flag-driven bump is safer. See the note below.)
|
|
40
|
+
|
|
41
|
+
2. **Commit** with the project's release-commit shape — a `chore: Release X.Y.Z`
|
|
42
|
+
subject, a short body summarising what the release contains (issue refs welcome),
|
|
43
|
+
and the standard co-author trailer:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
chore: Release 0.1.3
|
|
47
|
+
|
|
48
|
+
Patch release fixing `--version` reporting "unknown" instead of the
|
|
49
|
+
package version (#3).
|
|
50
|
+
|
|
51
|
+
Co-Authored-By: <current model> <noreply@anthropic.com>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
3. **Tag.** Use a **lightweight** tag matching the recent convention
|
|
55
|
+
(`v0.1.1`, `v0.1.2`, `v0.1.3` are lightweight; only the original `v0.1.0` was
|
|
56
|
+
annotated):
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git tag vX.Y.Z
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
4. **Push the commit, then the tag.** The tag is what triggers publishing:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git push origin main
|
|
66
|
+
git push origin vX.Y.Z
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
5. **Watch the publish.** The tag push fires `.github/workflows/publish.yml`
|
|
70
|
+
(trigger: `push` on `v*.*.*`). It runs the shared `public-github-actions` node-gate,
|
|
71
|
+
then publishes to npm via OIDC trusted publishing (automatic provenance, no
|
|
72
|
+
stored token). Confirm:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
gh run list --workflow Publish --limit 1
|
|
76
|
+
npm view @genvidtech/c3-domain-manager version # should show the new version as latest
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
6. **Smoke-check the CLI version** (catches the class of bug that motivated this doc):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npx -y @genvidtech/c3-domain-manager@X.Y.Z --version # prints X.Y.Z, not "unknown"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
7. **File the downstream plugin update request.** The `genvid-c3` plugin
|
|
86
|
+
(`GenvidTechnologies/claude-code-plugin-gvt-construct3`) **pins** this package in
|
|
87
|
+
`plugin/.claude-plugin/plugin.json` (`mcpServers.c3-domain-manager`, e.g.
|
|
88
|
+
`@genvidtech/c3-domain-manager@0.3.0`) and references the pinned version in its
|
|
89
|
+
`c3-explorer` / `c3-implementer` agent docs. Every publish here therefore needs a
|
|
90
|
+
follow-up issue there to bump the pin and reconcile the tool surface. Open one with
|
|
91
|
+
`gh issue create --repo GenvidTechnologies/claude-code-plugin-gvt-construct3`, and call out
|
|
92
|
+
any **MCP tool-surface change** (a tool added/renamed/removed) — that repo runs
|
|
93
|
+
`docs/tool-surface-reconciliation.md` and updates the `c3-explorer` `tools:`
|
|
94
|
+
allow-list off it. Example: 0.4.0 added the `validate-editor` READ_ONLY tool, so the
|
|
95
|
+
request flagged it for the allow-list (issue
|
|
96
|
+
[#12](https://github.com/GenvidTechnologies/claude-code-plugin-gvt-construct3/issues/12)).
|
|
97
|
+
|
|
98
|
+
## Notes & gotchas
|
|
99
|
+
|
|
100
|
+
- **`process.cwd()` is the target project, not this package.** The CLI reads its
|
|
101
|
+
own version from `package.json` resolved via `import.meta.url`. If you add files
|
|
102
|
+
the published CLI must read at runtime, resolve them relative to the module, never
|
|
103
|
+
`cwd`. See the "TypeScript / module setup" section in `CLAUDE.md`.
|
|
104
|
+
- **Why `npm version --no-git-tag-version` and not a bare `npm version`?** A bare
|
|
105
|
+
`npm version patch` bumps all three spots but *also* makes a commit (default message
|
|
106
|
+
`X.Y.Z`) and an **annotated** tag — neither matches the `chore: Release X.Y.Z` +
|
|
107
|
+
lightweight-tag + co-author-trailer convention. The `--no-git-tag-version` flag keeps
|
|
108
|
+
the correct three-spot bump while making no commit and no tag, so you commit and
|
|
109
|
+
lightweight-tag by hand (steps 2–4) to match the convention. Hand-editing the three
|
|
110
|
+
spots also works but risks missing the second `package-lock.json` spot
|
|
111
|
+
(`packages."".version`).
|
|
112
|
+
- **If the version bump already landed with the feature/fix branch**, the release step
|
|
113
|
+
is just *tag the merge commit* — there's no need for a separate `chore: Release X.Y.Z`
|
|
114
|
+
commit. The tag publishes whatever `main` points at, and `main` already carries the
|
|
115
|
+
bumped version. (This is how issue #5 shipped: `package.json`/`package-lock.json` were
|
|
116
|
+
bumped to `0.2.0` in the fix branch, so releasing it is a one-step `git tag v0.2.0`.)
|
|
117
|
+
- **A republish of an already-published version is rejected by npm.** If the publish
|
|
118
|
+
workflow fails *after* the version was published, bump to the next patch rather than
|
|
119
|
+
retrying the same version.
|
|
120
|
+
- **Publish entry-point pitfall:** keep `main`/`types`/`exports` at the top level of
|
|
121
|
+
`package.json` pointing at `./dist/...`; do not move them into `publishConfig`
|
|
122
|
+
(see the "Publish pitfall" note in `CLAUDE.md`). Verify against `npm pack` if in doubt.
|
package/package.json
CHANGED
|
@@ -1,10 +1,81 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
"name": "@genvidtech/c3-domain-manager",
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"description": "Analyzes Construct 3 projects through a domain-driven-design lens: classifies eventSheets/layouts/scripts into named domains and produces a domain index, health/coupling metrics, boundary validation, glossary checks, and a context map. Exposed as both a CLI and an MCP server.",
|
|
5
|
+
"license": "MIT-0",
|
|
6
|
+
"author": "Genvid Technologies, inc. <support@genvidtech.com>",
|
|
7
|
+
"homepage": "https://github.com/GenvidTechnologies/c3-domain-manager#readme",
|
|
8
|
+
"bugs": "https://github.com/GenvidTechnologies/c3-domain-manager/issues",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/GenvidTechnologies/c3-domain-manager.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"construct3",
|
|
15
|
+
"construct",
|
|
16
|
+
"domain-driven-design",
|
|
17
|
+
"ddd",
|
|
18
|
+
"mcp",
|
|
19
|
+
"model-context-protocol",
|
|
20
|
+
"static-analysis"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"main": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"bin": {
|
|
26
|
+
"c3-domain-manager": "./dist/cli.js"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./mcp": {
|
|
34
|
+
"types": "./dist/mcp/server.d.ts",
|
|
35
|
+
"default": "./dist/mcp/server.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"docs",
|
|
41
|
+
"LICENSE",
|
|
42
|
+
"README.md"
|
|
43
|
+
],
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"overrides": {
|
|
48
|
+
"serialize-javascript": "^7.0.5"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc && node -e \"const fs=require('fs');const f='dist/cli.js';const c=fs.readFileSync(f,'utf8');if(!c.startsWith('#!')){fs.writeFileSync(f,'#!/usr/bin/env node\\n'+c)}\"",
|
|
52
|
+
"prepack": "npm run build",
|
|
53
|
+
"test": "mocha --timeout 5000 --import=tsx --require ./test/setup.ts 'test/**/*.test.ts' --exit",
|
|
54
|
+
"lint": "eslint --ext .ts --max-warnings 0 src/ test/",
|
|
55
|
+
"typecheck": "tsc -p tsconfig.test.json --noEmit"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=22"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@genvidtech/c3source": "^1.7.0",
|
|
62
|
+
"@genvidtech/mcp-utils": "^0.5.1",
|
|
63
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
64
|
+
"yargs": "^17.7.2",
|
|
65
|
+
"zod": "^3.23.0"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@types/chai": "^4.3.16",
|
|
69
|
+
"@types/mocha": "^10.0.6",
|
|
70
|
+
"@types/node": "^22.0.0",
|
|
71
|
+
"@types/yargs": "^17.0.33",
|
|
72
|
+
"@typescript-eslint/eslint-plugin": "^7.10.0",
|
|
73
|
+
"@typescript-eslint/parser": "^7.10.0",
|
|
74
|
+
"chai": "^5.1.1",
|
|
75
|
+
"eslint": "^8.36.0",
|
|
76
|
+
"eslint-config-prettier": "^8.7.0",
|
|
77
|
+
"mocha": "^10.4.0",
|
|
78
|
+
"tsx": "^4.21.0",
|
|
79
|
+
"typescript": "^5.4.5"
|
|
80
|
+
}
|
|
10
81
|
}
|