@platforma-sdk/block-tools 2.10.14 → 2.10.16

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 (169) hide show
  1. package/dist/cli.js +23 -2
  2. package/dist/cli.js.map +1 -1
  3. package/dist/cli.mjs +1944 -100
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/cmd/index.d.ts +10 -4
  6. package/dist/cmd/structure/check.d.ts +10 -0
  7. package/dist/cmd/structure/init.d.ts +18 -0
  8. package/dist/cmd/structure/refresh.d.ts +11 -0
  9. package/dist/cmd/update-deps.d.ts +7 -0
  10. package/dist/structure/cli/run-structure.d.ts +19 -0
  11. package/dist/structure/engine/api.d.ts +55 -0
  12. package/dist/structure/engine/builders.d.ts +95 -0
  13. package/dist/structure/engine/content-rules.d.ts +148 -0
  14. package/dist/structure/engine/ctx.d.ts +34 -0
  15. package/dist/structure/engine/discovery-fs.d.ts +22 -0
  16. package/dist/structure/engine/discovery.d.ts +39 -0
  17. package/dist/structure/engine/flatten.d.ts +3 -0
  18. package/dist/structure/engine/fs/api.d.ts +27 -0
  19. package/dist/structure/engine/fs/memory.d.ts +16 -0
  20. package/dist/structure/engine/fs/node.d.ts +14 -0
  21. package/dist/structure/engine/glob.d.ts +4 -0
  22. package/dist/structure/engine/ir.d.ts +124 -0
  23. package/dist/structure/engine/parsers/json.d.ts +37 -0
  24. package/dist/structure/engine/parsers/lines.d.ts +9 -0
  25. package/dist/structure/engine/parsers/yaml.d.ts +18 -0
  26. package/dist/structure/engine/registry-client.d.ts +34 -0
  27. package/dist/structure/engine/runner.d.ts +45 -0
  28. package/dist/structure/engine/templates.d.ts +30 -0
  29. package/dist/structure/engine/testing.d.ts +34 -0
  30. package/dist/structure/engine/version.d.ts +18 -0
  31. package/dist/structure/init-block-constructor.d.ts +32 -0
  32. package/dist/structure/rules/block-package-json.d.ts +9 -0
  33. package/dist/structure/rules/block.d.ts +1 -0
  34. package/dist/structure/rules/migrations.d.ts +2 -0
  35. package/dist/structure/rules/model-package-json.d.ts +3 -0
  36. package/dist/structure/rules/model.d.ts +1 -0
  37. package/dist/structure/rules/root-catalog-bump.d.ts +1 -0
  38. package/dist/structure/rules/root-gitignore.d.ts +2 -0
  39. package/dist/structure/rules/root-package-json.d.ts +3 -0
  40. package/dist/structure/rules/root-pnpm-workspace.d.ts +15 -0
  41. package/dist/structure/rules/root.d.ts +1 -0
  42. package/dist/structure/rules/shared/colocated-tests.d.ts +2 -0
  43. package/dist/structure/rules/shared/key-order.d.ts +1 -0
  44. package/dist/structure/rules/software-package-json.d.ts +3 -0
  45. package/dist/structure/rules/software.d.ts +1 -0
  46. package/dist/structure/rules/test-package-json.d.ts +3 -0
  47. package/dist/structure/rules/test.d.ts +1 -0
  48. package/dist/structure/rules/ui-package-json.d.ts +3 -0
  49. package/dist/structure/rules/ui.d.ts +1 -0
  50. package/dist/structure/rules/workflow-package-json.d.ts +3 -0
  51. package/dist/structure/rules/workflow.d.ts +1 -0
  52. package/dist/structure/structure-definition.d.ts +1 -0
  53. package/package.json +9 -7
  54. package/src/cmd/index.ts +10 -4
  55. package/src/cmd/structure/check.ts +51 -0
  56. package/src/cmd/structure/init.ts +65 -0
  57. package/src/cmd/structure/refresh.ts +44 -0
  58. package/src/cmd/update-deps.ts +15 -3
  59. package/src/structure/__tests__/colocated-test-wiring.test.ts +107 -0
  60. package/src/structure/__tests__/floor-version.test.ts +52 -0
  61. package/src/structure/__tests__/init-catalog-resolution.test.ts +82 -0
  62. package/src/structure/__tests__/init-check-parity.test.ts +59 -0
  63. package/src/structure/__tests__/model-package-json.snapshot.test.ts +60 -0
  64. package/src/structure/__tests__/oxfmt-clean-init.test.ts +64 -0
  65. package/src/structure/__tests__/root-catalog-bump.test.ts +110 -0
  66. package/src/structure/__tests__/seed-disjointness.test.ts +79 -0
  67. package/src/structure/cli/run-structure.ts +89 -0
  68. package/src/structure/engine/__tests__/content-rules/active-state-guards.test.ts +61 -0
  69. package/src/structure/engine/__tests__/content-rules/catalog-pin.test.ts +46 -0
  70. package/src/structure/engine/__tests__/content-rules/enforce-alphabetical-order.test.ts +55 -0
  71. package/src/structure/engine/__tests__/content-rules/enforce-field-order.test.ts +73 -0
  72. package/src/structure/engine/__tests__/content-rules/ensure-catalog-absent.test.ts +29 -0
  73. package/src/structure/engine/__tests__/content-rules/ensure-catalog-latest.test.ts +70 -0
  74. package/src/structure/engine/__tests__/content-rules/ensure-dep.test.ts +63 -0
  75. package/src/structure/engine/__tests__/content-rules/ensure-deps-bulk.test.ts +46 -0
  76. package/src/structure/engine/__tests__/content-rules/ensure-field-entries.test.ts +35 -0
  77. package/src/structure/engine/__tests__/content-rules/ensure-field.test.ts +56 -0
  78. package/src/structure/engine/__tests__/content-rules/ensure-script.test.ts +39 -0
  79. package/src/structure/engine/__tests__/content-rules/ensure-workspace-scope-deps.test.ts +92 -0
  80. package/src/structure/engine/__tests__/content-rules/gitignore.test.ts +50 -0
  81. package/src/structure/engine/__tests__/content-rules/pin-catalog-to.test.ts +64 -0
  82. package/src/structure/engine/__tests__/content-rules/prune-keys.test.ts +59 -0
  83. package/src/structure/engine/__tests__/content-rules/registry-client.test.ts +116 -0
  84. package/src/structure/engine/__tests__/content-rules/remove-field.test.ts +49 -0
  85. package/src/structure/engine/__tests__/content-rules/require-field.test.ts +40 -0
  86. package/src/structure/engine/__tests__/content-rules/transform-at.test.ts +33 -0
  87. package/src/structure/engine/__tests__/content-rules/when-inner.test.ts +244 -0
  88. package/src/structure/engine/__tests__/content-rules/workspace-module-paths.test.ts +53 -0
  89. package/src/structure/engine/__tests__/discovery.test.ts +160 -0
  90. package/src/structure/engine/__tests__/fs-memory.test.ts +59 -0
  91. package/src/structure/engine/__tests__/glob.test.ts +43 -0
  92. package/src/structure/engine/__tests__/parsers-json.test.ts +189 -0
  93. package/src/structure/engine/__tests__/parsers-lines.test.ts +44 -0
  94. package/src/structure/engine/__tests__/parsers-yaml.test.ts +90 -0
  95. package/src/structure/engine/__tests__/recheck.test.ts +99 -0
  96. package/src/structure/engine/__tests__/registry-lookup.test.ts +49 -0
  97. package/src/structure/engine/__tests__/runner-when-inside-managed.test.ts +136 -0
  98. package/src/structure/engine/__tests__/runner.test.ts +136 -0
  99. package/src/structure/engine/__tests__/synthetic.test.ts +153 -0
  100. package/src/structure/engine/__tests__/version.test.ts +44 -0
  101. package/src/structure/engine/__tests__/when-files-exist.test.ts +89 -0
  102. package/src/structure/engine/api.ts +131 -0
  103. package/src/structure/engine/builders.ts +341 -0
  104. package/src/structure/engine/content-rules.ts +616 -0
  105. package/src/structure/engine/ctx.ts +94 -0
  106. package/src/structure/engine/discovery-fs.ts +209 -0
  107. package/src/structure/engine/discovery.ts +168 -0
  108. package/src/structure/engine/flatten.ts +117 -0
  109. package/src/structure/engine/fs/api.ts +40 -0
  110. package/src/structure/engine/fs/memory.ts +132 -0
  111. package/src/structure/engine/fs/node.ts +89 -0
  112. package/src/structure/engine/glob.ts +42 -0
  113. package/src/structure/engine/ir.ts +149 -0
  114. package/src/structure/engine/parsers/json.ts +212 -0
  115. package/src/structure/engine/parsers/lines.ts +42 -0
  116. package/src/structure/engine/parsers/yaml.ts +72 -0
  117. package/src/structure/engine/registry-client.ts +140 -0
  118. package/src/structure/engine/runner.ts +519 -0
  119. package/src/structure/engine/templates.ts +74 -0
  120. package/src/structure/engine/testing.ts +93 -0
  121. package/src/structure/engine/version.ts +60 -0
  122. package/src/structure/init-block-constructor.ts +164 -0
  123. package/src/structure/rules/block-package-json.ts +156 -0
  124. package/src/structure/rules/block.ts +29 -0
  125. package/src/structure/rules/migrations.ts +63 -0
  126. package/src/structure/rules/model-package-json.ts +123 -0
  127. package/src/structure/rules/model.ts +65 -0
  128. package/src/structure/rules/root-catalog-bump.ts +77 -0
  129. package/src/structure/rules/root-gitignore.ts +27 -0
  130. package/src/structure/rules/root-package-json.ts +119 -0
  131. package/src/structure/rules/root-pnpm-workspace.ts +103 -0
  132. package/src/structure/rules/root.ts +43 -0
  133. package/src/structure/rules/shared/colocated-tests.ts +11 -0
  134. package/src/structure/rules/shared/key-order.ts +34 -0
  135. package/src/structure/rules/software-package-json.ts +86 -0
  136. package/src/structure/rules/software.ts +33 -0
  137. package/src/structure/rules/test-package-json.ts +70 -0
  138. package/src/structure/rules/test.ts +40 -0
  139. package/src/structure/rules/ui-package-json.ts +108 -0
  140. package/src/structure/rules/ui.ts +75 -0
  141. package/src/structure/rules/workflow-package-json.ts +92 -0
  142. package/src/structure/rules/workflow.ts +51 -0
  143. package/src/structure/structure-definition.ts +28 -0
  144. package/src/structure/templates/static/block/index.d.ts +6 -0
  145. package/src/structure/templates/static/block/index.js +8 -0
  146. package/src/structure/templates/static/block/logos/block-logo.png +0 -0
  147. package/src/structure/templates/static/block/logos/organization-logo.png +0 -0
  148. package/src/structure/templates/static/model/.oxfmtrc.json +4 -0
  149. package/src/structure/templates/static/model/.oxlintrc.json +3 -0
  150. package/src/structure/templates/static/model/src/index.ts +13 -0
  151. package/src/structure/templates/static/model/tsconfig.json +4 -0
  152. package/src/structure/templates/static/root/.gitignore +13 -0
  153. package/src/structure/templates/static/root/.vscode/settings.json +3 -0
  154. package/src/structure/templates/static/root/turbo.json +35 -0
  155. package/src/structure/templates/static/test/tsconfig.json +5 -0
  156. package/src/structure/templates/static/test/vitest.config.mts +8 -0
  157. package/src/structure/templates/static/ui/.oxfmtrc.json +3 -0
  158. package/src/structure/templates/static/ui/.oxlintrc.json +3 -0
  159. package/src/structure/templates/static/ui/index.html +12 -0
  160. package/src/structure/templates/static/ui/src/main.ts +5 -0
  161. package/src/structure/templates/static/ui/tsconfig.json +4 -0
  162. package/src/structure/templates/static/workflow/format.el +42 -0
  163. package/src/structure/templates/static/workflow/tsconfig.json +16 -0
  164. package/src/structure/templates/static/workflow/vitest.config.mts +9 -0
  165. package/src/structure/templates/text/README.md +5 -0
  166. package/src/structure/templates/text/docs/description.md +3 -0
  167. package/src/structure/templates/text/ui/src/MainPage.tpl.vue +9 -0
  168. package/src/structure/templates/text/ui/src/app.tpl.ts +11 -0
  169. package/src/structure/templates/text/workflow/src/main.tpl.tengo +10 -0
@@ -6,8 +6,11 @@ import { default as Cmd5 } from './pack';
6
6
  import { default as Cmd6 } from './publish';
7
7
  import { default as Cmd7 } from './refresh-registry';
8
8
  import { default as Cmd8 } from './restore-overview-from-snapshot';
9
- import { default as Cmd9 } from './upload-package-v1';
10
- import { default as Cmd10 } from './update-deps';
9
+ import { default as Cmd9 } from './update-deps';
10
+ import { default as Cmd10 } from './upload-package-v1';
11
+ import { default as Cmd11 } from './structure/check';
12
+ import { default as Cmd12 } from './structure/init';
13
+ import { default as Cmd13 } from './structure/refresh';
11
14
  export declare const COMMANDS: {
12
15
  "build-meta": typeof Cmd0;
13
16
  "build-model": typeof Cmd1;
@@ -17,6 +20,9 @@ export declare const COMMANDS: {
17
20
  publish: typeof Cmd6;
18
21
  "refresh-registry": typeof Cmd7;
19
22
  "restore-overview-from-snapshot": typeof Cmd8;
20
- "upload-package-v1": typeof Cmd9;
21
- "update-deps": typeof Cmd10;
23
+ "update-deps": typeof Cmd9;
24
+ "upload-package-v1": typeof Cmd10;
25
+ "structure:check": typeof Cmd11;
26
+ "structure:init": typeof Cmd12;
27
+ "structure:refresh": typeof Cmd13;
22
28
  };
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class StructureCheck extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static strict: boolean;
6
+ static flags: {
7
+ "sdk-internal": import('@oclif/core/interfaces').BooleanFlag<boolean>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,18 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class StructureInit extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ path: import('@oclif/core/interfaces').Arg<string | undefined, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ "npm-org": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
10
+ "org-scope": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
11
+ "short-name": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
12
+ "with-software": import('@oclif/core/interfaces').BooleanFlag<boolean>;
13
+ "no-software": import('@oclif/core/interfaces').BooleanFlag<boolean>;
14
+ platform: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
15
+ "non-interactive": import('@oclif/core/interfaces').BooleanFlag<boolean>;
16
+ };
17
+ run(): Promise<void>;
18
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class StructureRefresh extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static strict: boolean;
6
+ static flags: {
7
+ "sdk-internal": import('@oclif/core/interfaces').BooleanFlag<boolean>;
8
+ "update-deps-only": import('@oclif/core/interfaces').BooleanFlag<boolean>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -1,4 +1,11 @@
1
1
  import { Command } from '@oclif/core';
2
+ /**
3
+ * Deprecated. Phase-2 forwarding alias (spec.md § "Coexistence And
4
+ * Retirement"): delegates to `structure refresh --update-deps-only`,
5
+ * which lands at parity with the old `blocks-deps-updater` catalog-bump
6
+ * semantics. Prints a deprecation warning; will be removed once the
7
+ * structurer path has been live without surprises.
8
+ */
2
9
  export default class UpdateDeps extends Command {
3
10
  static description: string;
4
11
  static examples: string[];
@@ -0,0 +1,19 @@
1
+ import { Change } from '../engine/runner';
2
+ export type StructureMode = "check" | "refresh";
3
+ export type RunStructureInput = {
4
+ /** User-supplied block path (resolved against cwd). */
5
+ blockPath: string;
6
+ isSdkInternal: boolean;
7
+ updateDepsOnly: boolean;
8
+ mode: StructureMode;
9
+ /** `<block-tools>/src/structure/templates` (from oclif `config.root`). */
10
+ templatesRoot: string;
11
+ log: (msg: string) => void;
12
+ };
13
+ export type RunStructureResult = {
14
+ blockPath: string;
15
+ changes: Change[];
16
+ };
17
+ export declare function runStructureForPath(input: RunStructureInput): Promise<RunStructureResult>;
18
+ /** One-line-per-change summary for CLI output. */
19
+ export declare function formatChanges(blockPath: string, changes: Change[]): string;
@@ -0,0 +1,55 @@
1
+ import { ContentForm, ManagedBody, RunMode, Structure, TriggerFn } from './ir';
2
+ export type Scope = "root" | "block" | "model" | "ui" | "workflow" | "test" | "software";
3
+ /** Variables describing a block — populated by `init` or parsed by
4
+ * `check`/`refresh` from the block's package.json `name`. */
5
+ export type BlockVars = {
6
+ /** e.g. `@platforma-open/my-org.mixcr-clonotyping` */
7
+ facadeName: string;
8
+ /** e.g. `my-org.mixcr-clonotyping` */
9
+ baseName: string;
10
+ /** e.g. `@platforma-open` */
11
+ npmOrg: string;
12
+ /** e.g. `my-org` */
13
+ orgScope: string;
14
+ /** e.g. `mixcr-clonotyping` */
15
+ shortName: string;
16
+ /** Platform picked at init for the (single) software sub-package.
17
+ * Only populated by `init`; absent on `check` / `refresh`. Blocks
18
+ * that legitimately have multiple software modules (encountered via
19
+ * DISCOVERY on refresh) are not affected — this field only governs
20
+ * what `init` scaffolds. */
21
+ softwarePlatform?: string;
22
+ };
23
+ /** Discovered workspace module. */
24
+ export type Module = {
25
+ scope: Scope;
26
+ /** Package name from the module's package.json. */
27
+ name: string;
28
+ /** Block-relative path of the module ("" for workspace root). */
29
+ path: string;
30
+ };
31
+ /** Run context — passed into engine.run and surfaced inside trigger
32
+ * predicates as the `ctx` field. */
33
+ export type RunContext = {
34
+ /** `--sdk-internal` flag. */
35
+ isSdkInternal: boolean;
36
+ /** `--update-deps-only` flag. When true, the run is in mode
37
+ * `"updateDeps"`: only `onUpdateDeps` / `onInitOrUpdate` leaves fire;
38
+ * all default-mode leaves are skipped. The caller is then expected to
39
+ * run `pnpm install` and re-invoke `refresh` without the flag for the
40
+ * default-mode rules to apply against the updated dep set. */
41
+ updateDepsOnly: boolean;
42
+ /** Discovered modules (every scope). */
43
+ modules: Module[];
44
+ /** Block vars; on `init` populated from flags/prompts, on
45
+ * `check`/`refresh` parsed from block/package.json. */
46
+ blockVars: BlockVars;
47
+ /** Layout version read from `.structure`. */
48
+ version: number;
49
+ /** True for `check` mode and the post-run recheck. */
50
+ dryRun: boolean;
51
+ };
52
+ export type { ContentForm, ManagedBody, RunMode, Structure, TriggerFn };
53
+ export { defineStructure, scope, when, whenFilesExist, onUpdateDeps, onInitOrUpdate, fixed, managed, scaffold, seed, remove, rename, file, binaryFile, text, tpl, generate, blockVars, } from './builders';
54
+ export { ensureField, removeField, requireField, ensureFieldEntries, ensureScript, removeScript, ensureDep, ensureDevDep, ensurePeerDep, ensureOptionalDep, removeDep, ensureDeps, ensureDevDeps, ensurePeerDeps, ensureOptionalDeps, ensureWorkspaceScopeDeps, ensureWorkspaceScopeDevDeps, ensureWorkspaceScopePeerDeps, pruneKeysMatching, pruneKeysMatchingAt, enforceFieldOrder, enforceFieldOrderAt, enforceAlphabeticalOrder, transformAt, ensureWorkspaceModulePaths, ensureCatalogVersion, pinCatalogTo, ensureCatalogLatest, ensureCatalogAbsent, ensureGitignoreEntries, removeGitignoreEntries, withManagedBody, withManagedYaml, withManagedLines, } from './content-rules';
55
+ export type { DepVersion } from './content-rules';
@@ -0,0 +1,95 @@
1
+ import { Scope, RunContext, BlockVars, ContentForm } from './api';
2
+ import { ManagedBody, Structure, TriggerFn } from './ir';
3
+ /** Engine-internal: scope `blockVars()` lookups during a run. The body is
4
+ * synchronous, so the module-global `activeRunContext` cannot be observed
5
+ * by an interleaved run — a sync call stack runs to completion before any
6
+ * other `run()` can start. The try/finally restores the previous context
7
+ * (supporting the nested-run case the post-run recheck used to imply). */
8
+ export declare function withRunContext<T>(ctx: RunContext, fn: () => T): T;
9
+ /** Engine-internal: content-rule builders that need `ctx.modules` look
10
+ * up the active context through this accessor. Returns `undefined`
11
+ * outside a run. */
12
+ export declare function tryGetActiveRunContext(): RunContext | undefined;
13
+ /** Get-or-die counterpart of `tryGetActiveRunContext`. Generators run
14
+ * only inside `engine.run()`; an absent context is framework misuse, not
15
+ * a valid state, so throw rather than emit degenerate (empty) output.
16
+ * Mirrors `blockVars()`. */
17
+ export declare function getActiveRunContext(): RunContext;
18
+ /** The single entry point: build a {@link Structure} from `fn`, which calls
19
+ * the scaffold-DSL builders (`scope`, `fixed`, `managed`, `seed`, …). Throws
20
+ * if called nested, or if `fn` leaves an unclosed group frame. */
21
+ export declare function defineStructure(fn: () => void): Structure;
22
+ /** Open a scope (`root` / `block` / `model` / `ui` / `workflow` / `test` /
23
+ * `software`); builders called inside `body` attach to it. Cannot nest. */
24
+ export declare function scope(name: Scope, body: () => void): void;
25
+ /** Inner-mode `when` handler. Registered by `content-rules.ts` at
26
+ * load time. Returns true if the call was dispatched (an inner active
27
+ * state was present); false otherwise. Avoids a circular import. */
28
+ type InnerWhenHandler = (trigger: TriggerFn, body: () => void) => boolean;
29
+ /** Engine-internal: register the inner-mode `when` handler (set by
30
+ * `content-rules.ts` at load time to avoid a circular import). */
31
+ export declare function registerInnerWhenHandler(h: InnerWhenHandler): void;
32
+ /**
33
+ * Conditionally run `body`. Two dispatch modes by active state:
34
+ * - inside `defineStructure(...)` → push a `WhenFrame` into the tree;
35
+ * trigger fires later at runner time per `FlatItem`.
36
+ * - inside a `managed(...)` body → evaluate `trigger` immediately
37
+ * against the runner-supplied `TriggerContext`; run/skip `body`
38
+ * synchronously.
39
+ *
40
+ * One `when` symbol for both layers — same user contract, dispatch
41
+ * picks the matching execution timing.
42
+ */
43
+ export declare function when(trigger: TriggerFn, body: () => void): void;
44
+ /** Trigger factory: true when at least one file in the leaf's module
45
+ * matches `glob` (module-relative — see `TriggerContext.filesMatch`). Use
46
+ * to gate a rule on the presence of co-located files, e.g. add a vitest
47
+ * `test` script only when `src/**\/*.test.ts` exists. Pairs with `when`:
48
+ * `when(whenFilesExist("src/**\/*.test.ts"), () => { ... })`. */
49
+ export declare function whenFilesExist(glob: string): TriggerFn;
50
+ /** Leaves inside fire ONLY under `--update-deps-only` (mode
51
+ * `"updateDeps"`); they are skipped on default refresh/check and init. */
52
+ export declare function onUpdateDeps(body: () => void): void;
53
+ /** Leaves inside fire on `init` AND `--update-deps-only`, but NOT on
54
+ * default refresh/check. The frame for rules that resolve/write current
55
+ * versions: both init and update-deps mean "fetch and write latest",
56
+ * while a plain refresh leaves them as the author/lockfile has them. */
57
+ export declare function onInitOrUpdate(body: () => void): void;
58
+ /** Engine-OWNED file: (re)written verbatim from `content` on every refresh —
59
+ * author edits are overwritten. */
60
+ export declare function fixed(path: string, content: ContentForm): void;
61
+ /** Engine-RECONCILED file: parsed from disk (or `initial` when absent),
62
+ * mutated by `body` (the JSON/YAML/lines builders), then re-serialised.
63
+ * Content the body does not touch is preserved. */
64
+ export declare function managed(path: string, initial: ContentForm, body: ManagedBody): void;
65
+ /** Write-once file: created from `initial` if absent (on init AND refresh),
66
+ * never overwritten once present. For files the author subsequently owns. */
67
+ export declare function scaffold(path: string, initial: ContentForm): void;
68
+ /** Author-owned starter file: written from `initial` only on `init`, and only
69
+ * if absent; `refresh` / `check` never touch it. */
70
+ export declare function seed(path: string, initial: ContentForm): void;
71
+ /** Delete `path` if present, on every refresh. */
72
+ export declare function remove(path: string): void;
73
+ /** Rename file `from` → `to` on refresh (migrating a renamed scaffold file). */
74
+ export declare function rename(from: string, to: string): void;
75
+ /** Content form: a UTF-8 static template read from the structurer's static
76
+ * templates. Use inside `fixed` / `managed` / `scaffold` / `seed`. */
77
+ export declare function file(path: string): ContentForm;
78
+ /** A binary static asset (e.g. a logo) read verbatim from `<root>/static/`.
79
+ * Unlike `file()`, the bytes are never decoded to a string — use for
80
+ * images / archives. Only valid inside `seed()` / `scaffold()`. */
81
+ export declare function binaryFile(path: string): ContentForm;
82
+ /** Content form: an inline literal string. */
83
+ export declare function text(value: string): ContentForm;
84
+ /** Content form: a text template (the structurer's `text/` templates) with
85
+ * `${var}` placeholders substituted from `vars`. */
86
+ export declare function tpl(path: string, vars: Record<string, string> | (() => Record<string, string>)): ContentForm;
87
+ /** Content form: content computed at run time. The return value is serialised
88
+ * as JSON / YAML by the target file's extension, or used verbatim if it is
89
+ * already a string. */
90
+ export declare function generate(fn: () => unknown): ContentForm;
91
+ /** The active run's {@link BlockVars} (block name parts + software platform).
92
+ * Valid only during a run (inside a generator or managed body); throws
93
+ * otherwise. */
94
+ export declare function blockVars(): BlockVars;
95
+ export {};
@@ -0,0 +1,148 @@
1
+ import { RunContext, Scope } from './api';
2
+ import { TriggerContext } from './ir';
3
+ import { JsonObject } from './parsers/json';
4
+ import { YamlDocument } from './parsers/yaml';
5
+ export type { JsonObject };
6
+ /** Allowed dep version strings. Specific versions live in the catalog.
7
+ * `"sdk:"` is an authoring abstraction, not an on-disk value: the engine
8
+ * resolves it at write time (`workspace:*` when `ctx.isSdkInternal`, else
9
+ * `"catalog:"`) and the resolved literal is what serializes. Use it for
10
+ * every dep that is a member of the platforma monorepo's pnpm workspace
11
+ * (the `@platforma-sdk/*` packages + `@milaboratories/ts-builder` /
12
+ * `ts-configs`). */
13
+ export type DepVersion = "catalog:" | "sdk:" | `workspace:${string}` | "*";
14
+ /** Resolve the `"sdk:"` sentinel to its on-disk literal. All other
15
+ * `DepVersion` forms pass through unchanged — `"sdk:"` never serializes. */
16
+ export declare function resolveDepVersion(version: DepVersion, isSdkInternal: boolean): Exclude<DepVersion, "sdk:">;
17
+ /** Resolve any `"sdk:"` sentinels in the dep sections of a generated
18
+ * package.json object, in place. Mirrors `resolveDepVersion` for the
19
+ * generator (`initial` content) path — the runner calls this on every
20
+ * `generate()`-produced `.json` value so the sentinel never reaches disk
21
+ * via a generator. */
22
+ export declare function resolveSdkSentinelsInJson(value: unknown, isSdkInternal: boolean): void;
23
+ export type WithManagedOpts = {
24
+ ctx?: RunContext;
25
+ /** Trigger context for `when(...)` calls inside the body. The runner
26
+ * builds this from the post-structural-pass FS snapshot + run ctx.
27
+ * Without it, `when(...)` inside the body throws. */
28
+ triggerContext?: TriggerContext;
29
+ };
30
+ /** Engine-internal: run `body` with `obj` as the active JSON state so the
31
+ * JSON builders mutate it; returns the mutated object. Exported for tests —
32
+ * the runner calls this for managed `.json` files. */
33
+ export declare function withManagedBody(obj: JsonObject, body: () => void, opts?: WithManagedOpts): JsonObject;
34
+ export type WithManagedYamlOpts = WithManagedOpts & {
35
+ /** Sync accessor for prefetched latest versions. Required for
36
+ * `ensureCatalogLatest` to take effect. */
37
+ getLatestVersion?: (packageName: string) => string | undefined;
38
+ };
39
+ /** Engine-internal: run `body` with `doc` as the active YAML state (for
40
+ * `pnpm-workspace.yaml`); returns the mutated document. Exported for tests. */
41
+ export declare function withManagedYaml(doc: YamlDocument, body: () => void, opts?: WithManagedYamlOpts): YamlDocument;
42
+ /** Engine-internal: run `body` with `lines` as the active line-based state
43
+ * (for `.gitignore`); returns the mutated lines. Exported for tests. */
44
+ export declare function withManagedLines(lines: string[], body: () => void, opts?: WithManagedOpts): string[];
45
+ /** Set the value at `jsonPath` in the active managed JSON object. */
46
+ export declare function ensureField(jsonPath: string, value: unknown): void;
47
+ /** Remove the field at `jsonPath`. With `predicate`, only removes when
48
+ * the predicate returns true against the current value. */
49
+ export declare function removeField(jsonPath: string, predicate?: (currentValue: unknown) => boolean): void;
50
+ /** Assert a field exists; throw if absent. No mutation. */
51
+ export declare function requireField(jsonPath: string, message?: string): void;
52
+ /** Merge `entries` into the object at `jsonPath`. Auto-creates the
53
+ * object if missing. Existing other entries preserved. */
54
+ export declare function ensureFieldEntries(jsonPath: string, entries: Record<string, unknown>): void;
55
+ /** Set `scripts.<name>` to `command`. */
56
+ export declare function ensureScript(name: string, command: string): void;
57
+ /** Remove `scripts.<name>` if present. */
58
+ export declare function removeScript(name: string): void;
59
+ /** Pin `name` to `version` in `dependencies`. Enforces the single-section
60
+ * invariant — `name` may live in only one dependency section, so it is
61
+ * removed from the others first. A `sdk:` sentinel version is resolved
62
+ * against the run's `--sdk-internal` flag before it reaches disk. */
63
+ export declare function ensureDep(name: string, version: DepVersion): void;
64
+ /** Pin `name` to `version` in `devDependencies` (see {@link ensureDep} for the
65
+ * single-section + `sdk:` semantics). */
66
+ export declare function ensureDevDep(name: string, version: DepVersion): void;
67
+ /** Pin `name` to `version` in `peerDependencies` (see {@link ensureDep}). */
68
+ export declare function ensurePeerDep(name: string, version: DepVersion): void;
69
+ /** Pin `name` to `version` in `optionalDependencies` (see {@link ensureDep}). */
70
+ export declare function ensureOptionalDep(name: string, version: DepVersion): void;
71
+ /** Remove `name` from every dependency section. */
72
+ export declare function removeDep(name: string): void;
73
+ /** Bulk {@link ensureDep} for each `name → version` entry. */
74
+ export declare function ensureDeps(entries: Record<string, DepVersion>): void;
75
+ /** Bulk {@link ensureDevDep} for each `name → version` entry. */
76
+ export declare function ensureDevDeps(entries: Record<string, DepVersion>): void;
77
+ /** Bulk {@link ensurePeerDep} for each `name → version` entry. */
78
+ export declare function ensurePeerDeps(entries: Record<string, DepVersion>): void;
79
+ /** Bulk {@link ensureOptionalDep} for each `name → version` entry. */
80
+ export declare function ensureOptionalDeps(entries: Record<string, DepVersion>): void;
81
+ /** Add every discovered module of `scope` as a `workspace:*` entry in
82
+ * `dependencies` — wires a block's intra-workspace links (e.g. the test
83
+ * scope depending on the other scopes). Single-section invariant per
84
+ * {@link ensureDep}. */
85
+ export declare function ensureWorkspaceScopeDeps(scope: Scope): void;
86
+ /** Like {@link ensureWorkspaceScopeDeps}, into `devDependencies`. */
87
+ export declare function ensureWorkspaceScopeDevDeps(scope: Scope): void;
88
+ /** Like {@link ensureWorkspaceScopeDeps}, into `peerDependencies`. */
89
+ export declare function ensureWorkspaceScopePeerDeps(scope: Scope): void;
90
+ /** Delete every top-level key for which `predicate(key, value)` is true. */
91
+ export declare function pruneKeysMatching(predicate: (key: string, value: unknown) => boolean): void;
92
+ /** Delete every key of the object at `jsonPath` for which
93
+ * `predicate(key, value)` is true. No-op if the path is not an object. */
94
+ export declare function pruneKeysMatchingAt(jsonPath: string, predicate: (key: string, value: unknown) => boolean): void;
95
+ /** Reorder top-level keys to `orderedKeys`; keys not listed keep their
96
+ * position relative to the preceding listed key. Typically the LAST call in
97
+ * a managed body, projecting the canonical field order. */
98
+ export declare function enforceFieldOrder(orderedKeys: string[]): void;
99
+ /** Like {@link enforceFieldOrder}, applied to the object at `jsonPath`. No-op
100
+ * if the path is not an object. */
101
+ export declare function enforceFieldOrderAt(jsonPath: string, orderedKeys: string[]): void;
102
+ /** Sort keys alphabetically. Called with no args it is a deliberate no-op
103
+ * (guards against accidental whole-file sorts); pass a `jsonPath` to sort one
104
+ * object, or `{ recursive: true }` to sort the whole tree. Matches oxfmt's
105
+ * dependency-section ordering. */
106
+ export declare function enforceAlphabeticalOrder(jsonPath?: string, opts?: {
107
+ recursive?: boolean;
108
+ }): void;
109
+ /** Escape hatch: replace the value at `jsonPath` with `transform(current)`,
110
+ * for shapes the typed builders above do not cover. */
111
+ export declare function transformAt<T = unknown>(jsonPath: string, transform: (current: T) => T): void;
112
+ /** Set the workspace `packages:` list to all discovered NON-root module
113
+ * paths (sorted lex). The block root ("") is discovered implicitly
114
+ * and is NEVER written to `packages:` — listing "." there breaks turbo's
115
+ * task graph. Equality-guarded — skips the rewrite when the existing
116
+ * list already matches, so a YAML round-trip on an already-canonical
117
+ * file produces zero churn. */
118
+ export declare function ensureWorkspaceModulePaths(): void;
119
+ /** Add `catalog.<name>` at `version` ONLY if the key is absent. An entry
120
+ * the block already carries is left untouched — no overwrite, no
121
+ * downgrade. This is the seeding primitive for curated fixed versions
122
+ * (`INFRA_CATALOG_FLOOR`, the python runenv pin): on
123
+ * `refresh --update-deps-only` a missing standard catalog key is added,
124
+ * while a key the block already pins keeps its own version. To force a
125
+ * specific version regardless of what is present, use `pinCatalogTo`. */
126
+ export declare function ensureCatalogVersion(name: string, version: string): void;
127
+ /** Set `catalog.<name>` to `version` EXACTLY — creates the entry if
128
+ * missing, overwrites it (including a downgrade) if present. Use to force
129
+ * a specific version; with top-to-bottom declaration order a later
130
+ * `pinCatalogTo` overrides an earlier `ensureCatalogLatest`. Distinct
131
+ * from `ensureCatalogVersion`, which never touches a present key. */
132
+ export declare function pinCatalogTo(name: string, version: string): void;
133
+ /** Resolve `catalog.<name>` to npm "latest" from the active state's
134
+ * prefetched `getLatestVersion` accessor (the caller pre-resolves; no
135
+ * network here), creating the key if absent. No-op when no latest is
136
+ * available — default refresh passes no lookup, and a name that was not
137
+ * prefetched resolves to `undefined`; in both cases any existing entry is
138
+ * left untouched. This is the SDK-family resolver: on
139
+ * `refresh --update-deps-only` it both SEEDS a missing standard SDK key
140
+ * and refreshes a present one, and on `init` it overwrites the
141
+ * placeholder with the real latest. */
142
+ export declare function ensureCatalogLatest(name: string): void;
143
+ /** Remove `catalog.<name>` if present; no-op when absent. */
144
+ export declare function ensureCatalogAbsent(name: string): void;
145
+ /** Append each `entry` if not already present (comment-aware equality). */
146
+ export declare function ensureGitignoreEntries(entries: string[]): void;
147
+ /** Drop any line whose normalised form matches any of `patterns`. */
148
+ export declare function removeGitignoreEntries(patterns: RegExp[]): void;
@@ -0,0 +1,34 @@
1
+ import { BlockVars, Module, RunContext, Scope } from './api';
2
+ /** All modules of `scope` (zero or more). Never throws. Use when "zero or
3
+ * more" is the right intent (e.g. software). */
4
+ export declare function findModules(ctx: RunContext, scope: Scope): Module[];
5
+ /** The single module of `scope`. Throws if absent OR if more than one
6
+ * exists. Use when exactly one is required (model / ui / workflow). */
7
+ export declare function findModule(ctx: RunContext, scope: Scope): Module;
8
+ /** Workspace dep map `{ name: "workspace:*" }` for the single module of
9
+ * `scope`. Throws if absent (via `findModule`) — guarantees the dep. */
10
+ export declare function scopeDepMap(ctx: RunContext, scope: Scope): Record<string, string>;
11
+ /** Workspace dep map for ALL modules of `scope` (zero or more). Never
12
+ * throws — use where multiple modules are legitimate (e.g. software). */
13
+ export declare function scopeDepMaps(ctx: RunContext, scope: Scope): Record<string, string>;
14
+ /**
15
+ * Module set produced by `init` for the given BlockVars: one module per
16
+ * base scope (root/block/model/ui/workflow/test) plus, when a platform
17
+ * was selected, one `software` module. `--platform` is single-valued, so
18
+ * `init` produces at most one software module; multi-software shapes only
19
+ * arise via DISCOVERY on existing blocks.
20
+ *
21
+ * Single source of truth shared by the real `init` constructor and the
22
+ * `simulateInit` test helper — keeping them in lockstep is what makes the
23
+ * init→check zero-diff invariant meaningful.
24
+ */
25
+ export declare function modulesForInit(vars: BlockVars): Module[];
26
+ export type CreateRunContextInput = {
27
+ isSdkInternal?: boolean;
28
+ updateDepsOnly?: boolean;
29
+ modules: Module[];
30
+ blockVars: BlockVars;
31
+ version?: number;
32
+ dryRun?: boolean;
33
+ };
34
+ export declare function createRunContext(input: CreateRunContextInput): RunContext;
@@ -0,0 +1,22 @@
1
+ import { BlockVars, RunContext } from './api';
2
+ import { FileSystem } from './fs/api';
3
+ export declare class StructureCliError extends Error {
4
+ constructor(msg: string);
5
+ }
6
+ /** Parse a facade package name `@npmOrg/orgScope.shortName` into BlockVars. */
7
+ export declare function parseBlockVars(facadeName: string): BlockVars;
8
+ export type DiscoverInput = {
9
+ /** Block-rooted filesystem (NodeFileSystem for the CLI, MemoryFileSystem
10
+ * for the Layer-2 round-trip). */
11
+ fs: FileSystem;
12
+ isSdkInternal: boolean;
13
+ updateDepsOnly?: boolean;
14
+ dryRun?: boolean;
15
+ };
16
+ /**
17
+ * Run DISCOVERY against a block filesystem and return a fully-assembled
18
+ * `RunContext`, ready for `engine.run`. Throws `StructureCliError` /
19
+ * `DiscoveryError` / `StructureVersionFloorError` on a non-block dir,
20
+ * an unclassified package, or a below-floor version.
21
+ */
22
+ export declare function discoverRunContext(input: DiscoverInput): RunContext;
@@ -0,0 +1,39 @@
1
+ import { Module, Scope } from './api';
2
+ export declare const ALL_SCOPES: Scope[];
3
+ export type WorkspacePackage = {
4
+ /** Block-relative path of the package — "" or "." means the
5
+ * workspace root. */
6
+ path: string;
7
+ /** Parsed package.json. */
8
+ pkg: PackageJsonLike;
9
+ };
10
+ export type PackageJsonLike = {
11
+ name?: string;
12
+ main?: string;
13
+ files?: string[];
14
+ dependencies?: Record<string, string>;
15
+ devDependencies?: Record<string, string>;
16
+ peerDependencies?: Record<string, string>;
17
+ optionalDependencies?: Record<string, string>;
18
+ "block-scope"?: string;
19
+ "block-software"?: unknown;
20
+ };
21
+ export declare class DiscoveryError extends Error {
22
+ readonly path?: string | undefined;
23
+ constructor(msg: string, path?: string | undefined);
24
+ }
25
+ /**
26
+ * Classify one package.
27
+ *
28
+ * @param wp The workspace package.
29
+ * @param siblingNames Set of all workspace package `name`s (used by
30
+ * rule 4 "block": depends on ≥2 sibling .model/.ui/.workflow).
31
+ * @returns Scope or `undefined` if unclassified.
32
+ */
33
+ export declare function classifyOne(wp: WorkspacePackage, siblingNames: Set<string>): Scope | undefined;
34
+ /**
35
+ * Classify a whole workspace. Throws on the first unclassified package
36
+ * with a message that directs the operator to add `block-scope` to its
37
+ * package.json.
38
+ */
39
+ export declare function discoverModules(packages: WorkspacePackage[]): Module[];
@@ -0,0 +1,3 @@
1
+ import { RunContext } from './api';
2
+ import { FlatItem, Structure } from './ir';
3
+ export declare function flatten(structure: Structure, ctx: RunContext): FlatItem[];
@@ -0,0 +1,27 @@
1
+ /** One shallow child of a directory (file or sub-directory). */
2
+ export type DirEntry = {
3
+ name: string;
4
+ isDirectory: boolean;
5
+ };
6
+ export interface FileSystem {
7
+ /** Read file as utf-8 string. Throws on missing file. */
8
+ read(path: string): string;
9
+ /** Write file (utf-8). Creates parent dirs as needed. Overwrites. */
10
+ write(path: string, content: string): void;
11
+ /** Write raw bytes. Creates parent dirs as needed. Overwrites. For binary
12
+ * assets (logos, images) that must not be utf-8 encoded. */
13
+ writeBinary(path: string, content: Uint8Array): void;
14
+ /** Path exists (file or directory). */
15
+ exists(path: string): boolean;
16
+ /** Recursive listing under a directory (relative paths, files only).
17
+ * Empty array if directory missing. */
18
+ list(dir: string): string[];
19
+ /** Shallow listing of a directory's immediate children (files +
20
+ * sub-dirs). Empty array if the directory is missing. Used by
21
+ * filesystem-backed DISCOVERY. */
22
+ listDir(dir: string): DirEntry[];
23
+ /** Move a file or directory. Source must exist; dest must not. */
24
+ move(from: string, to: string): void;
25
+ /** Delete a file or directory recursively. Missing is no-op. */
26
+ delete(path: string): void;
27
+ }
@@ -0,0 +1,16 @@
1
+ import { DirEntry, FileSystem } from './api';
2
+ export declare class MemoryFileSystem implements FileSystem {
3
+ private files;
4
+ constructor(initial?: Record<string, string>);
5
+ /** Snapshot of all files — handy for assertions. Binary entries are
6
+ * rendered as a placeholder so the snapshot stays a string map. */
7
+ snapshot(): Record<string, string>;
8
+ read(path: string): string;
9
+ write(path: string, content: string): void;
10
+ writeBinary(path: string, content: Uint8Array): void;
11
+ exists(path: string): boolean;
12
+ list(dir: string): string[];
13
+ listDir(dir: string): DirEntry[];
14
+ move(from: string, to: string): void;
15
+ delete(path: string): void;
16
+ }
@@ -0,0 +1,14 @@
1
+ import { DirEntry, FileSystem } from './api';
2
+ export declare class NodeFileSystem implements FileSystem {
3
+ private root;
4
+ constructor(root: string);
5
+ private abs;
6
+ read(p: string): string;
7
+ write(p: string, content: string): void;
8
+ writeBinary(p: string, content: Uint8Array): void;
9
+ exists(p: string): boolean;
10
+ list(dir: string): string[];
11
+ listDir(dir: string): DirEntry[];
12
+ move(from: string, to: string): void;
13
+ delete(p: string): void;
14
+ }
@@ -0,0 +1,4 @@
1
+ /** Compile a glob to an anchored RegExp. */
2
+ export declare function globToRegExp(glob: string): RegExp;
3
+ /** True if `path` matches `glob` (whole-path, anchored). */
4
+ export declare function matchesGlob(glob: string, path: string): boolean;