@sensigo/realm-cli 0.40.0 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/agent/providers/agent-utils.d.ts +37 -13
  2. package/dist/agent/providers/agent-utils.d.ts.map +1 -1
  3. package/dist/agent/providers/agent-utils.js +92 -17
  4. package/dist/agent/providers/agent-utils.js.map +1 -1
  5. package/dist/agent/run-attach.d.ts.map +1 -1
  6. package/dist/agent/run-attach.js +8 -21
  7. package/dist/agent/run-attach.js.map +1 -1
  8. package/dist/commands/agent.d.ts +6 -0
  9. package/dist/commands/agent.d.ts.map +1 -1
  10. package/dist/commands/agent.js +28 -4
  11. package/dist/commands/agent.js.map +1 -1
  12. package/dist/commands/drain.d.ts.map +1 -1
  13. package/dist/commands/drain.js +60 -9
  14. package/dist/commands/drain.js.map +1 -1
  15. package/dist/commands/inspect.d.ts.map +1 -1
  16. package/dist/commands/inspect.js +20 -2
  17. package/dist/commands/inspect.js.map +1 -1
  18. package/dist/commands/list.d.ts.map +1 -1
  19. package/dist/commands/list.js +61 -8
  20. package/dist/commands/list.js.map +1 -1
  21. package/dist/commands/listen.d.ts +13 -0
  22. package/dist/commands/listen.d.ts.map +1 -1
  23. package/dist/commands/listen.js +36 -4
  24. package/dist/commands/listen.js.map +1 -1
  25. package/dist/commands/register.d.ts +1 -14
  26. package/dist/commands/register.d.ts.map +1 -1
  27. package/dist/commands/register.js +52 -56
  28. package/dist/commands/register.js.map +1 -1
  29. package/dist/commands/replay.d.ts.map +1 -1
  30. package/dist/commands/replay.js +4 -2
  31. package/dist/commands/replay.js.map +1 -1
  32. package/dist/commands/respond.d.ts.map +1 -1
  33. package/dist/commands/respond.js +30 -3
  34. package/dist/commands/respond.js.map +1 -1
  35. package/dist/commands/resume.d.ts.map +1 -1
  36. package/dist/commands/resume.js +3 -2
  37. package/dist/commands/resume.js.map +1 -1
  38. package/dist/commands/run.d.ts +35 -0
  39. package/dist/commands/run.d.ts.map +1 -1
  40. package/dist/commands/run.js +246 -12
  41. package/dist/commands/run.js.map +1 -1
  42. package/dist/commands/test.d.ts.map +1 -1
  43. package/dist/commands/test.js +51 -8
  44. package/dist/commands/test.js.map +1 -1
  45. package/dist/commands/validate.d.ts +31 -0
  46. package/dist/commands/validate.d.ts.map +1 -1
  47. package/dist/commands/validate.js +658 -132
  48. package/dist/commands/validate.js.map +1 -1
  49. package/dist/commands/watch.d.ts +43 -1
  50. package/dist/commands/watch.d.ts.map +1 -1
  51. package/dist/commands/watch.js +366 -42
  52. package/dist/commands/watch.js.map +1 -1
  53. package/dist/commands/workflow-list.d.ts +16 -0
  54. package/dist/commands/workflow-list.d.ts.map +1 -0
  55. package/dist/commands/workflow-list.js +96 -0
  56. package/dist/commands/workflow-list.js.map +1 -0
  57. package/dist/commands-registry.d.ts.map +1 -1
  58. package/dist/commands-registry.js +2 -0
  59. package/dist/commands-registry.js.map +1 -1
  60. package/dist/extensions/load-project-extensions.d.ts.map +1 -1
  61. package/dist/extensions/load-project-extensions.js +9 -3
  62. package/dist/extensions/load-project-extensions.js.map +1 -1
  63. package/dist/index.js +22 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/lib/admission-context.d.ts +58 -0
  66. package/dist/lib/admission-context.d.ts.map +1 -0
  67. package/dist/lib/admission-context.js +57 -0
  68. package/dist/lib/admission-context.js.map +1 -0
  69. package/dist/lib/load-workflow-for-admission.d.ts +69 -0
  70. package/dist/lib/load-workflow-for-admission.d.ts.map +1 -0
  71. package/dist/lib/load-workflow-for-admission.js +130 -0
  72. package/dist/lib/load-workflow-for-admission.js.map +1 -0
  73. package/dist/lib/loader-warnings.d.ts +28 -10
  74. package/dist/lib/loader-warnings.d.ts.map +1 -1
  75. package/dist/lib/loader-warnings.js +84 -30
  76. package/dist/lib/loader-warnings.js.map +1 -1
  77. package/package.json +4 -4
@@ -0,0 +1,130 @@
1
+ // The ONE admission path (issue #553): what `validate` blesses, `register` accepts, and what
2
+ // `register` refuses, `validate` refuses — by construction, because both (and `watch`) call
3
+ // this function and nothing else. Relocated from register.ts, where validate could not import
4
+ // it without a cycle.
5
+ import { loadWorkflowFromFileWithDiagnostics, } from '@sensigo/realm';
6
+ import { loadProjectExtensions, } from '../extensions/load-project-extensions.js';
7
+ import { ManifestSecretsError } from '../extensions/manifest-secrets.js';
8
+ import { wrapSentinelWarnings } from './loader-warnings.js';
9
+ /**
10
+ * Tags a failure thrown by the extensions load inside `loadWorkflowForAdmission` so the
11
+ * callers' catches can say `Error loading extensions:` — the sentence run and validate already
12
+ * print for this class (issue #451) — without guessing from the message. The message is the
13
+ * original's, byte for byte (register-extensions.test.ts's broken-module cell matches on it
14
+ * THROUGH this wrapper), and the original rides along as `cause`.
15
+ *
16
+ * Minted at exactly the two throw paths out of the extensions block: the real-mode load's
17
+ * non-secrets failure, and the sentinel retry. The retry can never throw ManifestSecretsError
18
+ * itself (sentinel mode resolves every name without reading a source), so nothing is wrapped
19
+ * twice. A WorkflowError from the two-pass re-validation is thrown OUTSIDE the block and keeps
20
+ * the family split.
21
+ *
22
+ * Carries the workflow's own pass-1 loader warnings (issue #463 — the #424 carry shape on this
23
+ * vehicle) so the catch that renders the sentence can print them FIRST, instead of the author
24
+ * fixing the module, re-running, and only then learning about the typo. ABSENT, never `[]`: a
25
+ * construction that passes no warnings, or an empty list, leaves the field unset.
26
+ *
27
+ * Carries the pass-1 definition too (issue #553): validate's `--json` names `workflow_id` on
28
+ * this arm and computes the retry advisory from the definition before printing the sentence.
29
+ *
30
+ * @internal Exported for register.ts, watch.ts, validate.ts and for tests.
31
+ */
32
+ export class ExtensionLoadError extends Error {
33
+ warnings;
34
+ definition;
35
+ constructor(original, warnings, definition) {
36
+ super(original instanceof Error ? original.message : String(original), { cause: original });
37
+ this.name = 'ExtensionLoadError';
38
+ // The if-guard form on purpose: a ternary to `undefined` is a TS2412 under the repo's
39
+ // exactOptionalPropertyTypes (lane-executed, #463).
40
+ if (warnings !== undefined && warnings.length > 0)
41
+ this.warnings = [...warnings];
42
+ if (definition !== undefined)
43
+ this.definition = definition;
44
+ }
45
+ }
46
+ /**
47
+ * The pass-1 definition of a workflow whose pass-2 (config_schema) re-validation threw. The
48
+ * thrown WorkflowError is register's and watch's to render exactly as before — its identity,
49
+ * message and family are untouched — so the definition rides beside it rather than on it.
50
+ * validate's `--json` reads it back for `workflow_id` (issue #553, audit round 2 Q9).
51
+ */
52
+ const admittedDefinitions = new WeakMap();
53
+ /** @internal Exported for validate.ts. */
54
+ export function admittedDefinitionOf(err) {
55
+ return typeof err === 'object' && err !== null ? admittedDefinitions.get(err) : undefined;
56
+ }
57
+ /**
58
+ * The project-extensions pass ALONE (issue #553 correction C2) — the real load, degrading to
59
+ * SENTINEL credentials with a loud, surface-keyed WARN pair when a secret source is unavailable,
60
+ * and the RAW error on any other failure (the caller decides how to wrap/report it; this function
61
+ * throws nothing `ExtensionLoadError`-shaped itself). This is the ONE mint site for "⚠ …with
62
+ * SENTINEL credentials — execution paths still require real secret resolution." — before this
63
+ * extraction it was minted here AND hand-typed a second time in `validate --registered`'s own
64
+ * extensions arm (the #444/#508 two-mints-of-one-string class); both callers now share it.
65
+ * `overrideModule` is `--extensions-module`: it must travel into BOTH loads (the real attempt and
66
+ * the sentinel retry) or a repair flag dies in its own retry (the #353/#466 flag-travel class).
67
+ */
68
+ export async function admitProjectExtensions(definition, opts) {
69
+ const override = opts.overrideModule !== undefined ? { overrideModule: opts.overrideModule } : {};
70
+ // Full module load + duck validation + manifest construction BEFORE persisting. Secret sources
71
+ // may be unavailable at provisioning time: degrade to SENTINEL construction with a loud WARN
72
+ // (never silent, never a registration blocker); execution paths still require real resolution.
73
+ try {
74
+ return await loadProjectExtensions(definition, { ...override });
75
+ }
76
+ catch (err) {
77
+ // The guard is the degradation itself: only a secrets failure degrades, everything else is
78
+ // the caller's to tag and report. Dropping the conditional kills degradation —
79
+ // register-extensions.test.ts's sentinel control is the cell in this command's own home that
80
+ // sees it (the manifest E2E in extensions/ does too, one substring deep).
81
+ if (!(err instanceof ManifestSecretsError))
82
+ throw err;
83
+ console.warn(`⚠ ${err.message}`);
84
+ // Surface-keyed (issue #553): validate registers nothing, so "Registering" there is a false
85
+ // claim; register and watch keep their text byte for byte.
86
+ console.warn(`⚠ ${opts.surface === 'validate' ? 'Validating' : 'Registering'} with SENTINEL credentials — execution paths still require real secret resolution.`);
87
+ return await loadProjectExtensions(definition, { ...override, secretMode: 'sentinel' });
88
+ }
89
+ }
90
+ /**
91
+ * Loads and validates a workflow for admission — register, watch and validate all take exactly
92
+ * this path (issue #553). The file loader (agent-profile resolution included), then the
93
+ * UNCONDITIONAL project-extensions load (modules, manifest, config_schema two-pass), degrading
94
+ * to SENTINEL credentials with a loud WARN when a secret source is unavailable.
95
+ * Returns the definition alongside every accumulated LoaderWarning (issue #169) — pass-1's
96
+ * structural warnings plus the sentinel-credential warnings, if any — and the resolved manifest
97
+ * (validate's `Extensions:` line reports its counts). Prints NOTHING itself beyond the two
98
+ * sentinel ⚠ lines; every caller decides how to surface/act on warnings (register supports
99
+ * `--strict` + the dormant #170 reject; watch just prints and continues; validate reports).
100
+ * @throws on any validation or extension-load failure — nothing is persisted on throw.
101
+ * Extension-load failures are tagged `ExtensionLoadError` (issue #451).
102
+ */
103
+ export async function loadWorkflowForAdmission(filePath, opts) {
104
+ const { definition, warnings: pass1Warnings } = loadWorkflowFromFileWithDiagnostics(filePath);
105
+ let loaded;
106
+ try {
107
+ loaded = await admitProjectExtensions(definition, opts);
108
+ }
109
+ catch (err) {
110
+ throw new ExtensionLoadError(err, pass1Warnings, definition);
111
+ }
112
+ // Two-pass: re-validate with the resolved registry so step config is checked against
113
+ // each adapter's config_schema before the definition is persisted. Its warnings are proven
114
+ // identical to pass-1's (same content, registry only adds config_schema checks) — discarded
115
+ // here to avoid double-counting the same unknown key twice.
116
+ try {
117
+ loadWorkflowFromFileWithDiagnostics(filePath, loaded.registry);
118
+ }
119
+ catch (err) {
120
+ if (typeof err === 'object' && err !== null)
121
+ admittedDefinitions.set(err, definition);
122
+ throw err;
123
+ }
124
+ return {
125
+ definition,
126
+ warnings: [...pass1Warnings, ...wrapSentinelWarnings(loaded.sentinelWarnings)],
127
+ manifest: loaded.manifest,
128
+ };
129
+ }
130
+ //# sourceMappingURL=load-workflow-for-admission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-workflow-for-admission.js","sourceRoot":"","sources":["../../src/lib/load-workflow-for-admission.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,11 @@
1
- import { type LoaderWarning, type WarningCode } from '@sensigo/realm';
1
+ import { type WorkflowError, type LoaderWarning, type WarningCode } from '@sensigo/realm';
2
2
  /**
3
- * Prints every warning via the single renderLoaderWarning format source, correcting the
4
- * "— ignored" claim for any warning this boundary will actually refuse.
5
- *
6
- * Resolved against DEFAULT_POLICY, which is the policy the boundary-reject itself uses. A warning
7
- * that only fails under `--strict` still renders "— ignored" — see the report's design note; the
8
- * `--strict` path prints its own "failing due to --strict" line, so the author is not left
9
- * without an explanation.
3
+ * Prints every warning via the single renderLoaderWarning format source no substitution (see
4
+ * the module header for why the former "— ignored" "— REFUSED below" rewrite was deleted,
5
+ * issue #540). The `DEFAULT_POLICY` import above stays: `rejectOnErrorSeverity` and
6
+ * `failsStrict`, both exported from this module, still resolve against it.
10
7
  */
11
- export declare function printLoaderWarnings(warnings: LoaderWarning[]): void;
8
+ export declare function printLoaderWarnings(warnings: readonly LoaderWarning[]): void;
12
9
  /**
13
10
  * The dormant issue #170 boundary-reject hook, factored ONCE so validate/register/watch can't
14
11
  * drift from each other: resolves every warning against `policy` (default DEFAULT_POLICY — inert
@@ -20,6 +17,17 @@ export declare function printLoaderWarnings(warnings: LoaderWarning[]): void;
20
17
  export declare function rejectOnErrorSeverity(warnings: LoaderWarning[], policy?: Record<WarningCode, 'warn' | 'error'>): boolean;
21
18
  /** True if `--strict` should fail the command given these accumulated warnings. */
22
19
  export declare function failsStrict(warnings: LoaderWarning[]): boolean;
20
+ /**
21
+ * Wraps loadProjectExtensions' sentinel-credential warnings as LoaderWarning (issue #169).
22
+ *
23
+ * ONE copy (issue #444): validate.ts and register.ts each carried a byte-identical private one,
24
+ * and both baked a two-space `⚠ ` into the message. The prefix now belongs to
25
+ * `renderLoaderWarning` alone, so the message here is the input string verbatim.
26
+ *
27
+ * register's caller is `loadWorkflowForAdmission`, which `watch` and `validate` also use — so the strip
28
+ * reaches watch too, and there is no third caller.
29
+ */
30
+ export declare function wrapSentinelWarnings(sentinelWarnings: string[] | undefined): LoaderWarning[];
23
31
  /**
24
32
  * Renders a load failure without saying "invalid" twice (issue #417).
25
33
  *
@@ -32,5 +40,15 @@ export declare function failsStrict(warnings: LoaderWarning[]): boolean;
32
40
  * Applies only to the message-echoing renders. The standalone strict-escalation lines have their
33
41
  * own text and are untouched.
34
42
  */
35
- export declare function renderLoadFailure(message: string): string;
43
+ export declare function renderLoadFailure(err: WorkflowError | string): string;
44
+ /**
45
+ * The escalation line (issue #425). Extracted so the keyless branch below is reachable from a
46
+ * test: every WarningCode that escalates under the default policy happens to carry a key today,
47
+ * so no real fixture can drive it — and a clause nothing can exercise rots into a wrong guess
48
+ * about what a future keyless code would print.
49
+ *
50
+ * Shared by validate, register and watch (issue #451) — three callers earned it this home, per
51
+ * the one-caller rule recorded on validate's exitOnLoadFailure.
52
+ */
53
+ export declare function renderEscalationLine(warnings: readonly LoaderWarning[]): string;
36
54
  //# sourceMappingURL=loader-warnings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"loader-warnings.d.ts","sourceRoot":"","sources":["../../src/lib/loader-warnings.ts"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAC;AAiBxB;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI,CASnE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,aAAa,EAAE,EACzB,MAAM,GAAE,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAkB,GAC7D,OAAO,CAET;AAWD,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,OAAO,CAE9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzD"}
1
+ {"version":3,"file":"loader-warnings.d.ts","sourceRoot":"","sources":["../../src/lib/loader-warnings.ts"],"names":[],"mappings":"AA2BA,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAC;AAExB;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAI5E;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,aAAa,EAAE,EACzB,MAAM,GAAE,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAkB,GAC7D,OAAO,CAET;AAWD,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,OAAO,CAE9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,gBAAgB,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,aAAa,EAAE,CAO5F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,GAAG,MAAM,CAiBrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAW/E"}
@@ -1,37 +1,40 @@
1
1
  // loader-warnings.ts — shared CLI surfacing for the structured loader-warning channel (issue
2
- // #169). Every CLI command that prints loader warnings funnels through printLoaderWarnings (the
3
- // only caller of renderLoaderWarning no command hand-rolls a `⚠ ` string), and the dormant
4
- // #170 boundary-reject is factored into ONE shared helper so validate/register/watch can't drift.
2
+ // #169). The BOUNDARY commands validate, register, watch funnel every LoaderWarning through
3
+ // printLoaderWarnings, and the dormant #170 boundary-reject is factored into ONE shared helper so
4
+ // they can't drift.
5
+ //
6
+ // issue #540: printLoaderWarnings used to rewrite the mint's "— ignored" clause to
7
+ // "— REFUSED below" for any warning the boundary resolves to 'error', on the theory that
8
+ // "ignored" is false once a boundary is about to refuse the workflow over it. That substitution
9
+ // is gone: "— ignored" is a true statement about what the PARSE did (the key was dropped) on
10
+ // EVERY surface, including this one — the refusal is a separate fact, already stated per-key by
11
+ // renderEscalationLine below. The substitution could also name the WRONG cause on any arm that
12
+ // bypasses renderEscalationLine's own gate (see the "hard-error carry"/orphan-manifest/extensions-
13
+ // failure comments in validate.ts and register.ts) and, being a first-occurrence unanchored
14
+ // string replace, could corrupt author-controlled text that happened to contain the clause
15
+ // (issue #525 item 1). See
16
+ // `plans/issue-540/design-d2.md` for the full adjudication between this and issue #170's
17
+ // (superseded) legibility argument for the substitution.
18
+ //
19
+ // One consequence, since `test` was never the exception any more (issue #450): with the
20
+ // substitution gone, printLoaderWarnings is now behaviorally identical to
21
+ // `renderLoaderWarning`'s plain-render loop that `realm workflow test` already used directly.
22
+ // Whether the two call shapes should unify is its own question — filed as #542, not answered here.
23
+ //
24
+ // Precise as of issue #444: no command hand-rolls a ⚠ prefix for a LOADER WARNING. A few
25
+ // adjacent one-off notices — register's sentinel lines, test's sentinel echo — still print their
26
+ // own `⚠ ` directly, because they are plain strings rather than LoaderWarnings; they were
27
+ // normalized to the same single-space grammar so a mixed block cannot recur.
5
28
  import { renderLoaderWarning, resolveSeverity, DEFAULT_POLICY, } from '@sensigo/realm';
6
29
  /**
7
- * The unknown-key warning is minted with "— ignored", which is true of the LENIENT loader
8
- * (run/agent/listen really do ignore the key and carry on) and false here: the only callers of
9
- * this function are validate/register/watch, and post-#170 those three REFUSE a workflow whose
10
- * warning resolves to 'error'. Printing "— ignored" one line above "escalated to an error" tells
11
- * the author the opposite of what is about to happen to them.
12
- *
13
- * Substituted at the RENDER, not the mint, precisely because the mint is shared with the lenient
14
- * path — where the original wording is true and worth keeping. The did-you-mean fragment is
15
- * untouched: it is the most useful half of the line and the reason the author can fix this in one
16
- * edit.
17
- */
18
- const IGNORED_CLAUSE = '— ignored';
19
- const REFUSED_CLAUSE = '— REFUSED below';
20
- /**
21
- * Prints every warning via the single renderLoaderWarning format source, correcting the
22
- * "— ignored" claim for any warning this boundary will actually refuse.
23
- *
24
- * Resolved against DEFAULT_POLICY, which is the policy the boundary-reject itself uses. A warning
25
- * that only fails under `--strict` still renders "— ignored" — see the report's design note; the
26
- * `--strict` path prints its own "failing due to --strict" line, so the author is not left
27
- * without an explanation.
30
+ * Prints every warning via the single renderLoaderWarning format source no substitution (see
31
+ * the module header for why the former "— ignored" "— REFUSED below" rewrite was deleted,
32
+ * issue #540). The `DEFAULT_POLICY` import above stays: `rejectOnErrorSeverity` and
33
+ * `failsStrict`, both exported from this module, still resolve against it.
28
34
  */
29
35
  export function printLoaderWarnings(warnings) {
30
36
  for (const w of warnings) {
31
- const line = renderLoaderWarning(w);
32
- console.warn(resolveSeverity(w.code, DEFAULT_POLICY) === 'error'
33
- ? line.replace(IGNORED_CLAUSE, REFUSED_CLAUSE)
34
- : line);
37
+ console.warn(renderLoaderWarning(w));
35
38
  }
36
39
  }
37
40
  /**
@@ -55,6 +58,24 @@ const ALL_ERROR_POLICY = Object.fromEntries(Object.keys(DEFAULT_POLICY).map((cod
55
58
  export function failsStrict(warnings) {
56
59
  return rejectOnErrorSeverity(warnings, ALL_ERROR_POLICY);
57
60
  }
61
+ /**
62
+ * Wraps loadProjectExtensions' sentinel-credential warnings as LoaderWarning (issue #169).
63
+ *
64
+ * ONE copy (issue #444): validate.ts and register.ts each carried a byte-identical private one,
65
+ * and both baked a two-space `⚠ ` into the message. The prefix now belongs to
66
+ * `renderLoaderWarning` alone, so the message here is the input string verbatim.
67
+ *
68
+ * register's caller is `loadWorkflowForAdmission`, which `watch` and `validate` also use — so the strip
69
+ * reaches watch too, and there is no third caller.
70
+ */
71
+ export function wrapSentinelWarnings(sentinelWarnings) {
72
+ return (sentinelWarnings ?? []).map((message) => ({
73
+ code: 'EXTENSION_SENTINEL',
74
+ severity: resolveSeverity('EXTENSION_SENTINEL'),
75
+ scope: 'workflow',
76
+ message,
77
+ }));
78
+ }
58
79
  /**
59
80
  * Renders a load failure without saying "invalid" twice (issue #417).
60
81
  *
@@ -67,7 +88,40 @@ export function failsStrict(warnings) {
67
88
  * Applies only to the message-echoing renders. The standalone strict-escalation lines have their
68
89
  * own text and are untouched.
69
90
  */
70
- export function renderLoadFailure(message) {
71
- return message.startsWith('Invalid workflow:') ? message : `Invalid: ${message}`;
91
+ export function renderLoadFailure(err) {
92
+ // The string branch FIRST, and not only for the unit cells that drive it: several call sites
93
+ // pass `err instanceof Error ? err.message : String(err)`, so a plain string is a real caller
94
+ // shape, and an object-first implementation would reach for `.errors` on it.
95
+ if (typeof err === 'string') {
96
+ return err.startsWith('Invalid workflow:') ? err : `Invalid: ${err}`;
97
+ }
98
+ // issue #425: several problems collected into one throw get one line each. The array is the
99
+ // only place the boundaries survive — a loader message can itself contain '; ' (the #413
100
+ // four-clause text does), so splitting the joined message back apart would cut one message in
101
+ // half and call the halves two errors.
102
+ const parts = err.errors;
103
+ if (parts !== undefined && parts.length > 1) {
104
+ return [`Invalid workflow — ${parts.length} errors:`, ...parts.map((e) => ` ${e}`)].join('\n');
105
+ }
106
+ return renderLoadFailure(err.message);
107
+ }
108
+ /**
109
+ * The escalation line (issue #425). Extracted so the keyless branch below is reachable from a
110
+ * test: every WarningCode that escalates under the default policy happens to carry a key today,
111
+ * so no real fixture can drive it — and a clause nothing can exercise rots into a wrong guess
112
+ * about what a future keyless code would print.
113
+ *
114
+ * Shared by validate, register and watch (issue #451) — three callers earned it this home, per
115
+ * the one-caller rule recorded on validate's exitOnLoadFailure.
116
+ */
117
+ export function renderEscalationLine(warnings) {
118
+ // Same default policy `rejectOnErrorSeverity` just gated on, so the list can never disagree
119
+ // with the refusal it explains.
120
+ const escalated = warnings.filter((w) => resolveSeverity(w.code) === 'error');
121
+ const list = escalated
122
+ .map((w) => (w.key === undefined ? w.code : `${w.code} '${w.key}'`))
123
+ .join(', ');
124
+ return (`Invalid: ${warnings.length} ${warnings.length === 1 ? 'warning' : 'warnings'}, ` +
125
+ `${escalated.length} escalated to an error by policy: ${list}`);
72
126
  }
73
127
  //# sourceMappingURL=loader-warnings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"loader-warnings.js","sourceRoot":"","sources":["../../src/lib/loader-warnings.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,gGAAgG;AAChG,6FAA6F;AAC7F,kGAAkG;AAClG,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,cAAc,GAGf,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;;GAWG;AACH,MAAM,cAAc,GAAG,WAAW,CAAC;AACnC,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAEzC;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAyB;IAC3D,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CACV,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,cAAc,CAAC,KAAK,OAAO;YACjD,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,cAAc,CAAC;YAC9C,CAAC,CAAC,IAAI,CACT,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAyB,EACzB,SAAgD,cAAc;IAE9D,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,gBAAgB,GAA0C,MAAM,CAAC,WAAW,CAC/E,MAAM,CAAC,IAAI,CAAC,cAAc,CAAmB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CACrC,CAAC;AAE3C,mFAAmF;AACnF,MAAM,UAAU,WAAW,CAAC,QAAyB;IACnD,OAAO,qBAAqB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,OAAO,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,OAAO,EAAE,CAAC;AACnF,CAAC"}
1
+ {"version":3,"file":"loader-warnings.js","sourceRoot":"","sources":["../../src/lib/loader-warnings.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sensigo/realm-cli",
3
- "version": "0.40.0",
3
+ "version": "0.42.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -64,9 +64,9 @@
64
64
  "vitest": "^4.1.0"
65
65
  },
66
66
  "dependencies": {
67
- "@sensigo/realm": "^0.40.0",
68
- "@sensigo/realm-mcp": "^0.40.0",
69
- "@sensigo/realm-testing": "^0.40.0",
67
+ "@sensigo/realm": "^0.42.0",
68
+ "@sensigo/realm-mcp": "^0.42.0",
69
+ "@sensigo/realm-testing": "^0.42.0",
70
70
  "@modelcontextprotocol/sdk": "1.30.0",
71
71
  "chalk": "^5.0.0",
72
72
  "commander": "^15.0.0",