@metaobjectsdev/sdk 0.23.2 → 0.24.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/skills/metaobjects-audit/SKILL.md +20 -7
- package/agent-context/skills/metaobjects-audit/references/capability-checklist.md +65 -19
- package/agent-context/skills/metaobjects-audit/references/csharp.md +2 -1
- package/agent-context/skills/metaobjects-audit/references/java.md +3 -2
- package/agent-context/skills/metaobjects-audit/references/kotlin.md +2 -1
- package/agent-context/skills/metaobjects-audit/references/requirements.md +3 -4
- package/agent-context/skills/metaobjects-audit/references/typescript.md +1 -1
- package/agent-context/skills/metaobjects-authoring/SKILL.md +53 -10
- package/agent-context/skills/metaobjects-authoring/references/requirements.md +49 -23
- package/agent-context/skills/metaobjects-codegen/SKILL.md +4 -3
- package/agent-context/skills/metaobjects-codegen/references/csharp.md +12 -2
- package/agent-context/skills/metaobjects-codegen/references/java.md +3 -3
- package/agent-context/skills/metaobjects-codegen/references/kotlin.md +4 -4
- package/agent-context/skills/metaobjects-codegen/references/python.md +12 -2
- package/agent-context/skills/metaobjects-codegen/references/typescript.md +14 -3
- package/agent-context/skills/metaobjects-fit-assessment/SKILL.md +4 -4
- package/agent-context/skills/metaobjects-prompts/SKILL.md +53 -32
- package/agent-context/skills/metaobjects-prompts/references/csharp.md +26 -21
- package/agent-context/skills/metaobjects-prompts/references/java.md +24 -18
- package/agent-context/skills/metaobjects-prompts/references/kotlin.md +25 -20
- package/agent-context/skills/metaobjects-prompts/references/python.md +68 -26
- package/agent-context/skills/metaobjects-prompts/references/typescript.md +29 -23
- package/agent-context/skills/metaobjects-verify/references/migration.md +1 -1
- package/agent-context/skills/metaobjects-verify/references/requirements.md +36 -22
- package/agent-context/templates/always-on.md.mustache +3 -1
- package/dist/agent-docs/body.d.ts +1 -1
- package/dist/agent-docs/body.d.ts.map +1 -1
- package/dist/agent-docs/body.js +24 -2
- package/dist/agent-docs/body.js.map +1 -1
- package/dist/collection.d.ts +71 -0
- package/dist/collection.d.ts.map +1 -0
- package/dist/collection.js +203 -0
- package/dist/collection.js.map +1 -0
- package/dist/config.d.ts +51 -21
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +76 -10
- package/dist/config.js.map +1 -1
- package/dist/discovery.d.ts +43 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +100 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -4
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +42 -19
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +38 -95
- package/dist/memory.js.map +1 -1
- package/dist/metadata-files.d.ts +67 -0
- package/dist/metadata-files.d.ts.map +1 -0
- package/dist/metadata-files.js +155 -0
- package/dist/metadata-files.js.map +1 -0
- package/dist/records/any.d.ts +8 -8
- package/dist/records/decision.d.ts +2 -2
- package/dist/records/glossary.d.ts +4 -4
- package/dist/records/principle.d.ts +2 -2
- package/dist/scope.d.ts +16 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +75 -0
- package/dist/scope.js.map +1 -0
- package/dist/sources.d.ts +86 -0
- package/dist/sources.d.ts.map +1 -0
- package/dist/sources.js +130 -0
- package/dist/sources.js.map +1 -0
- package/package.json +2 -2
- package/src/agent-docs/body.ts +24 -2
- package/src/collection.ts +268 -0
- package/src/config.ts +80 -12
- package/src/discovery.ts +110 -0
- package/src/index.ts +26 -9
- package/src/memory.ts +65 -99
- package/src/metadata-files.ts +158 -0
- package/src/scope.ts +95 -0
- package/src/sources.ts +160 -0
package/src/sources.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// server/typescript/packages/sdk/src/sources.ts
|
|
2
|
+
//
|
|
3
|
+
// Phase-1 metadata-source-resolution — source spec resolution.
|
|
4
|
+
//
|
|
5
|
+
// Turns a declared source SET (`.metaobjects/config.json`'s `sources`) into a
|
|
6
|
+
// canonically-ordered, de-duplicated list of metadata file paths. The FULL
|
|
7
|
+
// result — including which spec each entry attributes to — is a pure
|
|
8
|
+
// function of the source SET, never of declaration order: permuting `specs`
|
|
9
|
+
// cannot change the output, even when two specs overlap on the same file.
|
|
10
|
+
// `test/order-independence.test.ts` pins that (the design's linchpin), so the
|
|
11
|
+
// canonical spec ordering below is load-bearing.
|
|
12
|
+
//
|
|
13
|
+
// Canonical is NOT the same as "flat-sorted". Within one directory spec the
|
|
14
|
+
// order is `listMetadataFiles`'s (metadata-files.ts) — files at a level, then
|
|
15
|
+
// that level's subdirectories, depth-first — because that is the order production
|
|
16
|
+
// has always handed the loader, and declaration order survives into generated
|
|
17
|
+
// output (the barrel's export list, the shared `enums.ts`, `meta docs` page
|
|
18
|
+
// order, `meta export`'s sibling order). A flat sort of absolute paths
|
|
19
|
+
// silently reorders any project with a subdirectory whose name sorts before a
|
|
20
|
+
// sibling file. Across specs, order is decided by spec CONTENT, which is what
|
|
21
|
+
// keeps the whole result permutation-invariant. `test/source-order.test.ts`
|
|
22
|
+
// pins both halves.
|
|
23
|
+
import { stat } from "node:fs/promises";
|
|
24
|
+
import { isAbsolute, resolve } from "node:path";
|
|
25
|
+
import { ParseError, codeSource } from "@metaobjectsdev/metadata";
|
|
26
|
+
import { DEFAULT_METADATA_DIR, listMetadataFiles } from "./metadata-files.js";
|
|
27
|
+
|
|
28
|
+
/** Tagged union of source kinds. `resource` and `package` are declared now so
|
|
29
|
+
* the config shape is stable across phases; only `path` resolves in phase 1 —
|
|
30
|
+
* `resource`/`package` throw `ERR_SOURCE_KIND_UNSUPPORTED`. */
|
|
31
|
+
export type SourceSpec =
|
|
32
|
+
| { readonly path: string }
|
|
33
|
+
| { readonly resource: string }
|
|
34
|
+
| { readonly package: string };
|
|
35
|
+
|
|
36
|
+
export interface ResolvedSource {
|
|
37
|
+
/** Absolute path of one metadata file. */
|
|
38
|
+
readonly file: string;
|
|
39
|
+
/** The spec that contributed it — provenance for diagnostics. */
|
|
40
|
+
readonly spec: SourceSpec;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Used when `sources` is absent or empty in `.metaobjects/config.json`. A
|
|
44
|
+
* DEFAULT, never a requirement — a project that declares `sources` explicitly
|
|
45
|
+
* need not include the default directory at all. Built from
|
|
46
|
+
* `DEFAULT_METADATA_DIR` (`metadata-files.ts`'s single definition) rather than
|
|
47
|
+
* restating that name here: a second independent encoding of the same
|
|
48
|
+
* default would let `resolveCollection`'s "does the default dir exist"
|
|
49
|
+
* check (`collection.ts`) desync from what `resolveSources` actually
|
|
50
|
+
* resolves the moment the default ever changed — silently reproducing the
|
|
51
|
+
* "two code paths disagree about where metadata lives" class of bug this
|
|
52
|
+
* whole mechanism exists to eliminate. */
|
|
53
|
+
export const DEFAULT_SOURCES: readonly SourceSpec[] = [{ path: DEFAULT_METADATA_DIR }];
|
|
54
|
+
|
|
55
|
+
/** Narrows `spec` to its `path` arm, throwing `ERR_SOURCE_KIND_UNSUPPORTED`
|
|
56
|
+
* for `resource`/`package` — phase 1 resolves `path` only. Returns rather than
|
|
57
|
+
* asserting so one call both validates and narrows: an `asserts` signature has
|
|
58
|
+
* to be re-invoked wherever TypeScript's control-flow analysis cannot carry the
|
|
59
|
+
* narrowing, which is a language workaround masquerading as a second check. */
|
|
60
|
+
function toPathSpec(spec: SourceSpec): { readonly path: string } {
|
|
61
|
+
if ("path" in spec) return spec;
|
|
62
|
+
const kind = "resource" in spec ? "resource" : "package";
|
|
63
|
+
throw new ParseError(
|
|
64
|
+
`source kind "${kind}" is not supported by this toolchain yet; use a "path" source`,
|
|
65
|
+
{ code: "ERR_SOURCE_KIND_UNSUPPORTED", source: codeSource("resolveSources") },
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The declared source SET in CANONICAL order — kind-validated, then sorted by
|
|
71
|
+
* spec CONTENT rather than by declaration order.
|
|
72
|
+
*
|
|
73
|
+
* This is the ONE place declaration order is discarded, and the module's "pure
|
|
74
|
+
* function of the SET" invariant rests on it: the emitted file order, the spec
|
|
75
|
+
* attributed to a file two specs both reach, and which of several unresolvable
|
|
76
|
+
* paths reports its `ERR_SOURCE_UNRESOLVED` first are all decided here.
|
|
77
|
+
* Validation runs across the WHOLE list before any sorting or filesystem I/O —
|
|
78
|
+
* interleaved with resolution, which error code came back would depend on
|
|
79
|
+
* declaration order, contradicting that same invariant.
|
|
80
|
+
*
|
|
81
|
+
* Exported because `resolveCollection` derives `sourceRoots` from the declared
|
|
82
|
+
* specs and must use this identical ordering; a second sort would be a second
|
|
83
|
+
* definition of "canonical".
|
|
84
|
+
*/
|
|
85
|
+
export function orderedPathSpecs(specs: readonly SourceSpec[]): { readonly path: string }[] {
|
|
86
|
+
return specs.map(toPathSpec).sort((a, b) => {
|
|
87
|
+
const [ja, jb] = [JSON.stringify(a), JSON.stringify(b)];
|
|
88
|
+
return ja < jb ? -1 : ja > jb ? 1 : 0;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Where a declared `path` source lives on disk: absolute as written, otherwise
|
|
94
|
+
* relative to the DECLARING config's directory — never to ambient
|
|
95
|
+
* `process.cwd()`.
|
|
96
|
+
*
|
|
97
|
+
* One definition, because this expression *is* the rule for where a declared
|
|
98
|
+
* source lives, which is the single piece of knowledge this module exists to
|
|
99
|
+
* own. A caller that needs a source's root directory (rather than its files)
|
|
100
|
+
* calls this rather than restating it.
|
|
101
|
+
*/
|
|
102
|
+
export function resolveSpecPath(configDir: string, spec: { readonly path: string }): string {
|
|
103
|
+
return isAbsolute(spec.path) ? spec.path : resolve(configDir, spec.path);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Resolve a declared source SET to a canonically-ordered list of metadata files.
|
|
108
|
+
*
|
|
109
|
+
* The full result — each entry's `.file` AND its `.spec` — is a pure function
|
|
110
|
+
* of the SET of `specs`: permuting `specs` cannot change the output. One thing
|
|
111
|
+
* makes that hold: the specs are processed in CONTENT order
|
|
112
|
+
* (`JSON.stringify(spec)`, ascending) rather than declared order, so both the
|
|
113
|
+
* emitted file order and the spec attributed to a file overlapping two specs
|
|
114
|
+
* are decided by content alone. Declared order carries no information anywhere
|
|
115
|
+
* in this function.
|
|
116
|
+
*
|
|
117
|
+
* Within one directory spec the file order is `listMetadataFiles`'s — files at
|
|
118
|
+
* a level, then that level's subdirectories, depth-first. That is deliberately
|
|
119
|
+
* NOT a flat sort of absolute paths: see the file header, and
|
|
120
|
+
* `test/source-order.test.ts`.
|
|
121
|
+
*
|
|
122
|
+
* Only `path` specs resolve in phase 1: a directory is walked recursively, a
|
|
123
|
+
* file is taken as-is. An unresolvable `path` throws `ERR_SOURCE_UNRESOLVED`
|
|
124
|
+
* rather than silently contributing nothing; `resource`/`package` specs throw
|
|
125
|
+
* `ERR_SOURCE_KIND_UNSUPPORTED`.
|
|
126
|
+
*
|
|
127
|
+
* @param configDir absolute directory of the declaring config (the parent of
|
|
128
|
+
* `.metaobjects/`) — relative `path` specs resolve against it, never against
|
|
129
|
+
* ambient `process.cwd()`.
|
|
130
|
+
*/
|
|
131
|
+
export async function resolveSources(
|
|
132
|
+
configDir: string,
|
|
133
|
+
specs: readonly SourceSpec[],
|
|
134
|
+
): Promise<ResolvedSource[]> {
|
|
135
|
+
// Kind-validated and content-ordered in one pass — see `orderedPathSpecs`.
|
|
136
|
+
const ordered = orderedPathSpecs(specs);
|
|
137
|
+
|
|
138
|
+
// Insertion order IS output order — a Map preserves it, so the per-spec walk
|
|
139
|
+
// order above survives to the caller. First contributor wins a shared file,
|
|
140
|
+
// which is content-determined because `ordered` is.
|
|
141
|
+
const byFile = new Map<string, SourceSpec>();
|
|
142
|
+
|
|
143
|
+
for (const spec of ordered) {
|
|
144
|
+
const target = resolveSpecPath(configDir, spec);
|
|
145
|
+
const stats = await stat(target).catch(() => undefined);
|
|
146
|
+
if (stats === undefined) {
|
|
147
|
+
throw new ParseError(
|
|
148
|
+
`source path "${spec.path}" does not exist (resolved to ${target}, relative to ${configDir})`,
|
|
149
|
+
{ code: "ERR_SOURCE_UNRESOLVED", source: codeSource("resolveSources") },
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const found = stats.isDirectory() ? await listMetadataFiles(target) : [target];
|
|
154
|
+
for (const file of found) {
|
|
155
|
+
if (!byFile.has(file)) byFile.set(file, spec);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return [...byFile].map(([file, spec]) => ({ file, spec }));
|
|
160
|
+
}
|