@metaobjectsdev/sdk 0.24.4 → 0.25.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 +1 -7
- package/agent-context/servers/csharp.meta.json +3 -1
- package/agent-context/servers/java.meta.json +3 -1
- package/agent-context/servers/kotlin.meta.json +3 -1
- package/agent-context/servers/python.meta.json +3 -1
- package/agent-context/servers/typescript.meta.json +3 -1
- package/agent-context/skills/metaobjects-audit/SKILL.md +15 -8
- package/agent-context/skills/metaobjects-audit/references/capability-checklist.md +6 -1
- package/agent-context/skills/metaobjects-audit/references/csharp.md +10 -1
- package/agent-context/skills/metaobjects-audit/references/java.md +10 -0
- package/agent-context/skills/metaobjects-audit/references/kotlin.md +11 -0
- package/agent-context/skills/metaobjects-audit/references/python.md +12 -2
- package/agent-context/skills/metaobjects-audit/references/typescript.md +7 -2
- package/agent-context/skills/metaobjects-authoring/SKILL.md +35 -6
- package/agent-context/skills/metaobjects-codegen/SKILL.md +249 -10
- package/agent-context/skills/metaobjects-codegen/references/csharp.md +1 -0
- package/agent-context/skills/metaobjects-codegen/references/java.md +1 -0
- package/agent-context/skills/metaobjects-codegen/references/kotlin.md +1 -0
- package/agent-context/skills/metaobjects-codegen/references/python.md +1 -0
- package/agent-context/skills/metaobjects-codegen/references/typescript.md +190 -6
- package/agent-context/skills/metaobjects-prompts/references/typescript.md +10 -1
- package/agent-context/skills/metaobjects-runtime-ui/SKILL.md +22 -0
- package/agent-context/skills/metaobjects-runtime-ui/references/csharp.md +15 -0
- package/agent-context/skills/metaobjects-runtime-ui/references/java.md +33 -0
- package/agent-context/skills/metaobjects-runtime-ui/references/kotlin.md +23 -0
- package/agent-context/skills/metaobjects-runtime-ui/references/python.md +25 -0
- package/agent-context/skills/metaobjects-runtime-ui/references/tanstack.md +34 -7
- package/agent-context/skills/metaobjects-runtime-ui/references/typescript.md +20 -0
- package/agent-context/skills/metaobjects-verify/SKILL.md +28 -0
- package/agent-context/templates/always-on.md.mustache +45 -4
- package/dist/agent-context/assemble.d.ts.map +1 -1
- package/dist/agent-context/assemble.js +52 -4
- package/dist/agent-context/assemble.js.map +1 -1
- package/dist/agent-context/scaffold.d.ts +16 -1
- package/dist/agent-context/scaffold.d.ts.map +1 -1
- package/dist/agent-context/scaffold.js +81 -4
- package/dist/agent-context/scaffold.js.map +1 -1
- package/dist/forge-types.d.ts.map +1 -1
- package/dist/forge-types.js +19 -1
- package/dist/forge-types.js.map +1 -1
- package/package.json +4 -9
- package/src/agent-context/assemble.ts +86 -6
- package/src/agent-context/scaffold.ts +91 -5
- package/src/forge-types.ts +21 -0
- package/dist/agent-docs/body.d.ts +0 -6
- package/dist/agent-docs/body.d.ts.map +0 -1
- package/dist/agent-docs/body.js +0 -593
- package/dist/agent-docs/body.js.map +0 -1
- package/dist/agent-docs/content-hash.d.ts +0 -8
- package/dist/agent-docs/content-hash.d.ts.map +0 -1
- package/dist/agent-docs/content-hash.js +0 -23
- package/dist/agent-docs/content-hash.js.map +0 -1
- package/dist/agent-docs/index.d.ts +0 -3
- package/dist/agent-docs/index.d.ts.map +0 -1
- package/dist/agent-docs/index.js +0 -4
- package/dist/agent-docs/index.js.map +0 -1
- package/src/agent-docs/body.ts +0 -592
- package/src/agent-docs/content-hash.ts +0 -25
- package/src/agent-docs/index.ts +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/agent-context/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,mFAAmF;AACnF,MAAM,CAAC,MAAM,2BAA2B,GAAG,kCAAkC,CAAC;AAiB9E,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/agent-context/scaffold.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forge-types.d.ts","sourceRoot":"","sources":["../src/forge-types.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAC9C,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAChD,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAClD,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAC9C,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C,eAAO,MAAM,WAAW,yEAMd,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAMrD,eAAO,MAAM,uBAAuB,uCAAwC,CAAC;AAC7E,eAAO,MAAM,wBAAwB,2CAA4C,CAAC;AAClF,eAAO,MAAM,yBAAyB,mBAAoB,CAAC;AAC3D,eAAO,MAAM,uBAAuB,mBAAoB,CAAC;AACzD,eAAO,MAAM,sBAAsB,mBAAoB,CAAC;AAOxD,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AACvD,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAC/C,eAAO,MAAM,sBAAsB,oBAAoB,CAAC;AACxD,eAAO,MAAM,gCAAgC,6BAA6B,CAAC;AAG3E,eAAO,MAAM,2BAA2B,yBAAyB,CAAC;AAClE,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAGzD,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AACrD,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAC3D,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAG7C,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AACrD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAGzD,eAAO,MAAM,8BAA8B,4BAA4B,CAAC;AACxE,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,2BAA2B,yBAAyB,CAAC;AAClE,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAGtD,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AACvD,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAC1D,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAGlD,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAC7D,eAAO,MAAM,wBAAwB,qBAAqB,CAAC;AAE3D,eAAO,MAAM,WAAW,ubAuBd,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAMrD,OAAO,EAGL,KAAK,oBAAoB,EAGzB,YAAY,
|
|
1
|
+
{"version":3,"file":"forge-types.d.ts","sourceRoot":"","sources":["../src/forge-types.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAC9C,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAChD,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAClD,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAC9C,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C,eAAO,MAAM,WAAW,yEAMd,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAMrD,eAAO,MAAM,uBAAuB,uCAAwC,CAAC;AAC7E,eAAO,MAAM,wBAAwB,2CAA4C,CAAC;AAClF,eAAO,MAAM,yBAAyB,mBAAoB,CAAC;AAC3D,eAAO,MAAM,uBAAuB,mBAAoB,CAAC;AACzD,eAAO,MAAM,sBAAsB,mBAAoB,CAAC;AAOxD,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AACvD,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAC/C,eAAO,MAAM,sBAAsB,oBAAoB,CAAC;AACxD,eAAO,MAAM,gCAAgC,6BAA6B,CAAC;AAG3E,eAAO,MAAM,2BAA2B,yBAAyB,CAAC;AAClE,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAGzD,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AACrD,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAC3D,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAG7C,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AACrD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAGzD,eAAO,MAAM,8BAA8B,4BAA4B,CAAC;AACxE,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,2BAA2B,yBAAyB,CAAC;AAClE,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAGtD,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AACvD,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAC1D,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAGlD,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAC7D,eAAO,MAAM,wBAAwB,qBAAqB,CAAC;AAE3D,eAAO,MAAM,WAAW,ubAuBd,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAMrD,OAAO,EAGL,KAAK,oBAAoB,EAGzB,YAAY,EAOb,MAAM,0BAA0B,CAAC;AA0ClC;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,oBAwDhC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAE/D"}
|
package/dist/forge-types.js
CHANGED
|
@@ -84,7 +84,7 @@ export const FORGE_ATTRS = [
|
|
|
84
84
|
// ---------------------------------------------------------------------------
|
|
85
85
|
// registerForgeTypes
|
|
86
86
|
// ---------------------------------------------------------------------------
|
|
87
|
-
import { TypeId, TypeRegistry, MetaData, TYPE_ATTR, TYPE_METADATA, SUBTYPE_ROOT, CHILD_RULE_WILDCARD, } from "@metaobjectsdev/metadata";
|
|
87
|
+
import { TypeId, TypeRegistry, MetaData, TYPE_ATTR, TYPE_METADATA, SUBTYPE_ROOT, SUBTYPE_BASE, CHILD_RULE_WILDCARD, } from "@metaobjectsdev/metadata";
|
|
88
88
|
/** Minimal concrete MetaData subclass used for all forge descriptive nodes. */
|
|
89
89
|
class ForgeNode extends MetaData {
|
|
90
90
|
}
|
|
@@ -147,6 +147,24 @@ export const forgeTypesProvider = {
|
|
|
147
147
|
for (const subType of FORGE_FAILURE_SUBTYPES) {
|
|
148
148
|
registry.register(def(FORGE_TYPE_FAILURE, subType, `Forge failure record (${subType})`, forgeChildRules));
|
|
149
149
|
}
|
|
150
|
+
// A BARE wrapper key (`{ "decision": … }`) resolves to the type's DECLARED default —
|
|
151
|
+
// the same accessor the YAML desugar has always used, which core declares for `object`
|
|
152
|
+
// (`object` → `object.entity`). The forge types are authored bare in memory files, with
|
|
153
|
+
// the subType in the body, so each declares its first member as its default.
|
|
154
|
+
//
|
|
155
|
+
// This used to work by accident: the JSON parsers GUESSED at registration order
|
|
156
|
+
// (`allSubTypesOf()[0]`) rather than asking the registry, and for a single-subtype type
|
|
157
|
+
// the guess happened to be right. Declaring the default makes it true on purpose, and
|
|
158
|
+
// survives someone registering a second subtype ahead of it.
|
|
159
|
+
// The first CONCRETE member where there is one, else the type's only member. `decision`
|
|
160
|
+
// and `principle` list `base` first with real siblings after it, so `[0]` would declare
|
|
161
|
+
// the anchor as the default — the very thing a bare key must not resolve to.
|
|
162
|
+
const concreteDefault = (subs) => subs.find((sub) => sub !== SUBTYPE_BASE) ?? subs[0];
|
|
163
|
+
registry.setDefaultSubType(FORGE_TYPE_DECISION, concreteDefault(FORGE_DECISION_SUBTYPES));
|
|
164
|
+
registry.setDefaultSubType(FORGE_TYPE_PRINCIPLE, concreteDefault(FORGE_PRINCIPLE_SUBTYPES));
|
|
165
|
+
registry.setDefaultSubType(FORGE_TYPE_CONVENTION, concreteDefault(FORGE_CONVENTION_SUBTYPES));
|
|
166
|
+
registry.setDefaultSubType(FORGE_TYPE_GLOSSARY, concreteDefault(FORGE_GLOSSARY_SUBTYPES));
|
|
167
|
+
registry.setDefaultSubType(FORGE_TYPE_FAILURE, concreteDefault(FORGE_FAILURE_SUBTYPES));
|
|
150
168
|
// #96 — the @forge* provenance attrs are common (admissible on any node).
|
|
151
169
|
registry.registerCommonAttrs([...FORGE_ATTR_SCHEMAS]);
|
|
152
170
|
// FR-033 / #96 — admit the forge descriptive types as top-level children of
|
package/dist/forge-types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forge-types.js","sourceRoot":"","sources":["../src/forge-types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"forge-types.js","sourceRoot":"","sources":["../src/forge-types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Workspace helpers and agent-
|
|
3
|
+
"version": "0.25.0",
|
|
4
|
+
"description": "Workspace helpers and agent-context assembly for MetaObjects projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -11,11 +11,6 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"default": "./dist/index.js"
|
|
13
13
|
},
|
|
14
|
-
"./agent-docs": {
|
|
15
|
-
"bun": "./src/agent-docs/index.ts",
|
|
16
|
-
"types": "./dist/agent-docs/index.d.ts",
|
|
17
|
-
"default": "./dist/agent-docs/index.js"
|
|
18
|
-
},
|
|
19
14
|
"./agent-context": {
|
|
20
15
|
"bun": "./src/agent-context/index.ts",
|
|
21
16
|
"types": "./dist/agent-context/index.d.ts",
|
|
@@ -49,14 +44,14 @@
|
|
|
49
44
|
"keywords": [
|
|
50
45
|
"metaobjects",
|
|
51
46
|
"sdk",
|
|
52
|
-
"agent-
|
|
47
|
+
"agent-context",
|
|
53
48
|
"workspace"
|
|
54
49
|
],
|
|
55
50
|
"publishConfig": {
|
|
56
51
|
"access": "public"
|
|
57
52
|
},
|
|
58
53
|
"dependencies": {
|
|
59
|
-
"@metaobjectsdev/metadata": "0.
|
|
54
|
+
"@metaobjectsdev/metadata": "0.25.0",
|
|
60
55
|
"zod": "^3.23.0"
|
|
61
56
|
},
|
|
62
57
|
"devDependencies": {
|
|
@@ -10,7 +10,22 @@ import {
|
|
|
10
10
|
// its matching references/<token>.md fragment here.
|
|
11
11
|
const SCOPED_FRAGMENT_TOKENS = new Set<string>([...SERVER_LANGS, ...CLIENT_FRAMEWORKS, ...CONCERN_TOKENS]);
|
|
12
12
|
|
|
13
|
-
interface ServerMeta {
|
|
13
|
+
interface ServerMeta {
|
|
14
|
+
displayName: string;
|
|
15
|
+
install: string;
|
|
16
|
+
codegenCommand: string;
|
|
17
|
+
/** The command that writes THIS port's api docs — `mvn metaobjects:docs`, `metaobjects
|
|
18
|
+
* docs`, `dotnet meta docs`, `meta docs`. Named per server because the always-on
|
|
19
|
+
* pointer tells a reader to run it, and a pointer naming a command the stack does not
|
|
20
|
+
* have is worse than no pointer. */
|
|
21
|
+
docsCommand: string;
|
|
22
|
+
/** The docs-root-relative directory THIS port's docs command writes its api pages into.
|
|
23
|
+
* It is NOT `api` outside TypeScript — Python defaults to `api/python`, C# to
|
|
24
|
+
* `api/csharp`, the Maven plugin to `api/<lang>` — so a pointer naming `api/AGENT-API.md`
|
|
25
|
+
* to a Python project sends a reader to a path that does not exist. Naming the command
|
|
26
|
+
* correctly and the FILE wrongly is the same defect one field over. */
|
|
27
|
+
apiSubDir: string;
|
|
28
|
+
}
|
|
14
29
|
|
|
15
30
|
function readServerMeta(contentRoot: string, server: string): ServerMeta | undefined {
|
|
16
31
|
const p = join(contentRoot, "servers", `${server}.meta.json`);
|
|
@@ -18,7 +33,10 @@ function readServerMeta(contentRoot: string, server: string): ServerMeta | undef
|
|
|
18
33
|
return JSON.parse(readFileSync(p, "utf8")) as ServerMeta;
|
|
19
34
|
}
|
|
20
35
|
|
|
21
|
-
function stackLine(
|
|
36
|
+
function stackLine(
|
|
37
|
+
contentRoot: string,
|
|
38
|
+
stack: Stack,
|
|
39
|
+
): { line: string; codegenCommand: string; docsCommand: string; apiSubDir: string } {
|
|
22
40
|
const primary = stack.servers[0];
|
|
23
41
|
const meta = primary ? readServerMeta(contentRoot, primary) : undefined;
|
|
24
42
|
const serverPart = stack.servers.length ? stack.servers.join(", ") + " server" : "no server";
|
|
@@ -31,11 +49,69 @@ function stackLine(contentRoot: string, stack: Stack): { line: string; codegenCo
|
|
|
31
49
|
// fragment carries the project-agnostic how. See issue #1.
|
|
32
50
|
line: `Stack: ${serverPart}, ${clientPart}.`,
|
|
33
51
|
codegenCommand: meta ? meta.codegenCommand : "meta gen",
|
|
52
|
+
docsCommand: meta ? meta.docsCommand : "meta docs",
|
|
53
|
+
apiSubDir: meta ? meta.apiSubDir : "api",
|
|
34
54
|
};
|
|
35
55
|
}
|
|
36
56
|
|
|
37
|
-
|
|
38
|
-
|
|
57
|
+
/**
|
|
58
|
+
* True when this stack runs the Node `meta` toolchain over a `metaobjects.config.ts`.
|
|
59
|
+
*
|
|
60
|
+
* This is the condition for the `agent/` docs surface EXISTING AT ALL: `meta docs` gates
|
|
61
|
+
* those three pages on a loadable gen config, because the physical names, the dialect and
|
|
62
|
+
* the view dispatch all come from it. A TypeScript server has one; so does any stack
|
|
63
|
+
* declaring a web CLIENT, because the React/TanStack tiers are generated by `meta gen`
|
|
64
|
+
* whatever the backend is. A port-only stack (java alone, python alone) has none, and for
|
|
65
|
+
* it the pointer must name only the one file its own docs command writes.
|
|
66
|
+
*
|
|
67
|
+
* The pointer landed verbatim in every stack before this existed, so a Python project was
|
|
68
|
+
* told to read four files that cannot exist and to run a command that cannot make them —
|
|
69
|
+
* on the one page an agent is told to trust.
|
|
70
|
+
*/
|
|
71
|
+
function hasNodeDocsSurface(stack: Stack): boolean {
|
|
72
|
+
return stack.servers.includes("typescript") || stack.clients.length > 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Substitute `{{var}}` and the two section forms `{{#name}}…{{/name}}` (render when the
|
|
77
|
+
* flag is true) and `{{^name}}…{{/name}}` (render when it is false).
|
|
78
|
+
*
|
|
79
|
+
* Sections do NOT nest — one pass, non-greedy to the matching close tag — which is all the
|
|
80
|
+
* always-on template needs. An unknown variable or section name THROWS, and so does any
|
|
81
|
+
* section tag left standing after the pass (mistyped close tag, unclosed section, nesting):
|
|
82
|
+
* a silently empty substitution, or a literal `{{#…}}` shipped into a file an agent is told
|
|
83
|
+
* to trust, is the failure this whole surface exists to prevent.
|
|
84
|
+
*/
|
|
85
|
+
function applyTemplate(
|
|
86
|
+
tpl: string,
|
|
87
|
+
vars: Record<string, string>,
|
|
88
|
+
sections: Record<string, boolean>,
|
|
89
|
+
): string {
|
|
90
|
+
const resolved = tpl.replace(
|
|
91
|
+
/\{\{([#^])(\w+)\}\}\n?([\s\S]*?)\{\{\/\2\}\}\n?/g,
|
|
92
|
+
(_m, sigil: string, name: string, body: string) => {
|
|
93
|
+
if (!(name in sections)) {
|
|
94
|
+
throw new Error(`agent-context: unknown template section {{${sigil}${name}}}`);
|
|
95
|
+
}
|
|
96
|
+
// `#` shows its body when the flag is true, `^` when it is false.
|
|
97
|
+
const shownWhen = sigil === "#";
|
|
98
|
+
return sections[name] === shownWhen ? body : "";
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
// A section tag that SURVIVED the pass above is malformed — a mistyped close tag, an
|
|
102
|
+
// unclosed section, or a nested one (the single non-greedy pass matches the first close
|
|
103
|
+
// tag, leaving the inner pair behind). Every one of those would otherwise ship a literal
|
|
104
|
+
// `{{#…}}` into a file an agent is told to trust, which is the failure this mechanism
|
|
105
|
+
// exists to prevent, so the leftover is an ERROR rather than passed through. The
|
|
106
|
+
// variable pass below cannot catch it: `{{#a}}` is not a `\w+` match.
|
|
107
|
+
const leftover = resolved.match(/\{\{[#^/]\w*\}\}/);
|
|
108
|
+
if (leftover !== null) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`agent-context: unresolved template section tag ${leftover[0]} — a section must be a ` +
|
|
111
|
+
"well-formed {{#name}}…{{/name}} or {{^name}}…{{/name}} pair, and sections do not nest",
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return resolved.replace(/\{\{(\w+)\}\}/g, (_m, k: string) => {
|
|
39
115
|
if (!(k in vars)) throw new Error(`agent-context: unknown template variable {{${k}}}`);
|
|
40
116
|
return vars[k]!;
|
|
41
117
|
});
|
|
@@ -48,8 +124,12 @@ export function assemble(opts: { contentRoot: string; stack: Stack }): Assembled
|
|
|
48
124
|
|
|
49
125
|
// 1. Always-on (AGENTS.md + CLAUDE.md, identical contents).
|
|
50
126
|
const tpl = readFileSync(join(contentRoot, "templates", "always-on.md.mustache"), "utf8");
|
|
51
|
-
const { line, codegenCommand } = stackLine(contentRoot, stack);
|
|
52
|
-
const alwaysOn = applyTemplate(
|
|
127
|
+
const { line, codegenCommand, docsCommand, apiSubDir } = stackLine(contentRoot, stack);
|
|
128
|
+
const alwaysOn = applyTemplate(
|
|
129
|
+
tpl,
|
|
130
|
+
{ stackLine: line, codegenCommand, docsCommand, apiSubDir },
|
|
131
|
+
{ nodeDocsSurface: hasNodeDocsSurface(stack) },
|
|
132
|
+
);
|
|
53
133
|
out.push({ path: ".metaobjects/AGENTS.md", contents: alwaysOn });
|
|
54
134
|
out.push({ path: ".metaobjects/CLAUDE.md", contents: alwaysOn });
|
|
55
135
|
|
|
@@ -30,7 +30,22 @@ export interface ScaffoldDecision {
|
|
|
30
30
|
conflicts: { path: string; newPath: string; contents: string }[];
|
|
31
31
|
/** the manifest to persist after writing. */
|
|
32
32
|
manifest: Manifest;
|
|
33
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Orphans safe to DELETE: the prior manifest tracked them, this stack no longer
|
|
35
|
+
* assembles them, and the on-disk content still hashes to what we recorded writing.
|
|
36
|
+
*
|
|
37
|
+
* Same predicate that separates `writes` from `conflicts` — we only ever remove a file
|
|
38
|
+
* we wrote and nobody has touched, so deleting is exactly as safe as the overwrite that
|
|
39
|
+
* predicate already authorises for a file still in the stack.
|
|
40
|
+
*/
|
|
41
|
+
prunes: string[];
|
|
42
|
+
/**
|
|
43
|
+
* Orphans that are HAND-EDITED — reported, never auto-deleted. Losing an adopter's
|
|
44
|
+
* writing is worse than leaving a stale file behind.
|
|
45
|
+
*
|
|
46
|
+
* An orphan already absent from disk appears in neither list: there is nothing to delete
|
|
47
|
+
* and nothing to report. It simply leaves the manifest.
|
|
48
|
+
*/
|
|
34
49
|
removed: string[];
|
|
35
50
|
}
|
|
36
51
|
|
|
@@ -68,17 +83,87 @@ export function planScaffold(opts: {
|
|
|
68
83
|
}
|
|
69
84
|
}
|
|
70
85
|
|
|
86
|
+
// An orphan is a path the prior manifest tracked that this stack no longer assembles —
|
|
87
|
+
// typically a language fragment left by `--refresh-docs --server <other>`. It used to be
|
|
88
|
+
// reported and never deleted whatever its state, so a python.md sat in a TypeScript
|
|
89
|
+
// project forever while every SKILL.md footer told the reader to read every
|
|
90
|
+
// references/*.md "one per server language in this project's stack".
|
|
71
91
|
const assembledPaths = new Set(assembled.map((f) => f.path));
|
|
72
|
-
const
|
|
92
|
+
const prunes: string[] = [];
|
|
93
|
+
const removed: string[] = [];
|
|
94
|
+
for (const path of prior ? Object.keys(prior.files) : []) {
|
|
95
|
+
if (assembledPaths.has(path)) continue;
|
|
96
|
+
const current = readCurrent(path);
|
|
97
|
+
if (current === undefined) continue; // already gone — nothing to do
|
|
98
|
+
if (hashContents(current) === prior?.files[path]) prunes.push(path);
|
|
99
|
+
else removed.push(path);
|
|
100
|
+
}
|
|
73
101
|
|
|
74
102
|
return {
|
|
75
103
|
writes,
|
|
76
104
|
conflicts,
|
|
105
|
+
// `files` holds only what this run assembled, so a pruned orphan does not survive into
|
|
106
|
+
// the new manifest — otherwise it would be re-reported as an orphan on every run.
|
|
77
107
|
manifest: { version: 1, generatedBy, servers: stack.servers, clients: stack.clients, files },
|
|
108
|
+
prunes,
|
|
78
109
|
removed,
|
|
79
110
|
};
|
|
80
111
|
}
|
|
81
112
|
|
|
113
|
+
/**
|
|
114
|
+
* The ordered release coordinate of a version — `[minor, patch]` — or `null` when the
|
|
115
|
+
* version cannot be ordered as a plain release.
|
|
116
|
+
*
|
|
117
|
+
* The MAJOR is deliberately dropped. It is a per-registry constant, not information:
|
|
118
|
+
* npm/PyPI/NuGet ship `0.<m>.<p>` and Maven Central the same `<m>.<p>` on its historical
|
|
119
|
+
* major `7`, so the minor.patch IS the shared release coordinate across all four (this is
|
|
120
|
+
* the same reduction the JVM's `releaseCoordinate` has always made for equality).
|
|
121
|
+
*
|
|
122
|
+
* Returns `null` — meaning "not orderable, so nudge" — for anything that is not exactly
|
|
123
|
+
* three dot-separated integers. That deliberately covers prereleases (`0.24.5-rc.1`),
|
|
124
|
+
* build metadata (`0.24.5+abc`), and the `0.0.0` sentinel a port emits when it cannot
|
|
125
|
+
* resolve its own installed version. Each must keep nudging: an RC-scaffolded context
|
|
126
|
+
* against a final release is still worth refreshing, and an unknown install must never
|
|
127
|
+
* be allowed to assert "in sync".
|
|
128
|
+
*/
|
|
129
|
+
function releaseSeries(version: string | undefined): [number, number] | null {
|
|
130
|
+
if (version === undefined) return null;
|
|
131
|
+
const m = /^(\d+)\.(\d+)\.(\d+)$/.exec(version.trim());
|
|
132
|
+
if (m === null) return null;
|
|
133
|
+
if (version.trim() === UNRESOLVED_VERSION) return null; // never assert in-sync on unknown
|
|
134
|
+
return [Number(m[2]), Number(m[3])];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** The sentinel a port stamps when it cannot resolve its own installed version. */
|
|
138
|
+
const UNRESOLVED_VERSION = "0.0.0";
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* True when the manifest was stamped by a release STRICTLY NEWER than the installed one.
|
|
142
|
+
*
|
|
143
|
+
* This is the one exemption from "any drift nudges", and it exists because of the
|
|
144
|
+
* publish-what-changed rule (docs/RELEASING.md): a registry publishes only when it has a
|
|
145
|
+
* changed product file, so a port legitimately sits behind npm — while `meta agent-docs`,
|
|
146
|
+
* the canonical scaffolder for EVERY port, stamps the npm version it was run from. A
|
|
147
|
+
* Python install at `0.24.4` whose context was scaffolded by npm `0.24.7` is correct, and
|
|
148
|
+
* nudging it is [#347](https://github.com/metaobjectsdev/metaobjects/issues/347) exactly:
|
|
149
|
+
* the remedy re-runs the scaffolder, which re-stamps `0.24.7`, so the advisory can never
|
|
150
|
+
* be satisfied and fires on every build forever. An advisory that cries wolf in the inner
|
|
151
|
+
* loop gets tuned out, and then it is not there for the upgrade it exists for.
|
|
152
|
+
*
|
|
153
|
+
* KNOWN BOUND, stated rather than hidden: ordering on minor.patch assumes both versions
|
|
154
|
+
* sit in the same release SERIES. That holds for every release to date and for every
|
|
155
|
+
* release after the 1.0/8.0 cut, but not ACROSS it — at that one cut a `0.24.x`-stamped
|
|
156
|
+
* context against a `1.0.0` install compares (24,x) > (0,0) and is read as "ahead", so the
|
|
157
|
+
* nudge is suppressed once when it should fire. The cost is a missed advisory, never a
|
|
158
|
+
* wrong action, and re-scaffolding at 1.0 is part of the cut anyway.
|
|
159
|
+
*/
|
|
160
|
+
function contextIsAheadOfInstall(generatedBy: string | undefined, currentVersion: string): boolean {
|
|
161
|
+
const stamped = releaseSeries(generatedBy);
|
|
162
|
+
const installed = releaseSeries(currentVersion);
|
|
163
|
+
if (stamped === null || installed === null) return false; // not orderable → nudge
|
|
164
|
+
return stamped[0] > installed[0] || (stamped[0] === installed[0] && stamped[1] > installed[1]);
|
|
165
|
+
}
|
|
166
|
+
|
|
82
167
|
/**
|
|
83
168
|
* A one-line nudge if the scaffolded agent context predates the installed MetaObjects
|
|
84
169
|
* (so `gen`/`verify` can remind the user to refresh the skills after an upgrade), or
|
|
@@ -91,10 +176,11 @@ export function agentContextStaleness(opts: {
|
|
|
91
176
|
}): string | null {
|
|
92
177
|
const { manifest, currentVersion } = opts;
|
|
93
178
|
if (manifest === undefined) return null; // no agent context here → nothing to nudge
|
|
94
|
-
// Exact-equality
|
|
95
|
-
//
|
|
96
|
-
//
|
|
179
|
+
// Exact-equality FIRST: ANY drift nudges (a re-scaffold is cheap + idempotent). A
|
|
180
|
+
// prerelease/build-metadata difference is still a reason to refresh, so this is not a
|
|
181
|
+
// semver compare — see releaseSeries() for the ONE case that is exempt.
|
|
97
182
|
if (manifest.generatedBy === currentVersion) return null; // in sync
|
|
183
|
+
if (contextIsAheadOfInstall(manifest.generatedBy, currentVersion)) return null;
|
|
98
184
|
const from = manifest.generatedBy ?? "an older MetaObjects";
|
|
99
185
|
return (
|
|
100
186
|
`MetaObjects agent context was generated by ${from}; you're on ${currentVersion}. ` +
|
package/src/forge-types.ts
CHANGED
|
@@ -113,6 +113,7 @@ import {
|
|
|
113
113
|
TYPE_ATTR,
|
|
114
114
|
TYPE_METADATA,
|
|
115
115
|
SUBTYPE_ROOT,
|
|
116
|
+
SUBTYPE_BASE,
|
|
116
117
|
CHILD_RULE_WILDCARD,
|
|
117
118
|
} from "@metaobjectsdev/metadata";
|
|
118
119
|
|
|
@@ -188,6 +189,26 @@ export const forgeTypesProvider: MetaDataTypeProvider = {
|
|
|
188
189
|
registry.register(def(FORGE_TYPE_FAILURE, subType, `Forge failure record (${subType})`, forgeChildRules));
|
|
189
190
|
}
|
|
190
191
|
|
|
192
|
+
// A BARE wrapper key (`{ "decision": … }`) resolves to the type's DECLARED default —
|
|
193
|
+
// the same accessor the YAML desugar has always used, which core declares for `object`
|
|
194
|
+
// (`object` → `object.entity`). The forge types are authored bare in memory files, with
|
|
195
|
+
// the subType in the body, so each declares its first member as its default.
|
|
196
|
+
//
|
|
197
|
+
// This used to work by accident: the JSON parsers GUESSED at registration order
|
|
198
|
+
// (`allSubTypesOf()[0]`) rather than asking the registry, and for a single-subtype type
|
|
199
|
+
// the guess happened to be right. Declaring the default makes it true on purpose, and
|
|
200
|
+
// survives someone registering a second subtype ahead of it.
|
|
201
|
+
// The first CONCRETE member where there is one, else the type's only member. `decision`
|
|
202
|
+
// and `principle` list `base` first with real siblings after it, so `[0]` would declare
|
|
203
|
+
// the anchor as the default — the very thing a bare key must not resolve to.
|
|
204
|
+
const concreteDefault = (subs: readonly string[]): string =>
|
|
205
|
+
subs.find((sub) => sub !== SUBTYPE_BASE) ?? subs[0]!;
|
|
206
|
+
registry.setDefaultSubType(FORGE_TYPE_DECISION, concreteDefault(FORGE_DECISION_SUBTYPES));
|
|
207
|
+
registry.setDefaultSubType(FORGE_TYPE_PRINCIPLE, concreteDefault(FORGE_PRINCIPLE_SUBTYPES));
|
|
208
|
+
registry.setDefaultSubType(FORGE_TYPE_CONVENTION, concreteDefault(FORGE_CONVENTION_SUBTYPES));
|
|
209
|
+
registry.setDefaultSubType(FORGE_TYPE_GLOSSARY, concreteDefault(FORGE_GLOSSARY_SUBTYPES));
|
|
210
|
+
registry.setDefaultSubType(FORGE_TYPE_FAILURE, concreteDefault(FORGE_FAILURE_SUBTYPES));
|
|
211
|
+
|
|
191
212
|
// #96 — the @forge* provenance attrs are common (admissible on any node).
|
|
192
213
|
registry.registerCommonAttrs([...FORGE_ATTR_SCHEMAS]);
|
|
193
214
|
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated The single-blob agent doc is replaced by the assembled agent-context
|
|
3
|
-
* (see `@metaobjectsdev/sdk/agent-context`). Kept only for back-compat; not scaffolded by `meta init`.
|
|
4
|
-
*/
|
|
5
|
-
export declare const AGENT_DOCS_BODY = "# Meta Forge \u2014 agent reference\n\nThis file is scaffolded by `meta init` and lives alongside your `metaobjects/` records. It teaches AI coding assistants (Claude Code, Codex, etc.) how to read and modify MetaObjects metadata correctly. Refresh after CLI updates with `meta init --refresh-docs`.\n\n## Five working principles (read first)\n\nThese shape every interaction with a metaobjects-driven project. Follow them when you author metadata, write hand-coded business logic, or review someone else's work.\n\n### 1. If it's pattern-derivable from metadata, generate it. Never hand-write boilerplate.\n\nThe metaobjects raison d'\u00EAtre is that anything the metadata fully describes \u2014 schemas, FK references, basic CRUD, query helpers, Zod validators, route handlers, RHF rules, form fields \u2014 should be produced by codegen, not hand-typed. If you find yourself hand-writing something the metadata already knows about, stop and use the generated artifact.\n\nThe first version of the trainer website's database layer had hand-written Drizzle schemas, Zod schemas, and CRUD endpoints. Every one of those is now generated. The hand-written code that remains is real business logic (Stripe webhooks, Loops integration, custom auth flows) \u2014 things the generator genuinely cannot derive.\n\nWhen you're about to add a new field or entity: edit `metaobjects/*.json` and re-run `meta gen`. Don't reach for the generated file directly.\n\n### 2. Use the generated constants. Never use magic strings that touch metadata.\n\nAfter `meta gen`, each entity file exports a rich metadata-constants block. Each non-dollar-prefixed key is a per-field object that carries everything a consumer might need (name, label, view, html input type, placeholder, RHF validation rules):\n\n```ts\nexport const Subscriber = {\n $entity: \"Subscriber\", // entity name string\n $table: \"subscribers\", // SQL table name\n $path: \"/subscribers\", // REST resource path\n\n email: {\n name: \"email\", // field name string (use for filters, register())\n label: \"Email Address\", // humanized fallback or @label override\n view: \"text\", // MetaView subtype\n htmlType: \"email\", // optional; maps view \u2192 HTML <input type=>\n placeholder: \"you@example.com\", // optional; only when @placeholder is set on the view\n helpText: \"We never share this.\", // optional; only when @helpText is set\n rules: { // optional; derived from validator children\n required: \"Email is required\",\n maxLength: { value: 255, message: \"Too long\" },\n pattern: { value: /.../, message: \"Invalid email\" },\n },\n },\n firstName: { name: \"firstName\", label: \"First Name\", view: \"text\", htmlType: \"text\", rules: { required: \"First Name is required\" } },\n // ...\n} as const;\n```\n\n**Use them everywhere \u2014 in both generated AND hand-written code:**\n\n```tsx\n// \u2717 Don't:\n<input name=\"email\" type=\"email\" placeholder=\"Email\" />\n\n// \u2713 Do:\n<input\n type={Subscriber.email.htmlType}\n name={Subscriber.email.name}\n placeholder={Subscriber.email.placeholder}\n aria-label={Subscriber.email.label}\n/>\n```\n\nRename a field in `metaobjects/` and re-gen \u2014 TypeScript catches every stale reference.\n\n**Special case \u2014 Drizzle column access:** when you're already inside Drizzle's typed builder, just use the column properties directly. Drizzle's table-const types are themselves derived from metadata, so `weeks.programId` is already TS-safe:\n\n```ts\n// \u2713 Use Drizzle's typed accessor directly \u2014 no constants needed here:\ndb.select().from(weeks).where(eq(weeks.programId, X))\n\n// \u2717 Don't do this \u2014 it's redundant indirection:\ndb.select().from(weeks).where(eq(weeks[Week.programId.name], X))\n```\n\nUse the constants when you need a STRING (filter object keys, registration arguments, REST paths, labels). Use Drizzle properties directly when the type system already does the work.\n\n### 3. Forms: spread `form.input.<field>` from useEntityForm. One line per input.\n\nFor React forms, use `useEntityForm` from `@metaobjectsdev/react`. It returns the standard React Hook Form surface plus a pre-bound `.input` accessor \u2014 one entry per field, ready to spread onto an `<input>`:\n\n```tsx\nimport { useEntityForm } from '@metaobjectsdev/react';\nimport { Subscriber, SubscriberInsertSchema } from './generated/Subscriber';\n\nconst form = useEntityForm(Subscriber, SubscriberInsertSchema);\n\n<label>{Subscriber.email.label}</label>\n<input {...form.input.email} /> // \u2190 type, placeholder, name, rules, aria-label all spread automatically\n```\n\nFor non-`<input>` controls (textarea, select), the `type` attr is omitted from `form.input.X` \u2014 pick the right element yourself.\n\nThe same Zod schema (`SubscriberInsertSchema`) validates on the server (in Fastify routes) and on the client (via the resolver). One schema, two surfaces, zero drift.\n\n### 4. Routes: use the generated `<Entity>.routes.ts` for stock CRUD. Hand-write only what's custom.\n\n`meta gen` emits a per-entity routes file that mounts the 5 standard verbs via `mountCrudRoutes` from `@metaobjectsdev/runtime-ts/drizzle-fastify`. The runtime is plain Drizzle + Zod \u2014 no extra ORM.\n\nFor custom flows (Stripe webhooks, side effects, auth-gated actions), hand-write the route \u2014 but import the entity constants + generated Zod schema. The boilerplate (CRUD, validation, 404 mapping, pagination) lives in the helper; your hand-written code is just the business logic.\n\n**Auth pattern:** install a plugin-level Fastify `preHandler` hook at the top of your route plugin. The hook applies to every route registered after it \u2014 both hand-written handlers AND metaobjects-generated routes via the `routeOptions` field. Beats sprinkling `if (!auth(...)) return;` at the top of every handler.\n\n### 5. Hand-coded code is always available, but coexists with generated code.\n\nGenerated code does the boilerplate. Hand-coded code does the business logic. They live in the same project, the same package, sometimes the same file. The hand-coded code consumes the generated constants and generated Zod schemas \u2014 it never duplicates schema, never hard-codes paths, never declares its own validators that metadata could declare.\n\nConcrete pattern from the trainer website:\n- Generated `Subscriber.routes.ts` registers GET / GET-by-id / POST / PATCH / DELETE on `/api/subscribers`.\n- Hand-written `apps/api/src/routes/subscribers.ts` keeps `POST /subscribe` \u2014 the custom endpoint with the Loops side-effect.\n- Both registered with `fastify.register()`. Both validate via `SubscriberInsertSchema`. Both use `Subscriber.email.name` / etc. Neither knows the other exists.\n\n## Metaobjects metamodel \u2014 quick rules\n\nThe format used by `metaobjects/*.json` is **metaobjects metadata**, a cross-language standard. Eight base types:\n\n| Type | Purpose |\n|---|---|\n| `metadata` | Root document wrapper |\n| `object` | An entity (table/record) |\n| `field` | A property on an object |\n| `attr` | Named scalar/array decoration on any parent |\n| `validator` | A validation rule |\n| `view` | A UI control kind |\n| `identity` | A primary/secondary key |\n| `relationship` | An association between objects |\n\n### Two most-violated rules\n\n1. **Attribute uniqueness.** Within a single parent metadata node, all attribute names must be unique. You cannot have two `attr` children both named `alternative`. For multi-value, use a single `stringarray` attr: `\"@alternatives\": [\"a\", \"b\", \"c\"]`.\n\n2. **Inline `@<name>` and `attr` child are the same thing.** `\"@maxLength\": 50` is shorthand for `{\"attr\": {\"name\": \"maxLength\", \"subType\": \"int\", \"value\": \"50\"}}`. The parser converts inline form into attr children. Don't use both forms for the same attribute name on the same parent.\n\n### Object subtypes (v0.3)\n\n- `base` \u2014 abstract template (no runtime semantics)\n- `entity` \u2014 persistent record; should have a primary identity\n- `value` \u2014 value-object; equality by content; must NOT have a primary identity\n\nJava-runtime strategies (pojo / map / proxy) belong on `@javaRuntime`, not in `subType`.\n\n### Reserved structural keys (NOT attributes)\n\n`name`, `subType`, `package`, `extends`, `isAbstract`, `children`, `merge`, `value`.\n\nThe v0.2 keys (`super`, `overlay`, `override`, `isInterface`, `implements`) are **gone**. The current parser will reject them. Use:\n- `extends:` instead of `super:` for the supertype reference\n- `merge: true` instead of `overlay: true` / `override: true` for in-place modification\n- `@isAbstract: true` instead of `isInterface: true` (multiple inheritance is not supported)\n\n### Package paths and inheritance\n\n- Package segments separated by `::` \u2014 `acme::common::id`\n- Relative references in `extends:` \u2014 `..::common::id` means \"go up to parent package, descend into `common::id`\". Relative forms (`..::` parent-relative, leading `::` root-absolute) are a **YAML-authoring affordance only**; canonical JSON must be fully-qualified (a relative ref in JSON is rejected with `ERR_RELATIVE_REF_IN_CANONICAL`).\n- Cross-file resolution works as long as all files are passed to Loader (or live in the same `metaobjects/` directory)\n\n### Two special intercepted attrs (parser-routed)\n\n- `@isArray` \u2192 marks a field as a collection\n- `@isAbstract` \u2192 marks a node as abstract (inheritable but not instantiable)\n\n## Validators \u2014 two layers\n\nValidators can attach in two places, and they compose:\n\n**Field-level validators** describe what makes the *stored value* valid. They survive across UI, API, batch import, manual SQL \u2014 anywhere data enters the system. The generated Zod `<Entity>InsertSchema` encodes these.\n\n```json\n{\"field\": {\"name\": \"email\", \"subType\": \"string\",\n \"children\": [\n {\"validator\": {\"subType\": \"required\"}},\n {\"validator\": {\"subType\": \"regex\", \"@pattern\": \"^[^@]+@[^@]+\\\\.[^@]+$\"}}\n ]\n}}\n```\n\n**View-level validators** describe what makes user *input* valid in a specific UI surface \u2014 possibly stricter, possibly with different messages, possibly format-specific. They run client-side in generated forms. They do NOT necessarily reject the stored value if it's already in the DB.\n\n```json\n{\"field\": {\"name\": \"phone\", \"subType\": \"string\",\n \"children\": [\n {\"validator\": {\"subType\": \"regex\", \"@pattern\": \"^\\\\+?[0-9]+$\"}},\n {\"view\": {\"subType\": \"text-input\", \"@label\": \"Phone\",\n \"children\": [\n {\"validator\": {\"subType\": \"length\", \"@min\": 7, \"@max\": 20,\n \"@message\": \"Phone must be 7-20 digits\"}}\n ]\n }}\n ]\n}}\n```\n\nRule of thumb: rules that protect data integrity \u2192 field. Rules that improve input UX \u2192 view.\n\n## metaobjects.config.ts \u2014 generator wiring (project root)\n\n`meta gen` reads `metaobjects.config.ts` at the project root. This is where you declare which generators run and their options. It is TypeScript, type-checked, and imported via `jiti` at run time.\n\n```ts\nimport { defineConfig } from \"@metaobjectsdev/cli\";\nimport {\n entityFile, queriesFile, routesFile, /* formFile, */ barrel,\n} from \"@metaobjectsdev/codegen-ts/generators\";\n\nexport default defineConfig({\n outDir: \"packages/database/src/generated\",\n extStyle: \"none\",\n dbImport: \"../index\",\n dialect: \"sqlite\",\n generators: [\n entityFile(),\n queriesFile(),\n routesFile(),\n // formFile(), // opt-in: emits stock React forms per entity\n barrel(),\n ],\n});\n```\n\n3rd-party generator example: `import { tanstackQuery } from \"@metaobjectsdev/codegen-ts-tanstack\"; // then add tanstackQuery({ ... }) to the generators array`\n\nFilters live on the generator entry: `routesFile({ filter: e => e.name !== \"AuditLog\" })`\n\n`.metaobjects/config.json` holds static project state (schema_version, pending_in_git, confidence_thresholds) **and `sources` \u2014 the set of places your metadata comes from** (see \"Where metadata comes from\" below). Generator wiring belongs in `metaobjects.config.ts` so TypeScript can type-check the imports.\n\n## Generated hooks + grids (TanStack)\n\nWhen `tanstackQuery()` is in your `metaobjects.config.ts`, every entity gets `<Entity>.hooks.ts` with a query-key factory + `useEntity`, `useEntities`, `useCreate`, `useUpdate`, `useDelete` hooks. When `tanstackGrid()` is in the config, entities with a `layout[dataGrid]` child also get `<Entity>.columns.tsx`.\n\n```tsx\nimport { usePrograms, useCreateProgram } from \"@your-pkg/database/generated/Program.hooks\";\nimport { programDefaultColumns, programDefaultGrid } from \"@your-pkg/database/generated/Program.columns\";\nimport { EntityGrid } from \"@metaobjectsdev/tanstack\";\n\nconst { data, isLoading } = usePrograms();\nconst create = useCreateProgram({ onSuccess: () => navigate(\"/programs\") });\n\n<EntityGrid\n columns={programDefaultColumns}\n grid={programDefaultGrid}\n data={data ?? []}\n isLoading={isLoading}\n onRowClick={(row) => navigate(`/admin/programs/${row.id}`)}\n/>\n```\n\n**Provider setup.** Wrap your app with `<EntityFetcherProvider value={fetcher}>` (supplies the HTTP fetcher to all generated hooks). For an admin subtree with different auth, wrap a second time inside: `<EntityFetcherProvider value={adminFetch}>...</EntityFetcherProvider>` overrides the outer one.\n\n**Metadata layer \u2014 grid definition:**\n\n```jsonc\n{ \"layout\": {\n \"subType\": \"dataGrid\",\n \"name\": \"default\",\n \"@pageSize\": 25,\n \"@defaultSortField\": \"createdAt\",\n \"@defaultSortOrder\": \"desc\",\n \"@filterable\": true,\n \"@columns\": [\"email\", \"firstName\", \"subscribed\", \"createdAt\"]\n}}\n```\n\nThe `@columns` attr is a flat string array listing fields to display. Per-column rendering comes from each field's own `view` subtype (the same one that drives forms); sortability comes from the field's `@sortable` attr; width belongs in app CSS. There are no nested per-column children \u2014 just `@columns`.\n\n**Cell renderers.** Field rendering inside grids comes from each field's own `view` subtype (the same one that drives forms). Override defaults app-wide with `<CellRendererProvider value={{ currency: ({ getValue }) => <Money value={getValue()} /> }}>`.\n\n**Per-entity opt-out.** `@emitTanstack: false` on an entity skips both hooks and columns.\n\n## Filtering generated lists\n\nMark filterable fields in metadata with `@filterable: true`:\n\n```jsonc\n{ \"field\": { \"name\": \"email\", \"subType\": \"string\", \"@filterable\": true } }\n```\n\nThe generated `useSubscribers(filter)` hook accepts a typed filter:\n\n```tsx\nconst { data } = useSubscribers({\n email: { like: \"amy@%\" },\n subscribed: true,\n sort: \"createdAt:desc\",\n limit: 25,\n});\n```\n\nURL sent: `/subscribers?filter[email][like]=amy@%25&filter[subscribed]=true&sort=createdAt:desc&limit=25`\n\n**Leading wildcards are rejected by default.** The generated `<Entity>FilterAllowlist` ships `leadingWildcard: false` on every field, so a `like` pattern starting with `%` (e.g. `\"%@example.com\"`) is a 400 `filter.leading_wildcard_disallowed` \u2014 an unanchored LIKE defeats index usage, so it is fail-closed. To opt a field in, hand-edit that field's entry in the generated allowlist to `leadingWildcard: true` (hand edits inside generated files survive regeneration via the three-way merge). This gate is TypeScript-only; other ports' generated APIs do not enforce it.\n\n**Operators by field subtype:**\n- String: `eq, ne, in, like, isNull`\n- Number/date: `eq, ne, gt, gte, lt, lte, in, isNull`\n- Boolean: `eq, isNull`\n\nIllegal combinations like `useSubscribers({ subscribed: { gte: true } })` fail to compile (booleans don't support `gte`).\n\n**Per-grid preset filter** via layout `@filter`:\n\n```jsonc\n{ \"layout\": { \"subType\": \"dataGrid\", \"name\": \"active\",\n \"@filter\": { \"subscribed\": true },\n \"@columns\": [\"email\", \"firstName\", \"subscribed\"] }}\n```\n\nGenerates `subscriberActiveFilter` const consumable in pages. Compose with ad-hoc filters via object spread.\n\n## Projections (read models with joined/aggregated columns)\n\nWhen a list needs computed columns (counts, sums, joined fields), create a **projection** \u2014 an entity that extends a base entity but reads from a SQL view:\n\n```json\n// metaobjects/meta.commerce.json (inline with Program)\n{\n \"object\": {\n \"name\": \"ProgramSummary\",\n \"subType\": \"entity\",\n \"extends\": \"Program\",\n \"children\": [\n { \"source\": { \"subType\": \"rdb\", \"@kind\": \"view\", \"@table\": \"v_program_summary\" } },\n { \"field\": { \"name\": \"weekCount\", \"subType\": \"int\", \"children\": [\n { \"origin\": { \"subType\": \"aggregate\",\n \"@agg\": \"count\", \"@of\": \"Week.id\", \"@via\": \"Program.weeks\" }}\n ]}},\n { \"identity\": { \"subType\": \"primary\", \"name\": \"id\", \"@fields\": \"id\" } }\n ]\n }\n}\n```\n\n`meta gen` produces a read-only `useProgramSummaries(filter)` hook, a SQL view DDL in the migration, and a read-only GET-only route.\n\n**Aggregate vocabulary** (`origin.aggregate @agg`): `count`, `sum`, `avg`, `min`, `max`; plus `any`/`all` (a boolean predicate quantifier over a required `@filter` \u2014 no `@of`; \"did any/every related row match?\"), and `collect` (an array rollup of `@of` \u2014 the field must be `isArray: true`; `@distinct` dedupes, `@orderBy` sets element order).\n\n**Other read-model origins**: `origin.computed` \u2014 a row-level value from the base row's own fields via a structured `@expr` tree (e.g. `{ \"op\": \"isNotNull\", \"arg\": { \"field\": \"payloadJson\" } }` \u2192 a boolean, to avoid shipping a heavy column); `origin.first` \u2014 the single related row picked by `@orderBy` along `@via`, projecting `@of` (e.g. \"the latest child's status\"; the field must not be `@required` \u2014 an empty related set yields null).\n\n**Multi-level via paths** are supported: `@via: \"Program.weeks.workouts\"` builds a 2-level JOIN tree.\n\n**For pages that need a full nested tree** (e.g., Program \u2192 Weeks \u2192 Workouts \u2192 Exercises), use 4 entity hooks with Project D's filter syntax for batched lookups (no projection needed \u2014 flat hooks + client-side stitching is enough):\n\n```tsx\nconst { data: weeks } = useWeeks({ programId, sort: \"weekNumber:asc\" });\nconst weekIds = weeks?.map((w) => w.id) ?? [];\nconst { data: workouts } = useWorkouts(\n weekIds.length ? { weekId: { in: weekIds } } : undefined,\n);\n```\n\n## Currency fields\n\nDeclare a money field with `subType: \"currency\"`:\n\n```json\n{ \"field\": { \"name\": \"priceCents\", \"subType\": \"currency\", \"@currency\": \"USD\" } }\n```\n\nStorage stays as integer minor units (cents for USD). The generated `<Entity>` constants block carries `view`, `currency`, `locale` so admin grids auto-format prices.\n\n**Imports \u2014 use sub-paths in browser code:**\n\n```tsx\nimport { formatCurrency } from \"@metaobjectsdev/runtime-web\";\nimport { CurrencyInput } from \"@metaobjectsdev/react\";\n```\n\n**Display:**\n\n```tsx\n<span>{formatCurrency(program.priceCents)}</span> // $15.00\n<span>{formatCurrency(p.amountCents, \"EUR\", \"de-DE\")}</span> // 15,00 \u20AC\n```\n\n**Form input:**\n\n```tsx\n<CurrencyInput value={priceCents} onChange={setPriceCents} currency=\"USD\" />\n```\n\nUser types `15.99` \u2192 component emits `1599` to `onChange` on blur. Wire format is always integer cents.\n\n**Locale override** via a `view[currency]` child:\n\n```json\n{ \"field\": { \"name\": \"priceCents\", \"subType\": \"currency\", \"@currency\": \"EUR\",\n \"children\": [{ \"view\": { \"subType\": \"currency\", \"@locale\": \"de-DE\" } }]\n}}\n```\n\nCurrency code lives on the field; locale lives on the view.\n\n## Generated artifacts \u2014 what `meta gen` produces\n\nAfter `meta gen`, you get one barrel + per-entity files in your configured `outDir` (default `packages/database/src/generated/`):\n\n| File | What's in it | When to touch by hand |\n|---|---|---|\n| `<Entity>.ts` | Drizzle table, relations(), inferred types, Zod insert/update schemas, and the rich `<Entity>` constants block (per-field objects with name, label, view, htmlType, rules, etc.) | Never. Regenerate. |\n| `<Entity>.queries.ts` | Typed query helpers (`findUserById`, `listUsers`, `createUser`, ...) using prepared statements | Never. Regenerate. |\n| `<Entity>.routes.ts` | Fastify CRUD plugin delegating to `mountCrudRoutes` from `@metaobjectsdev/runtime-ts/drizzle-fastify` (5 verbs, Zod validation, 404/204 mapping, Drizzle-direct under the hood) | Never. Regenerate. |\n| `<Entity>.form.tsx` | React form using `useEntityForm` + the entity constants. **OPT-IN at project level:** add `formFile()` to `generators` in `metaobjects.config.ts`. Opt out per-entity via `@emitForm: false`. | Never. Regenerate. |\n| `index.ts` | Barrel re-exporting every entity file | Never. Regenerate. |\n\nFor business logic the generator doesn't cover, create a SIBLING file: `<Entity>.extra.ts` for query/route helpers, or any file you like in your apps directory. Import the constants from the generated `<Entity>.ts`.\n\n### Stock route mounting\n\n```ts\nimport { subscriberRoutes } from \"@your-pkg/database/generated/Subscriber.routes\";\nfastify.register(subscriberRoutes, { prefix: \"/api\" });\n```\n\nThat mounts: `GET /api/subscribers`, `GET /api/subscribers/:id`, `POST /api/subscribers`, `PATCH /api/subscribers/:id`, `DELETE /api/subscribers/:id`. Pagination via `?limit=` & `?offset=`. Validation via the generated Zod schemas. Drizzle calls under the hood.\n\n### Mixing custom routes alongside generated\n\n```ts\nimport { db, subscribers } from \"@your-pkg/database\";\nimport { Subscriber, SubscriberInsertSchema } from \"@your-pkg/database/generated/Subscriber\";\nimport { eq } from \"drizzle-orm\";\n\nfastify.post(\"/subscribe\", async (req, reply) => {\n // Generated Zod schema validates the body \u2014 same schema the API route uses.\n const parsed = SubscriberInsertSchema.safeParse(req.body);\n if (!parsed.success) return reply.code(400).send({ issues: parsed.error.issues });\n\n // Drizzle's typed accessors are already TS-safe; no need for indirection.\n const existing = await db.select().from(subscribers).where(eq(subscribers.email, parsed.data.email)).get();\n if (existing) return reply.code(409).send({ error: \"Already subscribed\" });\n\n const [row] = await db.insert(subscribers).values(parsed.data).returning();\n // ... your business logic (analytics, Loops/Mailchimp, navigation, etc.)\n return reply.code(201).send(row);\n});\n```\n\nThe fact that every metadata-derived value flows from `Subscriber` / `SubscriberInsertSchema` / the typed `subscribers` table is what makes rename-the-field-in-metadata-and-regen safe.\n\n### Hand-written form using `useEntityForm`\n\n```tsx\nimport { useEntityForm } from '@metaobjectsdev/react';\nimport { Subscriber, SubscriberInsertSchema, type Subscriber as Row } from './generated/Subscriber';\n\nexport function SubscribeForm() {\n const form = useEntityForm(Subscriber, SubscriberInsertSchema);\n const { handleSubmit, formState: { errors } } = form;\n\n return (\n <form onSubmit={handleSubmit(/* your onSubmit */)} className=\"your-design-system\">\n <label>{Subscriber.email.label}</label>\n <input {...form.input.email} />\n {errors.email && <span>{errors.email.message}</span>}\n\n <label>{Subscriber.firstName.label}</label>\n <input {...form.input.firstName} />\n {errors.firstName && <span>{errors.firstName.message}</span>}\n\n <button type=\"submit\">Subscribe</button>\n </form>\n );\n}\n```\n\nSpread `form.input.<field>` \u2014 it carries name, type, placeholder, rules, aria-label automatically. No magic strings.\n\n## Meta Forge additions\n\n### `@forge*` attribute namespace\n\nProvenance and confidence concerns expressed as inline attributes on any metadata child. Names use camelCase (no separator).\n\nMost common:\n- `@forgeConfidence` (double 0..1) \u2014 confidence the record is correct\n- `@forgeSource` (string) \u2014 `human` | `claude` | `ts-ast` | `drizzle` | ...\n- `@forgePrimaryLocation` (string) \u2014 file path for an entity\n- `@forgeRationale` (string, decision only) \u2014 why this decision\n- `@forgeAlternatives` (stringarray, decision only) \u2014 alternatives considered\n\nFull inventory in `packages/sdk/FORGE-METADATA.md`.\n\n### New top-level types\n\nRegistered by `@metaobjectsdev/sdk` into the TypeRegistry:\n\n| Type | Purpose |\n|---|---|\n| `decision` | Architectural or design decision |\n| `principle` | Design principle (advisory/enforced) |\n| `convention` | Coding/structural convention |\n| `glossary` | Domain-term definition |\n| `failure` | Recorded failure mode |\n\nThese coexist with `object` children in the same package files. `meta gen` and `meta migrate` only consume `object`; the descriptive types are context for AI tooling and don't drive codegen.\n\n## File layout\n\n```\nmetaobjects/\n\u251C\u2500\u2500 meta.common.json shared base fields/validators (optional)\n\u251C\u2500\u2500 meta.<domain>.json your entity packages(s)\n\u2514\u2500\u2500 _pending/<pkg>.json proposed packages awaiting review\n\n.metaobjects/\n\u251C\u2500\u2500 config.json static project state + `sources`\n\u251C\u2500\u2500 migrations/ written by meta migrate\n\u2514\u2500\u2500 .gen-state/ codegen merge base (gitignored)\n\nmetaobjects.config.ts generator wiring (committed)\n```\n\n### Where metadata comes from \u2014 the `sources` set\n\n**`metaobjects/` is the DEFAULT VALUE of `sources`, not a requirement.** When `sources` is absent or empty in `.metaobjects/config.json`, it takes that default \u2014 the `metaobjects/` directory beside the `.metaobjects/` folder holding the config. `meta init` scaffolds `\"sources\": []`, so a project that does nothing takes the default.\n\nDo NOT assume that directory exists. A project may declare `sources` and put its metadata anywhere \u2014 a sibling module, a shared model repository, a single file \u2014 and need not have a directory of that name at all:\n\n```json\n{\n \"schema_version\": 1,\n \"sources\": [\n { \"path\": \"../model/src/main/resources/metadata\" },\n { \"path\": \"metaobjects\" }\n ]\n}\n```\n\n`meta gen`, `meta migrate`, `meta verify`, `meta docs` and `meta export` all read exactly that set, so pointing `sources` elsewhere moves every command together. A `path` is read **in place and never installed** or copied.\n\n`sources` is read by **all four CLI surfaces** \u2014 the Node `meta` CLI, `dotnet meta` (C#), `metaobjects` (Python) and `metaobjects:generate` (Java and Kotlin, via Maven). Each resolves the same files from the same declaration.\n\n**`sources` is a set, not an ordered list** \u2014 resolution is order-independent, so declaration order never changes what loads. `config.json` also rejects unknown top-level keys, so a misspelled key is an error rather than a silently ignored one.\n\n## Worked example\n\n```json\n{\n \"metadata\": {\n \"package\": \"myapp\",\n \"children\": [\n {\n \"object\": {\n \"name\": \"User\",\n \"subType\": \"entity\",\n \"@forgeConfidence\": 0.95,\n \"@forgeSource\": \"human\",\n \"@forgePrimaryLocation\": \"src/db/users.schema.ts\",\n \"children\": [\n {\"field\": {\"name\": \"id\", \"extends\": \"common::id\"}},\n {\"field\": {\"name\": \"email\", \"subType\": \"string\",\n \"@column\": \"email_address\",\n \"children\": [{\"validator\": {\"subType\": \"required\"}}]\n }},\n {\"identity\": {\"name\": \"pk\", \"subType\": \"primary\", \"@fields\": [\"id\"], \"@generation\": \"increment\"}}\n ]\n }\n },\n {\n \"decision\": {\n \"name\": \"useTanstackQuery\",\n \"subType\": \"global\",\n \"@forgeConfidence\": 0.9,\n \"@forgeSource\": \"human\",\n \"@forgeRationale\": \"Real-time invalidation matters for live game state.\",\n \"@forgeAlternatives\": [\"swr\", \"redux-toolkit-query\"]\n }\n }\n ]\n }\n}\n```\n\n## Authoring guidance\n\n| Situation | Action |\n|---|---|\n| Adding a field to an existing entity | Edit the `object`'s `children`; append a `field` node, then `meta gen` |\n| New entity in an existing domain | Append an `object` to the appropriate package file, then `meta gen` |\n| Renaming an entity or field | Edit the metadata, regenerate; TS will surface every stale consumer of the constants |\n| New REST resource | Already done \u2014 `meta gen` produced `<Entity>.routes.ts`. Just `fastify.register(...)` it |\n| Custom business logic (Stripe webhook, side-effects, auth flows) | Hand-write a route/handler that imports the generated constants + `om()` |\n| Architectural choice affecting how entities are built | Add a `decision` with `@forgeRationale` + `@forgeAlternatives` |\n| Coding convention | Add a `convention` with `@forgePatternDescription` + `@forgeAppliesTo` |\n| Domain term | Add a `glossary` entry with `@forgeTerm` + `@forgeDefinition` |\n\n## Deeper references\n\n- `packages/metadata/METAMODEL.md` \u2014 full metamodel reference\n- `packages/sdk/FORGE-METADATA.md` \u2014 full `@forge*` inventory + MetaObjects layout details\n- `docs/strategy/2026-05-12-v0.3-ai-first-metadata-loading.md` \u2014 current strategy (v0.3 vocab, packages, AI-first loading)\n";
|
|
6
|
-
//# sourceMappingURL=body.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../src/agent-docs/body.ts"],"names":[],"mappings":"AACA;;;GAGG;AACH,eAAO,MAAM,eAAe,uy6BA0kB3B,CAAC"}
|