opensip-cli 0.1.4 → 0.1.5
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/bootstrap/authored-tool-admission.d.ts +23 -0
- package/dist/bootstrap/authored-tool-admission.d.ts.map +1 -0
- package/dist/bootstrap/authored-tool-admission.js +54 -0
- package/dist/bootstrap/authored-tool-admission.js.map +1 -0
- package/dist/bootstrap/build-per-run-scope.d.ts.map +1 -1
- package/dist/bootstrap/build-per-run-scope.js +0 -14
- package/dist/bootstrap/build-per-run-scope.js.map +1 -1
- package/dist/bootstrap/config-and-capabilities.d.ts.map +1 -1
- package/dist/bootstrap/config-and-capabilities.js +6 -5
- package/dist/bootstrap/config-and-capabilities.js.map +1 -1
- package/dist/bootstrap/execute-post-bailout-bootstrap.js +1 -1
- package/dist/bootstrap/execute-post-bailout-bootstrap.js.map +1 -1
- package/dist/bootstrap/installed-tool-admission.d.ts +20 -0
- package/dist/bootstrap/installed-tool-admission.d.ts.map +1 -0
- package/dist/bootstrap/installed-tool-admission.js +60 -0
- package/dist/bootstrap/installed-tool-admission.js.map +1 -0
- package/dist/bootstrap/load-tool-capabilities.d.ts +2 -2
- package/dist/bootstrap/load-tool-capabilities.d.ts.map +1 -1
- package/dist/bootstrap/load-tool-capabilities.js +2 -12
- package/dist/bootstrap/load-tool-capabilities.js.map +1 -1
- package/dist/bootstrap/register-tools-discovery.d.ts +0 -59
- package/dist/bootstrap/register-tools-discovery.d.ts.map +1 -1
- package/dist/bootstrap/register-tools-discovery.js +3 -176
- package/dist/bootstrap/register-tools-discovery.js.map +1 -1
- package/dist/bootstrap/register-tools.d.ts +2 -1
- package/dist/bootstrap/register-tools.d.ts.map +1 -1
- package/dist/bootstrap/register-tools.js +2 -1
- package/dist/bootstrap/register-tools.js.map +1 -1
- package/dist/bootstrap/tool-admission-types.d.ts +12 -0
- package/dist/bootstrap/tool-admission-types.d.ts.map +1 -0
- package/dist/bootstrap/tool-admission-types.js +2 -0
- package/dist/bootstrap/tool-admission-types.js.map +1 -0
- package/dist/bootstrap/validate-tool.d.ts +1 -1
- package/dist/bootstrap/validate-tool.d.ts.map +1 -1
- package/dist/bootstrap/validate-tool.js +6 -2
- package/dist/bootstrap/validate-tool.js.map +1 -1
- package/dist/telemetry/profiling.d.ts +1 -1
- package/dist/telemetry/profiling.d.ts.map +1 -1
- package/dist/telemetry/profiling.js +93 -35
- package/dist/telemetry/profiling.js.map +1 -1
- package/dist/ui/result-to-view.d.ts.map +1 -1
- package/dist/ui/result-to-view.js +4 -12
- package/dist/ui/result-to-view.js.map +1 -1
- package/package.json +32 -32
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// @fitness-ignore-file performance-anti-patterns -- sequential await across discovered tool packages preserves load order for plugin-conflict detection; bounded by installed plugin count
|
|
2
|
-
|
|
3
|
-
import { admitTool, assertManifestMatchesTool, discoverAuthoredToolSidecars, discoverToolPackagesFromAnchors, loadToolManifest, logger, PluginIncompatibleError, PROJECT_LOCAL_MANIFEST_FILE, resolveProjectContext, resolveProjectPaths, resolveUserPaths, } from '@opensip-cli/core';
|
|
2
|
+
import { assertManifestMatchesTool, discoverAuthoredToolSidecars, discoverToolPackagesFromAnchors, logger, PluginIncompatibleError, resolveProjectContext, resolveProjectPaths, resolveUserPaths, } from '@opensip-cli/core';
|
|
4
3
|
import { importToolRuntime } from './admit-tool-package.js';
|
|
4
|
+
import { admitProjectLocalTool, admitUserGlobalTool, } from './authored-tool-admission.js';
|
|
5
|
+
import { admitInstalledTool, emitInstalledLoadFailure } from './installed-tool-admission.js';
|
|
5
6
|
import { BOOTSTRAP_MODULE } from './register-tools-shared.js';
|
|
6
|
-
import { isProjectLocalToolTrusted } from './tool-trust.js';
|
|
7
7
|
/**
|
|
8
8
|
* Build the ordered tool-discovery sources. Order is precedence
|
|
9
9
|
* (first-occurrence-wins on duplicate name):
|
|
@@ -37,84 +37,6 @@ export function buildToolDiscoverySources(cwd, cliInstallDir) {
|
|
|
37
37
|
sources.push({ dir: cwd, mode: 'walkUp' }, { dir: resolveUserPaths().pluginsDir('tool'), mode: 'scanDir' }, { dir: cliInstallDir, mode: 'walkUp' });
|
|
38
38
|
return sources;
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Run the admission gate over a discovered INSTALLED tool package
|
|
42
|
-
* before its module is imported. Reads the static
|
|
43
|
-
* `package.json#opensipTools` manifest and runs the shared `admitTool` gate
|
|
44
|
-
* (source `'installed'`, best-effort `explicitlyRequested: false` so an
|
|
45
|
-
* incompatible installed tool skips rather than failing the whole CLI).
|
|
46
|
-
*
|
|
47
|
-
* Returns:
|
|
48
|
-
* - `undefined` — skip this package (no conformant manifest, gate skipped
|
|
49
|
-
* it, or its id collides with a built-in). The reason is logged.
|
|
50
|
-
* - the admission `{ provenance, manifest }` — the manifest is conformant +
|
|
51
|
-
* compatible; the caller continues to import + register, and records the
|
|
52
|
-
* provenance/manifest only AFTER the runtime actually registered (so
|
|
53
|
-
* `plugin list` and the capability registry never see a tool whose import
|
|
54
|
-
* subsequently failed — matching the bundled/authored legs).
|
|
55
|
-
*
|
|
56
|
-
* Public launch: the grace window ended. A discovered `kind:'tool'` package whose
|
|
57
|
-
* manifest is missing/malformed (`loadToolManifest` → undefined) or declares no
|
|
58
|
-
* `apiVersion` (`admitTool` → skip via {@link checkCompatibility}) is no longer
|
|
59
|
-
* admitted off the marker alone — it is rejected with a diagnostic.
|
|
60
|
-
*/
|
|
61
|
-
function admitInstalledTool(pkg, builtInIds) {
|
|
62
|
-
const manifest = loadToolManifest('installed', pkg.packageDir);
|
|
63
|
-
if (manifest === undefined) {
|
|
64
|
-
// Launch: a discovered tool with no conformant manifest is no longer admitted
|
|
65
|
-
// off the `kind:'tool'` marker alone (the grace window ended) — skip it.
|
|
66
|
-
process.stderr.write(`opensip: tool package ${pkg.name} has no conformant package.json#opensipTools manifest — skipping\n`);
|
|
67
|
-
logger.warn({
|
|
68
|
-
evt: 'cli.tool.manifest_invalid',
|
|
69
|
-
module: BOOTSTRAP_MODULE,
|
|
70
|
-
name: pkg.name,
|
|
71
|
-
});
|
|
72
|
-
return undefined;
|
|
73
|
-
}
|
|
74
|
-
if (builtInIds.has(manifest.id))
|
|
75
|
-
return undefined; // builtInIds are human ids from manifests (compat)
|
|
76
|
-
const result = admitTool({
|
|
77
|
-
manifest,
|
|
78
|
-
source: 'installed',
|
|
79
|
-
dir: pkg.packageDir,
|
|
80
|
-
packageName: pkg.name,
|
|
81
|
-
// Best-effort: discovery alone can't tell whether THIS run targets this
|
|
82
|
-
// tool's command, so default false → incompatible installed tools skip.
|
|
83
|
-
explicitlyRequested: false,
|
|
84
|
-
});
|
|
85
|
-
if (result.decision !== 'admit')
|
|
86
|
-
return undefined;
|
|
87
|
-
return { provenance: result.provenance, manifest: result.manifest };
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Emit the best-effort stderr line + structured warning for a discovered
|
|
91
|
-
* INSTALLED tool whose runtime failed to load. Each `ToolRuntimeLoad` failure
|
|
92
|
-
* reason maps to its own message + event (preserving the admission diagnostics) —
|
|
93
|
-
* an installed tool's load failure skips it, never crashing the CLI.
|
|
94
|
-
*/
|
|
95
|
-
function emitInstalledLoadFailure(name, load) {
|
|
96
|
-
if (load.reason === 'no-entry') {
|
|
97
|
-
process.stderr.write(`opensip: tool package ${name} has no resolvable entry point — skipping\n`);
|
|
98
|
-
logger.warn({ evt: 'cli.tool.no_entry', module: BOOTSTRAP_MODULE, name });
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
if (load.reason === 'invalid-shape') {
|
|
102
|
-
process.stderr.write(`opensip: tool package ${name} does not export a valid \`tool\` — skipping\n`);
|
|
103
|
-
logger.warn({
|
|
104
|
-
evt: 'cli.tool.invalid_shape',
|
|
105
|
-
module: BOOTSTRAP_MODULE,
|
|
106
|
-
name,
|
|
107
|
-
});
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
process.stderr.write(`opensip: failed to load tool ${name}: ${load.detail ?? 'import failed'}\n`);
|
|
111
|
-
logger.warn({
|
|
112
|
-
evt: 'cli.tool.load_failed',
|
|
113
|
-
module: BOOTSTRAP_MODULE,
|
|
114
|
-
name,
|
|
115
|
-
error: load.detail,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
40
|
/**
|
|
119
41
|
* Discover and register third-party tool packages from npm — any
|
|
120
42
|
* `package.json` declaring `opensipTools.kind === 'tool'`. Built-in
|
|
@@ -187,101 +109,6 @@ export async function discoverAndRegisterToolPackages(registry, opts, builtInIds
|
|
|
187
109
|
}
|
|
188
110
|
}
|
|
189
111
|
}
|
|
190
|
-
/**
|
|
191
|
-
* The shared admission TAIL for both authored sources.
|
|
192
|
-
* When `preloadedManifest` is supplied we use that snapshot (no re-read) so a
|
|
193
|
-
* prior trust decision (project-local) and the compat gate see the identical
|
|
194
|
-
* declaration. This removes the TOCTOU between the trust-bearing read and the
|
|
195
|
-
* gate read for the deny-by-default authored path.
|
|
196
|
-
*
|
|
197
|
-
* @throws {PluginIncompatibleError} when the sidecar is missing/malformed or
|
|
198
|
-
* the tool is compatibility-incompatible.
|
|
199
|
-
*/
|
|
200
|
-
function admitAuthoredTool(source, dir, preloadedManifest) {
|
|
201
|
-
// When a preloaded manifest is supplied (project-local trust path), we use
|
|
202
|
-
// that exact snapshot for the compat gate. This eliminates a TOCTOU between
|
|
203
|
-
// the read that decided "this id is allowlisted" and the read that feeds the
|
|
204
|
-
// compatibility check. The later dynamic import of the .mjs still sees
|
|
205
|
-
// whatever is on disk at execution time (inherent for authored code).
|
|
206
|
-
const rawManifest = preloadedManifest ?? loadToolManifest(source, dir);
|
|
207
|
-
if (rawManifest === undefined) {
|
|
208
|
-
throw new PluginIncompatibleError(`${source} tool at '${dir}' has no conformant ${PROJECT_LOCAL_MANIFEST_FILE} sidecar`, { diagnostic: 'manifest missing or malformed' });
|
|
209
|
-
}
|
|
210
|
-
const result = admitTool({
|
|
211
|
-
manifest: rawManifest,
|
|
212
|
-
source,
|
|
213
|
-
dir,
|
|
214
|
-
// An authored tool (placed in the project tree or the user's home dir) was
|
|
215
|
-
// explicitly authored by the user, so an incompatible one fails the run
|
|
216
|
-
// rather than skipping silently.
|
|
217
|
-
explicitlyRequested: true,
|
|
218
|
-
});
|
|
219
|
-
if (result.decision !== 'admit') {
|
|
220
|
-
throw new PluginIncompatibleError(`${source} tool '${rawManifest.id}' is incompatible: ${result.diagnostic ?? 'compatibility gate rejected it'}`, { diagnostic: result.diagnostic });
|
|
221
|
-
}
|
|
222
|
-
return { provenance: result.provenance, manifest: result.manifest };
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Admit (or reject) a single PROJECT-LOCAL authored tool under the
|
|
226
|
-
* deny-by-default trust policy (launch, Phase 3 Task 3.2; wired into
|
|
227
|
-
* production discovery in the launch contract).
|
|
228
|
-
*
|
|
229
|
-
* A project-local tool is authored code under
|
|
230
|
-
* `<project>/opensip-cli/tools/<name>/` declaring its identity via a JSON
|
|
231
|
-
* sidecar (`opensip-tool.manifest.json`). It is read + gated WITHOUT importing
|
|
232
|
-
* its module:
|
|
233
|
-
*
|
|
234
|
-
* 1. `loadToolManifest('project-local', dir)` — identity only, no code run.
|
|
235
|
-
* 2. Trust check — {@link isProjectLocalToolTrusted}. Not allowlisted ⇒
|
|
236
|
-
* throw {@link PluginIncompatibleError} (fail-closed, exit 5) before any
|
|
237
|
-
* import. Allowlisted ⇒ run the shared compatibility tail; an incompatible
|
|
238
|
-
* explicitly-trusted tool is likewise fail-closed.
|
|
239
|
-
*
|
|
240
|
-
* Returns the admitted tool's `{ provenance, manifest }` on success. The trust
|
|
241
|
-
* decision always precedes import (it is the FIRST statement here, ahead of the
|
|
242
|
-
* shared {@link admitAuthoredTool} tail).
|
|
243
|
-
*
|
|
244
|
-
* @throws {PluginIncompatibleError} when the tool has no conformant sidecar
|
|
245
|
-
* manifest, is not allowlisted, or is compatibility-incompatible.
|
|
246
|
-
*/
|
|
247
|
-
export function admitProjectLocalTool(args) {
|
|
248
|
-
// Trust decision FIRST — deny-by-default, before any compatibility maths
|
|
249
|
-
// and (critically) before the tool's module could ever be imported. The id
|
|
250
|
-
// is read from the sidecar identity, so load the manifest once here for the
|
|
251
|
-
// trust check, then hand the same dir to the shared tail.
|
|
252
|
-
const manifest = loadToolManifest('project-local', args.dir);
|
|
253
|
-
if (manifest === undefined) {
|
|
254
|
-
throw new PluginIncompatibleError(`project-local tool at '${args.dir}' has no conformant ${PROJECT_LOCAL_MANIFEST_FILE} sidecar`, { diagnostic: 'manifest missing or malformed' });
|
|
255
|
-
}
|
|
256
|
-
if (!isProjectLocalToolTrusted(manifest.id, args.env)) {
|
|
257
|
-
throw new PluginIncompatibleError(`project-local tool '${manifest.id}' is not trusted to load (deny-by-default). ` +
|
|
258
|
-
`Allowlist it via OPENSIP_CLI_ALLOW_PROJECT_TOOLS='${manifest.id}' to admit it.`, { diagnostic: 'project-local tool not allowlisted (deny-by-default)' });
|
|
259
|
-
}
|
|
260
|
-
// Pass the manifest we just loaded (and whose id we just trusted) so the
|
|
261
|
-
// compat gate in the tail sees the identical declaration. Closes the
|
|
262
|
-
// read-re-read TOCTOU for the deny-by-default path.
|
|
263
|
-
return admitAuthoredTool('project-local', args.dir, manifest);
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Admit a single USER-GLOBAL authored tool — the trusted-by-default sibling of
|
|
267
|
-
* {@link admitProjectLocalTool}.
|
|
268
|
-
*
|
|
269
|
-
* A user-global tool is an authored sidecar under
|
|
270
|
-
* `~/.opensip-cli/tools/<name>/`. The user deliberately placed it in their
|
|
271
|
-
* own home dir (the `npm i -g` analogue for authored code), so there is **no
|
|
272
|
-
* allowlist gate** — it is trusted-by-default. It still reads the static
|
|
273
|
-
* sidecar and runs `admitTool` BEFORE the module could be imported (the shared
|
|
274
|
-
* {@link admitAuthoredTool} tail), so trust-before-import holds for this leg
|
|
275
|
-
* too: a global tool the user explicitly authored is fail-closed on a
|
|
276
|
-
* missing/incompatible manifest, never a silent skip.
|
|
277
|
-
*
|
|
278
|
-
* @throws {PluginIncompatibleError} when the tool has no conformant sidecar
|
|
279
|
-
* manifest or is compatibility-incompatible.
|
|
280
|
-
*/
|
|
281
|
-
export function admitUserGlobalTool(args) {
|
|
282
|
-
// No trust gate — `user-global` is trusted-by-shipping-into-$HOME.
|
|
283
|
-
return admitAuthoredTool('user-global', args.dir);
|
|
284
|
-
}
|
|
285
112
|
/**
|
|
286
113
|
* Discover + admit + register AUTHORED Tool sidecars from the two authored
|
|
287
114
|
* roots, then dynamic-import each admitted runtime through the shared
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-tools-discovery.js","sourceRoot":"","sources":["../../src/bootstrap/register-tools-discovery.ts"],"names":[],"mappings":"AAAA,2LAA2L;AAC3L,
|
|
1
|
+
{"version":3,"file":"register-tools-discovery.js","sourceRoot":"","sources":["../../src/bootstrap/register-tools-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export { BUNDLED_TOOL_PACKAGES, EXPECTED_SCAFFOLDING_TOOL_IDS } from './register-tools-shared.js';
|
|
14
14
|
export { registerFirstPartyTools } from './register-tools-bundled.js';
|
|
15
|
-
export { type DiscoveryOptions, buildToolDiscoverySources, discoverAndRegisterToolPackages,
|
|
15
|
+
export { type DiscoveryOptions, buildToolDiscoverySources, discoverAndRegisterToolPackages, discoverAndRegisterAuthoredTools, } from './register-tools-discovery.js';
|
|
16
|
+
export { type AuthoredAdmission, admitProjectLocalTool, admitUserGlobalTool, } from './authored-tool-admission.js';
|
|
16
17
|
export { mountAllToolCommands } from './register-tools-mount.js';
|
|
17
18
|
//# sourceMappingURL=register-tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-tools.d.ts","sourceRoot":"","sources":["../../src/bootstrap/register-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAElG,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EACL,KAAK,gBAAgB,EACrB,yBAAyB,EACzB,+BAA+B,EAC/B,KAAK,iBAAiB,EACtB,qBAAqB,EACrB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"register-tools.d.ts","sourceRoot":"","sources":["../../src/bootstrap/register-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAElG,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EACL,KAAK,gBAAgB,EACrB,yBAAyB,EACzB,+BAA+B,EAC/B,gCAAgC,GACjC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,KAAK,iBAAiB,EACtB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export { BUNDLED_TOOL_PACKAGES, EXPECTED_SCAFFOLDING_TOOL_IDS } from './register-tools-shared.js';
|
|
14
14
|
export { registerFirstPartyTools } from './register-tools-bundled.js';
|
|
15
|
-
export { buildToolDiscoverySources, discoverAndRegisterToolPackages,
|
|
15
|
+
export { buildToolDiscoverySources, discoverAndRegisterToolPackages, discoverAndRegisterAuthoredTools, } from './register-tools-discovery.js';
|
|
16
|
+
export { admitProjectLocalTool, admitUserGlobalTool, } from './authored-tool-admission.js';
|
|
16
17
|
export { mountAllToolCommands } from './register-tools-mount.js';
|
|
17
18
|
//# sourceMappingURL=register-tools.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-tools.js","sourceRoot":"","sources":["../../src/bootstrap/register-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAElG,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EAEL,yBAAyB,EACzB,+BAA+B,
|
|
1
|
+
{"version":3,"file":"register-tools.js","sourceRoot":"","sources":["../../src/bootstrap/register-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAElG,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EAEL,yBAAyB,EACzB,+BAA+B,EAC/B,gCAAgC,GACjC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAEL,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ToolPluginManifest, ToolProvenance } from '@opensip-cli/core';
|
|
2
|
+
/**
|
|
3
|
+
* The outcome of admitting a tool — the recorded `ToolProvenance` plus the
|
|
4
|
+
* loaded `ToolPluginManifest`. The manifest is returned (not re-read) so the
|
|
5
|
+
* register step can run the drift guard against the imported runtime and seed
|
|
6
|
+
* the per-run capability registry without a second filesystem read.
|
|
7
|
+
*/
|
|
8
|
+
export interface ToolAdmission {
|
|
9
|
+
readonly provenance: ToolProvenance;
|
|
10
|
+
readonly manifest: ToolPluginManifest;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=tool-admission-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-admission-types.d.ts","sourceRoot":"","sources":["../../src/bootstrap/tool-admission-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;CACvC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-admission-types.js","sourceRoot":"","sources":["../../src/bootstrap/tool-admission-types.ts"],"names":[],"mappings":""}
|
|
@@ -17,6 +17,6 @@
|
|
|
17
17
|
* tool that is not allowlisted is fail-closed without its code ever running,
|
|
18
18
|
* and never reaches `isValidTool`.
|
|
19
19
|
*/
|
|
20
|
-
import type
|
|
20
|
+
import { type Tool } from '@opensip-cli/core';
|
|
21
21
|
export declare function isValidTool(value: unknown): value is Tool;
|
|
22
22
|
//# sourceMappingURL=validate-tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-tool.d.ts","sourceRoot":"","sources":["../../src/bootstrap/validate-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"validate-tool.d.ts","sourceRoot":"","sources":["../../src/bootstrap/validate-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAuB,KAAK,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEnE,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,IAAI,CAkBzD"}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* tool that is not allowlisted is fail-closed without its code ever running,
|
|
18
18
|
* and never reaches `isValidTool`.
|
|
19
19
|
*/
|
|
20
|
+
import { validateCommandSpec } from '@opensip-cli/core';
|
|
20
21
|
export function isValidTool(value) {
|
|
21
22
|
if (typeof value !== 'object' || value === null)
|
|
22
23
|
return false;
|
|
@@ -30,9 +31,12 @@ export function isValidTool(value) {
|
|
|
30
31
|
// A tool must expose a command surface: a non-empty declarative `commandSpecs`
|
|
31
32
|
// array (the one command surface, launch — `register()` was removed). A tool
|
|
32
33
|
// with no commandSpecs cannot contribute any command and is rejected.
|
|
33
|
-
|
|
34
|
-
if (!hasSpecs)
|
|
34
|
+
if (!Array.isArray(candidate.commandSpecs) || candidate.commandSpecs.length === 0)
|
|
35
35
|
return false;
|
|
36
|
+
for (const spec of candidate.commandSpecs) {
|
|
37
|
+
if (!validateCommandSpec(spec))
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
36
40
|
return true;
|
|
37
41
|
}
|
|
38
42
|
//# sourceMappingURL=validate-tool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-tool.js","sourceRoot":"","sources":["../../src/bootstrap/validate-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"validate-tool.js","sourceRoot":"","sources":["../../src/bootstrap/validate-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,mBAAmB,EAAa,MAAM,mBAAmB,CAAC;AAEnE,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,SAAS,GAAG,KAIjB,CAAC;IACF,IAAI,OAAO,SAAS,CAAC,QAAQ,KAAK,QAAQ,IAAI,SAAS,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACxF,IAAI,OAAQ,SAAS,CAAC,QAA6B,CAAC,EAAE,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACrD,+EAA+E;IAC/E,6EAA6E;IAC7E,sEAAsE;IACtE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,SAAS,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAChG,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;QAC1C,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;IAC/C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -36,7 +36,7 @@ export declare function startProfiling(scope?: RunScope, command?: string): void
|
|
|
36
36
|
* Stop profiling and flush the .cpuprofile + labels sidecar.
|
|
37
37
|
* Safe and idempotent.
|
|
38
38
|
*/
|
|
39
|
-
export declare function stopProfiling(): void;
|
|
39
|
+
export declare function stopProfiling(scope?: RunScope): void;
|
|
40
40
|
/** Exposed for tests / shutdown. */
|
|
41
41
|
export declare function resetProfilingForTests(): void;
|
|
42
42
|
//# sourceMappingURL=profiling.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiling.d.ts","sourceRoot":"","sources":["../../src/telemetry/profiling.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"profiling.d.ts","sourceRoot":"","sources":["../../src/telemetry/profiling.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAkD1D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,IAAI,OAAO,CAY5C;AAgBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CA4DvE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CA2CpD;AAiBD,oCAAoC;AACpC,wBAAgB,sBAAsB,IAAI,IAAI,CAI7C"}
|
|
@@ -23,10 +23,38 @@ import { Session } from 'node:inspector';
|
|
|
23
23
|
import { join } from 'node:path';
|
|
24
24
|
import { logger } from '@opensip-cli/core';
|
|
25
25
|
import { hostEnv } from '../env/host-env-specs.js';
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
function createProfilingState() {
|
|
27
|
+
return {
|
|
28
|
+
session: null,
|
|
29
|
+
isProfiling: false,
|
|
30
|
+
profilePath: null,
|
|
31
|
+
labelsPath: null,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function isProfilingState(value) {
|
|
35
|
+
return (typeof value === 'object' &&
|
|
36
|
+
value !== null &&
|
|
37
|
+
'session' in value &&
|
|
38
|
+
'isProfiling' in value &&
|
|
39
|
+
'profilePath' in value &&
|
|
40
|
+
'labelsPath' in value);
|
|
41
|
+
}
|
|
42
|
+
function profilingStateFor(scope) {
|
|
43
|
+
if (scope === undefined)
|
|
44
|
+
return fallbackProfilingState;
|
|
45
|
+
const existing = scope.telemetry.profiling;
|
|
46
|
+
if (isProfilingState(existing))
|
|
47
|
+
return existing;
|
|
48
|
+
const created = createProfilingState();
|
|
49
|
+
scope.telemetry.profiling = created;
|
|
50
|
+
return created;
|
|
51
|
+
}
|
|
52
|
+
const fallbackProfilingState = createProfilingState();
|
|
53
|
+
// Node's inspector CPU profiler is process-global. State details live on the
|
|
54
|
+
// RunScope telemetry bag; this pointer lets shutdownTelemetry stop the active
|
|
55
|
+
// profile when it is invoked outside the original scope.
|
|
56
|
+
let activeProfilingState = null;
|
|
57
|
+
let warnedOtelOnlyProfiling = false;
|
|
30
58
|
/** Module tag for structured logging (also dedupes the sonarjs/no-duplicate-string occurrences). */
|
|
31
59
|
const MODULE = 'cli:telemetry';
|
|
32
60
|
/** Returns true if the recommended or OTEL-only profiling gate is satisfied. */
|
|
@@ -34,7 +62,9 @@ export function isProfilingEnabled() {
|
|
|
34
62
|
const endpoint = hostEnv.get('OTEL_EXPORTER_OTLP_ENDPOINT');
|
|
35
63
|
if (!endpoint)
|
|
36
64
|
return false;
|
|
37
|
-
const explicit = hostEnv.get('OPENSIP_PROFILING');
|
|
65
|
+
const explicit = hostEnv.get('OPENSIP_PROFILING')?.toLowerCase();
|
|
66
|
+
if (explicit === '0' || explicit === 'false')
|
|
67
|
+
return false;
|
|
38
68
|
if (explicit === '1' || explicit === 'true')
|
|
39
69
|
return true;
|
|
40
70
|
// Supported "just the OTEL endpoint" alternative (with warnings in docs/ADR-0049).
|
|
@@ -42,24 +72,44 @@ export function isProfilingEnabled() {
|
|
|
42
72
|
// Operators who do not want this can set OPENSIP_PROFILING=0 explicitly.
|
|
43
73
|
return true; // OTEL endpoint present ⇒ profiling on in this fallback mode
|
|
44
74
|
}
|
|
75
|
+
function warnIfOtelOnlyProfilingMode() {
|
|
76
|
+
const endpoint = hostEnv.get('OTEL_EXPORTER_OTLP_ENDPOINT');
|
|
77
|
+
const explicit = hostEnv.get('OPENSIP_PROFILING');
|
|
78
|
+
if (!endpoint || explicit !== undefined || warnedOtelOnlyProfiling)
|
|
79
|
+
return;
|
|
80
|
+
warnedOtelOnlyProfiling = true;
|
|
81
|
+
logger.warn({
|
|
82
|
+
evt: 'cli.profiling.otel_only_enabled',
|
|
83
|
+
module: MODULE,
|
|
84
|
+
msg: 'CPU profiling is enabled because OTEL_EXPORTER_OTLP_ENDPOINT is set and ' +
|
|
85
|
+
'OPENSIP_PROFILING is unset; set OPENSIP_PROFILING=0 to disable profile artifacts.',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
45
88
|
/**
|
|
46
89
|
* Start CPU profiling for this invocation (if gate is open).
|
|
47
90
|
* Must be called after RunScope is entered (so runId is available).
|
|
48
91
|
* Safe to call multiple times (idempotent).
|
|
49
92
|
*/
|
|
50
93
|
export function startProfiling(scope, command) {
|
|
51
|
-
if (isProfiling)
|
|
94
|
+
if (activeProfilingState?.isProfiling === true)
|
|
95
|
+
return;
|
|
96
|
+
const state = profilingStateFor(scope);
|
|
97
|
+
if (state.isProfiling)
|
|
52
98
|
return;
|
|
53
99
|
try {
|
|
54
100
|
if (!isProfilingEnabled())
|
|
55
101
|
return;
|
|
56
|
-
|
|
57
|
-
session
|
|
58
|
-
session.
|
|
59
|
-
|
|
102
|
+
warnIfOtelOnlyProfilingMode();
|
|
103
|
+
state.session = new Session();
|
|
104
|
+
state.session.connect();
|
|
105
|
+
state.isProfiling = true;
|
|
106
|
+
activeProfilingState = state;
|
|
107
|
+
state.session.post('Profiler.enable', (_err, _res) => {
|
|
108
|
+
if (!state.session)
|
|
60
109
|
return;
|
|
61
|
-
session.post('Profiler.start', (_err2, _res2) => {
|
|
62
|
-
|
|
110
|
+
state.session.post('Profiler.start', (_err2, _res2) => {
|
|
111
|
+
if (!state.session)
|
|
112
|
+
return;
|
|
63
113
|
const runId = scope?.runId ?? 'unknown';
|
|
64
114
|
const safeCommand = (command ?? 'cli').replace(/[^a-z0-9_-]/gi, '_');
|
|
65
115
|
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
@@ -68,21 +118,21 @@ export function startProfiling(scope, command) {
|
|
|
68
118
|
? join(scope.projectContext.projectRoot, 'opensip-cli/.runtime/profiles')
|
|
69
119
|
: join(process.cwd(), 'opensip-cli/.runtime/profiles');
|
|
70
120
|
mkdirSync(baseDir, { recursive: true });
|
|
71
|
-
profilePath = join(baseDir, `${ts}-${safeCommand}-${runId}.cpuprofile`);
|
|
72
|
-
labelsPath = join(baseDir, `${ts}-${safeCommand}-${runId}.labels.json`);
|
|
121
|
+
state.profilePath = join(baseDir, `${ts}-${safeCommand}-${runId}.cpuprofile`);
|
|
122
|
+
state.labelsPath = join(baseDir, `${ts}-${safeCommand}-${runId}.labels.json`);
|
|
73
123
|
const labels = {
|
|
74
124
|
runId,
|
|
75
125
|
command: command ?? 'unknown',
|
|
76
126
|
service: 'opensip-cli',
|
|
77
127
|
// Add any OTEL_RESOURCE_ATTRIBUTES derived labels here if needed in future
|
|
78
128
|
};
|
|
79
|
-
writeFileSync(labelsPath, JSON.stringify(labels, null, 2));
|
|
129
|
+
writeFileSync(state.labelsPath, JSON.stringify(labels, null, 2));
|
|
80
130
|
logger.info({
|
|
81
131
|
evt: 'cli.profiling.started',
|
|
82
132
|
module: MODULE,
|
|
83
133
|
runId,
|
|
84
134
|
command,
|
|
85
|
-
profilePath,
|
|
135
|
+
profilePath: state.profilePath,
|
|
86
136
|
});
|
|
87
137
|
});
|
|
88
138
|
});
|
|
@@ -94,23 +144,26 @@ export function startProfiling(scope, command) {
|
|
|
94
144
|
error: error instanceof Error ? error.message : String(error),
|
|
95
145
|
});
|
|
96
146
|
// Best effort — profiling failure must never break the run
|
|
97
|
-
cleanup();
|
|
147
|
+
cleanup(state);
|
|
98
148
|
}
|
|
99
149
|
}
|
|
100
150
|
/**
|
|
101
151
|
* Stop profiling and flush the .cpuprofile + labels sidecar.
|
|
102
152
|
* Safe and idempotent.
|
|
103
153
|
*/
|
|
104
|
-
export function stopProfiling() {
|
|
105
|
-
|
|
106
|
-
|
|
154
|
+
export function stopProfiling(scope) {
|
|
155
|
+
const state = scope === undefined
|
|
156
|
+
? (activeProfilingState ?? fallbackProfilingState)
|
|
157
|
+
: profilingStateFor(scope);
|
|
158
|
+
if (!state.isProfiling || !state.session) {
|
|
159
|
+
cleanup(state);
|
|
107
160
|
return;
|
|
108
161
|
}
|
|
109
162
|
try {
|
|
110
163
|
// node:inspector post callbacks for Profiler.* use structural types not fully declared
|
|
111
164
|
// in the ambient types we consume; the result object (incl. profile) arrives as any.
|
|
112
165
|
// We narrow locally for the write path; the disable is scoped to the wire call.
|
|
113
|
-
session.post('Profiler.stop', (err, result = {}) => {
|
|
166
|
+
state.session.post('Profiler.stop', (err, result = {}) => {
|
|
114
167
|
if (err) {
|
|
115
168
|
logger.warn({
|
|
116
169
|
evt: 'cli.profiling.stop_failed',
|
|
@@ -118,16 +171,16 @@ export function stopProfiling() {
|
|
|
118
171
|
error: err.message || String(err),
|
|
119
172
|
});
|
|
120
173
|
}
|
|
121
|
-
else if (result.profile && profilePath) {
|
|
122
|
-
writeFileSync(profilePath, JSON.stringify(result.profile));
|
|
174
|
+
else if (result.profile && state.profilePath) {
|
|
175
|
+
writeFileSync(state.profilePath, JSON.stringify(result.profile));
|
|
123
176
|
logger.info({
|
|
124
177
|
evt: 'cli.profiling.stopped',
|
|
125
178
|
module: MODULE,
|
|
126
|
-
profilePath,
|
|
127
|
-
labelsPath,
|
|
179
|
+
profilePath: state.profilePath,
|
|
180
|
+
labelsPath: state.labelsPath,
|
|
128
181
|
});
|
|
129
182
|
}
|
|
130
|
-
cleanup();
|
|
183
|
+
cleanup(state);
|
|
131
184
|
});
|
|
132
185
|
}
|
|
133
186
|
catch (error) {
|
|
@@ -136,25 +189,30 @@ export function stopProfiling() {
|
|
|
136
189
|
module: MODULE,
|
|
137
190
|
error: error instanceof Error ? error.message : String(error),
|
|
138
191
|
});
|
|
139
|
-
cleanup();
|
|
192
|
+
cleanup(state);
|
|
140
193
|
}
|
|
141
194
|
}
|
|
142
|
-
function cleanup() {
|
|
143
|
-
if (session) {
|
|
195
|
+
function cleanup(state) {
|
|
196
|
+
if (state.session) {
|
|
144
197
|
try {
|
|
145
|
-
session.disconnect();
|
|
198
|
+
state.session.disconnect();
|
|
146
199
|
}
|
|
147
200
|
catch {
|
|
148
201
|
// @swallow-ok best-effort inspector session disconnect during profiling teardown
|
|
149
202
|
}
|
|
150
203
|
}
|
|
151
|
-
session = null;
|
|
152
|
-
isProfiling = false;
|
|
153
|
-
profilePath = null;
|
|
154
|
-
labelsPath = null;
|
|
204
|
+
state.session = null;
|
|
205
|
+
state.isProfiling = false;
|
|
206
|
+
state.profilePath = null;
|
|
207
|
+
state.labelsPath = null;
|
|
208
|
+
if (activeProfilingState === state)
|
|
209
|
+
activeProfilingState = null;
|
|
155
210
|
}
|
|
156
211
|
/** Exposed for tests / shutdown. */
|
|
157
212
|
export function resetProfilingForTests() {
|
|
158
|
-
|
|
213
|
+
if (activeProfilingState !== null)
|
|
214
|
+
cleanup(activeProfilingState);
|
|
215
|
+
cleanup(fallbackProfilingState);
|
|
216
|
+
warnedOtelOnlyProfiling = false;
|
|
159
217
|
}
|
|
160
218
|
//# sourceMappingURL=profiling.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiling.js","sourceRoot":"","sources":["../../src/telemetry/profiling.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,MAAM,EAAiB,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"profiling.js","sourceRoot":"","sources":["../../src/telemetry/profiling.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result-to-view.d.ts","sourceRoot":"","sources":["../../src/ui/result-to-view.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAaL,KAAK,QAAQ,EACd,MAAM,qBAAqB,CAAC;AA4B7B,OAAO,KAAK,EACV,aAAa,EAIb,cAAc,EACd,aAAa,EACd,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"result-to-view.d.ts","sourceRoot":"","sources":["../../src/ui/result-to-view.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAaL,KAAK,QAAQ,EACd,MAAM,qBAAqB,CAAC;AA4B7B,OAAO,KAAK,EACV,aAAa,EAIb,cAAc,EACd,aAAa,EACd,MAAM,wBAAwB,CAAC;AAkOhC;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAInE;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,cAAc,EACxB,aAAa,CAAC,EAAE,aAAa,GAC5B,QAAQ,CAoBV;AAED,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAwF5D"}
|