opensip-cli 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/bootstrap/bind-tool-context.d.ts +16 -0
  2. package/dist/bootstrap/bind-tool-context.d.ts.map +1 -0
  3. package/dist/bootstrap/bind-tool-context.js +160 -0
  4. package/dist/bootstrap/bind-tool-context.js.map +1 -0
  5. package/dist/bootstrap/build-per-run-scope.d.ts.map +1 -1
  6. package/dist/bootstrap/build-per-run-scope.js +35 -2
  7. package/dist/bootstrap/build-per-run-scope.js.map +1 -1
  8. package/dist/bootstrap/execute-post-bailout-bootstrap.d.ts +45 -0
  9. package/dist/bootstrap/execute-post-bailout-bootstrap.d.ts.map +1 -0
  10. package/dist/bootstrap/execute-post-bailout-bootstrap.js +108 -0
  11. package/dist/bootstrap/execute-post-bailout-bootstrap.js.map +1 -0
  12. package/dist/bootstrap/plan-pre-action-bootstrap.d.ts +45 -0
  13. package/dist/bootstrap/plan-pre-action-bootstrap.d.ts.map +1 -0
  14. package/dist/bootstrap/plan-pre-action-bootstrap.js +86 -0
  15. package/dist/bootstrap/plan-pre-action-bootstrap.js.map +1 -0
  16. package/dist/bootstrap/pre-action-bootstrap-phases.d.ts +20 -0
  17. package/dist/bootstrap/pre-action-bootstrap-phases.d.ts.map +1 -0
  18. package/dist/bootstrap/pre-action-bootstrap-phases.js +25 -0
  19. package/dist/bootstrap/pre-action-bootstrap-phases.js.map +1 -0
  20. package/dist/bootstrap/pre-action-hook.d.ts +6 -66
  21. package/dist/bootstrap/pre-action-hook.d.ts.map +1 -1
  22. package/dist/bootstrap/pre-action-hook.js +22 -266
  23. package/dist/bootstrap/pre-action-hook.js.map +1 -1
  24. package/dist/bootstrap/pre-action-runtime.d.ts +9 -0
  25. package/dist/bootstrap/pre-action-runtime.d.ts.map +1 -0
  26. package/dist/bootstrap/pre-action-runtime.js +2 -0
  27. package/dist/bootstrap/pre-action-runtime.js.map +1 -0
  28. package/dist/bootstrap/register-tools-bundled.d.ts +28 -0
  29. package/dist/bootstrap/register-tools-bundled.d.ts.map +1 -0
  30. package/dist/bootstrap/register-tools-bundled.js +107 -0
  31. package/dist/bootstrap/register-tools-bundled.js.map +1 -0
  32. package/dist/bootstrap/register-tools-discovery.d.ts +154 -0
  33. package/dist/bootstrap/register-tools-discovery.d.ts.map +1 -0
  34. package/dist/bootstrap/register-tools-discovery.js +385 -0
  35. package/dist/bootstrap/register-tools-discovery.js.map +1 -0
  36. package/dist/bootstrap/register-tools-mount.d.ts +25 -0
  37. package/dist/bootstrap/register-tools-mount.d.ts.map +1 -0
  38. package/dist/bootstrap/register-tools-mount.js +91 -0
  39. package/dist/bootstrap/register-tools-mount.js.map +1 -0
  40. package/dist/bootstrap/register-tools-shared.d.ts +40 -0
  41. package/dist/bootstrap/register-tools-shared.d.ts.map +1 -0
  42. package/dist/bootstrap/register-tools-shared.js +98 -0
  43. package/dist/bootstrap/register-tools-shared.js.map +1 -0
  44. package/dist/bootstrap/register-tools.d.ts +4 -196
  45. package/dist/bootstrap/register-tools.d.ts.map +1 -1
  46. package/dist/bootstrap/register-tools.js +4 -668
  47. package/dist/bootstrap/register-tools.js.map +1 -1
  48. package/dist/commands/mount-command-spec.d.ts +2 -1
  49. package/dist/commands/mount-command-spec.d.ts.map +1 -1
  50. package/dist/commands/mount-command-spec.js +3 -6
  51. package/dist/commands/mount-command-spec.js.map +1 -1
  52. package/dist/env/host-env-specs.d.ts +4 -3
  53. package/dist/env/host-env-specs.d.ts.map +1 -1
  54. package/dist/env/host-env-specs.js +8 -3
  55. package/dist/env/host-env-specs.js.map +1 -1
  56. 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` body.
2
+ * pre-action-hook — Commander `preAction` adapter (ADR-0052).
3
3
  *
4
- * Runs before every subcommand's action. Centralises run-id generation,
5
- * config-merge, project-context resolution, schema-version bailout, and
6
- * (only when the run will proceed) log file initialisation. Datastore is
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 { type LanguageRegistry, type ToolPluginManifest, type ToolProvenance, type ToolRegistry } from '@opensip-cli/core';
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;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,EASL,KAAK,gBAAgB,EAErB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAiB3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;GAMG;AAEH;;;;;;;;;GASG;AACH,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;AAED;;;;;;;;;;;;GAYG;AAUH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,gBAAgB,GACxB,IAAI,CA4ON;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAS1C"}
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 invokes synchronous bootstrap helpers (mergeConfigDefaults, configureLogger, the checkSchemaVersion/checkNoProject/warnAboutPhantom bailout guards, enterScope) that the name-based heuristic mistakes for promise-returning calls. The one genuine async call (maybeInitializeOwningTool) is awaited. Matches the same suppression on index.ts and bootstrap/index.ts.
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` body.
3
+ * pre-action-hook — Commander `preAction` adapter (ADR-0052).
4
4
  *
5
- * Runs before every subcommand's action. Centralises run-id generation,
6
- * config-merge, project-context resolution, schema-version bailout, and
7
- * (only when the run will proceed) log file initialisation. Datastore is
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 { existsSync } from 'node:fs';
30
- import { configureLogger, currentScope, enterScope, generatePrefixedId, logger, resolveProjectContext, resolveProjectPaths, SystemError, } from '@opensip-cli/core';
31
- import { getMeter } from '@opensip-cli/core';
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
- // Keep the loaded defaults around: `mergeConfigDefaults` only copies the
77
- // flag-shaped fields onto opts, but `ui.banner` has no flag — we read it
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
- cliDefaults,
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
- command: actionCommand.name(),
232
- cwd,
233
- projectRoot: project.projectRoot,
234
- scope: project.scope,
24
+ commandName: actionCommand.name(),
25
+ explicitConfigPath: opts.config,
26
+ tools: runtime.tools,
235
27
  });
236
- if (project.walkedUp > 0) {
237
- logger.info({
238
- evt: 'cli.project.discovered',
239
- module: MODULE_TAG,
240
- runId,
241
- cwd,
242
- projectRoot: project.projectRoot,
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
- if (driven > 0) {
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":"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"}
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pre-action-runtime.js.map
@@ -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":"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"}