@mmnto/totem 2.12.2 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-resolve.d.ts +116 -0
- package/dist/cli-resolve.d.ts.map +1 -0
- package/dist/cli-resolve.js +248 -0
- package/dist/cli-resolve.js.map +1 -0
- package/dist/cli-resolve.test.d.ts +2 -0
- package/dist/cli-resolve.test.d.ts.map +1 -0
- package/dist/cli-resolve.test.js +328 -0
- package/dist/cli-resolve.test.js.map +1 -0
- package/dist/config-schema.d.ts +34 -0
- package/dist/config-schema.d.ts.map +1 -1
- package/dist/config-schema.js +20 -0
- package/dist/config-schema.js.map +1 -1
- package/dist/config-schema.test.js +55 -0
- package/dist/config-schema.test.js.map +1 -1
- package/dist/errors.d.ts +37 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +42 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/ingest/pipeline.js +3 -1
- package/dist/ingest/pipeline.js.map +1 -1
- package/dist/ingest/pipeline.test.js +23 -0
- package/dist/ingest/pipeline.test.js.map +1 -1
- package/dist/ledger.d.ts +4 -4
- package/dist/spine/authored-rule.test.js +16 -0
- package/dist/spine/authored-rule.test.js.map +1 -1
- package/dist/store/lance-store.d.ts +43 -7
- package/dist/store/lance-store.d.ts.map +1 -1
- package/dist/store/lance-store.js +70 -13
- package/dist/store/lance-store.js.map +1 -1
- package/dist/store/lance-store.test.js +92 -2
- package/dist/store/lance-store.test.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve Totem's own CLI entry explicitly (mmnto-ai/totem#3008).
|
|
3
|
+
*
|
|
4
|
+
* One resolver for every caller that must run "the Totem CLI": the CLI's
|
|
5
|
+
* prefer-local re-exec (`resolveLocalEntry`) and the MCP server's spawning
|
|
6
|
+
* tools (`resolveTotemCli`). Tiers, first hit wins:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Workspace build** — `packages/cli/dist/index.js`, identity-guarded on
|
|
9
|
+
* `packages/cli/package.json` naming `@mmnto/cli`, walking up.
|
|
10
|
+
* 2. **Pinned install** — `node_modules/@mmnto/cli/dist/index.js`, walking up.
|
|
11
|
+
* 3. **npm-layout global on PATH** — the two npm global layouts only.
|
|
12
|
+
*
|
|
13
|
+
* Otherwise a refusal that names what was looked for.
|
|
14
|
+
*
|
|
15
|
+
* **Identity is the install path.** An install that sits at
|
|
16
|
+
* `node_modules/@mmnto/cli` is ours by the package manager's own namespace,
|
|
17
|
+
* whatever its manifest is called, so a fork installed under that alias runs
|
|
18
|
+
* here as it does in the CLI's re-exec and the git hooks, and the result
|
|
19
|
+
* carries its real name (`aliasOf`). Where there is no such path, the
|
|
20
|
+
* manifest's name decides: the workspace build (`packages/cli`), and a global
|
|
21
|
+
* whose `totem` link resolves outside `node_modules` (a linked development
|
|
22
|
+
* install). A bare `totem` name is never the identity.
|
|
23
|
+
*
|
|
24
|
+
* These tiers differ on purpose from the git hooks' cascade
|
|
25
|
+
* (`buildResolveBlock` in the CLI's install-hooks): a spawn inside a tool call
|
|
26
|
+
* runs unattended, with nobody at a terminal to see what was fetched or run,
|
|
27
|
+
* so it stops at a local entry or an npm-layout global and never falls back to
|
|
28
|
+
* a package manager or the network.
|
|
29
|
+
*
|
|
30
|
+
* Light by contract: imports only `node:fs` and `node:path`, so it is also
|
|
31
|
+
* exported as the `@mmnto/totem/cli-resolve` subpath for callers that must
|
|
32
|
+
* not load the core barrel.
|
|
33
|
+
*/
|
|
34
|
+
/** Every filesystem read the resolver makes — a seam for tests. */
|
|
35
|
+
export interface CliResolveFs {
|
|
36
|
+
exists(p: string): boolean;
|
|
37
|
+
/** True for a regular file (a link to one counts); may throw on an unreadable path. */
|
|
38
|
+
isFile(p: string): boolean;
|
|
39
|
+
readText(p: string): string;
|
|
40
|
+
realpath(p: string): string;
|
|
41
|
+
}
|
|
42
|
+
export declare const NODE_CLI_RESOLVE_FS: CliResolveFs;
|
|
43
|
+
export interface LocalEntry {
|
|
44
|
+
/** Absolute path to the local `dist/index.js`. */
|
|
45
|
+
entry: string;
|
|
46
|
+
/** The local install's version, when its package.json is readable. */
|
|
47
|
+
version?: string;
|
|
48
|
+
/** Which tier matched: the workspace build or the pinned dependency. */
|
|
49
|
+
tier: 'workspace' | 'pinned';
|
|
50
|
+
}
|
|
51
|
+
export interface GlobalEntry {
|
|
52
|
+
/** Absolute path to the global install's `dist/index.js`. */
|
|
53
|
+
entry: string;
|
|
54
|
+
/** The global install's version, when its package.json is readable. */
|
|
55
|
+
version?: string;
|
|
56
|
+
tier: 'global';
|
|
57
|
+
/** The manifest's own name when it is not `@mmnto/cli`: a fork installed under the alias. */
|
|
58
|
+
aliasOf?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface GlobalProbe {
|
|
61
|
+
hit?: GlobalEntry;
|
|
62
|
+
/** Paths of a `totem` file found on PATH that could not be verified as an install of @mmnto/cli (by its path or its manifest's name). */
|
|
63
|
+
unverified: string[];
|
|
64
|
+
}
|
|
65
|
+
export type CliResolution = {
|
|
66
|
+
ok: true;
|
|
67
|
+
entry: string;
|
|
68
|
+
version?: string;
|
|
69
|
+
tier: 'workspace' | 'pinned' | 'global';
|
|
70
|
+
/**
|
|
71
|
+
* Present on a pinned or global hit whose manifest names another package:
|
|
72
|
+
* a fork installed under the `@mmnto/cli` alias. It runs, because the
|
|
73
|
+
* install path is the identity, and the caller can name what it really is.
|
|
74
|
+
*/
|
|
75
|
+
aliasOf?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Present on a global hit only, and only when a `totem` earlier on PATH
|
|
78
|
+
* was skipped because it could not be verified: the CLI that runs is then
|
|
79
|
+
* not the one the user's shell would run, and the caller can say so.
|
|
80
|
+
*/
|
|
81
|
+
unverified?: string[];
|
|
82
|
+
} | {
|
|
83
|
+
ok: false;
|
|
84
|
+
looked: string[];
|
|
85
|
+
unverified: string[];
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the project-local CLI entry by walking up from `cwd`:
|
|
89
|
+
*
|
|
90
|
+
* 1. **Workspace-HEAD** — `packages/cli/dist/index.js`, identity-guarded on
|
|
91
|
+
* `packages/cli/package.json` declaring `@mmnto/cli` (the dogfood monorepo;
|
|
92
|
+
* the build you just made wins over any installed copy).
|
|
93
|
+
* 2. **Pinned dependency** — `node_modules/@mmnto/cli/dist/index.js`, the
|
|
94
|
+
* project's version-locked install via the package's own entry point.
|
|
95
|
+
*
|
|
96
|
+
* Both tiers require the BUILT entry to exist. A read failure mid-walk throws;
|
|
97
|
+
* the caller decides the posture.
|
|
98
|
+
*/
|
|
99
|
+
export declare function resolveLocalEntry(cwd: string, fsx?: CliResolveFs): LocalEntry | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Find an npm-layout global install of `@mmnto/cli` on PATH, first hit wins.
|
|
102
|
+
* A `totem` FILE (a directory of that name is not one) found in a directory
|
|
103
|
+
* that yields no hit is reported in `unverified` and never run. Never throws.
|
|
104
|
+
*/
|
|
105
|
+
export declare function resolveGlobalEntry(pathEnv: string | undefined, fsx?: CliResolveFs): GlobalProbe;
|
|
106
|
+
/**
|
|
107
|
+
* Resolve the Totem CLI for an unattended spawn: the workspace build, then the
|
|
108
|
+
* pinned install (both walking up from `startDir`), then an npm-layout global
|
|
109
|
+
* on PATH. Otherwise `{ ok: false }` with the places looked and any `totem`
|
|
110
|
+
* found on PATH that could not be verified.
|
|
111
|
+
*/
|
|
112
|
+
export declare function resolveTotemCli(startDir: string, opts?: {
|
|
113
|
+
pathEnv?: string;
|
|
114
|
+
fs?: CliResolveFs;
|
|
115
|
+
}): CliResolution;
|
|
116
|
+
//# sourceMappingURL=cli-resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-resolve.d.ts","sourceRoot":"","sources":["../src/cli-resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAiCH,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,uFAAuF;IACvF,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,mBAAmB,EAAE,YAKjC,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,IAAI,EAAE,WAAW,GAAG,QAAQ,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,yIAAyI;IACzI,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,MAAM,aAAa,GACrB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACxC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAa1D;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,YAAkC,GACtC,UAAU,GAAG,SAAS,CAuBxB;AAsFD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,GAAE,YAAkC,GACtC,WAAW,CAUb;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,YAAY,CAAA;CAAE,GAC7C,aAAa,CA6Bf"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve Totem's own CLI entry explicitly (mmnto-ai/totem#3008).
|
|
3
|
+
*
|
|
4
|
+
* One resolver for every caller that must run "the Totem CLI": the CLI's
|
|
5
|
+
* prefer-local re-exec (`resolveLocalEntry`) and the MCP server's spawning
|
|
6
|
+
* tools (`resolveTotemCli`). Tiers, first hit wins:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Workspace build** — `packages/cli/dist/index.js`, identity-guarded on
|
|
9
|
+
* `packages/cli/package.json` naming `@mmnto/cli`, walking up.
|
|
10
|
+
* 2. **Pinned install** — `node_modules/@mmnto/cli/dist/index.js`, walking up.
|
|
11
|
+
* 3. **npm-layout global on PATH** — the two npm global layouts only.
|
|
12
|
+
*
|
|
13
|
+
* Otherwise a refusal that names what was looked for.
|
|
14
|
+
*
|
|
15
|
+
* **Identity is the install path.** An install that sits at
|
|
16
|
+
* `node_modules/@mmnto/cli` is ours by the package manager's own namespace,
|
|
17
|
+
* whatever its manifest is called, so a fork installed under that alias runs
|
|
18
|
+
* here as it does in the CLI's re-exec and the git hooks, and the result
|
|
19
|
+
* carries its real name (`aliasOf`). Where there is no such path, the
|
|
20
|
+
* manifest's name decides: the workspace build (`packages/cli`), and a global
|
|
21
|
+
* whose `totem` link resolves outside `node_modules` (a linked development
|
|
22
|
+
* install). A bare `totem` name is never the identity.
|
|
23
|
+
*
|
|
24
|
+
* These tiers differ on purpose from the git hooks' cascade
|
|
25
|
+
* (`buildResolveBlock` in the CLI's install-hooks): a spawn inside a tool call
|
|
26
|
+
* runs unattended, with nobody at a terminal to see what was fetched or run,
|
|
27
|
+
* so it stops at a local entry or an npm-layout global and never falls back to
|
|
28
|
+
* a package manager or the network.
|
|
29
|
+
*
|
|
30
|
+
* Light by contract: imports only `node:fs` and `node:path`, so it is also
|
|
31
|
+
* exported as the `@mmnto/totem/cli-resolve` subpath for callers that must
|
|
32
|
+
* not load the core barrel.
|
|
33
|
+
*/
|
|
34
|
+
import * as fs from 'node:fs';
|
|
35
|
+
import * as path from 'node:path';
|
|
36
|
+
const VERSION_RE = /"version"\s*:\s*"([^"]+)"/;
|
|
37
|
+
const NAME_IS_CLI_RE = /"name"\s*:\s*"@mmnto\/cli"/;
|
|
38
|
+
const PACKAGES_DIR = 'packages';
|
|
39
|
+
const DIST_DIR = 'dist';
|
|
40
|
+
const NODE_MODULES_DIR = 'node_modules';
|
|
41
|
+
const ENTRY_FILE = 'index.js';
|
|
42
|
+
const PACKAGE_JSON = 'package.json';
|
|
43
|
+
const CLI_PACKAGE = 'cli';
|
|
44
|
+
const SCOPE_DIR = '@mmnto';
|
|
45
|
+
const CLI_NAME = '@mmnto/cli';
|
|
46
|
+
const BIN_NAME = 'totem';
|
|
47
|
+
/** The path tail that identifies an install of the CLI under a `node_modules` directory. */
|
|
48
|
+
const ENTRY_TAIL = [
|
|
49
|
+
NODE_MODULES_DIR,
|
|
50
|
+
SCOPE_DIR,
|
|
51
|
+
CLI_PACKAGE,
|
|
52
|
+
DIST_DIR,
|
|
53
|
+
ENTRY_FILE,
|
|
54
|
+
];
|
|
55
|
+
/** Executable names a non-npm-layout `totem` may carry on PATH (reported, never run). */
|
|
56
|
+
const BIN_VARIANTS = [
|
|
57
|
+
BIN_NAME,
|
|
58
|
+
`${BIN_NAME}.cmd`,
|
|
59
|
+
`${BIN_NAME}.exe`,
|
|
60
|
+
`${BIN_NAME}.ps1`,
|
|
61
|
+
];
|
|
62
|
+
export const NODE_CLI_RESOLVE_FS = {
|
|
63
|
+
exists: (p) => fs.existsSync(p),
|
|
64
|
+
isFile: (p) => fs.statSync(p).isFile(),
|
|
65
|
+
readText: (p) => fs.readFileSync(p, 'utf-8'),
|
|
66
|
+
realpath: (p) => fs.realpathSync(p),
|
|
67
|
+
};
|
|
68
|
+
/** Probe-grade version read — no JSON.parse, no fail-open catch. */
|
|
69
|
+
function readVersion(pkgJsonPath, fsx) {
|
|
70
|
+
if (!fsx.exists(pkgJsonPath))
|
|
71
|
+
return undefined;
|
|
72
|
+
return VERSION_RE.exec(fsx.readText(pkgJsonPath))?.[1];
|
|
73
|
+
}
|
|
74
|
+
/** True when `pkgJsonPath` exists and names `@mmnto/cli`. */
|
|
75
|
+
function namesCli(pkgJsonPath, fsx) {
|
|
76
|
+
return fsx.exists(pkgJsonPath) && NAME_IS_CLI_RE.test(fsx.readText(pkgJsonPath));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Resolve the project-local CLI entry by walking up from `cwd`:
|
|
80
|
+
*
|
|
81
|
+
* 1. **Workspace-HEAD** — `packages/cli/dist/index.js`, identity-guarded on
|
|
82
|
+
* `packages/cli/package.json` declaring `@mmnto/cli` (the dogfood monorepo;
|
|
83
|
+
* the build you just made wins over any installed copy).
|
|
84
|
+
* 2. **Pinned dependency** — `node_modules/@mmnto/cli/dist/index.js`, the
|
|
85
|
+
* project's version-locked install via the package's own entry point.
|
|
86
|
+
*
|
|
87
|
+
* Both tiers require the BUILT entry to exist. A read failure mid-walk throws;
|
|
88
|
+
* the caller decides the posture.
|
|
89
|
+
*/
|
|
90
|
+
export function resolveLocalEntry(cwd, fsx = NODE_CLI_RESOLVE_FS) {
|
|
91
|
+
let dir = path.resolve(cwd);
|
|
92
|
+
for (;;) {
|
|
93
|
+
const workspacePkg = path.join(dir, PACKAGES_DIR, CLI_PACKAGE, PACKAGE_JSON);
|
|
94
|
+
const workspaceEntry = path.join(dir, PACKAGES_DIR, CLI_PACKAGE, DIST_DIR, ENTRY_FILE);
|
|
95
|
+
if (fsx.exists(workspaceEntry) && namesCli(workspacePkg, fsx)) {
|
|
96
|
+
return { entry: workspaceEntry, version: readVersion(workspacePkg, fsx), tier: 'workspace' };
|
|
97
|
+
}
|
|
98
|
+
const pinnedDir = path.join(dir, NODE_MODULES_DIR, SCOPE_DIR, CLI_PACKAGE);
|
|
99
|
+
const pinnedEntry = path.join(pinnedDir, DIST_DIR, ENTRY_FILE);
|
|
100
|
+
if (fsx.exists(pinnedEntry)) {
|
|
101
|
+
return {
|
|
102
|
+
entry: pinnedEntry,
|
|
103
|
+
version: readVersion(path.join(pinnedDir, PACKAGE_JSON), fsx),
|
|
104
|
+
tier: 'pinned',
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const parent = path.dirname(dir);
|
|
108
|
+
if (parent === dir)
|
|
109
|
+
return undefined;
|
|
110
|
+
dir = parent;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Run one filesystem probe of the PATH scan; undefined when it throws. The
|
|
115
|
+
* global tier never throws: a PATH directory with a dangling link, an
|
|
116
|
+
* unreadable `package.json` or an unreadable entry is "not a hit" there, and
|
|
117
|
+
* the scan moves on to the next directory. The local walk does not use this:
|
|
118
|
+
* a read failure mid-walk throws, as it always has.
|
|
119
|
+
*/
|
|
120
|
+
function attempt(probe) {
|
|
121
|
+
// totem-context: intentional probe — the catch below does not rethrow by
|
|
122
|
+
// design (mmnto-ai/totem#3008): one unreadable PATH directory must not stop
|
|
123
|
+
// the scan before a valid install later on PATH is tried.
|
|
124
|
+
try {
|
|
125
|
+
return probe();
|
|
126
|
+
// totem-context: intentional degradation — see directive above the try; placed on the line before the catch keyword, where the rule reads it.
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** The manifest's TOP-LEVEL `name`; undefined when it is absent, unreadable or not JSON. Never throws. */
|
|
133
|
+
function manifestName(pkgJsonPath, fsx) {
|
|
134
|
+
if (!fsx.exists(pkgJsonPath))
|
|
135
|
+
return undefined;
|
|
136
|
+
const parsed = attempt(() => JSON.parse(fsx.readText(pkgJsonPath)));
|
|
137
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
138
|
+
return undefined;
|
|
139
|
+
const name = parsed.name;
|
|
140
|
+
return typeof name === 'string' ? name : undefined;
|
|
141
|
+
}
|
|
142
|
+
/** The manifest's own name when it is readable and is not `@mmnto/cli` (a fork under the alias). */
|
|
143
|
+
function aliasOf(pkgJsonPath, fsx) {
|
|
144
|
+
const name = manifestName(pkgJsonPath, fsx);
|
|
145
|
+
return name !== undefined && name !== CLI_NAME ? name : undefined;
|
|
146
|
+
}
|
|
147
|
+
/** True when `entry` sits at `…/node_modules/@mmnto/cli/dist/index.js`: the install path is the identity. */
|
|
148
|
+
function sitsAtCliPath(entry) {
|
|
149
|
+
const tail = entry.split(/[\\/]/).slice(-ENTRY_TAIL.length);
|
|
150
|
+
return tail.length === ENTRY_TAIL.length && tail.every((part, i) => part === ENTRY_TAIL[i]);
|
|
151
|
+
}
|
|
152
|
+
/** True when a `totem` FILE (any of the shim names) sits in `dir`. Never throws. */
|
|
153
|
+
function findShim(dir, fsx) {
|
|
154
|
+
for (const name of BIN_VARIANTS) {
|
|
155
|
+
const candidate = path.join(dir, name);
|
|
156
|
+
if (fsx.exists(candidate) && attempt(() => fsx.isFile(candidate)) === true)
|
|
157
|
+
return candidate;
|
|
158
|
+
}
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
function globalEntry(entry, pkgJsonPath, fsx) {
|
|
162
|
+
const alias = aliasOf(pkgJsonPath, fsx);
|
|
163
|
+
return {
|
|
164
|
+
entry,
|
|
165
|
+
version: attempt(() => readVersion(pkgJsonPath, fsx)),
|
|
166
|
+
tier: 'global',
|
|
167
|
+
...(alias !== undefined ? { aliasOf: alias } : {}),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/** A global hit in one PATH directory, by the two npm layouts, or undefined. Never throws. */
|
|
171
|
+
function probeGlobalDir(dir, fsx) {
|
|
172
|
+
// (a) The win32 npm layout: the `totem` shim sits beside `node_modules`, and
|
|
173
|
+
// the install is `<prefix>/node_modules/@mmnto/cli`. Identity is that path,
|
|
174
|
+
// so a fork installed under the alias is a hit. A directory that holds the
|
|
175
|
+
// package but no shim is not a global install: nothing a shell would run.
|
|
176
|
+
const packagedDir = path.join(dir, NODE_MODULES_DIR, SCOPE_DIR, CLI_PACKAGE);
|
|
177
|
+
const packagedEntry = path.join(packagedDir, DIST_DIR, ENTRY_FILE);
|
|
178
|
+
if (fsx.exists(packagedEntry) && findShim(dir, fsx) !== undefined) {
|
|
179
|
+
return globalEntry(packagedEntry, path.join(packagedDir, PACKAGE_JSON), fsx);
|
|
180
|
+
}
|
|
181
|
+
// (b) The POSIX npm layout: `<bin>/totem` is a symlink to `<pkg>/dist/index.js`.
|
|
182
|
+
// Ours when the resolved entry sits at `node_modules/@mmnto/cli` (the path),
|
|
183
|
+
// or, where the link resolves elsewhere (a linked development install), when
|
|
184
|
+
// the manifest's top-level name is `@mmnto/cli`.
|
|
185
|
+
const shim = path.join(dir, BIN_NAME);
|
|
186
|
+
if (!fsx.exists(shim))
|
|
187
|
+
return undefined;
|
|
188
|
+
const real = attempt(() => fsx.realpath(shim));
|
|
189
|
+
if (real === undefined || !real.endsWith('.js') || !fsx.exists(real))
|
|
190
|
+
return undefined;
|
|
191
|
+
const realPkg = path.join(path.dirname(path.dirname(real)), PACKAGE_JSON);
|
|
192
|
+
if (!sitsAtCliPath(real) && manifestName(realPkg, fsx) !== CLI_NAME)
|
|
193
|
+
return undefined;
|
|
194
|
+
return globalEntry(real, realPkg, fsx);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Find an npm-layout global install of `@mmnto/cli` on PATH, first hit wins.
|
|
198
|
+
* A `totem` FILE (a directory of that name is not one) found in a directory
|
|
199
|
+
* that yields no hit is reported in `unverified` and never run. Never throws.
|
|
200
|
+
*/
|
|
201
|
+
export function resolveGlobalEntry(pathEnv, fsx = NODE_CLI_RESOLVE_FS) {
|
|
202
|
+
const unverified = [];
|
|
203
|
+
for (const dir of (pathEnv ?? '').split(path.delimiter)) {
|
|
204
|
+
if (!dir)
|
|
205
|
+
continue;
|
|
206
|
+
const hit = probeGlobalDir(dir, fsx);
|
|
207
|
+
if (hit !== undefined)
|
|
208
|
+
return { hit, unverified };
|
|
209
|
+
const shim = findShim(dir, fsx);
|
|
210
|
+
if (shim !== undefined)
|
|
211
|
+
unverified.push(shim);
|
|
212
|
+
}
|
|
213
|
+
return { unverified };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Resolve the Totem CLI for an unattended spawn: the workspace build, then the
|
|
217
|
+
* pinned install (both walking up from `startDir`), then an npm-layout global
|
|
218
|
+
* on PATH. Otherwise `{ ok: false }` with the places looked and any `totem`
|
|
219
|
+
* found on PATH that could not be verified.
|
|
220
|
+
*/
|
|
221
|
+
export function resolveTotemCli(startDir, opts) {
|
|
222
|
+
const fsx = opts?.fs ?? NODE_CLI_RESOLVE_FS;
|
|
223
|
+
const local = resolveLocalEntry(startDir, fsx);
|
|
224
|
+
if (local !== undefined) {
|
|
225
|
+
// The pinned tier is identified by its path under `node_modules`, so a fork
|
|
226
|
+
// installed under the alias runs; its manifest's own name rides along.
|
|
227
|
+
const alias = local.tier === 'pinned'
|
|
228
|
+
? aliasOf(path.join(path.dirname(path.dirname(local.entry)), PACKAGE_JSON), fsx)
|
|
229
|
+
: undefined;
|
|
230
|
+
return alias !== undefined ? { ok: true, ...local, aliasOf: alias } : { ok: true, ...local };
|
|
231
|
+
}
|
|
232
|
+
const globalProbe = resolveGlobalEntry(opts?.pathEnv ?? process.env.PATH, fsx);
|
|
233
|
+
if (globalProbe.hit !== undefined) {
|
|
234
|
+
return globalProbe.unverified.length > 0
|
|
235
|
+
? { ok: true, ...globalProbe.hit, unverified: globalProbe.unverified }
|
|
236
|
+
: { ok: true, ...globalProbe.hit };
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
ok: false,
|
|
240
|
+
looked: [
|
|
241
|
+
`a workspace build at packages/cli/dist/index.js, walking up from ${startDir}`,
|
|
242
|
+
`a pinned install at node_modules/@mmnto/cli/dist/index.js, walking up from ${startDir}`,
|
|
243
|
+
'an npm-layout global install of @mmnto/cli on PATH',
|
|
244
|
+
],
|
|
245
|
+
unverified: globalProbe.unverified,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=cli-resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-resolve.js","sourceRoot":"","sources":["../src/cli-resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,UAAU,GAAG,2BAA2B,CAAC;AAC/C,MAAM,cAAc,GAAG,4BAA4B,CAAC;AAEpD,MAAM,YAAY,GAAG,UAAU,CAAC;AAChC,MAAM,QAAQ,GAAG,MAAM,CAAC;AACxB,MAAM,gBAAgB,GAAG,cAAc,CAAC;AACxC,MAAM,UAAU,GAAG,UAAU,CAAC;AAC9B,MAAM,YAAY,GAAG,cAAc,CAAC;AACpC,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,SAAS,GAAG,QAAQ,CAAC;AAC3B,MAAM,QAAQ,GAAG,YAAY,CAAC;AAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC;AACzB,4FAA4F;AAC5F,MAAM,UAAU,GAAsB;IACpC,gBAAgB;IAChB,SAAS;IACT,WAAW;IACX,QAAQ;IACR,UAAU;CACX,CAAC;AACF,yFAAyF;AACzF,MAAM,YAAY,GAAsB;IACtC,QAAQ;IACR,GAAG,QAAQ,MAAM;IACjB,GAAG,QAAQ,MAAM;IACjB,GAAG,QAAQ,MAAM;CAClB,CAAC;AAWF,MAAM,CAAC,MAAM,mBAAmB,GAAiB;IAC/C,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;IACtC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;CACpC,CAAC;AAgDF,oEAAoE;AACpE,SAAS,WAAW,CAAC,WAAmB,EAAE,GAAiB;IACzD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/C,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,6DAA6D;AAC7D,SAAS,QAAQ,CAAC,WAAmB,EAAE,GAAiB;IACtD,OAAO,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AACnF,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAW,EACX,MAAoB,mBAAmB;IAEvC,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,SAAS,CAAC;QACR,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;QAC7E,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QACvF,IAAI,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE,CAAC;YAC9D,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;QAC/F,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;QAC3E,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC/D,IAAI,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACL,KAAK,EAAE,WAAW;gBAClB,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,GAAG,CAAC;gBAC7D,IAAI,EAAE,QAAQ;aACf,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,SAAS,CAAC;QACrC,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,OAAO,CAAI,KAAc;IAChC,yEAAyE;IACzE,4EAA4E;IAC5E,0DAA0D;IAC1D,IAAI,CAAC;QACH,OAAO,KAAK,EAAE,CAAC;QACf,8IAA8I;IAChJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,0GAA0G;AAC1G,SAAS,YAAY,CAAC,WAAmB,EAAE,GAAiB;IAC1D,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAY,CAAC,CAAC;IAC/E,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACpE,MAAM,IAAI,GAAI,MAA6B,CAAC,IAAI,CAAC;IACjD,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACrD,CAAC;AAED,oGAAoG;AACpG,SAAS,OAAO,CAAC,WAAmB,EAAE,GAAiB;IACrD,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAC5C,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACpE,CAAC;AAED,6GAA6G;AAC7G,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9F,CAAC;AAED,oFAAoF;AACpF,SAAS,QAAQ,CAAC,GAAW,EAAE,GAAiB;IAC9C,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACvC,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC;IAC/F,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,WAAW,CAAC,KAAa,EAAE,WAAmB,EAAE,GAAiB;IACxE,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IACxC,OAAO;QACL,KAAK;QACL,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QACrD,IAAI,EAAE,QAAQ;QACd,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnD,CAAC;AACJ,CAAC;AAED,8FAA8F;AAC9F,SAAS,cAAc,CAAC,GAAW,EAAE,GAAiB;IACpD,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,0EAA0E;IAC1E,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAC7E,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACnE,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;QAClE,OAAO,WAAW,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/E,CAAC;IAED,iFAAiF;IACjF,6EAA6E;IAC7E,6EAA6E;IAC7E,iDAAiD;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACtC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/C,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACvF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IAC1E,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACtF,OAAO,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAA2B,EAC3B,MAAoB,mBAAmB;IAEvC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACxD,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACrC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChC,IAAI,IAAI,KAAK,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,IAA8C;IAE9C,MAAM,GAAG,GAAG,IAAI,EAAE,EAAE,IAAI,mBAAmB,CAAC;IAC5C,MAAM,KAAK,GAAG,iBAAiB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC/C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,4EAA4E;QAC5E,uEAAuE;QACvE,MAAM,KAAK,GACT,KAAK,CAAC,IAAI,KAAK,QAAQ;YACrB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,GAAG,CAAC;YAChF,CAAC,CAAC,SAAS,CAAC;QAChB,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;IAC/F,CAAC;IAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/E,IAAI,WAAW,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,WAAW,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;YACtC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,CAAC,UAAU,EAAE;YACtE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACvC,CAAC;IAED,OAAO;QACL,EAAE,EAAE,KAAK;QACT,MAAM,EAAE;YACN,oEAAoE,QAAQ,EAAE;YAC9E,8EAA8E,QAAQ,EAAE;YACxF,oDAAoD;SACrD;QACD,UAAU,EAAE,WAAW,CAAC,UAAU;KACnC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-resolve.test.d.ts","sourceRoot":"","sources":["../src/cli-resolve.test.ts"],"names":[],"mappings":""}
|