@memberjunction/cli 6.1.0-edge.2 → 6.1.0-edge.4

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 (94) hide show
  1. package/LICENSE +180 -4
  2. package/README.md +1 -1
  3. package/dist/commands/codegen/manifest.d.ts +14 -0
  4. package/dist/commands/codegen/manifest.d.ts.map +1 -1
  5. package/dist/commands/codegen/manifest.js +26 -7
  6. package/dist/commands/codegen/manifest.js.map +1 -1
  7. package/dist/commands/dev/index.d.ts +7 -0
  8. package/dist/commands/dev/index.d.ts.map +1 -0
  9. package/dist/commands/dev/index.js +11 -0
  10. package/dist/commands/dev/index.js.map +1 -0
  11. package/dist/commands/dev/usage.d.ts +7 -0
  12. package/dist/commands/dev/usage.d.ts.map +1 -0
  13. package/dist/commands/dev/usage.js +10 -0
  14. package/dist/commands/dev/usage.js.map +1 -0
  15. package/dist/commands/dev/workspace/clean.d.ts +27 -0
  16. package/dist/commands/dev/workspace/clean.d.ts.map +1 -0
  17. package/dist/commands/dev/workspace/clean.js +87 -0
  18. package/dist/commands/dev/workspace/clean.js.map +1 -0
  19. package/dist/commands/dev/workspace/doctor.d.ts +28 -0
  20. package/dist/commands/dev/workspace/doctor.d.ts.map +1 -0
  21. package/dist/commands/dev/workspace/doctor.js +62 -0
  22. package/dist/commands/dev/workspace/doctor.js.map +1 -0
  23. package/dist/commands/dev/workspace/index.d.ts +60 -0
  24. package/dist/commands/dev/workspace/index.d.ts.map +1 -0
  25. package/dist/commands/dev/workspace/index.js +279 -0
  26. package/dist/commands/dev/workspace/index.js.map +1 -0
  27. package/dist/commands/dev/workspace/status.d.ts +19 -0
  28. package/dist/commands/dev/workspace/status.d.ts.map +1 -0
  29. package/dist/commands/dev/workspace/status.js +46 -0
  30. package/dist/commands/dev/workspace/status.js.map +1 -0
  31. package/dist/commands/migrate/convert.d.ts +25 -0
  32. package/dist/commands/migrate/convert.d.ts.map +1 -1
  33. package/dist/commands/migrate/convert.js +61 -8
  34. package/dist/commands/migrate/convert.js.map +1 -1
  35. package/dist/commands/migrate/index.d.ts +9 -0
  36. package/dist/commands/migrate/index.d.ts.map +1 -1
  37. package/dist/commands/migrate/index.js +41 -1
  38. package/dist/commands/migrate/index.js.map +1 -1
  39. package/dist/lib/cli-plugins.d.ts.map +1 -1
  40. package/dist/lib/cli-plugins.js +5 -0
  41. package/dist/lib/cli-plugins.js.map +1 -1
  42. package/dist/lib/dev-workspace/build.d.ts +180 -0
  43. package/dist/lib/dev-workspace/build.d.ts.map +1 -0
  44. package/dist/lib/dev-workspace/build.js +570 -0
  45. package/dist/lib/dev-workspace/build.js.map +1 -0
  46. package/dist/lib/dev-workspace/clean.d.ts +40 -0
  47. package/dist/lib/dev-workspace/clean.d.ts.map +1 -0
  48. package/dist/lib/dev-workspace/clean.js +193 -0
  49. package/dist/lib/dev-workspace/clean.js.map +1 -0
  50. package/dist/lib/dev-workspace/detect.d.ts +56 -0
  51. package/dist/lib/dev-workspace/detect.d.ts.map +1 -0
  52. package/dist/lib/dev-workspace/detect.js +343 -0
  53. package/dist/lib/dev-workspace/detect.js.map +1 -0
  54. package/dist/lib/dev-workspace/dir-flag.d.ts +23 -0
  55. package/dist/lib/dev-workspace/dir-flag.d.ts.map +1 -0
  56. package/dist/lib/dev-workspace/dir-flag.js +24 -0
  57. package/dist/lib/dev-workspace/dir-flag.js.map +1 -0
  58. package/dist/lib/dev-workspace/doctor.d.ts +96 -0
  59. package/dist/lib/dev-workspace/doctor.d.ts.map +1 -0
  60. package/dist/lib/dev-workspace/doctor.js +400 -0
  61. package/dist/lib/dev-workspace/doctor.js.map +1 -0
  62. package/dist/lib/dev-workspace/lockfile.d.ts +62 -0
  63. package/dist/lib/dev-workspace/lockfile.d.ts.map +1 -0
  64. package/dist/lib/dev-workspace/lockfile.js +456 -0
  65. package/dist/lib/dev-workspace/lockfile.js.map +1 -0
  66. package/dist/lib/dev-workspace/member-installs.d.ts +35 -0
  67. package/dist/lib/dev-workspace/member-installs.d.ts.map +1 -0
  68. package/dist/lib/dev-workspace/member-installs.js +139 -0
  69. package/dist/lib/dev-workspace/member-installs.js.map +1 -0
  70. package/dist/lib/dev-workspace/pnpm.d.ts +29 -0
  71. package/dist/lib/dev-workspace/pnpm.d.ts.map +1 -0
  72. package/dist/lib/dev-workspace/pnpm.js +59 -0
  73. package/dist/lib/dev-workspace/pnpm.js.map +1 -0
  74. package/dist/lib/dev-workspace/status.d.ts +16 -0
  75. package/dist/lib/dev-workspace/status.d.ts.map +1 -0
  76. package/dist/lib/dev-workspace/status.js +185 -0
  77. package/dist/lib/dev-workspace/status.js.map +1 -0
  78. package/dist/lib/dev-workspace/types.d.ts +312 -0
  79. package/dist/lib/dev-workspace/types.d.ts.map +1 -0
  80. package/dist/lib/dev-workspace/types.js +14 -0
  81. package/dist/lib/dev-workspace/types.js.map +1 -0
  82. package/dist/lib/dev-workspace/usage.d.ts +30 -0
  83. package/dist/lib/dev-workspace/usage.d.ts.map +1 -0
  84. package/dist/lib/dev-workspace/usage.js +177 -0
  85. package/dist/lib/dev-workspace/usage.js.map +1 -0
  86. package/dist/lib/dev-workspace/write.d.ts +25 -0
  87. package/dist/lib/dev-workspace/write.d.ts.map +1 -0
  88. package/dist/lib/dev-workspace/write.js +75 -0
  89. package/dist/lib/dev-workspace/write.js.map +1 -0
  90. package/dist/light-commands.d.ts.map +1 -1
  91. package/dist/light-commands.js +7 -0
  92. package/dist/light-commands.js.map +1 -1
  93. package/oclif.manifest.json +1228 -969
  94. package/package.json +22 -22
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dir-flag.d.ts","sourceRoot":"","sources":["../../../src/lib/dev-workspace/dir-flag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,yBAAyB,CAAC;AAE5D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAIjG;AAED,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAI3D"}
@@ -0,0 +1,24 @@
1
+ /** Environment variable every dev workspace command binds to its `--dir` flag. */
2
+ export const WORKSPACE_DIR_ENV_VAR = 'MJ_DEV_WORKSPACE_DIR';
3
+ /**
4
+ * Determines which input supplied `--dir`, mirroring oclif's own precedence: an
5
+ * explicit flag beats the environment variable, which beats the default. Pure —
6
+ * the caller passes its raw argv and the environment value, so this never reads
7
+ * `process.env` itself.
8
+ */
9
+ export function ResolveDirSource(argv, envValue) {
10
+ if (argv.some((arg) => arg === '--dir' || arg.startsWith('--dir=')))
11
+ return 'flag';
12
+ if (envValue !== undefined && envValue.length > 0)
13
+ return 'env';
14
+ return 'default';
15
+ }
16
+ /** How a resolved `--dir` should be described in output. */
17
+ export function DescribeDirSource(source) {
18
+ if (source === 'flag')
19
+ return '--dir flag';
20
+ if (source === 'env')
21
+ return `$${WORKSPACE_DIR_ENV_VAR}`;
22
+ return 'default (current directory)';
23
+ }
24
+ //# sourceMappingURL=dir-flag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dir-flag.js","sourceRoot":"","sources":["../../../src/lib/dev-workspace/dir-flag.ts"],"names":[],"mappings":"AAYA,kFAAkF;AAClF,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAuB,EAAE,QAA4B;IACpF,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,OAAO,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IACnF,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAChE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,YAAY,CAAC;IAC3C,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,IAAI,qBAAqB,EAAE,CAAC;IACzD,OAAO,6BAA6B,CAAC;AACvC,CAAC"}
@@ -0,0 +1,96 @@
1
+ import type { DirSource } from './types.js';
2
+ /**
3
+ * Packages that MUST resolve to exactly one copy across a joined workspace.
4
+ * Angular's DI, RxJS's operator identity checks and MJ's Global Object Store all
5
+ * key off module identity, so a second copy is not a duplicate — it is a second,
6
+ * mutually invisible runtime.
7
+ */
8
+ export declare const SINGLETON_PACKAGES: readonly string[];
9
+ /**
10
+ * Outcome of one health check. `skip` means the check did not apply — it is never a
11
+ * claim of health, which is exactly why it is not folded into `pass`.
12
+ */
13
+ export type DoctorSeverity = 'pass' | 'warn' | 'fail' | 'skip';
14
+ /** One health-check result: what was checked, how it went, and for warn/fail what to do. */
15
+ export interface DoctorCheck {
16
+ Name: string;
17
+ Severity: DoctorSeverity;
18
+ Detail: string;
19
+ }
20
+ /** One decoded pnpm virtual-store directory name. */
21
+ export interface StoreEntry {
22
+ /** Package name with the scope separator decoded (`@angular+core` -> `@angular/core`). */
23
+ Name: string;
24
+ /** Concrete version, peer suffix stripped. */
25
+ Version: string;
26
+ }
27
+ /** Distinct versions of one singleton package found in the parent's store. */
28
+ export interface SingletonVersions {
29
+ Package: string;
30
+ /** Sorted distinct versions — always at least one entry. */
31
+ Versions: string[];
32
+ }
33
+ /** What the one-copy census read out of `<parent>/node_modules/.pnpm`. */
34
+ export interface StoreCensus {
35
+ /** False when the parent has no virtual store — nothing has been installed there. */
36
+ StorePresent: boolean;
37
+ /** Every singleton package present in the store. Packages absent from it are omitted, not zero-filled. */
38
+ Packages: SingletonVersions[];
39
+ /**
40
+ * Store entries that are not `name@version` (the store's own `node_modules`,
41
+ * `file:`/`link:` entries). Counted and reported rather than silently dropped.
42
+ */
43
+ UnparsedEntryCount: number;
44
+ }
45
+ /** Everything `dev workspace doctor` reports. */
46
+ export interface DoctorReport {
47
+ ParentDir: string;
48
+ DirSource: DirSource;
49
+ Checks: DoctorCheck[];
50
+ Census: StoreCensus;
51
+ }
52
+ /**
53
+ * Decodes one `<parent>/node_modules/.pnpm` directory name into package name and
54
+ * version, or null when the entry is not a resolved package (the store's own
55
+ * `node_modules`, `file+..+repo@file+..+repo` link entries, and anything else whose
56
+ * version segment does not start with a digit).
57
+ *
58
+ * Peer suffixes come in BOTH shapes and both are handled — pnpm 10.33 writes the
59
+ * underscore form (verified against a real store: `@angular+core@21.1.3_@angular+
60
+ * compiler@21.1.3_rxjs@7.8.2_zone.js@0.16.0`), other versions write the parenthesised
61
+ * form (`@angular+common@21.1.3(@angular+core@21.1.3)`). Both carry `@` characters
62
+ * INSIDE the suffix, which is why the version is taken from the name/version
63
+ * separator forwards and then truncated, never from the LAST `@` backwards — on the
64
+ * entry above, the last `@` yields `0.16.0`, a version of a different package.
65
+ * Splitting the VERSION segment (not the whole entry) at `_` is safe: semver forbids
66
+ * `_` in a version, and a package name containing one is never reached. Pure.
67
+ */
68
+ export declare function ParseStoreEntry(entryName: string): StoreEntry | null;
69
+ /**
70
+ * Counts the distinct versions of each singleton package in the parent's pnpm
71
+ * virtual store, reading DIRECTORY NAMES ONLY — a store entry name already carries
72
+ * `name@version`, so no package.json is opened and the whole census is one
73
+ * `readdirSync`. An absent store is reported as `StorePresent: false`, never as a
74
+ * clean bill of health.
75
+ *
76
+ * KNOWN LIMIT, stated so the PASS is not read as more than it is: pnpm gives
77
+ * workspace-linked packages no virtual-store entry at all (verified — an MJ
78
+ * checkout's own store holds zero `@memberjunction+core@…` entries), so this counts
79
+ * copies IN THE PARENT STORE. A registry copy sitting alongside a workspace link is
80
+ * one store entry and reads as one copy. Catching that is the job of the family
81
+ * `workspace:*` overrides the generator emits, not of this census.
82
+ *
83
+ * SIDE EFFECT: one read-only directory listing.
84
+ */
85
+ export declare function CollectSingletonCensus(parentDir: string): StoreCensus;
86
+ /**
87
+ * Runs every health check at a parent directory. `activePnpmVersion` comes from the
88
+ * caller (a spawn — see `pnpm.ts`) and `dirSource` likewise, so this module reads
89
+ * neither processes nor the environment. Read-only.
90
+ */
91
+ export declare function CollectDoctorReport(parentDir: string, activePnpmVersion: string | null, dirSource: DirSource): DoctorReport;
92
+ /** True when any check failed — the command's exit-code decision. Pure. */
93
+ export declare function DoctorHasFailures(report: DoctorReport): boolean;
94
+ /** Renders a DoctorReport as the terminal report. Pure. */
95
+ export declare function RenderDoctor(report: DoctorReport): string;
96
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/lib/dev-workspace/doctor.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,YAAY,CAAC;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAQ/C,CAAC;AAQF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/D,4FAA4F;AAC5F,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC1B,qFAAqF;IACrF,YAAY,EAAE,OAAO,CAAC;IACtB,0GAA0G;IAC1G,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B;;;OAGG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,MAAM,EAAE,WAAW,CAAC;CACrB;AAoBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAQpE;AAgDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAOrE;AAiMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,SAAS,EAAE,SAAS,GACnB,YAAY,CAsBd;AAUD,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAE/D;AAWD,2DAA2D;AAC3D,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAYzD"}
@@ -0,0 +1,400 @@
1
+ /**
2
+ * Health checks for `mj dev workspace doctor`.
3
+ *
4
+ * SIDE EFFECTS: READ-ONLY filesystem access, and nothing else. Two reads happen
5
+ * here — the workspace state collection delegated to `status.ts` (existence checks
6
+ * plus small file reads), and ONE `readdirSync` of the parent's pnpm virtual store
7
+ * for the one-copy census. Doctor never writes, never deletes, never spawns a
8
+ * process (the active pnpm version is probed by the command and passed in, the same
9
+ * contract `CollectWorkspaceStatus` uses) and never touches the network.
10
+ *
11
+ * The census exists because the failure that actually bites a joined workspace is
12
+ * not a missing file — it is TWO COPIES of a package the runtime requires exactly
13
+ * one of. Two `@angular/core`s give `NG0203 inject() must be called from an
14
+ * injection context`; two `@memberjunction/global`s give two Global Object Stores,
15
+ * so every `BaseSingleton` silently becomes two singletons. Both look like
16
+ * application bugs and neither names the real cause, so doctor names it.
17
+ *
18
+ * @module lib/dev-workspace/doctor
19
+ */
20
+ import { existsSync, readdirSync } from 'node:fs';
21
+ import path from 'node:path';
22
+ import chalk from 'chalk';
23
+ import { SENTINEL_MARKER } from './build.js';
24
+ import { LOCKFILE_NAME, NODE_MODULES_NAME } from './clean.js';
25
+ import { DescribeDirSource } from './dir-flag.js';
26
+ import { CollectWorkspaceStatus } from './status.js';
27
+ import { SENTINEL_FILE_NAME } from './write.js';
28
+ /**
29
+ * Packages that MUST resolve to exactly one copy across a joined workspace.
30
+ * Angular's DI, RxJS's operator identity checks and MJ's Global Object Store all
31
+ * key off module identity, so a second copy is not a duplicate — it is a second,
32
+ * mutually invisible runtime.
33
+ */
34
+ export const SINGLETON_PACKAGES = [
35
+ '@angular/core',
36
+ '@angular/common',
37
+ '@angular/compiler',
38
+ 'rxjs',
39
+ 'zone.js',
40
+ '@memberjunction/core',
41
+ '@memberjunction/global',
42
+ ];
43
+ /** Hard cap on virtual-store entries the census will read; exceeding it throws rather than truncating. */
44
+ const MAX_STORE_ENTRIES = 100_000;
45
+ /** The pnpm virtual store, relative to the workspace parent. */
46
+ const STORE_REL_PATH = path.join(NODE_MODULES_NAME, '.pnpm');
47
+ /**
48
+ * Index of the `@` that separates name from version in a store directory name:
49
+ * the SECOND `@` for a scoped package (`@angular+core@21.1.3`), the first
50
+ * otherwise (`rxjs@7.8.1`). Returns -1 when there is none.
51
+ *
52
+ * Deliberately not "the last `@`": a peer-suffixed entry carries `@` characters
53
+ * INSIDE its suffix — `@angular+common@21.1.3(@angular+core@21.1.3)` — so the last
54
+ * `@` sits in the parentheses and the naive split yields nonsense.
55
+ */
56
+ function findVersionSeparator(entry) {
57
+ return entry.startsWith('@') ? entry.indexOf('@', 1) : entry.indexOf('@');
58
+ }
59
+ /** pnpm encodes the scope separator as `+`, and only that one: `@angular+core` -> `@angular/core`. */
60
+ function decodeStoreName(encodedName) {
61
+ return encodedName.startsWith('@') ? encodedName.replace('+', '/') : encodedName;
62
+ }
63
+ /**
64
+ * Decodes one `<parent>/node_modules/.pnpm` directory name into package name and
65
+ * version, or null when the entry is not a resolved package (the store's own
66
+ * `node_modules`, `file+..+repo@file+..+repo` link entries, and anything else whose
67
+ * version segment does not start with a digit).
68
+ *
69
+ * Peer suffixes come in BOTH shapes and both are handled — pnpm 10.33 writes the
70
+ * underscore form (verified against a real store: `@angular+core@21.1.3_@angular+
71
+ * compiler@21.1.3_rxjs@7.8.2_zone.js@0.16.0`), other versions write the parenthesised
72
+ * form (`@angular+common@21.1.3(@angular+core@21.1.3)`). Both carry `@` characters
73
+ * INSIDE the suffix, which is why the version is taken from the name/version
74
+ * separator forwards and then truncated, never from the LAST `@` backwards — on the
75
+ * entry above, the last `@` yields `0.16.0`, a version of a different package.
76
+ * Splitting the VERSION segment (not the whole entry) at `_` is safe: semver forbids
77
+ * `_` in a version, and a package name containing one is never reached. Pure.
78
+ */
79
+ export function ParseStoreEntry(entryName) {
80
+ const withoutPeers = entryName.split('(')[0];
81
+ const separator = findVersionSeparator(withoutPeers);
82
+ if (separator <= 0)
83
+ return null;
84
+ const encodedName = withoutPeers.slice(0, separator);
85
+ const version = withoutPeers.slice(separator + 1).split('_')[0];
86
+ if (!/^\d/.test(version))
87
+ return null;
88
+ return { Name: decodeStoreName(encodedName), Version: version };
89
+ }
90
+ /**
91
+ * Directory names in the virtual store. Reads the directory exactly once and is
92
+ * bounded by {@link MAX_STORE_ENTRIES} — hitting the cap throws rather than
93
+ * silently censusing a prefix of the store, which would be a false PASS.
94
+ */
95
+ function readStoreEntries(storeDir) {
96
+ let dirents;
97
+ try {
98
+ dirents = readdirSync(storeDir, { withFileTypes: true });
99
+ }
100
+ catch (error) {
101
+ const message = error instanceof Error ? error.message : String(error);
102
+ throw new Error(`Cannot read the package store at ${storeDir}: ${message}`);
103
+ }
104
+ if (dirents.length > MAX_STORE_ENTRIES) {
105
+ throw new Error(`${storeDir} holds ${dirents.length} entries, over the ${MAX_STORE_ENTRIES} cap — refusing to census it`);
106
+ }
107
+ return dirents.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
108
+ }
109
+ /** Groups parsed store entries into the distinct versions of each singleton package. Pure. */
110
+ function tallySingletons(entryNames) {
111
+ const wanted = new Set(SINGLETON_PACKAGES);
112
+ const found = new Map();
113
+ let unparsed = 0;
114
+ for (const entryName of entryNames) {
115
+ const entry = ParseStoreEntry(entryName);
116
+ if (entry === null) {
117
+ unparsed++;
118
+ continue;
119
+ }
120
+ if (!wanted.has(entry.Name))
121
+ continue;
122
+ const versions = found.get(entry.Name) ?? new Set();
123
+ versions.add(entry.Version);
124
+ found.set(entry.Name, versions);
125
+ }
126
+ const packages = [];
127
+ for (const name of SINGLETON_PACKAGES) {
128
+ const versions = found.get(name);
129
+ if (versions === undefined)
130
+ continue;
131
+ packages.push({ Package: name, Versions: [...versions].sort() });
132
+ }
133
+ return { StorePresent: true, Packages: packages, UnparsedEntryCount: unparsed };
134
+ }
135
+ /**
136
+ * Counts the distinct versions of each singleton package in the parent's pnpm
137
+ * virtual store, reading DIRECTORY NAMES ONLY — a store entry name already carries
138
+ * `name@version`, so no package.json is opened and the whole census is one
139
+ * `readdirSync`. An absent store is reported as `StorePresent: false`, never as a
140
+ * clean bill of health.
141
+ *
142
+ * KNOWN LIMIT, stated so the PASS is not read as more than it is: pnpm gives
143
+ * workspace-linked packages no virtual-store entry at all (verified — an MJ
144
+ * checkout's own store holds zero `@memberjunction+core@…` entries), so this counts
145
+ * copies IN THE PARENT STORE. A registry copy sitting alongside a workspace link is
146
+ * one store entry and reads as one copy. Catching that is the job of the family
147
+ * `workspace:*` overrides the generator emits, not of this census.
148
+ *
149
+ * SIDE EFFECT: one read-only directory listing.
150
+ */
151
+ export function CollectSingletonCensus(parentDir) {
152
+ if (!path.isAbsolute(parentDir)) {
153
+ throw new Error(`CollectSingletonCensus requires an absolute path, got: ${parentDir}`);
154
+ }
155
+ const storeDir = path.join(parentDir, STORE_REL_PATH);
156
+ if (!existsSync(storeDir))
157
+ return { StorePresent: false, Packages: [], UnparsedEntryCount: 0 };
158
+ return tallySingletons(readStoreEntries(storeDir));
159
+ }
160
+ /** The parent must be a plain directory holding sibling clones — never a git repo root itself. */
161
+ function checkParentShape(status) {
162
+ if (!status.ParentIsGitRepo) {
163
+ return { Name: 'parent directory', Severity: 'pass', Detail: 'a plain directory, not a git repo root' };
164
+ }
165
+ return {
166
+ Name: 'parent directory',
167
+ Severity: 'fail',
168
+ Detail: 'this directory is a git repo root (.git present) — a workspace parent must be the plain directory that ' +
169
+ 'HOLDS the sibling clones; re-run with --dir pointing at their common parent',
170
+ };
171
+ }
172
+ /** All generated files must be present; a missing one means the workspace was never (fully) generated. */
173
+ function checkGeneratedFiles(status) {
174
+ const missing = status.Files.filter((file) => !file.Exists).map((file) => file.Name);
175
+ if (missing.length === 0) {
176
+ return { Name: 'workspace files', Severity: 'pass', Detail: `all ${status.Files.length} generated files present` };
177
+ }
178
+ return {
179
+ Name: 'workspace files',
180
+ Severity: 'fail',
181
+ Detail: `missing: ${missing.join(', ')} — run \`mj dev workspace --dir ${status.ParentDir}\` to generate them`,
182
+ };
183
+ }
184
+ /** The lockfile and node_modules come from `pnpm install`, not the generator — absence is incomplete, not broken. */
185
+ function checkInstallArtifacts(status) {
186
+ const missing = [];
187
+ if (!status.LockfileExists)
188
+ missing.push(LOCKFILE_NAME);
189
+ if (!status.NodeModulesExists)
190
+ missing.push(NODE_MODULES_NAME);
191
+ if (missing.length === 0) {
192
+ return { Name: 'install', Severity: 'pass', Detail: `${LOCKFILE_NAME} and ${NODE_MODULES_NAME} present` };
193
+ }
194
+ return {
195
+ Name: 'install',
196
+ Severity: 'warn',
197
+ Detail: `missing ${missing.join(' and ')} — run \`pnpm install\` at ${status.ParentDir}`,
198
+ };
199
+ }
200
+ /** The sentinel is what proves this workspace came from the generator, and what `clean` requires. */
201
+ function checkSentinel(status) {
202
+ const sentinel = status.Sentinel;
203
+ if (sentinel.Kind === 'valid') {
204
+ const members = sentinel.Sentinel.members.join(', ') || '(none recorded)';
205
+ return { Name: 'sentinel', Severity: 'pass', Detail: `${SENTINEL_FILE_NAME} written by ${SENTINEL_MARKER} (members: ${members})` };
206
+ }
207
+ if (sentinel.Kind === 'invalid') {
208
+ return {
209
+ Name: 'sentinel',
210
+ Severity: 'warn',
211
+ Detail: `${SENTINEL_FILE_NAME} is present but not ours (${sentinel.Reason}) — clean needs --force`,
212
+ };
213
+ }
214
+ return {
215
+ Name: 'sentinel',
216
+ Severity: 'warn',
217
+ Detail: `no ${SENTINEL_FILE_NAME} — hand-made or pre-sentinel workspace; clean needs --force`,
218
+ };
219
+ }
220
+ /** The generated pin and the pnpm actually running at the parent must be the same version. */
221
+ function checkPnpmVersion(status) {
222
+ const pinned = status.PinnedPnpm === null ? null : status.PinnedPnpm.slice('pnpm@'.length);
223
+ if (pinned === null) {
224
+ return { Name: 'pnpm version', Severity: 'skip', Detail: 'no pnpm pin at the parent (no generated package.json)' };
225
+ }
226
+ if (status.ActivePnpmVersion === null) {
227
+ return { Name: 'pnpm version', Severity: 'warn', Detail: `pinned ${pinned}, but pnpm is not runnable at the parent` };
228
+ }
229
+ if (status.ActivePnpmVersion === pinned) {
230
+ return { Name: 'pnpm version', Severity: 'pass', Detail: `pinned ${pinned}, active ${status.ActivePnpmVersion} — match` };
231
+ }
232
+ return {
233
+ Name: 'pnpm version',
234
+ Severity: 'warn',
235
+ Detail: `pinned ${pinned}, active ${status.ActivePnpmVersion} — MISMATCH; run \`corepack enable\` so the pin is honored`,
236
+ };
237
+ }
238
+ /**
239
+ * Every member named in pnpm-workspace.yaml must exist on disk. This is a FAIL, not
240
+ * a warning: the generated parent manifest carries a `workspace:*` override for each
241
+ * member-provided package name, so a member whose checkout is gone makes the next
242
+ * `pnpm install` fail outright rather than degrade.
243
+ */
244
+ function checkMemberDirs(status) {
245
+ if (status.Members.length === 0) {
246
+ return { Name: 'member dirs', Severity: 'skip', Detail: 'no pnpm-workspace.yaml — no members to check' };
247
+ }
248
+ if (status.MissingMemberDirs.length === 0) {
249
+ return { Name: 'member dirs', Severity: 'pass', Detail: `all ${status.Members.length} member directories present` };
250
+ }
251
+ return {
252
+ Name: 'member dirs',
253
+ Severity: 'fail',
254
+ Detail: `in pnpm-workspace.yaml but missing on disk: ${status.MissingMemberDirs.join(', ')} — the parent manifest ` +
255
+ `overrides each member-provided package to workspace:*, so pnpm install will fail; re-clone them or ` +
256
+ `re-run \`mj dev workspace --force\` to regenerate without them`,
257
+ };
258
+ }
259
+ /** Repos on disk that qualify as members but are not in the workspace resolve against their own installs. */
260
+ function checkCandidates(status) {
261
+ if (status.DetectedCandidates.length === 0) {
262
+ return { Name: 'candidates', Severity: 'skip', Detail: 'no member-candidate repos detected at the parent' };
263
+ }
264
+ if (status.CandidatesNotInWorkspace.length === 0) {
265
+ return {
266
+ Name: 'candidates',
267
+ Severity: 'pass',
268
+ Detail: `all ${status.DetectedCandidates.length} detected repos are workspace members`,
269
+ };
270
+ }
271
+ return {
272
+ Name: 'candidates',
273
+ Severity: 'warn',
274
+ Detail: `detected on disk but not in the workspace: ${status.CandidatesNotInWorkspace.join(', ')} — they resolve ` +
275
+ `against their own installs, not this workspace; re-run \`mj dev workspace --force\` to include them`,
276
+ };
277
+ }
278
+ /**
279
+ * A member carrying its OWN package store has forked resolution away from the
280
+ * workspace. Note what does NOT count: a plain `node_modules` inside a member is
281
+ * what a healthy parent install creates (symlinks into the parent store) — only a
282
+ * member-root `.pnpm` store or npm's `.package-lock.json` marker proves a
283
+ * standalone install, which is the distinction `status.ts` already encodes.
284
+ *
285
+ * Scope, stated in the PASS text rather than implied: this reads the member ROOT
286
+ * only. A repo whose root tree was deleted but whose nested per-package trees
287
+ * survive (the half-finished cleanup #3795 describes) passes here — enumerating
288
+ * those is `--clean-members`' depth-independent walk, not a health check's job.
289
+ */
290
+ function checkStandaloneInstalls(status) {
291
+ if (status.MembersWithStandaloneInstalls.length === 0) {
292
+ return {
293
+ Name: 'standalone installs',
294
+ Severity: 'pass',
295
+ Detail: 'no member root carries its own package store (a member node_modules from the parent install is normal; ' +
296
+ 'nested per-package trees are not scanned — `dev workspace --clean-members` removes those)',
297
+ };
298
+ }
299
+ return {
300
+ Name: 'standalone installs',
301
+ Severity: 'fail',
302
+ Detail: `${status.MembersWithStandaloneInstalls.join(', ')} — each has its own package store, so its code resolves ` +
303
+ `against that store instead of this workspace (split singletons, stale deps). ` +
304
+ `Fix: re-run \`mj dev workspace --clean-members\`.`,
305
+ };
306
+ }
307
+ /** Appends the unparsed-entry tally to a census detail, so dropped store entries are never silent. */
308
+ function withUnparsedNote(detail, census) {
309
+ const count = census.UnparsedEntryCount;
310
+ if (count === 0)
311
+ return detail;
312
+ const noun = count === 1 ? 'entry is' : 'entries are';
313
+ return `${detail} (${count} store ${noun} not name@version — links and the store's own node_modules)`;
314
+ }
315
+ /** Exactly one version of each singleton package may exist in the parent's store. */
316
+ function checkOneCopyCensus(census) {
317
+ const name = 'one-copy census';
318
+ if (!census.StorePresent) {
319
+ return { Name: name, Severity: 'skip', Detail: `no ${STORE_REL_PATH} at the parent — no pnpm package store to census` };
320
+ }
321
+ if (census.Packages.length === 0) {
322
+ return { Name: name, Severity: 'skip', Detail: withUnparsedNote('none of the single-copy packages are installed here', census) };
323
+ }
324
+ const duplicated = census.Packages.filter((entry) => entry.Versions.length > 1);
325
+ if (duplicated.length === 0) {
326
+ const listed = census.Packages.map((entry) => `${entry.Package}@${entry.Versions[0]}`).join(', ');
327
+ return { Name: name, Severity: 'pass', Detail: withUnparsedNote(`one copy each in the parent store: ${listed}`, census) };
328
+ }
329
+ const broken = duplicated.map((entry) => `${entry.Package} (${entry.Versions.join(', ')})`).join('; ');
330
+ return {
331
+ Name: name,
332
+ Severity: 'fail',
333
+ Detail: `more than one version in the parent store: ${broken} — these must be single-copy (Angular DI and MJ's ` +
334
+ `Global Object Store key off module identity, so a second copy is a second, invisible runtime). ` +
335
+ `Fix: re-run \`mj dev workspace --force\` to re-derive the pins, then \`pnpm install\` at the parent.`,
336
+ };
337
+ }
338
+ /**
339
+ * Runs every health check at a parent directory. `activePnpmVersion` comes from the
340
+ * caller (a spawn — see `pnpm.ts`) and `dirSource` likewise, so this module reads
341
+ * neither processes nor the environment. Read-only.
342
+ */
343
+ export function CollectDoctorReport(parentDir, activePnpmVersion, dirSource) {
344
+ if (!path.isAbsolute(parentDir)) {
345
+ throw new Error(`CollectDoctorReport requires an absolute path, got: ${parentDir}`);
346
+ }
347
+ const status = CollectWorkspaceStatus(parentDir, activePnpmVersion, dirSource);
348
+ const census = CollectSingletonCensus(parentDir);
349
+ return {
350
+ ParentDir: parentDir,
351
+ DirSource: dirSource,
352
+ Census: census,
353
+ Checks: [
354
+ checkParentShape(status),
355
+ checkGeneratedFiles(status),
356
+ checkInstallArtifacts(status),
357
+ checkSentinel(status),
358
+ checkPnpmVersion(status),
359
+ checkMemberDirs(status),
360
+ checkCandidates(status),
361
+ checkStandaloneInstalls(status),
362
+ checkOneCopyCensus(census),
363
+ ],
364
+ };
365
+ }
366
+ /** Severity tag printed at the head of each line. */
367
+ const SEVERITY_TAGS = {
368
+ pass: chalk.green('[PASS]'),
369
+ warn: chalk.yellow('[WARN]'),
370
+ fail: chalk.red('[FAIL]'),
371
+ skip: chalk.dim('[SKIP]'),
372
+ };
373
+ /** True when any check failed — the command's exit-code decision. Pure. */
374
+ export function DoctorHasFailures(report) {
375
+ return report.Checks.some((check) => check.Severity === 'fail');
376
+ }
377
+ /** Counts each severity and states the exit-code consequence plainly. Pure. */
378
+ function renderSummary(report) {
379
+ const countOf = (severity) => report.Checks.filter((check) => check.Severity === severity).length;
380
+ const failed = countOf('fail');
381
+ const summary = `${countOf('pass')} passed, ${countOf('warn')} warned, ${failed} failed, ${countOf('skip')} skipped`;
382
+ if (failed === 0)
383
+ return chalk.green(`${summary} — no failures.`);
384
+ return chalk.red(`${summary} — doctor exits non-zero.`);
385
+ }
386
+ /** Renders a DoctorReport as the terminal report. Pure. */
387
+ export function RenderDoctor(report) {
388
+ const lines = [
389
+ chalk.bold(`Workspace doctor: ${report.ParentDir}`),
390
+ chalk.dim(` resolved from: ${DescribeDirSource(report.DirSource)}`),
391
+ '',
392
+ ];
393
+ for (const check of report.Checks) {
394
+ lines.push(`${SEVERITY_TAGS[check.Severity]} ${check.Name}: ${check.Detail}`);
395
+ }
396
+ lines.push('');
397
+ lines.push(renderSummary(report));
398
+ return lines.join('\n');
399
+ }
400
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/lib/dev-workspace/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { DevDepConflict, MemberLockfile, UnsupportedLockfile } from './types.js';
2
+ /** True when the string is a plain concrete semver version. */
3
+ export declare function IsResolvedVersion(version: string): boolean;
4
+ /** Major-version number of a concrete resolution. Throws on non-semver input (precondition). */
5
+ export declare function MajorOf(version: string): number;
6
+ /**
7
+ * Compares two CONCRETE versions: numeric triple first; on a triple tie a
8
+ * release beats a prerelease, and two prereleases compare by tag string.
9
+ * Throws on non-semver input — callers filter through {@link IsResolvedVersion} first.
10
+ */
11
+ export declare function CompareResolvedVersions(a: string, b: string): number;
12
+ /** Parses a committed pnpm-lock.yaml. Only v9+ is readable; older formats return an unsupported marker. */
13
+ export declare function ParsePnpmLockfile(lockText: string): MemberLockfile | UnsupportedLockfile;
14
+ /** Parses a committed npm package-lock.json. Only lockfileVersion 2/3 is readable. */
15
+ export declare function ParseNpmLockfile(lockText: string): MemberLockfile | UnsupportedLockfile;
16
+ /**
17
+ * Reads a member's committed lockfile: `pnpm-lock.yaml` first, `package-lock.json`
18
+ * otherwise, null when the repo commits neither. An unsupported format comes back
19
+ * as a marker (the command warns); unparseable content throws — a corrupt
20
+ * lockfile must never silently become "no pins for this member".
21
+ */
22
+ export declare function ReadMemberLockfile(repoPath: string): MemberLockfile | UnsupportedLockfile | null;
23
+ /** The pure result of the cross-member pin derivation. */
24
+ export interface LockfilePinsResult {
25
+ /**
26
+ * Override entries, sorted by key. Values are EXACT versions. Keys are plain
27
+ * names for single-major names, per-major selectors (`name@^N`) otherwise.
28
+ */
29
+ Pins: Record<string, string>;
30
+ /** Same-major disagreements the highest committed exact resolution won (key names the emitted selector). */
31
+ Conflicts: DevDepConflict[];
32
+ /** Names excluded because a workspace member provides them (workspace:* covers those). */
33
+ ExcludedFamilyNames: string[];
34
+ }
35
+ /** One member's candidate resolutions, tagged with the repo for conflict reporting. */
36
+ export interface MemberLockfileCandidates {
37
+ Repo: string;
38
+ Lockfile: MemberLockfile;
39
+ }
40
+ /**
41
+ * Derives the parent `pnpm.overrides` pins from the members' committed lockfiles.
42
+ * Pure.
43
+ *
44
+ * AUTHORITY RULE (adversarial-review round 3): a version may vote only where a
45
+ * member DIRECTLY declares the name (its importers resolve it), plus `@types/*`
46
+ * at any depth minus those parented solely by registry copies of family
47
+ * packages. At-depth resolutions of ordinary packages are NOT candidates — a
48
+ * bizapps lockfile resolved with registry `@memberjunction/*` describes a graph
49
+ * that cannot exist in the generated workspace, and letting it vote handed the
50
+ * field's floated versions (`@cerebras` 1.91.0, `@foblex` 18.6.1) a win over
51
+ * MJ's committed 1.64.1/18.0.0.
52
+ *
53
+ * KEY SCOPING: at-depth majors still decide the KEY SHAPE — when any member's
54
+ * graph holds another major of a pinned name anywhere, the pin is emitted as a
55
+ * `name@^N` selector so transitive consumers of the other majors float within
56
+ * their declared ranges (never forced cross-major); only majors present among
57
+ * the candidates get a selector at all. Values are EXACT — `^resolved` provably
58
+ * passed 6 of 7 field-measured breaks through. Disagreements within a major
59
+ * among direct declarations are genuine: highest committed exact wins, reported.
60
+ */
61
+ export declare function DeriveLockfilePins(members: readonly MemberLockfileCandidates[], familyNames: ReadonlySet<string>): LockfilePinsResult;
62
+ //# sourceMappingURL=lockfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lockfile.d.ts","sourceRoot":"","sources":["../../../src/lib/dev-workspace/lockfile.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,cAAc,EAAgB,cAAc,EAAqB,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAWvH,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,gGAAgG;AAChG,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAepE;AAwID,2GAA2G;AAC3G,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,mBAAmB,CAkBxF;AA4DD,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,mBAAmB,CA4BvF;AAyBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,mBAAmB,GAAG,IAAI,CAahG;AAED,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,4GAA4G;IAC5G,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,0FAA0F;IAC1F,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,uFAAuF;AACvF,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;CAC1B;AA2BD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,wBAAwB,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,kBAAkB,CA8BrI"}