@metaobjectsdev/sdk 0.21.6 → 0.22.0-rc.1
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/agent-context/README.md +1 -1
- package/agent-context/skills/metaobjects-audit/references/requirements.md +60 -0
- package/agent-context/skills/metaobjects-authoring/SKILL.md +4 -0
- package/agent-context/skills/metaobjects-authoring/references/requirements.md +69 -0
- package/agent-context/skills/metaobjects-fit-assessment/SKILL.md +29 -0
- package/agent-context/skills/metaobjects-verify/SKILL.md +7 -0
- package/agent-context/skills/metaobjects-verify/references/requirements.md +54 -0
- package/dist/agent-context/assemble.d.ts.map +1 -1
- package/dist/agent-context/assemble.js +13 -10
- package/dist/agent-context/assemble.js.map +1 -1
- package/dist/agent-context/resolve.d.ts +8 -2
- package/dist/agent-context/resolve.d.ts.map +1 -1
- package/dist/agent-context/resolve.js +13 -3
- package/dist/agent-context/resolve.js.map +1 -1
- package/dist/agent-context/types.d.ts +10 -1
- package/dist/agent-context/types.d.ts.map +1 -1
- package/dist/agent-context/types.js +7 -0
- package/dist/agent-context/types.js.map +1 -1
- package/package.json +2 -2
- package/scripts/regen-agent-context-conformance.ts +2 -1
- package/src/agent-context/assemble.ts +15 -10
- package/src/agent-context/resolve.ts +20 -4
- package/src/agent-context/types.ts +11 -1
package/agent-context/README.md
CHANGED
|
@@ -9,7 +9,7 @@ the slim always-on Markdown (`.metaobjects/AGENTS.md` + `CLAUDE.md`) and the six
|
|
|
9
9
|
- `servers/<lang>.meta.json` — per-server install + codegen command (drives the always-on).
|
|
10
10
|
- `templates/always-on.md.mustache` — the slim always-on body (`{{stackLine}}`, `{{codegenCommand}}`).
|
|
11
11
|
- `skills/<skill>/SKILL.md` — universal skill body.
|
|
12
|
-
- `skills/<skill>/references/<token>.md` — language fragment; installed iff `<token>` is in the stack.
|
|
12
|
+
- `skills/<skill>/references/<token>.md` — language/framework or concern fragment; installed iff `<token>` is in the stack (`Stack.tokens`; concern tokens are OBSERVED from project state, e.g. `requirements` for a project declaring `requirement.*` nodes — see `SDK`'s `CONCERN_TOKENS`).
|
|
13
13
|
|
|
14
14
|
The **scaffolded** set is exactly the six skills in the SDK's `SKILL_NAMES`
|
|
15
15
|
(`src/agent-context/types.ts`) — the assembler emits only those. `skills/`
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Requirements — the audit dimension
|
|
2
|
+
|
|
3
|
+
This project declares `requirement.*` nodes, so the ledger is an auditable surface. Audit it
|
|
4
|
+
for **truthfulness**, not volume. A large ledger that lies is worse than a small one that
|
|
5
|
+
does not, because every later reader trusts it.
|
|
6
|
+
|
|
7
|
+
Run `meta verify` first. It settles referential integrity mechanically — do not spend audit
|
|
8
|
+
effort re-deriving what a green run already proves.
|
|
9
|
+
|
|
10
|
+
## What verify has already proven (do not re-check by hand)
|
|
11
|
+
|
|
12
|
+
Links sit at or below the L4 floor, nesting agrees with levels, `@status` values are legal,
|
|
13
|
+
references resolve (with dangling allowed on `abandoned`/`superseded`), and named
|
|
14
|
+
`@verifiedBy` tests exist and are not skipped.
|
|
15
|
+
|
|
16
|
+
## What only a human or an agent reading the code can catch
|
|
17
|
+
|
|
18
|
+
**1. Statuses that are false.** The highest-value finding in the whole dimension. A
|
|
19
|
+
requirement marked `live` whose implementation was gutted; one marked `partial` that is now
|
|
20
|
+
complete; one marked `abandoned` whose code is demonstrably still running. Sample the claims
|
|
21
|
+
and read the nodes. `status` is the only payload with controlled evidence behind it — the
|
|
22
|
+
resurrection protection rides entirely on it being true.
|
|
23
|
+
|
|
24
|
+
**2. Non-violable statements.** Every requirement must state what breaking it looks like.
|
|
25
|
+
*"Every entity has a uuid primary key"* is violable — point at one with a composite key.
|
|
26
|
+
*"Things are persisted"* is not; it is a description wearing a requirement's shape. Flag
|
|
27
|
+
these: they inflate the ledger while proving nothing.
|
|
28
|
+
|
|
29
|
+
**3. Claim-padding.** An entity appended to an existing unrelated requirement's
|
|
30
|
+
`implementedBy` purely to silence the coverage warning. The claim resolves, so verify is
|
|
31
|
+
happy, but it carries no information about what the entity is *for*. Look for entities whose
|
|
32
|
+
only claim is a high-fan-out architectural rule when they plainly have product meaning.
|
|
33
|
+
|
|
34
|
+
**4. Misfiled kind.** `functional` is checked by EXISTENCE, `architectural` by UNIVERSALITY —
|
|
35
|
+
opposite polarity, and nothing mechanical catches a misfile. The discriminator: did this
|
|
36
|
+
exist because someone asked for something (functional), or because every entity here looks
|
|
37
|
+
like this (architectural)? An architectural entry with one claimant is usually a misfiled
|
|
38
|
+
functional one.
|
|
39
|
+
|
|
40
|
+
**5. Levels used as decoration.** L1–L3 are organisational and must never reference the
|
|
41
|
+
model. If the tree is flat, or every entry is L3, the levels are carrying no information and
|
|
42
|
+
should be simplified rather than defended.
|
|
43
|
+
|
|
44
|
+
## Scope — do NOT flag these as defects
|
|
45
|
+
|
|
46
|
+
- **Unclaimed `object.value` / `object.projection`.** Exempt by design: a value is a shape, a
|
|
47
|
+
projection derives from a claimable entity.
|
|
48
|
+
- **Fields, views, validators and identities without their own requirement.** Member-grain
|
|
49
|
+
coverage is explicitly rejected — plumbing members are covered by architectural
|
|
50
|
+
requirements with high fan-out. L5 exists so a member claim *can* be made where it means
|
|
51
|
+
something, never so every member must carry one.
|
|
52
|
+
- **Dangling links on `abandoned` / `superseded`.** Correct, and load-bearing.
|
|
53
|
+
- **A project with no requirements at all.** The feature is opt-in by declaration; absence is
|
|
54
|
+
not a finding.
|
|
55
|
+
|
|
56
|
+
## Reporting
|
|
57
|
+
|
|
58
|
+
Report findings as claims to verify, not as a score. "These 4 requirements are marked `live`
|
|
59
|
+
and I could not find their implementation" is actionable; "ledger maturity: 62%" is not, and
|
|
60
|
+
invites optimising the number.
|
|
@@ -974,6 +974,10 @@ mapping).
|
|
|
974
974
|
- field.int: { name: quantity, required: true }
|
|
975
975
|
```
|
|
976
976
|
|
|
977
|
+
## Requirements — capability ledger (opt-in)
|
|
978
|
+
|
|
979
|
+
If this project declares `requirement.functional` / `requirement.architectural` nodes, read `references/requirements.md` for the full authoring rules.
|
|
980
|
+
|
|
977
981
|
---
|
|
978
982
|
|
|
979
983
|
For non-trivial schema design, use `/superpowers:brainstorming` if installed;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Requirements — `requirement.functional` / `requirement.architectural`
|
|
2
|
+
|
|
3
|
+
Capabilities are **metadata**, declared in `metaobjects/` beside the entities they
|
|
4
|
+
describe. Read the existing requirement nodes before designing anything. Two rules matter
|
|
5
|
+
more than the rest.
|
|
6
|
+
|
|
7
|
+
**1. When you retire something, record it — at that moment.** Set the requirement's
|
|
8
|
+
`status` to `abandoned` (built, then deliberately dropped) or `superseded` (something else
|
|
9
|
+
does it now — name it in `supersededBy`), in the same change that removes the code.
|
|
10
|
+
|
|
11
|
+
This is the one thing a requirement does that the rest of the model cannot. Given a brief
|
|
12
|
+
matching a retired feature, agents reading only the model proposed **reviving** it 24 times
|
|
13
|
+
out of 24, each believing it was reusing. A retired feature is *more* attractive than a
|
|
14
|
+
live one: purpose-built for exactly the request, never complicated by production.
|
|
15
|
+
|
|
16
|
+
Leaving a dangling `implementedBy` on an `abandoned` or `superseded` requirement is
|
|
17
|
+
**correct** — those nodes are supposed to be gone, and `verify` allows it deliberately. On
|
|
18
|
+
`live` or `partial` the same dangling reference is an error: the model moved and the
|
|
19
|
+
requirement went stale.
|
|
20
|
+
|
|
21
|
+
**2. When you add an entity, claim it.** Every `object.entity` should appear in some
|
|
22
|
+
requirement's `implementedBy`, or `verify` says so.
|
|
23
|
+
|
|
24
|
+
**Every requirement states its violation.** One sentence: what breaking it looks like.
|
|
25
|
+
*"Every entity has a uuid primary key"* is violable — point at one with a composite string
|
|
26
|
+
key. *"Things are persisted"* is not, and is a description rather than a requirement. Same
|
|
27
|
+
rule kills *"the system is reliable"*. If you cannot say what breaking it looks like,
|
|
28
|
+
delete it.
|
|
29
|
+
|
|
30
|
+
**Hierarchy is nesting, and links live at the bottom.** L1 solution, L2 segment (an
|
|
31
|
+
application or library), L3 service — these never reference the model. **L4** binds an
|
|
32
|
+
object, **L5** binds a field, view or identity. `implementedBy` above L4 is an error.
|
|
33
|
+
Regrouping *moves* a node; it does not edit a parent string.
|
|
34
|
+
|
|
35
|
+
**Architectural requirements are the other kind.** `requirement.architectural` carries no
|
|
36
|
+
level — a uuid-PK rule, change attribution, tenant scoping. Its check is *universality*
|
|
37
|
+
rather than existence, so one that is `live` and claimed by nothing fails: a policy
|
|
38
|
+
declared and applied to nothing.
|
|
39
|
+
|
|
40
|
+
`@status` is a closed enum enforced by the loader, so a typo fails the load rather than
|
|
41
|
+
silently disabling the entry.
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
- requirement.functional:
|
|
45
|
+
name: Pacing
|
|
46
|
+
level: 3
|
|
47
|
+
status: live
|
|
48
|
+
statement: "Scene pacing follows story beats"
|
|
49
|
+
violation: "A scene that advances on a clock rather than on the story"
|
|
50
|
+
children:
|
|
51
|
+
- requirement.functional:
|
|
52
|
+
name: TurnTimer
|
|
53
|
+
level: 4
|
|
54
|
+
status: abandoned # retired deliberately -- do NOT revive
|
|
55
|
+
statement: "Pacing was driven by a per-turn wall-clock timer"
|
|
56
|
+
violation: "Pacing driven by elapsed time instead of beat completion"
|
|
57
|
+
supersededBy: BeatProgression
|
|
58
|
+
implementedBy: ["game::turn::TurnTimer"] # gone, and that is the point
|
|
59
|
+
|
|
60
|
+
- requirement.architectural:
|
|
61
|
+
name: UuidPrimaryKeys
|
|
62
|
+
status: live
|
|
63
|
+
statement: "Every entity has a uuid primary key"
|
|
64
|
+
violation: "An entity keyed by a composite string"
|
|
65
|
+
implementedBy: ["game::turn::Turn", "game::world::Location"]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
There is **no `satisfies:` on a field or entity** — links live on the requirement node, not
|
|
69
|
+
on the nodes it claims. Full reference: the repo's `spec/capability-ledger.md`.
|
|
@@ -13,6 +13,35 @@ truth. Its sibling is `metaobjects-audit` (POST-adoption; scaffolded). Design +
|
|
|
13
13
|
retro-test validation: `docs/superpowers/specs/2026-07-12-metaobjects-fit-assessment-design.md`.
|
|
14
14
|
How to run it: point a high-end LLM at a target repo + this file (e.g. paste it, or
|
|
15
15
|
fetch it from GitHub / metaobjects.dev) and let it produce the report below.
|
|
16
|
+
|
|
17
|
+
DEFERRED, ON PURPOSE — capability requirements (`requirement.functional` /
|
|
18
|
+
`requirement.architectural`). This skill deliberately says NOTHING about them, and that is a
|
|
19
|
+
decision, not an omission.
|
|
20
|
+
|
|
21
|
+
Why not now: (1) the grounding rule above requires every capability claim be verifiable
|
|
22
|
+
against the CURRENT RELEASE, and `requirement.*` is not in one yet. (2) The signal->feature
|
|
23
|
+
mapping is unvalidated against this skill's own kill criterion: the controlled evidence
|
|
24
|
+
(0/24 model-only revivals) measures POST-adoption model-reading, and the feature's premise --
|
|
25
|
+
that the disproof lives nowhere in the model -- cuts against pre-adoption detectability. If
|
|
26
|
+
the reasoning was never written down, there is nothing for an evidence-cited assessment to
|
|
27
|
+
cite. (3) Whether anyone fills the ledger in is itself untested; advertising it pre-adoption
|
|
28
|
+
is the brochure failure this skill exists to avoid.
|
|
29
|
+
|
|
30
|
+
TRIGGER to revisit — the release carrying `requirement.*` has shipped, AND either:
|
|
31
|
+
Arm A a dogfooded project's `abandoned`/`superseded` entries are shown, retrospectively,
|
|
32
|
+
to have been discoverable PRE-adoption from repo evidence at file:line standard
|
|
33
|
+
(removal commit, dead flag, do-not-reintroduce comment);
|
|
34
|
+
Arm B a team that adopted via this assessment hits a resurrection the ledger would have
|
|
35
|
+
caught, or asks why the assessment never mentioned it.
|
|
36
|
+
|
|
37
|
+
ANTI-TRIGGER (defer -> never): if dogfooded entries trace only to tribal knowledge with no
|
|
38
|
+
repo artifact, this assessment structurally cannot speak to the feature as a finding.
|
|
39
|
+
|
|
40
|
+
SHAPE, pre-committed so it is not re-litigated as new machinery: ONE P7 hunt line in the
|
|
41
|
+
existing grammar (observable signal -> vocabulary + metadata_sketch), gated like every other
|
|
42
|
+
P7 line by "if a hunt line has hits, it must appear" -- so a repo with no retirement scar
|
|
43
|
+
tissue produces zero requirements content. NOT a fifth pillar, NOT a P4 rubric row, NOT an
|
|
44
|
+
R0 verdict line: no verdict may turn on it.
|
|
16
45
|
-->
|
|
17
46
|
|
|
18
47
|
# MetaObjects Fit & Migration Assessment
|
|
@@ -66,6 +66,13 @@ paired with the advisory anti-pattern pass above, never all three subverbs. Trea
|
|
|
66
66
|
bare run as a smoke test: the real done-check is running the subverbs your project
|
|
67
67
|
uses explicitly — `verify --codegen`, and, where a DB exists, `verify --db <url>`.
|
|
68
68
|
|
|
69
|
+
## Requirements are checked on every run
|
|
70
|
+
|
|
71
|
+
If this project declares `requirement.functional` / `requirement.architectural` nodes, read
|
|
72
|
+
`references/requirements.md`: requirements are metadata, so they are checked on **every**
|
|
73
|
+
`meta verify` — there is no subverb — and the severity of a broken link depends on the
|
|
74
|
+
requirement's `@status`, which is the part that surprises people reading a failure.
|
|
75
|
+
|
|
69
76
|
## The `verify` subverbs
|
|
70
77
|
|
|
71
78
|
`verify` has three drift checks. Run them in CI.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Requirements — what `meta verify` checks
|
|
2
|
+
|
|
3
|
+
This project declares `requirement.*` nodes, so `verify` checks them. **There is no
|
|
4
|
+
subverb**: requirements are metadata, so they are checked on *every* `meta verify` run.
|
|
5
|
+
|
|
6
|
+
## The split, and why it matters when you read a failure
|
|
7
|
+
|
|
8
|
+
| | owns |
|
|
9
|
+
|---|---|
|
|
10
|
+
| **loader** | `@status` enum, required attrs, child rules, levels — unconditional |
|
|
11
|
+
| **`verify`** | `@implementedBy` / `@verifiedBy` resolution — **severity depends on `@status`** |
|
|
12
|
+
|
|
13
|
+
A typo'd `@status` fails the **load** ("failed to load metadata"), before verify runs. If you
|
|
14
|
+
see that, no other diagnostic in the run is trustworthy — fix it first and re-run.
|
|
15
|
+
|
|
16
|
+
## The status asymmetry — the one that surprises people
|
|
17
|
+
|
|
18
|
+
The **same** unresolved `@implementedBy` reference is:
|
|
19
|
+
|
|
20
|
+
- an **error** on `live` / `partial` — the model moved and the requirement is stale;
|
|
21
|
+
- **allowed** on `abandoned` / `superseded` — those nodes are *supposed* to be gone. That is
|
|
22
|
+
the entry doing its job, not drift.
|
|
23
|
+
|
|
24
|
+
So do not "fix" a dangling reference on an abandoned requirement by deleting it. Deleting it
|
|
25
|
+
destroys the record that something was deliberately retired, which is the single thing this
|
|
26
|
+
mechanism exists to preserve.
|
|
27
|
+
|
|
28
|
+
## Exit codes
|
|
29
|
+
|
|
30
|
+
| situation | exit |
|
|
31
|
+
|---|---|
|
|
32
|
+
| clean tree, or no `requirement.*` nodes at all | 0 |
|
|
33
|
+
| dangling `@implementedBy` on `live`/`partial` | 1 |
|
|
34
|
+
| the same reference on `abandoned`/`superseded` | 0 |
|
|
35
|
+
| `@implementedBy` above the L4 link floor | 1 |
|
|
36
|
+
| live `requirement.architectural` claimed by nothing | 1 |
|
|
37
|
+
| `@verifiedBy` naming a test that exists nowhere | 1 |
|
|
38
|
+
| `@verifiedBy` naming a test that is **skipped** | 0 (warning) |
|
|
39
|
+
| an entity no requirement claims | 0 (warning) |
|
|
40
|
+
|
|
41
|
+
## What a green run does NOT prove
|
|
42
|
+
|
|
43
|
+
It proves **referential integrity**: statuses parse, levels are in range, links sit at or
|
|
44
|
+
below the floor, references resolve, named tests exist and are not skipped.
|
|
45
|
+
|
|
46
|
+
It cannot prove a status is **true**, or that a node genuinely implements the requirement
|
|
47
|
+
claiming it. No test can. That judgement is yours.
|
|
48
|
+
|
|
49
|
+
Coverage is also narrower than the name suggests: it is checked at **entity grain only** —
|
|
50
|
+
`object.value` and `object.projection` are exempt, and fields, views, validators and
|
|
51
|
+
identities are never required to be claimed. Green means "every entity is claimed by
|
|
52
|
+
something", not "every node is described".
|
|
53
|
+
|
|
54
|
+
Full reference: the repo's `spec/capability-ledger.md`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/agent-context/assemble.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/agent-context/assemble.ts"],"names":[],"mappings":"AAEA,OAAO,EACyD,KAAK,aAAa,EAAE,KAAK,KAAK,EAC7F,MAAM,YAAY,CAAC;AAuCpB,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,aAAa,EAAE,CA0CrF"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { readFileSync, readdirSync, existsSync, statSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { SKILL_NAMES, SERVER_LANGS, CLIENT_FRAMEWORKS } from "./types.js";
|
|
4
|
-
// Language/framework reference fragments are stack-scoped; any other
|
|
5
|
-
// (e.g. capability-checklist) is universal and always installs.
|
|
6
|
-
|
|
3
|
+
import { SKILL_NAMES, SERVER_LANGS, CLIENT_FRAMEWORKS, CONCERN_TOKENS, } from "./types.js";
|
|
4
|
+
// Language/framework/concern reference fragments are stack-scoped; any other
|
|
5
|
+
// fragment (e.g. capability-checklist) is universal and always installs. Adding a
|
|
6
|
+
// future concern token to CONCERN_TOKENS (types.ts) is all that's needed to gate
|
|
7
|
+
// its matching references/<token>.md fragment here.
|
|
8
|
+
const SCOPED_FRAGMENT_TOKENS = new Set([...SERVER_LANGS, ...CLIENT_FRAMEWORKS, ...CONCERN_TOKENS]);
|
|
7
9
|
function readServerMeta(contentRoot, server) {
|
|
8
10
|
const p = join(contentRoot, "servers", `${server}.meta.json`);
|
|
9
11
|
if (!existsSync(p))
|
|
@@ -49,17 +51,18 @@ export function assemble(opts) {
|
|
|
49
51
|
out.push({ path: `.claude/skills/${skill}/SKILL.md`, contents: body });
|
|
50
52
|
const refDir = join(skillDir, "references");
|
|
51
53
|
if (existsSync(refDir) && statSync(refDir).isDirectory()) {
|
|
52
|
-
// Stack-scoped: a language/framework fragment installs only when its
|
|
53
|
-
// is in the resolved stack (Stack.tokens = servers ∪ clients ∪
|
|
54
|
-
// Non-
|
|
55
|
-
// install. Keeps each skill's references/ to what the
|
|
56
|
-
// so the SKILL.md "read every references/*.md" footer
|
|
54
|
+
// Stack-scoped: a language/framework/concern fragment installs only when its
|
|
55
|
+
// token is in the resolved stack (Stack.tokens = servers ∪ clients ∪ concerns
|
|
56
|
+
// ∪ {migration}). Non-scoped fragments (e.g. capability-checklist) are
|
|
57
|
+
// universal and always install. Keeps each skill's references/ to what the
|
|
58
|
+
// project actually uses, so the SKILL.md "read every references/*.md" footer
|
|
59
|
+
// stays accurate.
|
|
57
60
|
const refs = readdirSync(refDir)
|
|
58
61
|
.filter((f) => f.endsWith(".md"))
|
|
59
62
|
.map((f) => f.replace(/\.md$/, ""))
|
|
60
63
|
.sort();
|
|
61
64
|
for (const token of refs) {
|
|
62
|
-
if (
|
|
65
|
+
if (SCOPED_FRAGMENT_TOKENS.has(token) && !stack.tokens.has(token))
|
|
63
66
|
continue;
|
|
64
67
|
out.push({
|
|
65
68
|
path: `.claude/skills/${skill}/references/${token}.md`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/agent-context/assemble.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,
|
|
1
|
+
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/agent-context/assemble.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import { type ServerLang, type ClientFramework, type Stack } from "./types.js";
|
|
1
|
+
import { type ServerLang, type ClientFramework, type ConcernToken, type Stack } from "./types.js";
|
|
2
2
|
export interface ProjectProbe {
|
|
3
3
|
hasDep(name: string): boolean;
|
|
4
4
|
hasFileMatching(pattern: RegExp): boolean;
|
|
5
|
+
/** True if the project's declared metadata contains at least one `requirement.*` node. */
|
|
6
|
+
hasRequirementNodes(): boolean;
|
|
5
7
|
}
|
|
6
|
-
export declare function makeStack(servers: ServerLang[], clients: ClientFramework[]): Stack;
|
|
8
|
+
export declare function makeStack(servers: ServerLang[], clients: ClientFramework[], concerns?: ConcernToken[]): Stack;
|
|
7
9
|
/** Best-effort detection from a project probe. Always overridable; a wrong guess
|
|
8
10
|
* writes an extra fragment, never a wrong one (callers confirm before scaffolding). */
|
|
9
11
|
export declare function detectStack(probe: ProjectProbe): {
|
|
10
12
|
servers: ServerLang[];
|
|
11
13
|
clients: ClientFramework[];
|
|
12
14
|
};
|
|
15
|
+
/** Best-effort concern detection — OBSERVED project state, never a config flag.
|
|
16
|
+
* Independent of servers/clients: a project's use of a capability doesn't depend
|
|
17
|
+
* on which server language or client framework it runs. */
|
|
18
|
+
export declare function detectConcerns(probe: ProjectProbe): ConcernToken[];
|
|
13
19
|
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/agent-context/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/agent-context/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,KAAK,KAAK,EACrE,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1C,0FAA0F;IAC1F,mBAAmB,IAAI,OAAO,CAAC;CAChC;AAED,wBAAgB,SAAS,CACvB,OAAO,EAAE,UAAU,EAAE,EACrB,OAAO,EAAE,eAAe,EAAE,EAC1B,QAAQ,GAAE,YAAY,EAAO,GAC5B,KAAK,CAKP;AAED;uFACuF;AACvF,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG;IAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,OAAO,EAAE,eAAe,EAAE,CAAA;CAAE,CActG;AAED;;2DAE2D;AAC3D,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,EAAE,CAIlE"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { SERVER_LANGS, CLIENT_FRAMEWORKS, MIGRATION_TOKEN, } from "./types.js";
|
|
2
|
-
export function makeStack(servers, clients) {
|
|
1
|
+
import { SERVER_LANGS, CLIENT_FRAMEWORKS, CONCERN_TOKENS, MIGRATION_TOKEN, } from "./types.js";
|
|
2
|
+
export function makeStack(servers, clients, concerns = []) {
|
|
3
3
|
const s = SERVER_LANGS.filter((x) => servers.includes(x));
|
|
4
4
|
const c = CLIENT_FRAMEWORKS.filter((x) => clients.includes(x));
|
|
5
|
-
|
|
5
|
+
const k = CONCERN_TOKENS.filter((x) => concerns.includes(x));
|
|
6
|
+
return { servers: s, clients: c, concerns: k, tokens: new Set([...s, ...c, ...k, MIGRATION_TOKEN]) };
|
|
6
7
|
}
|
|
7
8
|
/** Best-effort detection from a project probe. Always overridable; a wrong guess
|
|
8
9
|
* writes an extra fragment, never a wrong one (callers confirm before scaffolding). */
|
|
@@ -27,4 +28,13 @@ export function detectStack(probe) {
|
|
|
27
28
|
clients.push("angular");
|
|
28
29
|
return { servers, clients };
|
|
29
30
|
}
|
|
31
|
+
/** Best-effort concern detection — OBSERVED project state, never a config flag.
|
|
32
|
+
* Independent of servers/clients: a project's use of a capability doesn't depend
|
|
33
|
+
* on which server language or client framework it runs. */
|
|
34
|
+
export function detectConcerns(probe) {
|
|
35
|
+
const concerns = [];
|
|
36
|
+
if (probe.hasRequirementNodes())
|
|
37
|
+
concerns.push("requirements");
|
|
38
|
+
return concerns;
|
|
39
|
+
}
|
|
30
40
|
//# sourceMappingURL=resolve.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/agent-context/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAAE,iBAAiB,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/agent-context/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe,GAEjE,MAAM,YAAY,CAAC;AASpB,MAAM,UAAU,SAAS,CACvB,OAAqB,EACrB,OAA0B,EAC1B,WAA2B,EAAE;IAE7B,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,GAAG,CAAS,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC;AAC/G,CAAC;AAED;uFACuF;AACvF,MAAM,UAAU,WAAW,CAAC,KAAmB;IAC7C,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,4BAA4B,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAClH,IAAI,KAAK,CAAC,eAAe,CAAC,8BAA8B,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAClF,IAAI,KAAK,CAAC,eAAe,CAAC,iBAAiB,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnE,IAAI,KAAK,CAAC,eAAe,CAAC,WAAW,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/D,IAAI,KAAK,CAAC,eAAe,CAAC,oCAAoC,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAExF,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,IAAI,KAAK,CAAC,MAAM,CAAC,uBAAuB,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjE,IAAI,KAAK,CAAC,MAAM,CAAC,0BAA0B,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvE,IAAI,KAAK,CAAC,MAAM,CAAC,yBAAyB,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAErE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED;;2DAE2D;AAC3D,MAAM,UAAU,cAAc,CAAC,KAAmB;IAChD,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,IAAI,KAAK,CAAC,mBAAmB,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC/D,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -2,6 +2,14 @@ export declare const SERVER_LANGS: readonly ["typescript", "java", "kotlin", "cs
|
|
|
2
2
|
export type ServerLang = (typeof SERVER_LANGS)[number];
|
|
3
3
|
export declare const CLIENT_FRAMEWORKS: readonly ["react", "tanstack", "angular"];
|
|
4
4
|
export type ClientFramework = (typeof CLIENT_FRAMEWORKS)[number];
|
|
5
|
+
/**
|
|
6
|
+
* Opt-in capability concerns, detected from OBSERVED project state (never a config
|
|
7
|
+
* flag — a flag goes stale, observed metadata cannot). Each token gates a
|
|
8
|
+
* `references/<token>.md` fragment the same way a language/framework token does.
|
|
9
|
+
* Add a new concern here; nothing else in the assembler needs to change.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CONCERN_TOKENS: readonly ["requirements"];
|
|
12
|
+
export type ConcernToken = (typeof CONCERN_TOKENS)[number];
|
|
5
13
|
/** Always-present token: schema migrations are TS-owned for every port (ADR-0015). */
|
|
6
14
|
export declare const MIGRATION_TOKEN = "migration";
|
|
7
15
|
export declare const SKILL_NAMES: readonly ["metaobjects-authoring", "metaobjects-codegen", "metaobjects-runtime-ui", "metaobjects-prompts", "metaobjects-verify", "metaobjects-audit"];
|
|
@@ -10,7 +18,8 @@ export type SkillName = (typeof SKILL_NAMES)[number];
|
|
|
10
18
|
export interface Stack {
|
|
11
19
|
servers: ServerLang[];
|
|
12
20
|
clients: ClientFramework[];
|
|
13
|
-
|
|
21
|
+
concerns: ConcernToken[];
|
|
22
|
+
/** servers ∪ clients ∪ concerns ∪ {"migration"} — the install-selection set for reference fragments. */
|
|
14
23
|
tokens: ReadonlySet<string>;
|
|
15
24
|
}
|
|
16
25
|
/** A file the assembler emits, path relative to the consumer project root. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agent-context/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,+DAAgE,CAAC;AAC1F,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,eAAO,MAAM,iBAAiB,2CAA4C,CAAC;AAC3E,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE,sFAAsF;AACtF,eAAO,MAAM,eAAe,cAAc,CAAC;AAE3C,eAAO,MAAM,WAAW,uJAOd,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,qDAAqD;AACrD,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agent-context/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,+DAAgE,CAAC;AAC1F,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,eAAO,MAAM,iBAAiB,2CAA4C,CAAC;AAC3E,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,cAAc,2BAA4B,CAAC;AACxD,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,sFAAsF;AACtF,eAAO,MAAM,eAAe,cAAc,CAAC;AAE3C,eAAO,MAAM,WAAW,uJAOd,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,qDAAqD;AACrD,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,wGAAwG;IACxG,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export const SERVER_LANGS = ["typescript", "java", "kotlin", "csharp", "python"];
|
|
2
2
|
export const CLIENT_FRAMEWORKS = ["react", "tanstack", "angular"];
|
|
3
|
+
/**
|
|
4
|
+
* Opt-in capability concerns, detected from OBSERVED project state (never a config
|
|
5
|
+
* flag — a flag goes stale, observed metadata cannot). Each token gates a
|
|
6
|
+
* `references/<token>.md` fragment the same way a language/framework token does.
|
|
7
|
+
* Add a new concern here; nothing else in the assembler needs to change.
|
|
8
|
+
*/
|
|
9
|
+
export const CONCERN_TOKENS = ["requirements"];
|
|
3
10
|
/** Always-present token: schema migrations are TS-owned for every port (ADR-0015). */
|
|
4
11
|
export const MIGRATION_TOKEN = "migration";
|
|
5
12
|
export const SKILL_NAMES = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agent-context/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAG1F,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAU,CAAC;AAG3E,sFAAsF;AACtF,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAE3C,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,uBAAuB;IACvB,qBAAqB;IACrB,wBAAwB;IACxB,qBAAqB;IACrB,oBAAoB;IACpB,mBAAmB;CACX,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agent-context/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAG1F,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAU,CAAC;AAG3E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,cAAc,CAAU,CAAC;AAGxD,sFAAsF;AACtF,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAE3C,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,uBAAuB;IACvB,qBAAqB;IACrB,wBAAwB;IACxB,qBAAqB;IACrB,oBAAoB;IACpB,mBAAmB;CACX,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0-rc.1",
|
|
4
4
|
"description": "Workspace helpers and agent-docs utilities for MetaObjects projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"access": "public"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@metaobjectsdev/metadata": "0.
|
|
59
|
+
"@metaobjectsdev/metadata": "0.22.0-rc.1",
|
|
60
60
|
"zod": "^3.23.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
@@ -17,8 +17,9 @@ for (const name of readdirSync(CORPUS)) {
|
|
|
17
17
|
const spec = JSON.parse(readFileSync(join(dir, "stack.json"), "utf8")) as {
|
|
18
18
|
servers: string[];
|
|
19
19
|
clients: string[];
|
|
20
|
+
concerns?: string[];
|
|
20
21
|
};
|
|
21
|
-
const stack = makeStack(spec.servers as never, spec.clients as never);
|
|
22
|
+
const stack = makeStack(spec.servers as never, spec.clients as never, (spec.concerns ?? []) as never);
|
|
22
23
|
const files = assemble({ contentRoot: CONTENT_ROOT, stack });
|
|
23
24
|
const expDir = join(dir, "expected");
|
|
24
25
|
rmSync(expDir, { recursive: true, force: true });
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { readFileSync, readdirSync, existsSync, statSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
SKILL_NAMES, SERVER_LANGS, CLIENT_FRAMEWORKS, CONCERN_TOKENS, type AssembledFile, type Stack,
|
|
5
|
+
} from "./types.js";
|
|
4
6
|
|
|
5
|
-
// Language/framework reference fragments are stack-scoped; any other
|
|
6
|
-
// (e.g. capability-checklist) is universal and always installs.
|
|
7
|
-
|
|
7
|
+
// Language/framework/concern reference fragments are stack-scoped; any other
|
|
8
|
+
// fragment (e.g. capability-checklist) is universal and always installs. Adding a
|
|
9
|
+
// future concern token to CONCERN_TOKENS (types.ts) is all that's needed to gate
|
|
10
|
+
// its matching references/<token>.md fragment here.
|
|
11
|
+
const SCOPED_FRAGMENT_TOKENS = new Set<string>([...SERVER_LANGS, ...CLIENT_FRAMEWORKS, ...CONCERN_TOKENS]);
|
|
8
12
|
|
|
9
13
|
interface ServerMeta { displayName: string; install: string; codegenCommand: string; }
|
|
10
14
|
|
|
@@ -57,17 +61,18 @@ export function assemble(opts: { contentRoot: string; stack: Stack }): Assembled
|
|
|
57
61
|
|
|
58
62
|
const refDir = join(skillDir, "references");
|
|
59
63
|
if (existsSync(refDir) && statSync(refDir).isDirectory()) {
|
|
60
|
-
// Stack-scoped: a language/framework fragment installs only when its
|
|
61
|
-
// is in the resolved stack (Stack.tokens = servers ∪ clients ∪
|
|
62
|
-
// Non-
|
|
63
|
-
// install. Keeps each skill's references/ to what the
|
|
64
|
-
// so the SKILL.md "read every references/*.md" footer
|
|
64
|
+
// Stack-scoped: a language/framework/concern fragment installs only when its
|
|
65
|
+
// token is in the resolved stack (Stack.tokens = servers ∪ clients ∪ concerns
|
|
66
|
+
// ∪ {migration}). Non-scoped fragments (e.g. capability-checklist) are
|
|
67
|
+
// universal and always install. Keeps each skill's references/ to what the
|
|
68
|
+
// project actually uses, so the SKILL.md "read every references/*.md" footer
|
|
69
|
+
// stays accurate.
|
|
65
70
|
const refs = readdirSync(refDir)
|
|
66
71
|
.filter((f) => f.endsWith(".md"))
|
|
67
72
|
.map((f) => f.replace(/\.md$/, ""))
|
|
68
73
|
.sort();
|
|
69
74
|
for (const token of refs) {
|
|
70
|
-
if (
|
|
75
|
+
if (SCOPED_FRAGMENT_TOKENS.has(token) && !stack.tokens.has(token)) continue;
|
|
71
76
|
out.push({
|
|
72
77
|
path: `.claude/skills/${skill}/references/${token}.md`,
|
|
73
78
|
contents: readFileSync(join(refDir, `${token}.md`), "utf8"),
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
|
-
SERVER_LANGS, CLIENT_FRAMEWORKS, MIGRATION_TOKEN,
|
|
3
|
-
type ServerLang, type ClientFramework, type Stack,
|
|
2
|
+
SERVER_LANGS, CLIENT_FRAMEWORKS, CONCERN_TOKENS, MIGRATION_TOKEN,
|
|
3
|
+
type ServerLang, type ClientFramework, type ConcernToken, type Stack,
|
|
4
4
|
} from "./types.js";
|
|
5
5
|
|
|
6
6
|
export interface ProjectProbe {
|
|
7
7
|
hasDep(name: string): boolean;
|
|
8
8
|
hasFileMatching(pattern: RegExp): boolean;
|
|
9
|
+
/** True if the project's declared metadata contains at least one `requirement.*` node. */
|
|
10
|
+
hasRequirementNodes(): boolean;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
export function makeStack(
|
|
13
|
+
export function makeStack(
|
|
14
|
+
servers: ServerLang[],
|
|
15
|
+
clients: ClientFramework[],
|
|
16
|
+
concerns: ConcernToken[] = [],
|
|
17
|
+
): Stack {
|
|
12
18
|
const s = SERVER_LANGS.filter((x) => servers.includes(x));
|
|
13
19
|
const c = CLIENT_FRAMEWORKS.filter((x) => clients.includes(x));
|
|
14
|
-
|
|
20
|
+
const k = CONCERN_TOKENS.filter((x) => concerns.includes(x));
|
|
21
|
+
return { servers: s, clients: c, concerns: k, tokens: new Set<string>([...s, ...c, ...k, MIGRATION_TOKEN]) };
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
/** Best-effort detection from a project probe. Always overridable; a wrong guess
|
|
@@ -31,3 +38,12 @@ export function detectStack(probe: ProjectProbe): { servers: ServerLang[]; clien
|
|
|
31
38
|
|
|
32
39
|
return { servers, clients };
|
|
33
40
|
}
|
|
41
|
+
|
|
42
|
+
/** Best-effort concern detection — OBSERVED project state, never a config flag.
|
|
43
|
+
* Independent of servers/clients: a project's use of a capability doesn't depend
|
|
44
|
+
* on which server language or client framework it runs. */
|
|
45
|
+
export function detectConcerns(probe: ProjectProbe): ConcernToken[] {
|
|
46
|
+
const concerns: ConcernToken[] = [];
|
|
47
|
+
if (probe.hasRequirementNodes()) concerns.push("requirements");
|
|
48
|
+
return concerns;
|
|
49
|
+
}
|
|
@@ -4,6 +4,15 @@ export type ServerLang = (typeof SERVER_LANGS)[number];
|
|
|
4
4
|
export const CLIENT_FRAMEWORKS = ["react", "tanstack", "angular"] as const;
|
|
5
5
|
export type ClientFramework = (typeof CLIENT_FRAMEWORKS)[number];
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Opt-in capability concerns, detected from OBSERVED project state (never a config
|
|
9
|
+
* flag — a flag goes stale, observed metadata cannot). Each token gates a
|
|
10
|
+
* `references/<token>.md` fragment the same way a language/framework token does.
|
|
11
|
+
* Add a new concern here; nothing else in the assembler needs to change.
|
|
12
|
+
*/
|
|
13
|
+
export const CONCERN_TOKENS = ["requirements"] as const;
|
|
14
|
+
export type ConcernToken = (typeof CONCERN_TOKENS)[number];
|
|
15
|
+
|
|
7
16
|
/** Always-present token: schema migrations are TS-owned for every port (ADR-0015). */
|
|
8
17
|
export const MIGRATION_TOKEN = "migration";
|
|
9
18
|
|
|
@@ -21,7 +30,8 @@ export type SkillName = (typeof SKILL_NAMES)[number];
|
|
|
21
30
|
export interface Stack {
|
|
22
31
|
servers: ServerLang[]; // deduped, in SERVER_LANGS order
|
|
23
32
|
clients: ClientFramework[]; // deduped, in CLIENT_FRAMEWORKS order
|
|
24
|
-
|
|
33
|
+
concerns: ConcernToken[]; // deduped, in CONCERN_TOKENS order — observed capability usage
|
|
34
|
+
/** servers ∪ clients ∪ concerns ∪ {"migration"} — the install-selection set for reference fragments. */
|
|
25
35
|
tokens: ReadonlySet<string>;
|
|
26
36
|
}
|
|
27
37
|
|