rman 1.3.0 → 2.0.0-beta.2

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 (153) hide show
  1. package/README.md +63 -19
  2. package/cli.d.ts +5 -0
  3. package/cli.js +214 -88
  4. package/commands/build.command.d.ts +177 -3
  5. package/commands/build.command.js +20 -10
  6. package/commands/changed.command.d.ts +80 -3
  7. package/commands/changed.command.js +19 -12
  8. package/commands/changelog.command.d.ts +192 -3
  9. package/commands/changelog.command.js +87 -43
  10. package/commands/config.command.d.ts +44 -3
  11. package/commands/config.command.js +30 -19
  12. package/commands/diff.command.d.ts +37 -3
  13. package/commands/diff.command.js +25 -16
  14. package/commands/exec.command.d.ts +193 -3
  15. package/commands/exec.command.js +60 -58
  16. package/commands/github-release.command.d.ts +154 -3
  17. package/commands/github-release.command.js +67 -37
  18. package/commands/import.command.d.ts +36 -3
  19. package/commands/import.command.js +28 -20
  20. package/commands/info.command.d.ts +35 -7
  21. package/commands/info.command.js +36 -30
  22. package/commands/list.command.d.ts +163 -3
  23. package/commands/list.command.js +109 -71
  24. package/commands/publish.command.d.ts +231 -0
  25. package/commands/publish.command.js +304 -0
  26. package/commands/run.command.d.ts +186 -6
  27. package/commands/run.command.js +26 -72
  28. package/commands/test.command.d.ts +173 -3
  29. package/commands/test.command.js +16 -10
  30. package/commands/version.command.d.ts +317 -3
  31. package/commands/version.command.js +149 -69
  32. package/commands.d.ts +32 -0
  33. package/commands.js +28 -0
  34. package/constants.js +1 -1
  35. package/core/application.d.ts +116 -0
  36. package/core/application.js +143 -0
  37. package/core/command-builder.d.ts +14 -0
  38. package/core/command-builder.js +78 -0
  39. package/core/config.d.ts +140 -19
  40. package/core/config.js +258 -74
  41. package/core/core-services.d.ts +14 -0
  42. package/core/core-services.js +30 -0
  43. package/core/core-targets.d.ts +14 -0
  44. package/core/core-targets.js +16 -0
  45. package/core/custom-command.d.ts +42 -6
  46. package/core/custom-command.js +44 -17
  47. package/core/extends-config.d.ts +13 -5
  48. package/core/extends-config.js +52 -12
  49. package/core/load-config-module.d.ts +28 -0
  50. package/core/load-config-module.js +42 -0
  51. package/core/manifest.d.ts +47 -25
  52. package/core/manifest.js +51 -69
  53. package/core/merge-config.d.ts +33 -34
  54. package/core/merge-config.js +137 -92
  55. package/core/package.d.ts +145 -17
  56. package/core/package.js +128 -36
  57. package/core/plugin-loader.d.ts +65 -0
  58. package/core/plugin-loader.js +234 -0
  59. package/core/plugin.d.ts +135 -90
  60. package/core/plugin.js +70 -173
  61. package/core/publish-target.d.ts +124 -0
  62. package/core/publish-target.js +30 -0
  63. package/core/registry.d.ts +30 -0
  64. package/core/registry.js +47 -0
  65. package/core/repository.d.ts +72 -9
  66. package/core/repository.js +293 -44
  67. package/core/resolve-target.d.ts +1 -1
  68. package/core/resolve-target.js +1 -1
  69. package/core/service.d.ts +49 -0
  70. package/core/service.js +40 -0
  71. package/core/version-scheme.d.ts +23 -1
  72. package/core/version-scheme.js +29 -1
  73. package/core/workspace.d.ts +84 -33
  74. package/core/workspace.js +63 -22
  75. package/index.d.ts +111 -14
  76. package/index.js +85 -9
  77. package/interfaces/rman-config.interface.d.ts +725 -202
  78. package/interfaces/rman-config.interface.js +61 -1
  79. package/package.json +2 -1
  80. package/plugins/builtins.d.ts +44 -0
  81. package/plugins/builtins.js +33 -0
  82. package/plugins/detect.d.ts +78 -0
  83. package/plugins/detect.js +70 -0
  84. package/plugins/node/augmentation/rman.augmentation.d.ts +84 -0
  85. package/plugins/node/augmentation/rman.augmentation.js +1 -0
  86. package/plugins/node/augmentation/system-info.augmentation.d.ts +26 -0
  87. package/plugins/node/augmentation/system-info.augmentation.js +79 -0
  88. package/plugins/node/commands/ci.command.d.ts +131 -0
  89. package/plugins/node/commands/ci.command.js +59 -0
  90. package/plugins/node/commands/clean.command.d.ts +183 -0
  91. package/plugins/node/commands/clean.command.js +73 -0
  92. package/plugins/node/index.d.ts +29 -0
  93. package/plugins/node/index.js +40 -0
  94. package/plugins/node/node-config.interface.d.ts +77 -0
  95. package/plugins/node/node-config.interface.js +7 -0
  96. package/plugins/node/node-manifest.provider.d.ts +68 -0
  97. package/plugins/node/node-manifest.provider.js +125 -0
  98. package/plugins/node/node.platform.d.ts +53 -0
  99. package/plugins/node/node.platform.js +134 -0
  100. package/plugins/node/npm-publish-target.d.ts +73 -0
  101. package/plugins/node/npm-publish-target.js +96 -0
  102. package/plugins/node/services/ci.service.d.ts +47 -0
  103. package/plugins/node/services/ci.service.js +213 -0
  104. package/plugins/node/services/clean.service.d.ts +53 -0
  105. package/plugins/node/services/clean.service.js +237 -0
  106. package/plugins/node/services/publish.service.d.ts +114 -0
  107. package/plugins/node/services/publish.service.js +371 -0
  108. package/plugins/node/services/version-plan.service.d.ts +44 -0
  109. package/plugins/node/services/version-plan.service.js +58 -0
  110. package/plugins/node/utils/npm-view.d.ts +48 -0
  111. package/plugins/node/utils/npm-view.js +71 -0
  112. package/plugins/node/utils/workspace-range.d.ts +26 -0
  113. package/plugins/node/utils/workspace-range.js +28 -0
  114. package/services/change-hash.service.d.ts +2 -2
  115. package/services/change-hash.service.js +2 -2
  116. package/services/changelog.service.d.ts +62 -51
  117. package/services/changelog.service.js +14 -11
  118. package/services/docker-publish.service.d.ts +50 -29
  119. package/services/docker-publish.service.js +43 -20
  120. package/services/exec.service.d.ts +23 -12
  121. package/services/exec.service.js +14 -9
  122. package/services/github-release.service.d.ts +44 -33
  123. package/services/github-release.service.js +13 -10
  124. package/services/import.service.d.ts +25 -14
  125. package/services/import.service.js +9 -5
  126. package/services/list.service.d.ts +62 -10
  127. package/services/list.service.js +62 -15
  128. package/services/run.service.d.ts +22 -13
  129. package/services/run.service.js +262 -223
  130. package/services/version-plan.service.d.ts +27 -4
  131. package/services/version-plan.service.js +42 -15
  132. package/services/version.service.d.ts +31 -11
  133. package/services/version.service.js +29 -13
  134. package/targets/docker.target.d.ts +53 -0
  135. package/targets/docker.target.js +40 -0
  136. package/utils/bin-path.d.ts +6 -7
  137. package/utils/bin-path.js +7 -18
  138. package/utils/branch-guard.d.ts +29 -0
  139. package/utils/branch-guard.js +31 -0
  140. package/utils/exec.d.ts +10 -0
  141. package/utils/exec.js +1 -1
  142. package/utils/logger.d.ts +1 -1
  143. package/utils/logger.js +1 -1
  144. package/utils/package-filter.d.ts +127 -7
  145. package/utils/package-filter.js +197 -16
  146. package/utils/printable-config.d.ts +1 -1
  147. package/utils/printable-config.js +1 -1
  148. package/utils/run-bin.d.ts +10 -0
  149. package/utils/run-bin.js +1 -1
  150. package/utils/run-options.d.ts +97 -0
  151. package/utils/run-options.js +81 -0
  152. package/utils/version-stamp.d.ts +1 -1
  153. package/utils/version-stamp.js +1 -1
@@ -0,0 +1,124 @@
1
+ import type { RmanConfig } from '../interfaces/rman-config.interface.js';
2
+ import type { PackageFilterOptions } from '../utils/package-filter.js';
3
+ import type { RmanApplication } from './application.js';
4
+ import type { Package } from './package.js';
5
+ import type { Repository } from './repository.js';
6
+ /**
7
+ * **Where a package's artifact ships, as a contribution.**
8
+ *
9
+ * `publish` used to be `rman-node`'s command, and that was backwards in a way worth stating: the
10
+ * command itself is about a *repository* - which packages are candidates, which versions are
11
+ * already out there, what order to push them in, what to print - and none of that is npm's. What is
12
+ * npm's is one answer to "is this version on the registry, and how do I push it", which is exactly
13
+ * the size of this interface. Docker publishing was in the core all along and could only be reached
14
+ * through a Node plugin's command; a Cargo repository could reach neither.
15
+ *
16
+ * So: the core ships `publish` and the `docker` target, the `node` built-in contributes `npm`, and a
17
+ * repository in any other ecosystem contributes its own without either package knowing about it.
18
+ *
19
+ * A target owns three things and no more:
20
+ *
21
+ * - **Which packages are its own by default** (`claims`) - see below.
22
+ * - **Its own CLI options**, merged into `publish`'s by the command. Every flag that only meant
23
+ * something to npm (`--access`, `--tag`, `--otp`, `--registry`, `--userconfig`, `--contents`,
24
+ * `--package-manager`) is declared here now instead of on a command the core would otherwise have
25
+ * to know them all in advance.
26
+ * - **`getPlan`/`applyPlan`** - the same two-step shape every other rman service uses, and the
27
+ * reason `--dry-run` and the confirmation prompt are the command's business rather than each
28
+ * target's.
29
+ */
30
+ export interface PublishTarget {
31
+ /** The name `publish.target` and `--target` use, and the label printed beside a package. */
32
+ readonly name: string;
33
+ /** One line for `--target`'s help - a reader asking `rman publish --help` in a polyglot
34
+ * repository has no other way to find out which targets are even installed. */
35
+ readonly describe?: string;
36
+ /**
37
+ * This target's own flags, merged into `publish`'s options.
38
+ *
39
+ * Flat, not namespaced: `--tag` reads better than `--npm-tag`, and two targets colliding on a
40
+ * name is refused loudly by the command rather than resolved by a rule nobody would remember.
41
+ * Name a flag for the target when it genuinely belongs to one (`--docker-namespace`).
42
+ */
43
+ readonly options?: Record<string, RmanConfig.CommandOption>;
44
+ /**
45
+ * Whether a package that declares **no** `publish.target` at all ships here.
46
+ *
47
+ * Absent means never - the target is opt-in, which is what `docker` is. `npm`'s answer is
48
+ * `pkg.provider === 'node'`, and that is the fix for a real bug rather than a nicety: the default
49
+ * used to be a hardcoded `['npm']` in the core, so `rman list --json` reported
50
+ * `publishTargets: ["npm"]` for a Cargo package and `publish` treated it as an npm candidate.
51
+ * A default only the ecosystem can state had been written down by someone who could not know it.
52
+ */
53
+ claims?(pkg: Package): boolean;
54
+ /** What this target *would* do - never publishes. Called even under `--dry-run`, which is the
55
+ * whole point of the split. */
56
+ getPlan(ctx: PublishTarget.Context): Promise<PublishTarget.Entry[]>;
57
+ /** Publishes every `'publish'` entry in `plan`, and returns what it did. */
58
+ applyPlan(ctx: PublishTarget.Context, plan: PublishTarget.Entry[]): Promise<PublishTarget.Entry[]>;
59
+ }
60
+ export declare namespace PublishTarget {
61
+ /**
62
+ * What a target is handed, once per call.
63
+ *
64
+ * `args` is the parsed argv, untyped on purpose: a target declared its own options, so it is the
65
+ * only thing that knows their names and types, and the core cannot be made to know them without
66
+ * becoming the thing this interface exists to stop it being.
67
+ */
68
+ interface Context {
69
+ readonly app: RmanApplication;
70
+ readonly repository: Repository;
71
+ /** The filters every target shares, read off argv once by the command. */
72
+ readonly options: Options;
73
+ /** The whole parsed argv - a target reads the options it declared out of this. */
74
+ readonly args: Record<string, any>;
75
+ }
76
+ interface Options extends PackageFilterOptions {
77
+ /** A package with uncommitted local changes is excluded (`'skip'`) instead of aborting the
78
+ * whole plan (`'error'`). */
79
+ ignoreDirty?: boolean;
80
+ }
81
+ /**
82
+ * One package's outcome for one target.
83
+ *
84
+ * `'skip'` and `'error'` differ in what they do to the run: an error aborts before anything is
85
+ * published, a skip is a package the plan deliberately leaves alone. A target may add fields of
86
+ * its own (docker carries the resolved image reference); `detail` is the one the command prints,
87
+ * so whatever a target wants shown beside a package goes there.
88
+ */
89
+ interface Entry {
90
+ package: Package;
91
+ version: string;
92
+ status: 'publish' | 'skip' | 'up-to-date' | 'error';
93
+ /** Printed after the package name - docker's resolved `<namespace>/<image>`, for instance. */
94
+ detail?: string;
95
+ reason?: string;
96
+ }
97
+ }
98
+ /**
99
+ * **A target's name, and deliberately not a union.**
100
+ *
101
+ * It was `'npm' | 'docker'`, the type half of a bug whose runtime half was a hardcoded `['npm']`
102
+ * default, so `rman list --json` reported `publishTargets: ["npm"]` for a Cargo package. Both are
103
+ * gone together - which targets exist is whatever the repository's plugins contribute
104
+ * (`RmanApplication.publishTargets`), so a union here would mean the core naming plugins it cannot
105
+ * know about, exactly as `Package.provider` must not.
106
+ *
107
+ * A name nothing implements is caught where the facts are, by `publish` itself, naming the targets
108
+ * this repository does have.
109
+ */
110
+ export type PublishTargetName = string;
111
+ /**
112
+ * The targets a package **declares**, or `undefined` when it declares none - which is not the same
113
+ * as an empty list, and the difference is what `claims` is asked about.
114
+ */
115
+ export declare function declaredTargets(pkg: Package): string[] | undefined;
116
+ /** Whether `pkg` ships to `target`: its own `publish.target` decides when it has one, and the
117
+ * target's own `claims` decides when it does not. */
118
+ export declare function shipsTo(pkg: Package, target: PublishTarget): boolean;
119
+ /** Every registered target `pkg` ships to, in registration order. The single answer to "where does
120
+ * this package go", so `publish` and `list --json` cannot disagree about it. */
121
+ export declare function targetsOf(app: RmanApplication, pkg: Package): PublishTarget[];
122
+ /** Names in a package's `publish.target` that no registered target answers to - a misconfiguration
123
+ * that used to be caught by a `choices: ['npm', 'docker']` the core can no longer write down. */
124
+ export declare function unknownTargets(app: RmanApplication, pkg: Package): string[];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The targets a package **declares**, or `undefined` when it declares none - which is not the same
3
+ * as an empty list, and the difference is what `claims` is asked about.
4
+ */
5
+ export function declaredTargets(pkg) {
6
+ const declared = pkg.config.publish?.target;
7
+ if (declared === undefined)
8
+ return undefined;
9
+ return Array.isArray(declared) ? [...declared] : [declared];
10
+ }
11
+ /** Whether `pkg` ships to `target`: its own `publish.target` decides when it has one, and the
12
+ * target's own `claims` decides when it does not. */
13
+ export function shipsTo(pkg, target) {
14
+ const declared = declaredTargets(pkg);
15
+ return declared ? declared.includes(target.name) : !!target.claims?.(pkg);
16
+ }
17
+ /** Every registered target `pkg` ships to, in registration order. The single answer to "where does
18
+ * this package go", so `publish` and `list --json` cannot disagree about it. */
19
+ export function targetsOf(app, pkg) {
20
+ return app.publishTargets.all.filter(target => shipsTo(pkg, target));
21
+ }
22
+ /** Names in a package's `publish.target` that no registered target answers to - a misconfiguration
23
+ * that used to be caught by a `choices: ['npm', 'docker']` the core can no longer write down. */
24
+ export function unknownTargets(app, pkg) {
25
+ const declared = declaredTargets(pkg);
26
+ if (!declared)
27
+ return [];
28
+ const known = new Set(app.publishTargets.all.map(t => t.name));
29
+ return declared.filter(name => !known.has(name));
30
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * An ordered collection of contributions, held **on the application** rather than in a module.
3
+ *
4
+ * Every registry rman had was a module-level array (`const providers: Provider[] = []` in
5
+ * `manifest.ts`, `workspace.ts`, `bin-path.ts`, `run.service.ts`), which made it process-global:
6
+ * two repositories in one process shared it. The test suite needed a root hook emptying five of
7
+ * them before every single test, and without it whichever spec ran first decided the answer for
8
+ * the rest - so the core appeared to work in tests that had registered nothing.
9
+ *
10
+ * An instance per `RmanApplication` closes the whole class: a new application starts empty, and
11
+ * nothing has to be cleaned up afterwards - the root hook is deleted.
12
+ *
13
+ * **Registry, not service.** The distinction is multiplicity: a registry is for a question whose
14
+ * answer is the *sum* of what was contributed (every provider's bin directories, the first provider
15
+ * that recognizes a directory). A question with exactly one answer is a service, replaceable
16
+ * through `RmanApplication.getService`.
17
+ */
18
+ export declare class Registry<T> implements Iterable<T> {
19
+ private readonly items;
20
+ /** Contributions in registration order, which for a plugin is `plugins` declaration order. */
21
+ get all(): readonly T[];
22
+ get size(): number;
23
+ /** Idempotent by identity: a plugin may both declare a contribution and register it itself, and
24
+ * the same function arriving twice would make the registry lie about what is in it. */
25
+ add(item: T): this;
26
+ /** The first contribution `ask` gives an answer for - "first that recognizes it" resolution,
27
+ * which is how a directory finds the manifest reader and the workspace layout that claim it. */
28
+ first<R>(ask: (item: T) => R | undefined): R | undefined;
29
+ [Symbol.iterator](): Iterator<T>;
30
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * An ordered collection of contributions, held **on the application** rather than in a module.
3
+ *
4
+ * Every registry rman had was a module-level array (`const providers: Provider[] = []` in
5
+ * `manifest.ts`, `workspace.ts`, `bin-path.ts`, `run.service.ts`), which made it process-global:
6
+ * two repositories in one process shared it. The test suite needed a root hook emptying five of
7
+ * them before every single test, and without it whichever spec ran first decided the answer for
8
+ * the rest - so the core appeared to work in tests that had registered nothing.
9
+ *
10
+ * An instance per `RmanApplication` closes the whole class: a new application starts empty, and
11
+ * nothing has to be cleaned up afterwards - the root hook is deleted.
12
+ *
13
+ * **Registry, not service.** The distinction is multiplicity: a registry is for a question whose
14
+ * answer is the *sum* of what was contributed (every provider's bin directories, the first provider
15
+ * that recognizes a directory). A question with exactly one answer is a service, replaceable
16
+ * through `RmanApplication.getService`.
17
+ */
18
+ export class Registry {
19
+ items = [];
20
+ /** Contributions in registration order, which for a plugin is `plugins` declaration order. */
21
+ get all() {
22
+ return this.items;
23
+ }
24
+ get size() {
25
+ return this.items.length;
26
+ }
27
+ /** Idempotent by identity: a plugin may both declare a contribution and register it itself, and
28
+ * the same function arriving twice would make the registry lie about what is in it. */
29
+ add(item) {
30
+ if (!this.items.includes(item))
31
+ this.items.push(item);
32
+ return this;
33
+ }
34
+ /** The first contribution `ask` gives an answer for - "first that recognizes it" resolution,
35
+ * which is how a directory finds the manifest reader and the workspace layout that claim it. */
36
+ first(ask) {
37
+ for (const item of this.items) {
38
+ const answer = ask(item);
39
+ if (answer !== undefined)
40
+ return answer;
41
+ }
42
+ return undefined;
43
+ }
44
+ [Symbol.iterator]() {
45
+ return this.items[Symbol.iterator]();
46
+ }
47
+ }
@@ -1,6 +1,10 @@
1
+ import type { RmanConfig } from '../interfaces/rman-config.interface.js';
2
+ import { type DetectedBuiltin } from '../plugins/detect.js';
3
+ import { RmanApplication } from './application.js';
1
4
  import { type ConfigScope, type GitScope, type PackageScope, type RepositoryScope } from './config.js';
2
- import type { LoadedCommand } from './custom-command.js';
3
5
  import { Package } from './package.js';
6
+ import type { Platform } from './plugin.js';
7
+ import { Workspace } from './workspace.js';
4
8
  export declare class Repository extends Package {
5
9
  readonly dirname: string;
6
10
  readonly monorepo: boolean;
@@ -10,9 +14,10 @@ export declare class Repository extends Package {
10
14
  * really was. Used by `currentPackage` to scope commands to "the package I'm standing in". */
11
15
  readonly cwd: string;
12
16
  readonly rootPackage: Package;
17
+ /** See the `defineProperty` in the constructor - what detection supplied, when it did. */
18
+ readonly detectedBuiltin?: DetectedBuiltin;
13
19
  /** Commands the repository's plugins contributed, loaded during `create` because the workspace
14
20
  * providers they bring are needed before any package can be found. `cli.ts` registers them. */
15
- pluginCommands: LoadedCommand[];
16
21
  /**
17
22
  * Cached repository scope - see `_repositoryScope`.
18
23
  *
@@ -36,11 +41,24 @@ export declare class Repository extends Package {
36
41
  * for every package that mentions it.
37
42
  */
38
43
  private readonly _readCache;
39
- protected constructor(dirname: string, monorepo: boolean, packages: Package[],
44
+ /**
45
+ * The application this repository belongs to - its services, its technologies, its logger.
46
+ *
47
+ * **Non-enumerable**, like `_repoScope` and `_git` beside it: the two things that walk a
48
+ * repository are `{...pkg}` spreads and the config scope, and an enumerable back-reference to the
49
+ * whole application would be dragged into both. A `Package` deliberately has no such field at
50
+ * all; a repository is never spread or serialized, which is what makes this one safe - measured,
51
+ * rather than assumed.
52
+ */
53
+ readonly app: RmanApplication;
54
+ protected constructor(app: RmanApplication, dirname: string, monorepo: boolean, packages: Package[],
40
55
  /** The directory `Repository.create()` was actually invoked from - unlike `dirname` (the
41
56
  * resolved repository root, possibly several levels up), this is where the user's shell
42
57
  * really was. Used by `currentPackage` to scope commands to "the package I'm standing in". */
43
- cwd?: string);
58
+ cwd?: string,
59
+ /** The root directory's own technology, from the same walk that found the packages - so the
60
+ * repository and its `rootPackage` agree without either searching the registry again. */
61
+ platform?: Platform);
44
62
  /**
45
63
  * The package whose own directory contains `cwd` (the deepest match, so a package nested
46
64
  * inside another's directory resolves to the innermost one) - or `undefined` when `cwd` *is*
@@ -60,9 +78,21 @@ export declare class Repository extends Package {
60
78
  * dirty, the reference point decides the rest: without `hash`, `committed`
61
79
  * means committed but not yet in the upstream branch; with `hash`, `changed`
62
80
  * means it differs from that commit. Otherwise a package is `clean`.
81
+ *
82
+ * **Keyed by `Package.selector`**, which is what addresses a package - it was `name`, and the two
83
+ * coincide wherever a technology names its packages. A repository whose does not had every such
84
+ * package answering to `""`, so one entry stood for all of them.
85
+ *
86
+ * **`includeRoot` is opt-in, and the reason is that the root's answer means something different.**
87
+ * Its directory contains every other package, so the same rule - "does a changed file fall under
88
+ * this directory" - reports `dirty` for the root whenever *anything* in the repository is dirty.
89
+ * That is the honest reading of the rule rather than a bug, and it is not what `run --changed`
90
+ * wants, so only a caller that asked for the root gets it (`rman list`'s table, which shows the
91
+ * root as the tree's own row).
63
92
  */
64
93
  listStatus(options?: {
65
94
  hash?: string;
95
+ includeRoot?: boolean;
66
96
  }): Promise<Record<string, Repository.PackageStatus>>;
67
97
  /**
68
98
  * The scope a `${{ ... }}` expression is evaluated against for `pkg`, optionally with the version
@@ -89,13 +119,44 @@ export declare class Repository extends Package {
89
119
  * nothing under `getPackages()` is the root, so only its own unmarked config applies.
90
120
  */
91
121
  /**
92
- * Gives every package its `repository` and `parent`, before any config is resolved - a config
93
- * expression or a provider may already want to navigate from a package outwards.
122
+ * Gives every package its `repository`, and hangs the `parent`/`children` tree off the walk that
123
+ * found them - before any config is resolved, since a config expression or a provider may already
124
+ * want to navigate from a package outwards.
125
+ *
126
+ * **The containment is read from the tree rather than recomputed from paths.** It used to be an
127
+ * O(n²) sweep comparing every package's directory against every other's and keeping the longest
128
+ * prefix - which is the same question `Workspace.walk` answers on the way down, asked again
129
+ * afterwards with the answer thrown away. Two places deriving one relationship is two places to
130
+ * disagree; there is one now.
131
+ *
132
+ * **`parent` is defined non-enumerably, `children` is a plain field**, which is the one asymmetry
133
+ * here and it is deliberate: a tree is serialized downwards, so `children` has to be walkable and
134
+ * `parent` must not be, or every `JSON.stringify` is a cycle. The same way `Repository.app` and
135
+ * `ORIGINS` travel.
94
136
  *
95
137
  * A repository's own `repository` is itself, which reads oddly and is the honest answer:
96
138
  * `Repository extends Package`, so the repository *is* a package of its own repository.
97
139
  */
98
- protected _linkPackages(): void;
140
+ protected _linkPackages(tree: Workspace.Node, nodes: Workspace.Node[], packages: Package[]): void;
141
+ /**
142
+ * Gives every package the selector a `"[glob]"` block and `--scope` match it by, and refuses two
143
+ * packages that would answer to the same one.
144
+ *
145
+ * **Its own step, before any config is resolved by a selector**, which is the ordering that makes
146
+ * the rest work: `_resolveConfigs` asks `resolveConfig` for each package *by selector*, so an
147
+ * address assigned afterwards would be applied to nothing.
148
+ *
149
+ * **`name` comes from the unmarked cascade only** - the same read `platform` gets, from the same
150
+ * cache, for the same reason. A `"[glob]"` block cannot set it (`assertSelectorBlocks` refuses
151
+ * one) because the glob matches the very thing the block would be setting.
152
+ *
153
+ * **Uniqueness is checked, and the cascade is the mistake it usually catches.** `name` cascades
154
+ * like every unmarked key, so one declaration above two packages gives both the same address -
155
+ * and the failure would otherwise be silent in the worst way: the config reaches both and
156
+ * `getPackage` returns whichever came first. The message names both directories, and says the
157
+ * cascade out loud when the two got it from one declaration.
158
+ */
159
+ protected _assignSelectors(rootDir: string, cache: Map<string, RmanConfig>): Promise<void>;
99
160
  protected _resolveConfigs(): Promise<void>;
100
161
  protected _topoSortPackages(packages: Package[]): void;
101
162
  protected _packageScope(pkg: Package, targetVersion?: string): PackageScope;
@@ -131,16 +192,18 @@ export declare class Repository extends Package {
131
192
  * otherwise: the plugins that know what a package is are named in the config file this step
132
193
  * is looking for.
133
194
  * 2. **Load the plugins** the root's config names, which registers their workspace providers
134
- * (and their commands, handed on via `pluginCommands` - `cli.ts` registers those).
195
+ * (their commands arrive through `.rmanrc "commands"`, which `cli.ts` reads).
135
196
  * 3. **Ask the providers** for the layout. None recognizing it means a repository that is itself
136
197
  * the one package.
137
198
  *
138
199
  * **A repository whose `.rmanrc` names no plugin has no packages beyond itself**, and that is the
139
200
  * boundary working rather than failing: `workspaces` in a `package.json` is npm's idea, so it
140
- * takes `plugins: ['rman-node']` to be read as one.
201
+ * takes `plugins: ['node']` - or detection reading the directory as a Node one - for it to be
202
+ * read as a workspace at all.
141
203
  */
142
204
  static create(root?: string, options?: {
143
205
  deep?: number;
206
+ app?: RmanApplication;
144
207
  }): Promise<Repository>;
145
208
  /** Finishes constructing `repo` with the async work a constructor can't do itself - resolving
146
209
  * `.rmanrc`/`.rmanrc.yml`/`.rmanrc.cjs`/`.mjs`/`.js` config (which may need a dynamic `import()`)