@metaobjectsdev/sdk 0.23.1 → 0.24.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.
Files changed (75) hide show
  1. package/agent-context/skills/metaobjects-audit/SKILL.md +20 -7
  2. package/agent-context/skills/metaobjects-audit/references/capability-checklist.md +64 -18
  3. package/agent-context/skills/metaobjects-audit/references/csharp.md +2 -1
  4. package/agent-context/skills/metaobjects-audit/references/java.md +3 -2
  5. package/agent-context/skills/metaobjects-audit/references/kotlin.md +2 -1
  6. package/agent-context/skills/metaobjects-audit/references/requirements.md +3 -4
  7. package/agent-context/skills/metaobjects-audit/references/typescript.md +1 -1
  8. package/agent-context/skills/metaobjects-authoring/SKILL.md +28 -3
  9. package/agent-context/skills/metaobjects-authoring/references/requirements.md +49 -23
  10. package/agent-context/skills/metaobjects-codegen/SKILL.md +4 -3
  11. package/agent-context/skills/metaobjects-codegen/references/csharp.md +2 -2
  12. package/agent-context/skills/metaobjects-codegen/references/java.md +3 -3
  13. package/agent-context/skills/metaobjects-codegen/references/kotlin.md +4 -4
  14. package/agent-context/skills/metaobjects-codegen/references/python.md +2 -2
  15. package/agent-context/skills/metaobjects-codegen/references/typescript.md +3 -3
  16. package/agent-context/skills/metaobjects-fit-assessment/SKILL.md +4 -4
  17. package/agent-context/skills/metaobjects-prompts/SKILL.md +53 -32
  18. package/agent-context/skills/metaobjects-prompts/references/csharp.md +26 -21
  19. package/agent-context/skills/metaobjects-prompts/references/java.md +24 -18
  20. package/agent-context/skills/metaobjects-prompts/references/kotlin.md +25 -20
  21. package/agent-context/skills/metaobjects-prompts/references/python.md +68 -26
  22. package/agent-context/skills/metaobjects-prompts/references/typescript.md +29 -23
  23. package/agent-context/skills/metaobjects-verify/references/migration.md +1 -1
  24. package/agent-context/skills/metaobjects-verify/references/requirements.md +36 -22
  25. package/agent-context/templates/always-on.md.mustache +3 -1
  26. package/dist/agent-docs/body.d.ts +1 -1
  27. package/dist/agent-docs/body.d.ts.map +1 -1
  28. package/dist/agent-docs/body.js +24 -2
  29. package/dist/agent-docs/body.js.map +1 -1
  30. package/dist/collection.d.ts +71 -0
  31. package/dist/collection.d.ts.map +1 -0
  32. package/dist/collection.js +121 -0
  33. package/dist/collection.js.map +1 -0
  34. package/dist/config.d.ts +51 -21
  35. package/dist/config.d.ts.map +1 -1
  36. package/dist/config.js +76 -10
  37. package/dist/config.js.map +1 -1
  38. package/dist/discovery.d.ts +43 -0
  39. package/dist/discovery.d.ts.map +1 -0
  40. package/dist/discovery.js +100 -0
  41. package/dist/discovery.js.map +1 -0
  42. package/dist/index.d.ts +10 -1
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +17 -4
  45. package/dist/index.js.map +1 -1
  46. package/dist/memory.d.ts +42 -19
  47. package/dist/memory.d.ts.map +1 -1
  48. package/dist/memory.js +38 -95
  49. package/dist/memory.js.map +1 -1
  50. package/dist/metadata-files.d.ts +67 -0
  51. package/dist/metadata-files.d.ts.map +1 -0
  52. package/dist/metadata-files.js +155 -0
  53. package/dist/metadata-files.js.map +1 -0
  54. package/dist/records/any.d.ts +8 -8
  55. package/dist/records/decision.d.ts +2 -2
  56. package/dist/records/glossary.d.ts +4 -4
  57. package/dist/records/principle.d.ts +2 -2
  58. package/dist/scope.d.ts +16 -0
  59. package/dist/scope.d.ts.map +1 -0
  60. package/dist/scope.js +75 -0
  61. package/dist/scope.js.map +1 -0
  62. package/dist/sources.d.ts +86 -0
  63. package/dist/sources.d.ts.map +1 -0
  64. package/dist/sources.js +130 -0
  65. package/dist/sources.js.map +1 -0
  66. package/package.json +2 -2
  67. package/src/agent-docs/body.ts +24 -2
  68. package/src/collection.ts +183 -0
  69. package/src/config.ts +80 -12
  70. package/src/discovery.ts +110 -0
  71. package/src/index.ts +26 -9
  72. package/src/memory.ts +65 -99
  73. package/src/metadata-files.ts +158 -0
  74. package/src/scope.ts +95 -0
  75. package/src/sources.ts +160 -0
package/dist/index.js CHANGED
@@ -24,10 +24,23 @@ FORGE_DECISION_SUBTYPES, FORGE_PRINCIPLE_SUBTYPES, FORGE_CONVENTION_SUBTYPES, FO
24
24
  FORGE_ATTR_CONFIDENCE, FORGE_ATTR_SOURCE, FORGE_ATTR_CAPTURED_AT, FORGE_ATTR_LAST_VALIDATED_COMMIT, FORGE_ATTR_PRIMARY_LOCATION, FORGE_ATTR_OCCURRENCES, FORGE_ATTR_RATIONALE, FORGE_ATTR_ALTERNATIVES, FORGE_ATTR_SCOPE, FORGE_ATTR_STATEMENT, FORGE_ATTR_ENFORCEMENT, FORGE_ATTR_PATTERN_DESCRIPTION, FORGE_ATTR_EXAMPLES, FORGE_ATTR_COUNTER_EXAMPLES, FORGE_ATTR_APPLIES_TO, FORGE_ATTR_TERM, FORGE_ATTR_SYNONYMS, FORGE_ATTR_DEFINITION, FORGE_ATTR_CODE_ANCHORS, FORGE_ATTR_SEE_ALSO, FORGE_ATTR_WHAT_WAS_TRIED, FORGE_ATTR_WHY_IT_FAILED, FORGE_ATTRS,
25
25
  // Registration helper + provider
26
26
  registerForgeTypes, forgeTypesProvider, } from "./forge-types.js";
27
- // Memory loader — read metaobjects/ into a MetaData tree
28
- // (workspace-aware: walks extends: deps via pnpm-workspace.yaml or
29
- // package.json workspaces field if present)
30
- export { loadMemory, defaultLoadMemoryProviders, DEFAULT_METADATA_DIR, DEFAULT_METAOBJECTS_DIR, } from "./memory.js";
27
+ // Memory loader — read a project's resolved metadata into a MetaData tree.
28
+ // Where those files come from is `resolveCollection`'s decision (below), which
29
+ // `loadMemory` calls when the caller supplies no explicit file set.
30
+ export { loadMemory, defaultLoadMemoryProviders } from "./memory.js";
31
+ // Default project layout — the DEFAULT value of `sources` (applied by
32
+ // `resolveCollection` alone) and the fixed directory holding the config that
33
+ // declares them. Exported for `meta init`, which SCAFFOLDS that layout.
34
+ export { DEFAULT_METADATA_DIR, DEFAULT_METAOBJECTS_DIR } from "./metadata-files.js";
35
+ // Scope — output filter over fully-qualified node names
36
+ export { compileScope, matchesScope } from "./scope.js";
37
+ // Source resolution — a declared source SET to a canonically-sorted file list
38
+ export { resolveSources, resolveSpecPath, orderedPathSpecs, DEFAULT_SOURCES } from "./sources.js";
39
+ // Discovery — nearest-ancestor project root (a `.metaobjects/config.json`,
40
+ // the only marker), bounded by the repo root
41
+ export { discoverCollectionRoot, resolveConfigDir } from "./discovery.js";
42
+ // Collection — the single authority on where a project's metadata lives
43
+ export { resolveCollection } from "./collection.js";
31
44
  // Workspace discovery — finds peer metadata packages in a monorepo
32
45
  export { discoverWorkspace, resolveExtendsOrder, packageLabel } from "./workspace.js";
33
46
  // Package manifest — the v0.3 package.meta.json model. Three-field manifest
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,UAAU;AACV,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,EACT,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAG5B,QAAQ;AACR,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEzD,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGnG,0EAA0E;AAC1E,0EAA0E;AAC1E,gCAAgC;AAChC,OAAO;AACL,aAAa;AACb,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,WAAW;AACX,WAAW;AACX,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB;AACtB,kBAAkB;AAClB,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,gCAAgC,EAChC,2BAA2B,EAC3B,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,8BAA8B,EAC9B,mBAAmB,EACnB,2BAA2B,EAC3B,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,EACzB,wBAAwB,EACxB,WAAW;AACX,iCAAiC;AACjC,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAG1B,yDAAyD;AACzD,mEAAmE;AACnE,6CAA6C;AAC7C,OAAO,EACL,UAAU,EACV,0BAA0B,EAC1B,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAGrB,mEAAmE;AACnE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGtF,4EAA4E;AAC5E,0EAA0E;AAC1E,wEAAwE;AACxE,yEAAyE;AACzE,uBAAuB;AACvB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AAGtB,uEAAuE;AACvE,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,UAAU;AACV,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,EACT,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAG5B,QAAQ;AACR,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEzD,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGnG,0EAA0E;AAC1E,0EAA0E;AAC1E,gCAAgC;AAChC,OAAO;AACL,aAAa;AACb,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,WAAW;AACX,WAAW;AACX,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB;AACtB,kBAAkB;AAClB,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,gCAAgC,EAChC,2BAA2B,EAC3B,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,8BAA8B,EAC9B,mBAAmB,EACnB,2BAA2B,EAC3B,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,EACzB,wBAAwB,EACxB,WAAW;AACX,iCAAiC;AACjC,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAG1B,2EAA2E;AAC3E,+EAA+E;AAC/E,oEAAoE;AACpE,OAAO,EAAE,UAAU,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAGrE,sEAAsE;AACtE,6EAA6E;AAC7E,wEAAwE;AACxE,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAEpF,wDAAwD;AACxD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGxD,8EAA8E;AAC9E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGlG,2EAA2E;AAC3E,6CAA6C;AAC7C,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAG1E,wEAAwE;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD,mEAAmE;AACnE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGtF,4EAA4E;AAC5E,0EAA0E;AAC1E,wEAAwE;AACxE,yEAAyE;AACzE,uBAAuB;AACvB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AAGtB,uEAAuE;AACvE,cAAc,0BAA0B,CAAC"}
package/dist/memory.d.ts CHANGED
@@ -1,15 +1,4 @@
1
1
  import { type MetaDataTypeProvider, type MetaRoot } from "@metaobjectsdev/metadata";
2
- /**
3
- * Default directory name (relative to project root) where metadata JSON files
4
- * are scanned. Scaffold via `meta init`; the directory is committed to git.
5
- */
6
- export declare const DEFAULT_METADATA_DIR = "metaobjects";
7
- /**
8
- * Default directory name (relative to project root) for MetaObjects' own
9
- * runtime state: config.json, .gen-state/, package.meta.json, agent docs.
10
- * Scaffold via `meta init`; most contents are committed to git.
11
- */
12
- export declare const DEFAULT_METAOBJECTS_DIR = ".metaobjects";
13
2
  /**
14
3
  * Options for {@link loadMemory}. Consumers can supply additional
15
4
  * {@link MetaDataTypeProvider}s to extend the metamodel with their own
@@ -36,6 +25,31 @@ export interface LoadMemoryOptions {
36
25
  * the `meta verify` command opts in to `true` (strict-by-default, #96).
37
26
  */
38
27
  strict?: boolean;
28
+ /**
29
+ * An already-resolved, absolute metadata file list — normally
30
+ * `resolveCollection(...).files`. When supplied, `loadMemory` loads exactly
31
+ * these files and resolves nothing itself.
32
+ *
33
+ * Omitting it is not a different WAY of finding metadata, only a different
34
+ * place the same resolution happens: `loadMemory` then calls
35
+ * `resolveCollection(repoRoot)` itself. Passing it saves the second
36
+ * resolution when the caller already holds a collection (every routed CLI
37
+ * command does) and lets a caller load a file set it computed some other
38
+ * way; it can no longer diverge from what the config declares.
39
+ */
40
+ files?: readonly string[];
41
+ /**
42
+ * MetaObjects-shipped library packages to load ALONGSIDE the project's own files
43
+ * (e.g. `["ai"]` for `metaobjects::ai::LlmCallBase`). Prepended, so an
44
+ * `extends: "metaobjects::ai::LlmCallBase"` in project metadata resolves.
45
+ *
46
+ * Opt-in rather than always-on: a library package registers real top-level nodes, and
47
+ * a project that never references one should not have them appear in its model, its
48
+ * generated output or its docs. Without this the CLI could not load the metadata that
49
+ * shipped generators like `trace-helper` exist to consume, so the generator was
50
+ * reachable from the command line while its input was not (#333).
51
+ */
52
+ libraries?: readonly string[];
39
53
  }
40
54
  /** Default provider bundle threaded by {@link loadMemory} when no options
41
55
  * override is supplied. Exposed for tests/inspection; callers shouldn't need
@@ -43,10 +57,15 @@ export interface LoadMemoryOptions {
43
57
  * composes `[...defaultLoadMemoryProviders, mine]` automatically. */
44
58
  export declare const defaultLoadMemoryProviders: readonly MetaDataTypeProvider[];
45
59
  /**
46
- * Load all metadata files from `<repoRoot>/metaobjects/` into a single
47
- * MetaData. If `<repoRoot>/.meta/package.meta.json` declares `extends:` deps
48
- * and a workspace can be discovered (pnpm-workspace.yaml or package.json
49
- * workspaces), peer packages are loaded too in topological dep-first order.
60
+ * Load a project's metadata into a single MetaData tree.
61
+ *
62
+ * Which files those are is `resolveCollection`'s decision, never this
63
+ * function's: with no {@link LoadMemoryOptions.files} it calls
64
+ * `resolveCollection(repoRoot)` — nearest-ancestor `.metaobjects/config.json`,
65
+ * then that config's declared `sources`, falling back to the default source
66
+ * directory only when a project declares none. `loadMemory` names no directory
67
+ * of its own, so a caller cannot end up loading from somewhere the rest of the
68
+ * toolchain does not.
50
69
  *
51
70
  * Excludes `_pending/`. Registers metaobjects core types plus Meta Forge's
52
71
  * descriptive top-level types (decision, principle, etc.) so mixed content
@@ -54,11 +73,15 @@ export declare const defaultLoadMemoryProviders: readonly MetaDataTypeProvider[]
54
73
  * {@link LoadMemoryOptions.providers}) are composed AFTER the defaults so
55
74
  * they may depend on core/forge ids.
56
75
  *
57
- * Throws if `metaobjects/` doesn't exist (callers should run `meta init`).
76
+ * Throws `ERR_COLLECTION_NOT_FOUND` when nothing resolves (callers should run
77
+ * `meta init`), unless `options.files` is supplied.
58
78
  *
59
- * @param repoRoot The project's working-directory root (e.g. process.cwd()).
60
- * `loadMemory` resolves `metaobjects/` and (if workspace-aware) the
61
- * transitive `extends:` graph automatically.
79
+ * @param repoRoot Where resolution STARTS — the working directory, typically
80
+ * `process.cwd()`. The walk goes up from here for the governing config, so
81
+ * this need not be the project root itself.
82
+ * **Ignored entirely when `options.files` is supplied**: that list is already
83
+ * resolved, so nothing reads this path. Every routed CLI command passes both,
84
+ * and the argument is inert at all of them.
62
85
  * @param options Optional {@link LoadMemoryOptions} — supply additional
63
86
  * providers or replace the default bundle entirely.
64
87
  */
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,QAAQ,EACd,MAAM,0BAA0B,CAAC;AAKlC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAC5C;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;sEAGsE;AACtE,eAAO,MAAM,0BAA0B,EAAE,SAAS,oBAAoB,EAGrE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,QAAQ,CAAC,CAgCnB"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,QAAQ,EACd,MAAM,0BAA0B,CAAC;AAKlC;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAC5C;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAED;;;sEAGsE;AACtE,eAAO,MAAM,0BAA0B,EAAE,SAAS,oBAAoB,EAGrE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,QAAQ,CAAC,CAiDnB"}
package/dist/memory.js CHANGED
@@ -1,20 +1,7 @@
1
- import { join } from "node:path";
2
- import { readdir, stat } from "node:fs/promises";
3
1
  import { composeRegistry, coreProviders, MetaDataLoader, } from "@metaobjectsdev/metadata";
4
2
  import { FileSource } from "@metaobjectsdev/metadata/core";
3
+ import { resolveCollection } from "./collection.js";
5
4
  import { forgeTypesProvider } from "./forge-types.js";
6
- import { discoverWorkspace, resolveExtendsOrder } from "./workspace.js";
7
- /**
8
- * Default directory name (relative to project root) where metadata JSON files
9
- * are scanned. Scaffold via `meta init`; the directory is committed to git.
10
- */
11
- export const DEFAULT_METADATA_DIR = "metaobjects";
12
- /**
13
- * Default directory name (relative to project root) for MetaObjects' own
14
- * runtime state: config.json, .gen-state/, package.meta.json, agent docs.
15
- * Scaffold via `meta init`; most contents are committed to git.
16
- */
17
- export const DEFAULT_METAOBJECTS_DIR = ".metaobjects";
18
5
  /** Default provider bundle threaded by {@link loadMemory} when no options
19
6
  * override is supplied. Exposed for tests/inspection; callers shouldn't need
20
7
  * to spread this manually — `loadMemory(root, { providers: [mine] })`
@@ -24,10 +11,15 @@ export const defaultLoadMemoryProviders = [
24
11
  forgeTypesProvider,
25
12
  ];
26
13
  /**
27
- * Load all metadata files from `<repoRoot>/metaobjects/` into a single
28
- * MetaData. If `<repoRoot>/.meta/package.meta.json` declares `extends:` deps
29
- * and a workspace can be discovered (pnpm-workspace.yaml or package.json
30
- * workspaces), peer packages are loaded too in topological dep-first order.
14
+ * Load a project's metadata into a single MetaData tree.
15
+ *
16
+ * Which files those are is `resolveCollection`'s decision, never this
17
+ * function's: with no {@link LoadMemoryOptions.files} it calls
18
+ * `resolveCollection(repoRoot)` — nearest-ancestor `.metaobjects/config.json`,
19
+ * then that config's declared `sources`, falling back to the default source
20
+ * directory only when a project declares none. `loadMemory` names no directory
21
+ * of its own, so a caller cannot end up loading from somewhere the rest of the
22
+ * toolchain does not.
31
23
  *
32
24
  * Excludes `_pending/`. Registers metaobjects core types plus Meta Forge's
33
25
  * descriptive top-level types (decision, principle, etc.) so mixed content
@@ -35,11 +27,15 @@ export const defaultLoadMemoryProviders = [
35
27
  * {@link LoadMemoryOptions.providers}) are composed AFTER the defaults so
36
28
  * they may depend on core/forge ids.
37
29
  *
38
- * Throws if `metaobjects/` doesn't exist (callers should run `meta init`).
30
+ * Throws `ERR_COLLECTION_NOT_FOUND` when nothing resolves (callers should run
31
+ * `meta init`), unless `options.files` is supplied.
39
32
  *
40
- * @param repoRoot The project's working-directory root (e.g. process.cwd()).
41
- * `loadMemory` resolves `metaobjects/` and (if workspace-aware) the
42
- * transitive `extends:` graph automatically.
33
+ * @param repoRoot Where resolution STARTS — the working directory, typically
34
+ * `process.cwd()`. The walk goes up from here for the governing config, so
35
+ * this need not be the project root itself.
36
+ * **Ignored entirely when `options.files` is supplied**: that list is already
37
+ * resolved, so nothing reads this path. Every routed CLI command passes both,
38
+ * and the argument is inert at all of them.
43
39
  * @param options Optional {@link LoadMemoryOptions} — supply additional
44
40
  * providers or replace the default bundle entirely.
45
41
  */
@@ -56,87 +52,34 @@ export async function loadMemory(repoRoot, options) {
56
52
  providers = [...defaultLoadMemoryProviders, ...extra];
57
53
  }
58
54
  const registry = composeRegistry(providers);
59
- // Collect all metadata file paths to load. Order matters for the parser's
60
- // deferred-resolution pass (it parses in array order, then resolves supers
61
- // against the merged tree afterwards) dep packages first, current last.
62
- const paths = await collectMetadataPaths(repoRoot);
55
+ // Both arms are `resolveCollection`'s answer one already computed by the
56
+ // caller, one computed here. There is no third way to find metadata, and
57
+ // that is the whole of this line's design: the previous no-`files` arm
58
+ // scanned `<repoRoot>/<default dir>` directly, so a caller that copied the
59
+ // routed shape but forgot `files` silently loaded from a directory the
60
+ // project's config may never have mentioned.
61
+ const paths = options?.files !== undefined
62
+ ? [...options.files]
63
+ : [...(await resolveCollection(repoRoot)).files];
63
64
  const loader = new MetaDataLoader({
64
65
  registry,
65
66
  ...(options?.strict === true ? { strict: true } : {}),
66
67
  });
67
- const result = await loader.load(paths.map((p) => new FileSource(p)));
68
+ // Library sources are imported lazily and only when asked for — the same reason
69
+ // `MetaDataLoader.fromDirectory` does it. `library-sources.ts` reads `node:fs`, so a
70
+ // static import from a root-reachable module drags Node built-ins into every consumer's
71
+ // graph; that is the #287 bundle defect, and the `./library` subpath exists for exactly
72
+ // the reason `./constants` does. Prepended, so a project's `extends` onto a
73
+ // library-shipped abstract base resolves — super resolution is order-independent, but
74
+ // prepending is the deterministic choice and matches `fromDirectory`.
75
+ const libSources = options?.libraries !== undefined && options.libraries.length > 0
76
+ ? (await import("@metaobjectsdev/metadata/library")).librarySources([...options.libraries])
77
+ : [];
78
+ const result = await loader.load([...libSources, ...paths.map((p) => new FileSource(p))]);
68
79
  if (result.errors.length > 0) {
69
80
  const first = result.errors[0];
70
81
  throw first;
71
82
  }
72
83
  return result.root;
73
84
  }
74
- // Dep packages' metaobjects/ files first (topological order), then current.
75
- async function collectMetadataPaths(repoRoot) {
76
- const currentMetaDir = join(repoRoot, ".meta");
77
- const ws = await discoverWorkspace(repoRoot);
78
- // Workspace path: walk extends, load dep metaobjects/ dirs first
79
- if (ws !== undefined) {
80
- const currentPkg = ws.packages.find((p) => p.metaDir === currentMetaDir);
81
- if (currentPkg !== undefined && currentPkg.manifest.extends.length > 0) {
82
- const ordered = resolveExtendsOrder(ws, currentMetaDir);
83
- const paths = [];
84
- for (const pkg of ordered) {
85
- // Each workspace package's metadata lives alongside its .meta/ dir
86
- const pkgRoot = join(pkg.metaDir, "..");
87
- paths.push(...(await listMetadataFiles(join(pkgRoot, DEFAULT_METADATA_DIR))));
88
- }
89
- return paths;
90
- }
91
- }
92
- // Single-package path: scan metaobjects/ at the project root
93
- return listMetadataFiles(join(repoRoot, DEFAULT_METADATA_DIR));
94
- }
95
- /**
96
- * Recursively list metadata files (*.json, *.yaml, *.yml) under a directory,
97
- * excluding _pending/ at any level. Subdirectories (e.g. projections/) are
98
- * walked depth-first. Files within a directory are sorted alphabetically for
99
- * deterministic load order; subdirectories are visited after files at the
100
- * same level.
101
- *
102
- * Format selection (parsing) happens downstream in `FileSource` from
103
- * `@metaobjectsdev/metadata`, which infers the parser from file extension.
104
- */
105
- async function listMetadataFiles(dir) {
106
- let entries;
107
- try {
108
- entries = await readdir(dir);
109
- }
110
- catch (err) {
111
- throw new Error(`loadMemory: cannot read ${dir}: ${err.message}`);
112
- }
113
- const paths = [];
114
- const subdirs = [];
115
- // #188: sort the raw `readdir` entries so file order is deterministic across
116
- // runtimes/filesystems (Node vs Bun return different `readdir` orders), matching
117
- // this function's docstring and the metadata package's own `DirectorySource`.
118
- // (Resolution is now order-INDEPENDENT — super-resolve.ts #188 — so this is the
119
- // deterministic-enumeration FLOOR, not the fix; it keeps every derived artifact
120
- // that preserves declaration order, e.g. serialization, stable across runtimes.)
121
- for (const entry of [...entries].sort()) {
122
- if (entry === "_pending")
123
- continue;
124
- const full = join(dir, entry);
125
- const s = await stat(full);
126
- if (s.isDirectory()) {
127
- subdirs.push(full);
128
- }
129
- else if (s.isFile() && isMetadataFile(entry)) {
130
- paths.push(full);
131
- }
132
- }
133
- // Recurse into subdirectories after collecting files at this level
134
- for (const sub of subdirs.sort()) {
135
- paths.push(...(await listMetadataFiles(sub)));
136
- }
137
- return paths;
138
- }
139
- function isMetadataFile(name) {
140
- return name.endsWith(".json") || name.endsWith(".yaml") || name.endsWith(".yml");
141
- }
142
85
  //# sourceMappingURL=memory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,aAAa,EACb,cAAc,GAGf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAuDtD;;;sEAGsE;AACtE,MAAM,CAAC,MAAM,0BAA0B,GAAoC;IACzE,GAAG,aAAa;IAChB,kBAAkB;CACnB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,QAAgB,EAChB,OAA2B;IAE3B,MAAM,KAAK,GAAG,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;IACvC,IAAI,SAA0C,CAAC;IAC/C,IAAI,OAAO,EAAE,eAAe,KAAK,IAAI,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,oFAAoF,CACrF,CAAC;QACJ,CAAC;QACD,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,CAAC,GAAG,0BAA0B,EAAE,GAAG,KAAK,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAE5C,2EAA2E;IAC3E,yEAAyE;IACzE,uEAAuE;IACvE,2EAA2E;IAC3E,uEAAuE;IACvE,6CAA6C;IAC7C,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,KAAK,SAAS;QACxC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;QACpB,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAEnD,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;QAChC,QAAQ;QACR,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC,CAAC;IAEH,gFAAgF;IAChF,qFAAqF;IACrF,wFAAwF;IACxF,wFAAwF;IACxF,4EAA4E;IAC5E,sFAAsF;IACtF,sEAAsE;IACtE,MAAM,UAAU,GACd,OAAO,EAAE,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;QAC9D,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QAC3F,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,UAAU,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1F,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;QAChC,MAAM,KAAK,CAAC;IACd,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The DEFAULT value of `sources` — the directory scanned when
3
+ * `.metaobjects/config.json` declares no sources. Scaffold via `meta init`;
4
+ * the directory is committed to git.
5
+ *
6
+ * **A default, and nothing else.** No read path may assume a directory of this
7
+ * name exists or is where metadata lives: that question is answered by
8
+ * `resolveCollection`, which applies this constant exactly once (via
9
+ * `DEFAULT_SOURCES` in `sources.ts`) when a project declares nothing. A
10
+ * project that declares `sources` may put its metadata anywhere, and every
11
+ * command follows the config. `test/no-hardcoded-metadata-dir.test.ts` is the
12
+ * enforcer.
13
+ */
14
+ export declare const DEFAULT_METADATA_DIR = "metaobjects";
15
+ /**
16
+ * Default directory name (relative to project root) for MetaObjects' own
17
+ * runtime state: config.json, .gen-state/, package.meta.json, agent docs.
18
+ * Scaffold via `meta init`; most contents are committed to git.
19
+ *
20
+ * Unlike {@link DEFAULT_METADATA_DIR} this one IS a fixed convention — it is
21
+ * where the config that answers "where is the metadata?" lives, so it cannot
22
+ * itself be configured.
23
+ */
24
+ export declare const DEFAULT_METAOBJECTS_DIR = ".metaobjects";
25
+ /** Recognized metadata file extensions, matched case-insensitively — mirrors
26
+ * `DirectorySource` in `@metaobjectsdev/metadata`, which checks
27
+ * `extname().toLowerCase()`. The single definition every metadata-file
28
+ * walker in this package uses — and since `resolveSources` (`sources.ts`)
29
+ * calls {@link listMetadataFiles} outright rather than keeping a second
30
+ * recursive walk of its own, there is exactly one walker to keep honest. */
31
+ export declare const METADATA_EXTENSIONS: Set<string>;
32
+ export declare function isMetadataFile(name: string): boolean;
33
+ /**
34
+ * Recursively list metadata files (*.json, *.yaml, *.yml, matched
35
+ * case-insensitively — see `isMetadataFile` above) under a directory,
36
+ * excluding _pending/ at any level. Subdirectories (e.g. projections/) are
37
+ * walked depth-first. Files within a directory are sorted alphabetically for
38
+ * deterministic load order; subdirectories are visited AFTER the files at the
39
+ * same level.
40
+ *
41
+ * That per-level rule is a contract, not an implementation detail. This is the
42
+ * order production has always handed the loader, and declaration order survives
43
+ * into generated output: `codegen-ts`'s barrel emits from `root.objects()`
44
+ * order, and so do the shared `enums.ts`, `meta docs` page ordering and `meta
45
+ * export`'s `canonicalSerialize` sibling order. A flat lexicographic sort of
46
+ * absolute paths is NOT the same list — it disagrees whenever a subdirectory
47
+ * name sorts before a sibling file (`common/` before `meta.users.json`) — so
48
+ * `resolveSources` calls this function rather than re-walking and re-sorting.
49
+ * Pinned by `test/source-order.test.ts`.
50
+ *
51
+ * Exported for that gate and for `sources.ts`; not re-exported from the package
52
+ * index — `resolveCollection` is the public door.
53
+ *
54
+ * An entry whose `stat` fails (a dangling symlink, a TOCTOU removal between
55
+ * `readdir` and `stat`, an EACCES entry) is SKIPPED, matching `DirectorySource`
56
+ * in `@metaobjectsdev/metadata`, which this walk otherwise mirrors. A failure to
57
+ * read the directory itself still throws — that is the "you have no metadata
58
+ * here" case callers report.
59
+ *
60
+ * A symlink CYCLE (e.g. `metaobjects/link -> ..`) is a loud error rather than
61
+ * unbounded recursion — see {@link listMetadataFilesGuarded}.
62
+ *
63
+ * Format selection (parsing) happens downstream in `FileSource` from
64
+ * `@metaobjectsdev/metadata`, which infers the parser from file extension.
65
+ */
66
+ export declare function listMetadataFiles(dir: string): Promise<string[]>;
67
+ //# sourceMappingURL=metadata-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata-files.d.ts","sourceRoot":"","sources":["../src/metadata-files.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAElD;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAEtD;;;;;6EAK6E;AAC7E,eAAO,MAAM,mBAAmB,aAAsC,CAAC;AAEvE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAEtE"}
@@ -0,0 +1,155 @@
1
+ // server/typescript/packages/sdk/src/metadata-files.ts
2
+ //
3
+ // The project's default directory names, what counts as a metadata file, and
4
+ // the one walk that turns a directory into an ordered file list.
5
+ //
6
+ // **This module imports nothing from its siblings, and that is the point.**
7
+ // `resolveCollection` (`collection.ts`) is the single authority on where
8
+ // metadata lives, so `memory.ts`'s `loadMemory` must call it — while
9
+ // `collection.ts` and `sources.ts` need the constants and the walk below.
10
+ // Homing those in `memory.ts` closes an ESM cycle whose failure mode is not a
11
+ // warning but a crash: `DEFAULT_SOURCES` (`sources.ts`) reads
12
+ // `DEFAULT_METADATA_DIR` at module top level, so the cycle surfaces as
13
+ // `ReferenceError: Cannot access 'DEFAULT_METADATA_DIR' before initialization`
14
+ // on whichever module the entry point happens to reach first. A leaf both
15
+ // sides import is the fix; a lazy `await import()` inside `loadMemory` is not
16
+ // — that hides the cycle rather than removing it.
17
+ import { extname, join } from "node:path";
18
+ import { readdir, realpath, stat } from "node:fs/promises";
19
+ /**
20
+ * The DEFAULT value of `sources` — the directory scanned when
21
+ * `.metaobjects/config.json` declares no sources. Scaffold via `meta init`;
22
+ * the directory is committed to git.
23
+ *
24
+ * **A default, and nothing else.** No read path may assume a directory of this
25
+ * name exists or is where metadata lives: that question is answered by
26
+ * `resolveCollection`, which applies this constant exactly once (via
27
+ * `DEFAULT_SOURCES` in `sources.ts`) when a project declares nothing. A
28
+ * project that declares `sources` may put its metadata anywhere, and every
29
+ * command follows the config. `test/no-hardcoded-metadata-dir.test.ts` is the
30
+ * enforcer.
31
+ */
32
+ export const DEFAULT_METADATA_DIR = "metaobjects";
33
+ /**
34
+ * Default directory name (relative to project root) for MetaObjects' own
35
+ * runtime state: config.json, .gen-state/, package.meta.json, agent docs.
36
+ * Scaffold via `meta init`; most contents are committed to git.
37
+ *
38
+ * Unlike {@link DEFAULT_METADATA_DIR} this one IS a fixed convention — it is
39
+ * where the config that answers "where is the metadata?" lives, so it cannot
40
+ * itself be configured.
41
+ */
42
+ export const DEFAULT_METAOBJECTS_DIR = ".metaobjects";
43
+ /** Recognized metadata file extensions, matched case-insensitively — mirrors
44
+ * `DirectorySource` in `@metaobjectsdev/metadata`, which checks
45
+ * `extname().toLowerCase()`. The single definition every metadata-file
46
+ * walker in this package uses — and since `resolveSources` (`sources.ts`)
47
+ * calls {@link listMetadataFiles} outright rather than keeping a second
48
+ * recursive walk of its own, there is exactly one walker to keep honest. */
49
+ export const METADATA_EXTENSIONS = new Set([".json", ".yaml", ".yml"]);
50
+ export function isMetadataFile(name) {
51
+ return METADATA_EXTENSIONS.has(extname(name).toLowerCase());
52
+ }
53
+ /** Directory excluded at every level of {@link listMetadataFiles} — drafts
54
+ * that are deliberately not part of the loaded model. */
55
+ const PENDING_DIR = "_pending";
56
+ /**
57
+ * Recursively list metadata files (*.json, *.yaml, *.yml, matched
58
+ * case-insensitively — see `isMetadataFile` above) under a directory,
59
+ * excluding _pending/ at any level. Subdirectories (e.g. projections/) are
60
+ * walked depth-first. Files within a directory are sorted alphabetically for
61
+ * deterministic load order; subdirectories are visited AFTER the files at the
62
+ * same level.
63
+ *
64
+ * That per-level rule is a contract, not an implementation detail. This is the
65
+ * order production has always handed the loader, and declaration order survives
66
+ * into generated output: `codegen-ts`'s barrel emits from `root.objects()`
67
+ * order, and so do the shared `enums.ts`, `meta docs` page ordering and `meta
68
+ * export`'s `canonicalSerialize` sibling order. A flat lexicographic sort of
69
+ * absolute paths is NOT the same list — it disagrees whenever a subdirectory
70
+ * name sorts before a sibling file (`common/` before `meta.users.json`) — so
71
+ * `resolveSources` calls this function rather than re-walking and re-sorting.
72
+ * Pinned by `test/source-order.test.ts`.
73
+ *
74
+ * Exported for that gate and for `sources.ts`; not re-exported from the package
75
+ * index — `resolveCollection` is the public door.
76
+ *
77
+ * An entry whose `stat` fails (a dangling symlink, a TOCTOU removal between
78
+ * `readdir` and `stat`, an EACCES entry) is SKIPPED, matching `DirectorySource`
79
+ * in `@metaobjectsdev/metadata`, which this walk otherwise mirrors. A failure to
80
+ * read the directory itself still throws — that is the "you have no metadata
81
+ * here" case callers report.
82
+ *
83
+ * A symlink CYCLE (e.g. `metaobjects/link -> ..`) is a loud error rather than
84
+ * unbounded recursion — see {@link listMetadataFilesGuarded}.
85
+ *
86
+ * Format selection (parsing) happens downstream in `FileSource` from
87
+ * `@metaobjectsdev/metadata`, which infers the parser from file extension.
88
+ */
89
+ export async function listMetadataFiles(dir) {
90
+ return listMetadataFilesGuarded(dir, new Set());
91
+ }
92
+ /**
93
+ * {@link listMetadataFiles}'s recursive worker, carrying the REAL (symlink-
94
+ * resolved) ancestor directories already on this walk branch.
95
+ *
96
+ * This walk follows symlinked directories on purpose (`stat`, not `lstat`,
97
+ * below — matching `DirectorySource` in `@metaobjectsdev/metadata`), so an
98
+ * unguarded directory symlink that revisits an ancestor recurses forever:
99
+ * Java and Python both added this exact guard when this PR promoted
100
+ * symlink-following to a cross-port contract; the TypeScript reference itself
101
+ * did not, even though the corpus cites it as authoritative. `ancestors` is
102
+ * extended only on the recursive call (never mutated in place), so it
103
+ * reflects the current branch, not siblings visited earlier at the same
104
+ * level — a directory legitimately reachable via two different symlinked
105
+ * paths (not a cycle) is not falsely rejected.
106
+ */
107
+ async function listMetadataFilesGuarded(dir, ancestors) {
108
+ // `realpath` failing (e.g. `dir` vanished between being listed and now) is
109
+ // not this guard's problem — fall back to the given path and let `readdir`
110
+ // below raise its own coded error.
111
+ const real = await realpath(dir).catch(() => dir);
112
+ if (ancestors.has(real)) {
113
+ throw new Error(`symlink loop detected while expanding metadata directory: ${dir} revisits ${real}`);
114
+ }
115
+ const nextAncestors = new Set(ancestors);
116
+ nextAncestors.add(real);
117
+ let entries;
118
+ try {
119
+ entries = await readdir(dir);
120
+ }
121
+ catch (err) {
122
+ throw new Error(`cannot read metadata directory ${dir}: ${err.message}`);
123
+ }
124
+ const paths = [];
125
+ const subdirs = [];
126
+ // #188: sort the raw `readdir` entries so file order is deterministic across
127
+ // runtimes/filesystems (Node vs Bun return different `readdir` orders), matching
128
+ // this function's docstring and the metadata package's own `DirectorySource`.
129
+ // (Resolution is now order-INDEPENDENT — super-resolve.ts #188 — so this is the
130
+ // deterministic-enumeration FLOOR, not the fix; it keeps every derived artifact
131
+ // that preserves declaration order, e.g. serialization, stable across runtimes.)
132
+ for (const entry of [...entries].sort()) {
133
+ if (entry === PENDING_DIR)
134
+ continue;
135
+ const full = join(dir, entry);
136
+ // `stat` (not `lstat`/`Dirent.isDirectory()`) so a symlinked subdirectory is
137
+ // traversed — `DirectorySource` has always followed symlinks this way.
138
+ const s = await stat(full).catch(() => undefined);
139
+ if (s === undefined)
140
+ continue;
141
+ if (s.isDirectory()) {
142
+ subdirs.push(full);
143
+ }
144
+ else if (s.isFile() && isMetadataFile(entry)) {
145
+ paths.push(full);
146
+ }
147
+ }
148
+ // Recurse into subdirectories after collecting files at this level.
149
+ // `subdirs` is already in sorted order (built from the sorted `entries` above).
150
+ for (const sub of subdirs) {
151
+ paths.push(...(await listMetadataFilesGuarded(sub, nextAncestors)));
152
+ }
153
+ return paths;
154
+ }
155
+ //# sourceMappingURL=metadata-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata-files.js","sourceRoot":"","sources":["../src/metadata-files.ts"],"names":[],"mappings":"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"}