opensip-cli 0.1.2 → 0.1.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.
- package/dist/bootstrap/bind-tool-context.d.ts +16 -0
- package/dist/bootstrap/bind-tool-context.d.ts.map +1 -0
- package/dist/bootstrap/bind-tool-context.js +160 -0
- package/dist/bootstrap/bind-tool-context.js.map +1 -0
- package/dist/bootstrap/build-per-run-scope.d.ts.map +1 -1
- package/dist/bootstrap/build-per-run-scope.js +35 -2
- package/dist/bootstrap/build-per-run-scope.js.map +1 -1
- package/dist/bootstrap/execute-post-bailout-bootstrap.d.ts +45 -0
- package/dist/bootstrap/execute-post-bailout-bootstrap.d.ts.map +1 -0
- package/dist/bootstrap/execute-post-bailout-bootstrap.js +108 -0
- package/dist/bootstrap/execute-post-bailout-bootstrap.js.map +1 -0
- package/dist/bootstrap/plan-pre-action-bootstrap.d.ts +45 -0
- package/dist/bootstrap/plan-pre-action-bootstrap.d.ts.map +1 -0
- package/dist/bootstrap/plan-pre-action-bootstrap.js +86 -0
- package/dist/bootstrap/plan-pre-action-bootstrap.js.map +1 -0
- package/dist/bootstrap/pre-action-bootstrap-phases.d.ts +20 -0
- package/dist/bootstrap/pre-action-bootstrap-phases.d.ts.map +1 -0
- package/dist/bootstrap/pre-action-bootstrap-phases.js +25 -0
- package/dist/bootstrap/pre-action-bootstrap-phases.js.map +1 -0
- package/dist/bootstrap/pre-action-hook.d.ts +6 -66
- package/dist/bootstrap/pre-action-hook.d.ts.map +1 -1
- package/dist/bootstrap/pre-action-hook.js +22 -266
- package/dist/bootstrap/pre-action-hook.js.map +1 -1
- package/dist/bootstrap/pre-action-runtime.d.ts +9 -0
- package/dist/bootstrap/pre-action-runtime.d.ts.map +1 -0
- package/dist/bootstrap/pre-action-runtime.js +2 -0
- package/dist/bootstrap/pre-action-runtime.js.map +1 -0
- package/dist/bootstrap/register-tools-bundled.d.ts +28 -0
- package/dist/bootstrap/register-tools-bundled.d.ts.map +1 -0
- package/dist/bootstrap/register-tools-bundled.js +107 -0
- package/dist/bootstrap/register-tools-bundled.js.map +1 -0
- package/dist/bootstrap/register-tools-discovery.d.ts +154 -0
- package/dist/bootstrap/register-tools-discovery.d.ts.map +1 -0
- package/dist/bootstrap/register-tools-discovery.js +385 -0
- package/dist/bootstrap/register-tools-discovery.js.map +1 -0
- package/dist/bootstrap/register-tools-mount.d.ts +25 -0
- package/dist/bootstrap/register-tools-mount.d.ts.map +1 -0
- package/dist/bootstrap/register-tools-mount.js +91 -0
- package/dist/bootstrap/register-tools-mount.js.map +1 -0
- package/dist/bootstrap/register-tools-shared.d.ts +40 -0
- package/dist/bootstrap/register-tools-shared.d.ts.map +1 -0
- package/dist/bootstrap/register-tools-shared.js +98 -0
- package/dist/bootstrap/register-tools-shared.js.map +1 -0
- package/dist/bootstrap/register-tools.d.ts +4 -196
- package/dist/bootstrap/register-tools.d.ts.map +1 -1
- package/dist/bootstrap/register-tools.js +4 -668
- package/dist/bootstrap/register-tools.js.map +1 -1
- package/dist/commands/mount-command-spec.d.ts +2 -1
- package/dist/commands/mount-command-spec.d.ts.map +1 -1
- package/dist/commands/mount-command-spec.js +3 -6
- package/dist/commands/mount-command-spec.js.map +1 -1
- package/dist/env/host-env-specs.d.ts +4 -3
- package/dist/env/host-env-specs.d.ts.map +1 -1
- package/dist/env/host-env-specs.js +8 -3
- package/dist/env/host-env-specs.js.map +1 -1
- package/package.json +32 -32
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical bootstrap phase names (ADR-0052). The hook is the Commander
|
|
3
|
+
* adapter; business rules live behind the planner and post-bailout executor.
|
|
4
|
+
*/
|
|
5
|
+
export const PRE_ACTION_PHASES = {
|
|
6
|
+
readCommandOptions: 'read-command-options',
|
|
7
|
+
mergeCliDefaults: 'merge-cli-defaults',
|
|
8
|
+
resolveProject: 'resolve-project',
|
|
9
|
+
bailoutWindow: 'bailout-window',
|
|
10
|
+
projectSideEffects: 'project-side-effects',
|
|
11
|
+
buildScope: 'build-scope',
|
|
12
|
+
enterScope: 'enter-scope',
|
|
13
|
+
hostStartEffects: 'host-start-effects',
|
|
14
|
+
toolPreflight: 'tool-preflight',
|
|
15
|
+
dispose: 'dispose',
|
|
16
|
+
};
|
|
17
|
+
/** Post-bailout phases in load-bearing order (phases 5–9 of ADR-0052). */
|
|
18
|
+
export const POST_BAILOUT_PHASE_ORDER = [
|
|
19
|
+
PRE_ACTION_PHASES.projectSideEffects,
|
|
20
|
+
PRE_ACTION_PHASES.buildScope,
|
|
21
|
+
PRE_ACTION_PHASES.enterScope,
|
|
22
|
+
PRE_ACTION_PHASES.hostStartEffects,
|
|
23
|
+
PRE_ACTION_PHASES.toolPreflight,
|
|
24
|
+
];
|
|
25
|
+
//# sourceMappingURL=pre-action-bootstrap-phases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-action-bootstrap-phases.js","sourceRoot":"","sources":["../../src/bootstrap/pre-action-bootstrap-phases.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,kBAAkB,EAAE,sBAAsB;IAC1C,gBAAgB,EAAE,oBAAoB;IACtC,cAAc,EAAE,iBAAiB;IACjC,aAAa,EAAE,gBAAgB;IAC/B,kBAAkB,EAAE,sBAAsB;IAC1C,UAAU,EAAE,aAAa;IACzB,UAAU,EAAE,aAAa;IACzB,gBAAgB,EAAE,oBAAoB;IACtC,aAAa,EAAE,gBAAgB;IAC/B,OAAO,EAAE,SAAS;CACV,CAAC;AAIX,0EAA0E;AAC1E,MAAM,CAAC,MAAM,wBAAwB,GAA8B;IACjE,iBAAiB,CAAC,kBAAkB;IACpC,iBAAiB,CAAC,UAAU;IAC5B,iBAAiB,CAAC,UAAU;IAC5B,iBAAiB,CAAC,gBAAgB;IAClC,iBAAiB,CAAC,aAAa;CACvB,CAAC"}
|
|
@@ -1,74 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* pre-action-hook — Commander `preAction`
|
|
2
|
+
* pre-action-hook — Commander `preAction` adapter (ADR-0052).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* NOT opened here — that's a lazy getter on ToolCliContext (Task 1.3).
|
|
8
|
-
*
|
|
9
|
-
* Ordering is load-bearing: side effects only fire AFTER all bailout
|
|
10
|
-
* decisions. Sequence:
|
|
11
|
-
*
|
|
12
|
-
* 1. generate runId
|
|
13
|
-
* 2. read opts; resolve project context (pure; may throw on strict --config)
|
|
14
|
-
* 3. expose context on opts.projectContext (collision-free name)
|
|
15
|
-
* 4. bailout window — schema check (Phase 6.3), phantom warn (Phase 7)
|
|
16
|
-
* 5. side-effect setup — configureLogger({ logDir }) + setProjectContextForRun
|
|
17
|
-
* gated on project.scope === 'project' && existsSync(projectRoot)
|
|
18
|
-
* 6. Project: header (Phase 2.2)
|
|
19
|
-
* 7. cli.start log line
|
|
20
|
-
* 8. lazy Tool.initialize() — run the owning tool's optional one-time
|
|
21
|
-
* init exactly once per process, after the scope is entered and just
|
|
22
|
-
* before the action body (P1a). CLI-only commands have no owner and
|
|
23
|
-
* skip it; a failing init is fatal.
|
|
24
|
-
*
|
|
25
|
-
* Strict --config: when `--config <path>` doesn't resolve, the
|
|
26
|
-
* underlying ValidationError surfaces with exit 2 — no silent walk-up.
|
|
4
|
+
* Business rules live in {@link planPreActionBootstrap} (phases 1–4) and
|
|
5
|
+
* {@link executePostBailoutBootstrap} (phases 5–9). This module wires those
|
|
6
|
+
* to Commander's preAction/postAction hooks.
|
|
27
7
|
*/
|
|
28
|
-
import
|
|
8
|
+
import type { PreActionRuntime } from './pre-action-runtime.js';
|
|
29
9
|
import type { Command } from 'commander';
|
|
30
10
|
export { resolveOwningTool } from './owning-tool-init.js';
|
|
31
|
-
|
|
32
|
-
* The `scope.configDocument` slot value (ADR-0023 one-reader): the validated
|
|
33
|
-
* document rides the scope so tools project their shapes from it instead of
|
|
34
|
-
* re-reading the file — but ONLY when a real config file was read. A
|
|
35
|
-
* config-less run stays document-less so tools that hard-error on a missing
|
|
36
|
-
* config (fitness) stay loud instead of silently validating `{}`.
|
|
37
|
-
*/
|
|
38
|
-
/**
|
|
39
|
-
* The per-invocation bootstrap result the hook needs to BUILD the scope —
|
|
40
|
-
* the populated registries plus the admitted-tool manifests/provenance. These
|
|
41
|
-
* are created in `main()` BEFORE the scope can be constructed (the registries
|
|
42
|
-
* are inputs to `RunScope`; you can't read them off a scope that doesn't exist
|
|
43
|
-
* yet), so the composition root captures them in this closure and hands them to
|
|
44
|
-
* `installPreActionHook`. After the hook calls `enterScope`, every per-run read
|
|
45
|
-
* (project, datastore, manifests, provenance, …) goes through `currentScope()`
|
|
46
|
-
* — there is NO module-global handoff bag (the former `currentRuntimeContext`).
|
|
47
|
-
*/
|
|
48
|
-
export interface PreActionRuntime {
|
|
49
|
-
readonly languages: LanguageRegistry;
|
|
50
|
-
readonly tools: ToolRegistry;
|
|
51
|
-
readonly manifests: readonly ToolPluginManifest[];
|
|
52
|
-
readonly provenance: readonly ToolProvenance[];
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Mount the bootstrap `preAction` hook on the supplied program.
|
|
56
|
-
*
|
|
57
|
-
* @param program The root Commander program.
|
|
58
|
-
* @param version The CLI version (from `readPackageVersion` at the entry
|
|
59
|
-
* point). Threaded in rather than re-read here so the `mini` banner shows
|
|
60
|
-
* the SAME version `--version` reports — and so the kernel-adjacent hook
|
|
61
|
-
* doesn't resolve cli-ui's or its own package version by mistake.
|
|
62
|
-
* @param runtime The bootstrap result (registries + admitted manifests/
|
|
63
|
-
* provenance). Captured in the hook closure instead of read from a module
|
|
64
|
-
* global — the composition root installs the hook AFTER `bootstrapCli`
|
|
65
|
-
* populates the registries (see {@link PreActionRuntime}).
|
|
66
|
-
*/
|
|
11
|
+
export type { PreActionRuntime } from './pre-action-runtime.js';
|
|
67
12
|
export declare function installPreActionHook(program: Command, version: string, runtime: PreActionRuntime): void;
|
|
68
|
-
/**
|
|
69
|
-
* Extracted seam (Task 3) for postAction disposal + error-path coverage.
|
|
70
|
-
* Narrow, testable, no Commander dep. Called from the hook; can be called
|
|
71
|
-
* explicitly in tests or future finally blocks on thrown handler paths.
|
|
72
|
-
*/
|
|
73
13
|
export declare function disposeCurrentScope(): void;
|
|
74
14
|
//# sourceMappingURL=pre-action-hook.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pre-action-hook.d.ts","sourceRoot":"","sources":["../../src/bootstrap/pre-action-hook.ts"],"names":[],"mappings":"AACA
|
|
1
|
+
{"version":3,"file":"pre-action-hook.d.ts","sourceRoot":"","sources":["../../src/bootstrap/pre-action-hook.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAiCN;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAS1C"}
|
|
@@ -1,285 +1,42 @@
|
|
|
1
|
-
// @fitness-ignore-file detached-promises -- the preAction hook is a composition root: its body
|
|
1
|
+
// @fitness-ignore-file detached-promises -- the preAction hook is a composition root: its body awaits maybeInitializeOwningTool inside executePostBailoutBootstrap. Matches the same suppression on index.ts and bootstrap/index.ts.
|
|
2
2
|
/**
|
|
3
|
-
* pre-action-hook — Commander `preAction`
|
|
3
|
+
* pre-action-hook — Commander `preAction` adapter (ADR-0052).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* NOT opened here — that's a lazy getter on ToolCliContext (Task 1.3).
|
|
9
|
-
*
|
|
10
|
-
* Ordering is load-bearing: side effects only fire AFTER all bailout
|
|
11
|
-
* decisions. Sequence:
|
|
12
|
-
*
|
|
13
|
-
* 1. generate runId
|
|
14
|
-
* 2. read opts; resolve project context (pure; may throw on strict --config)
|
|
15
|
-
* 3. expose context on opts.projectContext (collision-free name)
|
|
16
|
-
* 4. bailout window — schema check (Phase 6.3), phantom warn (Phase 7)
|
|
17
|
-
* 5. side-effect setup — configureLogger({ logDir }) + setProjectContextForRun
|
|
18
|
-
* gated on project.scope === 'project' && existsSync(projectRoot)
|
|
19
|
-
* 6. Project: header (Phase 2.2)
|
|
20
|
-
* 7. cli.start log line
|
|
21
|
-
* 8. lazy Tool.initialize() — run the owning tool's optional one-time
|
|
22
|
-
* init exactly once per process, after the scope is entered and just
|
|
23
|
-
* before the action body (P1a). CLI-only commands have no owner and
|
|
24
|
-
* skip it; a failing init is fatal.
|
|
25
|
-
*
|
|
26
|
-
* Strict --config: when `--config <path>` doesn't resolve, the
|
|
27
|
-
* underlying ValidationError surfaces with exit 2 — no silent walk-up.
|
|
5
|
+
* Business rules live in {@link planPreActionBootstrap} (phases 1–4) and
|
|
6
|
+
* {@link executePostBailoutBootstrap} (phases 5–9). This module wires those
|
|
7
|
+
* to Commander's preAction/postAction hooks.
|
|
28
8
|
*/
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import { startProfiling } from '../telemetry/profiling.js';
|
|
33
|
-
import { checkForUpdate, formatUpdateNag } from '../update-notifier.js';
|
|
34
|
-
import { BootstrapError } from './bootstrap-error.js';
|
|
35
|
-
import { buildPerRunScope } from './build-per-run-scope.js';
|
|
36
|
-
import { loadCliDefaults, mergeConfigDefaults } from './cli-defaults.js';
|
|
37
|
-
import { loadOwningToolCapabilities } from './load-tool-capabilities.js';
|
|
38
|
-
import { maybeInitializeOwningTool, resolveOwningTool } from './owning-tool-init.js';
|
|
39
|
-
import { checkNoProjectAndBailout, checkSchemaVersionAndBailout, warnAboutPhantomRuntimes, } from './pre-action-guards.js';
|
|
40
|
-
/** npm package whose version the update check compares against. */
|
|
41
|
-
const CLI_PACKAGE_NAME = 'opensip-cli';
|
|
42
|
-
const MODULE_TAG = 'cli:bootstrap';
|
|
43
|
-
// Owning-tool resolution + lazy `Tool.initialize()` live in `owning-tool-init.ts`
|
|
44
|
-
// (also imported below for local use). `resolveOwningTool` is re-exported so
|
|
45
|
-
// existing importers (e.g. the lifecycle test) keep their stable
|
|
46
|
-
// `pre-action-hook.js` entry point.
|
|
9
|
+
import { currentScope, generatePrefixedId } from '@opensip-cli/core';
|
|
10
|
+
import { executePostBailoutBootstrap } from './execute-post-bailout-bootstrap.js';
|
|
11
|
+
import { planPreActionBootstrap } from './plan-pre-action-bootstrap.js';
|
|
47
12
|
export { resolveOwningTool } from './owning-tool-init.js';
|
|
48
|
-
/**
|
|
49
|
-
* Mount the bootstrap `preAction` hook on the supplied program.
|
|
50
|
-
*
|
|
51
|
-
* @param program The root Commander program.
|
|
52
|
-
* @param version The CLI version (from `readPackageVersion` at the entry
|
|
53
|
-
* point). Threaded in rather than re-read here so the `mini` banner shows
|
|
54
|
-
* the SAME version `--version` reports — and so the kernel-adjacent hook
|
|
55
|
-
* doesn't resolve cli-ui's or its own package version by mistake.
|
|
56
|
-
* @param runtime The bootstrap result (registries + admitted manifests/
|
|
57
|
-
* provenance). Captured in the hook closure instead of read from a module
|
|
58
|
-
* global — the composition root installs the hook AFTER `bootstrapCli`
|
|
59
|
-
* populates the registries (see {@link PreActionRuntime}).
|
|
60
|
-
*/
|
|
61
|
-
// The body (including the preAction hook arrow it registers) sequences the full
|
|
62
|
-
// per-invocation bootstrap: runId, defaults merge, project resolve + bailouts,
|
|
63
|
-
// scope construction/enter, metrics, profiling start, lazy tool init, capability
|
|
64
|
-
// drive. It has many explicit early-exit paths by design (the documented contract
|
|
65
|
-
// for "only side effects after all bailouts"). Cognitive complexity exceeds 15
|
|
66
|
-
// because it is the single source of truth for ordering; splitting would obscure
|
|
67
|
-
// the load-bearing sequence and duplicate the guard/enter wiring. Acceptable for
|
|
68
|
-
// this composition root (see similar disables on other bootstrap entry points).
|
|
69
|
-
/* eslint-disable sonarjs/cognitive-complexity -- single source of truth for scope construction/enter ordering; splitting would obscure the load-bearing sequence (rationale above) */
|
|
70
13
|
export function installPreActionHook(program, version, runtime) {
|
|
71
14
|
program.hook('preAction', async (_thisCommand, actionCommand) => {
|
|
72
15
|
const runId = generatePrefixedId('run');
|
|
73
16
|
const opts = actionCommand.opts();
|
|
74
17
|
const cwd = opts.cwd ?? process.cwd();
|
|
75
18
|
const cwdExplicit = actionCommand.getOptionValueSource('cwd') === 'cli';
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// straight off the config object below to build the UiContext.
|
|
79
|
-
const cliDefaults = loadCliDefaults(cwd, opts.config);
|
|
80
|
-
mergeConfigDefaults(opts, cliDefaults);
|
|
81
|
-
// Single bootstrap-time configuration of the process-wide logger
|
|
82
|
-
// singleton. Replaces the four prior free mutators (`setSilent`,
|
|
83
|
-
// `setDebugMode`, `setRunId`, `initLogFile`). `logDir` is wired in
|
|
84
|
-
// below once the project context is resolved — at that point the
|
|
85
|
-
// logsDir is known and we apply a second `configureLogger` to fill
|
|
86
|
-
// it in. The two-call sequence is intentional: silencing stderr
|
|
87
|
-
// before the project-resolve step is what makes Ink renders clean
|
|
88
|
-
// even when the project is missing.
|
|
89
|
-
configureLogger({
|
|
90
|
-
silent: true,
|
|
91
|
-
debugMode: Boolean(opts.debug),
|
|
92
|
-
runId,
|
|
93
|
-
});
|
|
94
|
-
// 2. Resolve the project context — pure, no side effects.
|
|
95
|
-
// Strict --config: throws ValidationError when explicit path misses.
|
|
96
|
-
let project;
|
|
97
|
-
try {
|
|
98
|
-
project = resolveProjectContext({
|
|
99
|
-
cwd,
|
|
100
|
-
cwdExplicit,
|
|
101
|
-
explicitConfigPath: opts.config,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
// §4.7: a config-resolve failure (e.g. strict --config miss) becomes a typed
|
|
106
|
-
// BootstrapError the top-level boundary renders — human stderr / structured
|
|
107
|
-
// --json — instead of an inline stderr write + process.exit.
|
|
108
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
109
|
-
throw new BootstrapError({
|
|
110
|
-
message: msg,
|
|
111
|
-
humanMessage: `✗ ${msg}`,
|
|
112
|
-
suggestion: 'Check opensip-cli.config.yml (or your --config path).',
|
|
113
|
-
exitCode: 2,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
// 3. Stash the context on opts under the COLLISION-FREE name.
|
|
117
|
-
// `opts.project` is reserved for Commander's --project [path] flag
|
|
118
|
-
// in uninstall.ts; we never use that name here.
|
|
119
|
-
opts.projectContext = project;
|
|
120
|
-
// Stash the resolved "was --cwd typed on the CLI?" signal alongside it,
|
|
121
|
-
// so the `init` command-spec handler (launch Phase 6) reads ONE
|
|
122
|
-
// source instead of recomputing `getOptionValueSource('cwd')` on its own
|
|
123
|
-
// Commander command. `actionCommand` IS the init command here, so this is
|
|
124
|
-
// byte-identical to the former register-init computation.
|
|
125
|
-
opts.cwdExplicit = cwdExplicit;
|
|
126
|
-
// 4. Bailout window — each may THROW a BootstrapError (rendered by the
|
|
127
|
-
// top-level boundary) before any side effects. Phantom warn is non-fatal;
|
|
128
|
-
// warns then continues.
|
|
129
|
-
checkSchemaVersionAndBailout(project, runId);
|
|
130
|
-
// Build the effective set of project-agnostic command names from the base list
|
|
131
|
-
// PLUS any tool CommandSpecs that declare scope: 'none'. This makes the
|
|
132
|
-
// declared `CommandSpec.scope` drive enforcement (previously the hardcoded
|
|
133
|
-
// name list made the field dead for tools and third-party commands).
|
|
134
|
-
const extraAgnostic = new Set();
|
|
135
|
-
for (const tool of runtime.tools.list()) {
|
|
136
|
-
for (const c of tool.commands || []) {
|
|
137
|
-
if (c.scope === 'none') {
|
|
138
|
-
extraAgnostic.add(c.name);
|
|
139
|
-
(c.aliases ?? []).forEach((a) => extraAgnostic.add(a));
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
checkNoProjectAndBailout(project, cwd, actionCommand.name(), runId, extraAgnostic);
|
|
144
|
-
warnAboutPhantomRuntimes(project, opts.json === true);
|
|
145
|
-
// 5. Side-effect setup, gated on a real project being present.
|
|
146
|
-
if (project.scope === 'project' && existsSync(project.projectRoot)) {
|
|
147
|
-
const projectPaths = resolveProjectPaths(project.projectRoot);
|
|
148
|
-
// Second configureLogger call — fills in the project-scoped logDir
|
|
149
|
-
// now that the project context is resolved. Leaves silent/debugMode/runId
|
|
150
|
-
// untouched (configureLogger only writes fields present in the bag).
|
|
151
|
-
configureLogger({ logDir: projectPaths.logsDir });
|
|
152
|
-
}
|
|
153
|
-
// Build the per-run RunScope and enter it via AsyncLocalStorage so
|
|
154
|
-
// library functions deep in the call tree (currentScope() readers)
|
|
155
|
-
// see the bound logger/registries/project + a lazy datastore thunk.
|
|
156
|
-
// enterWith propagates forward through the same async chain, so the
|
|
157
|
-
// action body invoked after this hook sees the same scope without
|
|
158
|
-
// needing a callback wrapper — which Commander does not expose.
|
|
159
|
-
// (Phase 5 deferred Task 5.2 / T1 Item D close-out.)
|
|
160
|
-
// Resolve presentation + update state once, before the scope is built.
|
|
161
|
-
// bannerSize: explicit `cli.ui.banner`, else the product default `mini`.
|
|
162
|
-
// update: the cached newer-version string (best-effort; undefined when
|
|
163
|
-
// up-to-date / opted-out / non-TTY). The `mini` banner shows it inline;
|
|
164
|
-
// other sizes — and the banner-less `--json` path — fall back to the
|
|
165
|
-
// stderr nag so the signal is never silently lost.
|
|
166
|
-
const bannerSize = cliDefaults.ui?.banner ?? 'mini';
|
|
167
|
-
const update = checkForUpdate({ name: CLI_PACKAGE_NAME, version });
|
|
168
|
-
if (update && (bannerSize !== 'mini' || opts.json === true)) {
|
|
169
|
-
process.stderr.write(formatUpdateNag(version, update));
|
|
170
|
-
}
|
|
171
|
-
// ADR-0008: select the cloud signal sink for this run. Sync + cheap —
|
|
172
|
-
// keyless / `cloud.sync:false` / `--no-cloud` / non-https → no-op with no
|
|
173
|
-
// IO; the entitlement check is deferred to first emit so non-signal
|
|
174
|
-
// commands pay nothing. `opts.cloud === false` comes from `--no-cloud`.
|
|
175
|
-
//
|
|
176
|
-
// `cloud` layers the user-level opt-out (~/.opensip-cli/config.yml#cloud)
|
|
177
|
-
// over the project's `cli.cloud:` block (audit P0-2): a user `sync: false`
|
|
178
|
-
// disables sync for every project on this machine.
|
|
179
|
-
const { languages, tools, manifests, provenance } = runtime;
|
|
180
|
-
// Extracted to thin the composition root (GA architectural blocker #2).
|
|
181
|
-
// All scope construction + wiring now lives in a dedicated small builder
|
|
182
|
-
// with explicit inputs. The hook remains the high-level sequencer. The
|
|
183
|
-
// registries + admitted-tool manifests/provenance come from the closure
|
|
184
|
-
// the composition root captured (no module-global handoff bag); the
|
|
185
|
-
// builder stamps manifests/provenance onto the scope for host commands.
|
|
186
|
-
const scope = buildPerRunScope({
|
|
187
|
-
project,
|
|
188
|
-
runId,
|
|
19
|
+
const plan = planPreActionBootstrap({
|
|
20
|
+
opts: opts,
|
|
189
21
|
cwd,
|
|
190
|
-
|
|
191
|
-
registries: { languages, tools },
|
|
192
|
-
manifests,
|
|
193
|
-
provenance,
|
|
194
|
-
apiKey: opts.apiKey,
|
|
195
|
-
// @fitness-ignore-next-line null-safety -- Commander's optsWithGlobals() always returns an OptionValues object (never null/undefined); the heuristic misreads the method-call-then-property access. `.cloud` is an absent-or-boolean flag, compared with `=== false`.
|
|
196
|
-
noCloud: actionCommand.optsWithGlobals().cloud === false,
|
|
197
|
-
logger,
|
|
198
|
-
ui: { version, update },
|
|
199
|
-
});
|
|
200
|
-
enterScope(scope);
|
|
201
|
-
// Phase 3 hygiene: scope entry via ALS (enterScope) is now the single source of truth
|
|
202
|
-
// for per-run state. No holder mirror or mark dance. All subsequent readers (including
|
|
203
|
-
// host command bodies) must see a valid currentScope().
|
|
204
|
-
if (!currentScope()) {
|
|
205
|
-
throw new SystemError('Scope was not entered before command dispatch', {
|
|
206
|
-
code: 'SYSTEM.SCOPE.NOT_ENTERED',
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
// Lifecycle diagnostics (§5.10): record key construction facts on the per-run bus.
|
|
210
|
-
// These (plus the per-domain events emitted from loadCapabilityDomain and the
|
|
211
|
-
// wiring events from buildPerRunScope) ride on every CommandOutcome so --json
|
|
212
|
-
// consumers see the full uniform lifecycle (tools loaded, subscopes contributed,
|
|
213
|
-
// capability domains wired + driven, config validated, etc.). This directly
|
|
214
|
-
// improves observability of the blast-radius bootstrap paths (architecture review).
|
|
215
|
-
scope.diagnostics.event('load', 'debug', `${tools.list().length} tool(s) loaded`);
|
|
216
|
-
scope.diagnostics.counter('tools.loaded', tools.list().length);
|
|
217
|
-
// Phase 2 metrics (low cardinality)
|
|
218
|
-
getMeter('opensip-cli').createCounter('opensip_cli.commands.started').add(1, {
|
|
219
|
-
command: actionCommand.name(),
|
|
220
|
-
});
|
|
221
|
-
scope.diagnostics.event('validate', 'debug', `project config resolved (scope: ${project.scope})`);
|
|
222
|
-
// The `ℹ Project:` location line is rendered once, under the banner,
|
|
223
|
-
// by cli-ui's ProjectHeader — mounted by the App shell (static
|
|
224
|
-
// commands, via render.ts reading currentScope().project) and by each
|
|
225
|
-
// live view (fit/graph). No imperative pre-action print.
|
|
226
|
-
// Structured start log.
|
|
227
|
-
logger.info({
|
|
228
|
-
evt: 'cli.run.start',
|
|
229
|
-
module: MODULE_TAG,
|
|
22
|
+
cwdExplicit,
|
|
230
23
|
runId,
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
scope: project.scope,
|
|
24
|
+
commandName: actionCommand.name(),
|
|
25
|
+
explicitConfigPath: opts.config,
|
|
26
|
+
tools: runtime.tools,
|
|
235
27
|
});
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
walkedUp: project.walkedUp,
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
// Optional profiling (Phase 3, severable). Start after scope (runId available).
|
|
247
|
-
// Respects the dual-gate (OPENSIP_PROFILING + OTEL) or OTEL-only fallback.
|
|
248
|
-
startProfiling(scope, actionCommand.name());
|
|
249
|
-
// 8. Lazy, memoized Tool.initialize() — runs the owning tool's
|
|
250
|
-
// optional one-time init here, AFTER enterScope (so eager setup that
|
|
251
|
-
// registers packs / reads currentScope() sees the bound scope) and
|
|
252
|
-
// immediately before Commander invokes the action body. See the
|
|
253
|
-
// helper for the once-per-process + fail-fast semantics.
|
|
254
|
-
await maybeInitializeOwningTool(tools, actionCommand.name(), runId);
|
|
255
|
-
// 9. §5.3/§4.5: drive the generic capability loader for the invoked tool's
|
|
256
|
-
// declared domains (e.g. graph-adapter). Lazy per command — only the
|
|
257
|
-
// owning tool's domains load, routed through the host's capability
|
|
258
|
-
// registry to each owner's registrar. Replaces the host-coupled,
|
|
259
|
-
// eager register-graph-adapters.ts.
|
|
260
|
-
const driven = await loadOwningToolCapabilities({
|
|
261
|
-
owningTool: resolveOwningTool(tools, actionCommand.name()),
|
|
262
|
-
projectDir: project.projectRoot,
|
|
263
|
-
configPath: project.scope === 'project' ? project.configPath : undefined,
|
|
28
|
+
const { scope } = await executePostBailoutBootstrap({
|
|
29
|
+
plan,
|
|
30
|
+
runtime,
|
|
31
|
+
version,
|
|
32
|
+
// @fitness-ignore-next-line null-safety -- Commander optsWithGlobals always returns OptionValues; `.cloud` is absent-or-boolean.
|
|
33
|
+
noCloud: actionCommand.optsWithGlobals().cloud === false,
|
|
34
|
+
apiKey: opts.apiKey,
|
|
264
35
|
});
|
|
265
|
-
|
|
266
|
-
scope.diagnostics.event('load', 'debug', `drove ${String(driven)} owning-tool capability domain(s) (see per-domain 'capability ... loaded' events for contribution counts + errors)`);
|
|
267
|
-
scope.diagnostics.counter('capabilities.driven', driven);
|
|
268
|
-
}
|
|
36
|
+
scope.diagnostics.event('load', 'debug', `preAction bootstrap completed for '${actionCommand.name()}'`);
|
|
269
37
|
});
|
|
270
|
-
// Resilience: best-effort release of per-run resources (parseCache, recipe config slot,
|
|
271
|
-
// contributed sub-scopes, diagnostics bus) after the action body completes for every
|
|
272
|
-
// command. Complements the narrow dispose() impl and the current lack of finally in
|
|
273
|
-
// many paths. postAction fires for normal completion; error paths are covered by
|
|
274
|
-
// handleParseError + handleFatalBootstrapError (which may also dispose in future passes).
|
|
275
|
-
// Idempotent: dispose is cheap and safe to call more than once.
|
|
276
38
|
program.hook('postAction', disposeCurrentScope);
|
|
277
39
|
}
|
|
278
|
-
/**
|
|
279
|
-
* Extracted seam (Task 3) for postAction disposal + error-path coverage.
|
|
280
|
-
* Narrow, testable, no Commander dep. Called from the hook; can be called
|
|
281
|
-
* explicitly in tests or future finally blocks on thrown handler paths.
|
|
282
|
-
*/
|
|
283
40
|
export function disposeCurrentScope() {
|
|
284
41
|
try {
|
|
285
42
|
const s = currentScope();
|
|
@@ -291,5 +48,4 @@ export function disposeCurrentScope() {
|
|
|
291
48
|
// @swallow-ok dispose errors on shutdown; the run has already produced its outcome.
|
|
292
49
|
}
|
|
293
50
|
}
|
|
294
|
-
/* eslint-enable sonarjs/cognitive-complexity */
|
|
295
51
|
//# sourceMappingURL=pre-action-hook.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pre-action-hook.js","sourceRoot":"","sources":["../../src/bootstrap/pre-action-hook.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"pre-action-hook.js","sourceRoot":"","sources":["../../src/bootstrap/pre-action-hook.ts"],"names":[],"mappings":"AAAA,qOAAqO;AACrO;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAKxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG1D,MAAM,UAAU,oBAAoB,CAClC,OAAgB,EAChB,OAAe,EACf,OAAyB;IAEzB,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,EAAE;QAC9D,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;QAClC,MAAM,GAAG,GAAI,IAAI,CAAC,GAAc,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAClD,MAAM,WAAW,GAAG,aAAa,CAAC,oBAAoB,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC;QAExE,MAAM,IAAI,GAAG,sBAAsB,CAAC;YAClC,IAAI,EAAE,IAAI;YACV,GAAG;YACH,WAAW;YACX,KAAK;YACL,WAAW,EAAE,aAAa,CAAC,IAAI,EAAE;YACjC,kBAAkB,EAAE,IAAI,CAAC,MAA4B;YACrD,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAC;QAEH,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,2BAA2B,CAAC;YAClD,IAAI;YACJ,OAAO;YACP,OAAO;YACP,iIAAiI;YACjI,OAAO,EAAE,aAAa,CAAC,eAAe,EAAE,CAAC,KAAK,KAAK,KAAK;YACxD,MAAM,EAAE,IAAI,CAAC,MAA4B;SAC1C,CAAC,CAAC;QACH,KAAK,CAAC,WAAW,CAAC,KAAK,CACrB,MAAM,EACN,OAAO,EACP,sCAAsC,aAAa,CAAC,IAAI,EAAE,GAAG,CAC9D,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;YACzC,CAAC,CAAC,OAAO,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oFAAoF;IACtF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LanguageRegistry, ToolPluginManifest, ToolProvenance, ToolRegistry } from '@opensip-cli/core';
|
|
2
|
+
/** Per-invocation bootstrap inputs captured in the pre-action hook closure. */
|
|
3
|
+
export interface PreActionRuntime {
|
|
4
|
+
readonly languages: LanguageRegistry;
|
|
5
|
+
readonly tools: ToolRegistry;
|
|
6
|
+
readonly manifests: readonly ToolPluginManifest[];
|
|
7
|
+
readonly provenance: readonly ToolProvenance[];
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=pre-action-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-action-runtime.d.ts","sourceRoot":"","sources":["../../src/bootstrap/pre-action-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,YAAY,EACb,MAAM,mBAAmB,CAAC;AAE3B,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;CAChD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-action-runtime.js","sourceRoot":"","sources":["../../src/bootstrap/pre-action-runtime.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type ToolPluginManifest, type ToolProvenance, type ToolRegistry } from '@opensip-cli/core';
|
|
2
|
+
/**
|
|
3
|
+
* Register the bundled first-party tools into the supplied registry, each one
|
|
4
|
+
* flowing through the SAME admit → dynamic-import → register path the external
|
|
5
|
+
* path uses (launch cutover — replaces the static-import + gate path).
|
|
6
|
+
*
|
|
7
|
+
* Per package name: `resolveBundledPackageDir` → `loadToolManifest('bundled')`
|
|
8
|
+
* → `admitTool({ source: 'bundled', explicitlyRequested: true })` →
|
|
9
|
+
* `importToolRuntime` (dynamic import + shape validation) → drift guard →
|
|
10
|
+
* `registry.register`. A bundled tool ships with the CLI, so it is always
|
|
11
|
+
* explicitly present: a missing/incompatible manifest or a runtime that fails
|
|
12
|
+
* to load is FAIL-CLOSED (never a silent skip). The recorded `ToolProvenance`
|
|
13
|
+
* (source `'bundled'`, trusted-by-shipping) and manifest are pushed onto the
|
|
14
|
+
* optional collectors so the composition root can surface provenance
|
|
15
|
+
* (`plugin list`) and seed the per-run capability registry (§5.3).
|
|
16
|
+
*
|
|
17
|
+
* @param registry The per-invocation tool registry to populate.
|
|
18
|
+
* @param provenance Optional sink for the admitted tools' provenance records.
|
|
19
|
+
* @param manifests Optional sink for the admitted tools' manifests (§5.3).
|
|
20
|
+
* @param packages The bundled package names to load (defaults to
|
|
21
|
+
* {@link BUNDLED_TOOL_PACKAGES}; injectable so the fail-closed paths are
|
|
22
|
+
* testable with fixture packages).
|
|
23
|
+
* @throws {PluginIncompatibleError} when a bundled tool cannot be resolved,
|
|
24
|
+
* has no conformant manifest, is out of range, or its runtime fails to load
|
|
25
|
+
* — mapped to `EXIT_CODES.PLUGIN_INCOMPATIBLE` (exit 5) by the CLI boundary.
|
|
26
|
+
*/
|
|
27
|
+
export declare function registerFirstPartyTools(registry: ToolRegistry, provenance?: ToolProvenance[], manifests?: ToolPluginManifest[], packages?: readonly string[]): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=register-tools-bundled.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-tools-bundled.d.ts","sourceRoot":"","sources":["../../src/bootstrap/register-tools-bundled.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAc3B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,YAAY,EACtB,UAAU,GAAE,cAAc,EAAO,EACjC,SAAS,GAAE,kBAAkB,EAAO,EACpC,QAAQ,GAAE,SAAS,MAAM,EAA0B,GAClD,OAAO,CAAC,IAAI,CAAC,CAwCf"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { PluginIncompatibleError, } from '@opensip-cli/core';
|
|
2
|
+
import { admitToolPackage } from './admit-tool-package.js';
|
|
3
|
+
import { BUNDLED_TOOL_PACKAGES, resolveRequiredBundledPackageDir, } from './register-tools-shared.js';
|
|
4
|
+
// The runtime-load primitive (`importToolRuntime` + `ToolRuntimeLoad`) and the
|
|
5
|
+
// full admission SEQUENCE (`admitToolPackage`) live in `admit-tool-package.ts`
|
|
6
|
+
// (ADR-0041: one validator, four consumers). This file keeps the per-source
|
|
7
|
+
// POLICY: bundled fails closed below; the installed/authored legs skip with
|
|
8
|
+
// diagnostics.
|
|
9
|
+
/**
|
|
10
|
+
* Register the bundled first-party tools into the supplied registry, each one
|
|
11
|
+
* flowing through the SAME admit → dynamic-import → register path the external
|
|
12
|
+
* path uses (launch cutover — replaces the static-import + gate path).
|
|
13
|
+
*
|
|
14
|
+
* Per package name: `resolveBundledPackageDir` → `loadToolManifest('bundled')`
|
|
15
|
+
* → `admitTool({ source: 'bundled', explicitlyRequested: true })` →
|
|
16
|
+
* `importToolRuntime` (dynamic import + shape validation) → drift guard →
|
|
17
|
+
* `registry.register`. A bundled tool ships with the CLI, so it is always
|
|
18
|
+
* explicitly present: a missing/incompatible manifest or a runtime that fails
|
|
19
|
+
* to load is FAIL-CLOSED (never a silent skip). The recorded `ToolProvenance`
|
|
20
|
+
* (source `'bundled'`, trusted-by-shipping) and manifest are pushed onto the
|
|
21
|
+
* optional collectors so the composition root can surface provenance
|
|
22
|
+
* (`plugin list`) and seed the per-run capability registry (§5.3).
|
|
23
|
+
*
|
|
24
|
+
* @param registry The per-invocation tool registry to populate.
|
|
25
|
+
* @param provenance Optional sink for the admitted tools' provenance records.
|
|
26
|
+
* @param manifests Optional sink for the admitted tools' manifests (§5.3).
|
|
27
|
+
* @param packages The bundled package names to load (defaults to
|
|
28
|
+
* {@link BUNDLED_TOOL_PACKAGES}; injectable so the fail-closed paths are
|
|
29
|
+
* testable with fixture packages).
|
|
30
|
+
* @throws {PluginIncompatibleError} when a bundled tool cannot be resolved,
|
|
31
|
+
* has no conformant manifest, is out of range, or its runtime fails to load
|
|
32
|
+
* — mapped to `EXIT_CODES.PLUGIN_INCOMPATIBLE` (exit 5) by the CLI boundary.
|
|
33
|
+
*/
|
|
34
|
+
export async function registerFirstPartyTools(registry, provenance = [], manifests = [], packages = BUNDLED_TOOL_PACKAGES) {
|
|
35
|
+
for (const packageName of packages) {
|
|
36
|
+
const dir = resolveRequiredBundledPackageDir(packageName);
|
|
37
|
+
// The shared admission SEQUENCE (ADR-0041). The bundled POLICY below maps
|
|
38
|
+
// each failed section to the exact fail-closed error this path always
|
|
39
|
+
// threw — a bundled tool ships with the CLI, so every failure is a
|
|
40
|
+
// packaging fault, never a silent skip.
|
|
41
|
+
const report = await admitToolPackage({
|
|
42
|
+
dir,
|
|
43
|
+
source: 'bundled',
|
|
44
|
+
packageName,
|
|
45
|
+
// A bundled tool ships with the CLI; it is always explicitly present,
|
|
46
|
+
// so an incompatible manifest fails the run rather than skipping.
|
|
47
|
+
explicitlyRequested: true,
|
|
48
|
+
});
|
|
49
|
+
if (!report.ok) {
|
|
50
|
+
// @fitness-ignore-next-line detached-promises -- synchronous never-returning thrower; the heuristic mistakes the bare call for an unawaited promise
|
|
51
|
+
throwBundledAdmissionFailure(packageName, report);
|
|
52
|
+
}
|
|
53
|
+
/* v8 ignore next 3 -- throwBundledAdmissionFailure never returns on a failed report; this guard narrows types */
|
|
54
|
+
if (report.tool === undefined ||
|
|
55
|
+
report.provenance === undefined ||
|
|
56
|
+
report.manifest === undefined) {
|
|
57
|
+
throw new PluginIncompatibleError(`bundled tool '${packageName}' produced an incomplete admission report`, { diagnostic: 'incomplete admission report' });
|
|
58
|
+
}
|
|
59
|
+
registry.register(report.tool);
|
|
60
|
+
provenance.push(report.provenance);
|
|
61
|
+
// Record the manifest so the pre-action-hook can register this tool's
|
|
62
|
+
// declared capability domains into the per-run capability registry
|
|
63
|
+
// (launch, §5.3).
|
|
64
|
+
manifests.push(report.manifest);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The bundled FAIL-CLOSED policy: convert a failed {@link AdmissionReport}
|
|
69
|
+
* into the same `PluginIncompatibleError` (message + diagnostic) the inline
|
|
70
|
+
* pipeline threw before the ADR-0041 factoring. Never returns.
|
|
71
|
+
*
|
|
72
|
+
* @throws {PluginIncompatibleError} always (or rethrows the original
|
|
73
|
+
* coherence error from `assertManifestMatchesTool`, preserving its type).
|
|
74
|
+
*/
|
|
75
|
+
function throwBundledAdmissionFailure(packageName, report) {
|
|
76
|
+
const failed = report.sections.find((s) => !s.ok);
|
|
77
|
+
const failedSection = failed?.section;
|
|
78
|
+
if (failedSection === 'manifest') {
|
|
79
|
+
throw new PluginIncompatibleError(`bundled tool '${packageName}' has no conformant package.json#opensipTools manifest`, { diagnostic: 'manifest missing or malformed' });
|
|
80
|
+
}
|
|
81
|
+
const id = report.manifest?.id ?? packageName;
|
|
82
|
+
if (failedSection === 'compatibility') {
|
|
83
|
+
if (report.compatibilityDecision === 'fail-closed') {
|
|
84
|
+
throw new PluginIncompatibleError(`bundled tool '${id}' is incompatible: ${failed?.diagnostic ?? 'compatibility gate rejected it'}`, { diagnostic: failed?.diagnostic });
|
|
85
|
+
}
|
|
86
|
+
if (report.compatibilityDecision === 'skip') {
|
|
87
|
+
// Should not happen for an in-range bundled tool, but never silently
|
|
88
|
+
// drop a bundled tool — surface it loudly.
|
|
89
|
+
throw new PluginIncompatibleError(`bundled tool '${id}' was skipped by the compatibility gate: ${failed?.diagnostic ?? 'unknown reason'}`, { diagnostic: failed?.diagnostic });
|
|
90
|
+
}
|
|
91
|
+
throw new PluginIncompatibleError(`bundled tool '${id}' reached an unknown admission decision`, { diagnostic: 'unknown admission decision' });
|
|
92
|
+
}
|
|
93
|
+
if (failedSection === 'runtime-load' || failedSection === 'tool-shape') {
|
|
94
|
+
const reason = report.runtimeLoadReason ?? 'import-failed';
|
|
95
|
+
const detailSuffix = report.runtimeLoadDetail ? `: ${report.runtimeLoadDetail}` : '';
|
|
96
|
+
throw new PluginIncompatibleError(`bundled tool '${id}' failed to load via the plugin path (${reason}${detailSuffix})`, { diagnostic: `bundled tool runtime load failed: ${reason}` });
|
|
97
|
+
}
|
|
98
|
+
if (failedSection === 'manifest-runtime-coherence' && report.coherenceError instanceof Error) {
|
|
99
|
+
// Preserve the original drift-guard error type + message untouched.
|
|
100
|
+
// (assertManifestMatchesTool always throws Error subclasses; the
|
|
101
|
+
// instanceof narrowing satisfies only-throw-error without a cast.)
|
|
102
|
+
throw report.coherenceError;
|
|
103
|
+
}
|
|
104
|
+
/* v8 ignore next 4 -- defensive: a failed report always carries a failed section */
|
|
105
|
+
throw new PluginIncompatibleError(`bundled tool '${packageName}' failed admission for an unknown reason`, { diagnostic: 'unknown admission failure' });
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=register-tools-bundled.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-tools-bundled.js","sourceRoot":"","sources":["../../src/bootstrap/register-tools-bundled.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,GAIxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAwB,MAAM,yBAAyB,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,gCAAgC,GACjC,MAAM,4BAA4B,CAAC;AAEpC,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAC5E,4EAA4E;AAC5E,eAAe;AAEf;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,QAAsB,EACtB,aAA+B,EAAE,EACjC,YAAkC,EAAE,EACpC,WAA8B,qBAAqB;IAEnD,KAAK,MAAM,WAAW,IAAI,QAAQ,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,gCAAgC,CAAC,WAAW,CAAC,CAAC;QAE1D,0EAA0E;QAC1E,sEAAsE;QACtE,mEAAmE;QACnE,wCAAwC;QACxC,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC;YACpC,GAAG;YACH,MAAM,EAAE,SAAS;YACjB,WAAW;YACX,sEAAsE;YACtE,kEAAkE;YAClE,mBAAmB,EAAE,IAAI;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,oJAAoJ;YACpJ,4BAA4B,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACpD,CAAC;QACD,iHAAiH;QACjH,IACE,MAAM,CAAC,IAAI,KAAK,SAAS;YACzB,MAAM,CAAC,UAAU,KAAK,SAAS;YAC/B,MAAM,CAAC,QAAQ,KAAK,SAAS,EAC7B,CAAC;YACD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,WAAW,2CAA2C,EACvE,EAAE,UAAU,EAAE,6BAA6B,EAAE,CAC9C,CAAC;QACJ,CAAC;QAED,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC/B,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACnC,sEAAsE;QACtE,mEAAmE;QACnE,kBAAkB;QAClB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,4BAA4B,CAAC,WAAmB,EAAE,MAAuB;IAChF,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,MAAM,EAAE,OAAO,CAAC;IAEtC,IAAI,aAAa,KAAK,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,WAAW,wDAAwD,EACpF,EAAE,UAAU,EAAE,+BAA+B,EAAE,CAChD,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,EAAE,IAAI,WAAW,CAAC;IAC9C,IAAI,aAAa,KAAK,eAAe,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,qBAAqB,KAAK,aAAa,EAAE,CAAC;YACnD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EAAE,sBAAsB,MAAM,EAAE,UAAU,IAAI,gCAAgC,EAAE,EACjG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,CACnC,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,qBAAqB,KAAK,MAAM,EAAE,CAAC;YAC5C,qEAAqE;YACrE,2CAA2C;YAC3C,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EAAE,4CAA4C,MAAM,EAAE,UAAU,IAAI,gBAAgB,EAAE,EACvG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,CACnC,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EAAE,yCAAyC,EAC5D,EAAE,UAAU,EAAE,4BAA4B,EAAE,CAC7C,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,KAAK,cAAc,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;QACvE,MAAM,MAAM,GAAG,MAAM,CAAC,iBAAiB,IAAI,eAAe,CAAC;QAC3D,MAAM,YAAY,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EAAE,yCAAyC,MAAM,GAAG,YAAY,GAAG,EACpF,EAAE,UAAU,EAAE,qCAAqC,MAAM,EAAE,EAAE,CAC9D,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,KAAK,4BAA4B,IAAI,MAAM,CAAC,cAAc,YAAY,KAAK,EAAE,CAAC;QAC7F,oEAAoE;QACpE,iEAAiE;QACjE,mEAAmE;QACnE,MAAM,MAAM,CAAC,cAAc,CAAC;IAC9B,CAAC;IACD,oFAAoF;IACpF,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,WAAW,0CAA0C,EACtE,EAAE,UAAU,EAAE,2BAA2B,EAAE,CAC5C,CAAC;AACJ,CAAC"}
|