@cspeach/cli 1.1.18 → 1.1.19

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 (224) hide show
  1. package/README.md +3 -4
  2. package/dist/agent/loop.js +143 -25
  3. package/dist/agent/providers/local-provider.js +4 -1
  4. package/dist/agent/repair-partial.js +76 -19
  5. package/dist/agent/tool-dispatch.js +58 -21
  6. package/dist/agent/turn-error-ux.js +77 -26
  7. package/dist/agent/turn-stream.js +25 -3
  8. package/dist/approvals/adt-type.js +27 -0
  9. package/dist/approvals/advisory-prompt.js +48 -0
  10. package/dist/approvals/advisory-render.js +25 -11
  11. package/dist/approvals/approval-prompt.js +74 -24
  12. package/dist/approvals/jwt.js +2 -1
  13. package/dist/approvals/render.js +64 -36
  14. package/dist/approvals/risk-floor.js +53 -2
  15. package/dist/auth/api-key.js +30 -16
  16. package/dist/auth/keychain.js +0 -0
  17. package/dist/auth/me.js +25 -7
  18. package/dist/cli.js +25 -6
  19. package/dist/commands/compact.js +12 -9
  20. package/dist/commands/config-set.js +6 -2
  21. package/dist/commands/config-show.js +7 -5
  22. package/dist/commands/cost.js +41 -34
  23. package/dist/commands/help.js +88 -50
  24. package/dist/commands/login.js +28 -19
  25. package/dist/commands/logout.js +7 -3
  26. package/dist/commands/plan-chain.js +71 -77
  27. package/dist/commands/plan-continue.js +1 -0
  28. package/dist/commands/plan-resume.js +20 -12
  29. package/dist/commands/whoami.js +23 -9
  30. package/dist/config/loader.js +15 -3
  31. package/dist/cost/pricing.js +6 -5
  32. package/dist/doctor/checks/forge-rules.js +13 -3
  33. package/dist/doctor/checks/keychain.js +6 -4
  34. package/dist/doctor/run.js +101 -20
  35. package/dist/index.js +5 -2
  36. package/dist/lib/graceful-exit.js +56 -0
  37. package/dist/lib/piped-prompt.js +65 -0
  38. package/dist/lock-contention.js +2 -2
  39. package/dist/one-shot.js +135 -40
  40. package/dist/projects/answer-blockers.js +6 -1
  41. package/dist/projects/handover-md.js +15 -14
  42. package/dist/projects/plan-run.js +97 -54
  43. package/dist/projects/promote-command.js +11 -2
  44. package/dist/projects/save-command.js +3 -2
  45. package/dist/projects/status.js +2 -1
  46. package/dist/projects/yes-no.js +12 -0
  47. package/dist/renderer/abap-inline.js +18 -14
  48. package/dist/renderer/answer-trim.js +69 -0
  49. package/dist/renderer/banners.js +8 -8
  50. package/dist/renderer/brand-settled.js +19 -0
  51. package/dist/renderer/change-card.js +156 -0
  52. package/dist/renderer/checklist-format.js +130 -0
  53. package/dist/renderer/color-mode.js +45 -0
  54. package/dist/renderer/error-detail.js +104 -0
  55. package/dist/renderer/fence-state.js +46 -0
  56. package/dist/renderer/footer-line.js +96 -0
  57. package/dist/renderer/glyphs.js +25 -0
  58. package/dist/renderer/goodbye.js +38 -0
  59. package/dist/renderer/legacy-palette.js +41 -0
  60. package/dist/renderer/look.js +30 -0
  61. package/dist/renderer/markdown.js +299 -92
  62. package/dist/renderer/notice-log.js +72 -0
  63. package/dist/renderer/notice-shape.js +48 -0
  64. package/dist/renderer/notices.js +40 -8
  65. package/dist/renderer/panel-rows.js +16 -0
  66. package/dist/renderer/pipeline.js +66 -0
  67. package/dist/renderer/progress-chatter.js +23 -17
  68. package/dist/renderer/rendering-mode.js +34 -0
  69. package/dist/renderer/routing-line.js +14 -0
  70. package/dist/renderer/sanitize.js +12 -0
  71. package/dist/renderer/severity.js +2 -7
  72. package/dist/renderer/startup-lines.js +152 -0
  73. package/dist/renderer/status-footer.js +52 -34
  74. package/dist/renderer/steering-echo.js +41 -0
  75. package/dist/renderer/syntax.js +31 -12
  76. package/dist/renderer/tables.js +5 -1
  77. package/dist/renderer/theme.js +44 -0
  78. package/dist/renderer/thinking-heartbeat.js +33 -2
  79. package/dist/renderer/todo-block.js +10 -49
  80. package/dist/renderer/tool-labels.js +238 -0
  81. package/dist/renderer/tool-widget.js +245 -51
  82. package/dist/renderer/trace.js +42 -0
  83. package/dist/renderer/transcript-flow.js +132 -0
  84. package/dist/renderer/tty.js +34 -1
  85. package/dist/renderer/ui-width.js +42 -0
  86. package/dist/renderer/verify-chain.js +4 -2
  87. package/dist/renderer/widget-fallback.js +58 -65
  88. package/dist/repl/bracketed-paste.js +7 -1
  89. package/dist/repl/builtin-commands.js +19 -8
  90. package/dist/repl/credential-handover-gate.js +28 -0
  91. package/dist/repl/early-line-buffer.js +5 -2
  92. package/dist/repl/file-picker.js +54 -12
  93. package/dist/repl/ink-stdin-guard.js +66 -0
  94. package/dist/repl/inquirer-guard.js +59 -16
  95. package/dist/repl/inquirer-theme.js +27 -33
  96. package/dist/repl/paste-marker.js +19 -0
  97. package/dist/repl/plan-turn-end.js +20 -0
  98. package/dist/repl/post-turn-status.js +36 -11
  99. package/dist/repl/reroute-turn.js +21 -0
  100. package/dist/repl/reset-tty-stdin.js +44 -0
  101. package/dist/repl/restore-guard.js +22 -0
  102. package/dist/repl/resume-standalone.js +63 -0
  103. package/dist/repl/rule8-detector.js +11 -3
  104. package/dist/repl/safety-confirm.js +161 -93
  105. package/dist/repl/session-spend-line.js +8 -4
  106. package/dist/repl/themed-prompts.js +19 -0
  107. package/dist/repl/ui-look-command.js +75 -0
  108. package/dist/repl/update-method-preview-hook.js +48 -5
  109. package/dist/repl.js +795 -332
  110. package/dist/rewind/cli.js +3 -2
  111. package/dist/rewind/format.js +14 -9
  112. package/dist/rewind/restore.js +11 -0
  113. package/dist/router/classifier.js +47 -4
  114. package/dist/router/intent-extractor.js +24 -8
  115. package/dist/router/piped-routing.js +23 -0
  116. package/dist/router/resume-routing.js +16 -0
  117. package/dist/router/routing-failure.js +57 -0
  118. package/dist/sap/first-run-choice.js +1 -1
  119. package/dist/sap/onboarding.js +3 -2
  120. package/dist/sap/standalone-onboarding.js +1 -1
  121. package/dist/sap/system-info.js +4 -2
  122. package/dist/sap/unreachable.js +28 -0
  123. package/dist/sap-errors/clean-error-text.js +182 -0
  124. package/dist/session/interrupt-reason.js +39 -0
  125. package/dist/session/recap.js +36 -24
  126. package/dist/session/resume.js +104 -36
  127. package/dist/session/store.js +69 -27
  128. package/dist/session/user-prompt.js +21 -0
  129. package/dist/skill-catalog.js +7 -0
  130. package/dist/skills/bundled-skills.js +76 -69
  131. package/dist/standards/standards-init.js +1 -1
  132. package/dist/test-helpers/answer-any.js +46 -0
  133. package/dist/tools/approval.js +27 -11
  134. package/dist/tools/ask-question.js +47 -5
  135. package/dist/tools/filesystem/file-write.js +19 -2
  136. package/dist/tools/fiori/fe-extend.js +16 -1
  137. package/dist/tools/fiori/fe-scaffold.js +105 -3
  138. package/dist/tools/fiori/html-escapes.js +28 -0
  139. package/dist/tools/fiori/metadata/audit.js +605 -0
  140. package/dist/tools/fiori/metadata/references.js +104 -0
  141. package/dist/tools/fiori/metadata/types.js +8 -0
  142. package/dist/tools/fiori/preview/app-guard.js +215 -0
  143. package/dist/tools/fiori/preview/env.js +193 -0
  144. package/dist/tools/fiori/preview/readiness.js +127 -0
  145. package/dist/tools/fiori/preview/registry.js +412 -0
  146. package/dist/tools/fiori/preview/start.js +469 -0
  147. package/dist/tools/fiori/samples/loader.js +20 -5
  148. package/dist/tools/fiori/scaffold.js +18 -6
  149. package/dist/tools/fiori/smoke/app-driver-page.js +372 -0
  150. package/dist/tools/fiori/smoke/app-driver.js +100 -0
  151. package/dist/tools/fiori/smoke/assertions.js +161 -24
  152. package/dist/tools/fiori/smoke/audit-columns.js +21 -0
  153. package/dist/tools/fiori/smoke/batch.js +273 -0
  154. package/dist/tools/fiori/smoke/draft-safety.js +241 -0
  155. package/dist/tools/fiori/smoke/draft-smoke.js +473 -0
  156. package/dist/tools/fiori/smoke/driver.js +171 -4
  157. package/dist/tools/fiori/smoke/evidence.js +35 -0
  158. package/dist/tools/fiori/smoke/labels-codes.js +207 -0
  159. package/dist/tools/fiori/smoke/nav-error.js +26 -0
  160. package/dist/tools/fiori/smoke/run-smoke.js +155 -12
  161. package/dist/tools/fiori/tools.js +651 -7
  162. package/dist/tools/fiori/ui5-version.js +16 -0
  163. package/dist/tools/index.js +8 -0
  164. package/dist/tools/local-build.js +6 -0
  165. package/dist/tools/sap-read.js +16 -1
  166. package/dist/tools/sap-write.js +122 -10
  167. package/dist/tools/shell/shell_exec.js +30 -12
  168. package/dist/tools/syntax-state.js +67 -0
  169. package/dist/tools/todo.js +23 -18
  170. package/dist/tools/transport-fit.js +462 -0
  171. package/dist/tools/transport-resolution.js +3 -1
  172. package/dist/tools/transport.js +33 -7
  173. package/dist/tools/verify.js +184 -8
  174. package/dist/ui/app.js +284 -146
  175. package/dist/ui/approval-modal.js +41 -15
  176. package/dist/ui/ask-answer-text.js +17 -0
  177. package/dist/ui/body.js +25 -6
  178. package/dist/ui/card-slot.js +98 -0
  179. package/dist/ui/checklist.js +9 -0
  180. package/dist/ui/coaching-picker-classic.js +8 -5
  181. package/dist/ui/command-palette.js +6 -4
  182. package/dist/ui/confirm-request.js +18 -0
  183. package/dist/ui/context-grid.js +2 -1
  184. package/dist/ui/file-palette.js +6 -4
  185. package/dist/ui/files-card-emitter.js +19 -0
  186. package/dist/ui/footer-line.js +16 -0
  187. package/dist/ui/footer.js +105 -104
  188. package/dist/ui/input-wrap.js +122 -0
  189. package/dist/ui/interrupt.js +103 -0
  190. package/dist/ui/key-burst.js +117 -0
  191. package/dist/ui/line-resolution.js +4 -3
  192. package/dist/ui/live-area.js +71 -0
  193. package/dist/ui/login-banner.js +54 -43
  194. package/dist/ui/rewind-panel.js +76 -24
  195. package/dist/ui/role-props.js +47 -0
  196. package/dist/ui/sap-state-store.js +1 -0
  197. package/dist/ui/session-timeline.js +49 -3
  198. package/dist/ui/skill-picker.js +5 -47
  199. package/dist/ui/text-input.js +128 -24
  200. package/dist/ui/todo-emitter.js +19 -0
  201. package/dist/ui/turn-status-emitter.js +28 -2
  202. package/dist/ui/turn-status.js +16 -19
  203. package/dist/ui/use-card-request.js +44 -0
  204. package/dist/ui/widgets/ask-card.js +521 -0
  205. package/dist/ui/widgets/bar-chart.js +11 -5
  206. package/dist/ui/widgets/coaching-picker.js +50 -55
  207. package/dist/ui/widgets/confirm-card.js +193 -0
  208. package/dist/ui/widgets/dep-graph.js +3 -2
  209. package/dist/ui/widgets/diff-viewer.js +6 -5
  210. package/dist/ui/widgets/files-card.js +97 -0
  211. package/dist/ui/widgets/question-card.js +2 -1
  212. package/dist/ui/widgets/reclaim-raw-stdin.js +24 -0
  213. package/dist/ui/widgets/shortcuts-sheet.js +25 -0
  214. package/dist/ui/widgets/stack-frames.js +2 -1
  215. package/dist/upgrade-check.js +39 -8
  216. package/package.json +11 -2
  217. package/test-harness/fe-draft/app.ts +188 -0
  218. package/test-harness/fe-draft/fe-draft.e2e.test.ts +461 -0
  219. package/test-harness/fe-draft/manifest-enhancer.unit.test.ts +51 -0
  220. package/test-harness/fe-draft/routes.ts +224 -0
  221. package/test-harness/fe-draft/routes.unit.test.ts +45 -0
  222. package/test-harness/fe-draft/server.ts +225 -0
  223. package/test-harness/fe-draft/variants.ts +196 -0
  224. package/vitest.smoke-e2e.config.ts +20 -0
@@ -10,20 +10,177 @@
10
10
  *
11
11
  * (Confirmed from sap-client/src/adt-client.ts lines 82-87, 224-228, 547.)
12
12
  */
13
+ import { recordSyntaxCheck } from './syntax-state.js';
14
+ import { toObjectUrl, xmlParser } from '@cspeach/sap-client';
15
+ /** Line for display: the parsed line, else the `#start=L,C` fragment of the
16
+ * checkruns uri (sap-client <= 0.1.14 left line at 0 for checkruns). */
17
+ function lineOf(m) {
18
+ if (m.line > 0)
19
+ return m.line;
20
+ const pos = m.uri ? /#(?:.*[;&])?start=(\d+)/.exec(m.uri) : null;
21
+ return pos ? parseInt(pos[1], 10) : m.line;
22
+ }
23
+ function columnOf(m) {
24
+ if ((m.column ?? 0) > 0 || m.line > 0)
25
+ return m.column ?? 0;
26
+ const pos = m.uri ? /#(?:.*[;&])?start=\d+,(\d+)/.exec(m.uri) : null;
27
+ return pos ? parseInt(pos[1], 10) : (m.column ?? 0);
28
+ }
29
+ /** sap-client <= 0.1.14 passed `chkrun:shortText` through still XML-escaped. */
30
+ function decodeEntities(s) {
31
+ return s.replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
32
+ }
33
+ /**
34
+ * Normalise a sap-client syntax-check result. FAILS CLOSED — every consumer
35
+ * of a syntax check (the Rule 10 write gate, the sap_syntax_check tool the
36
+ * model reads, the doctor probe) goes through here (fix round 7, item 1).
37
+ *
38
+ * - `hasErrors` from sap-client always stands.
39
+ * - A message with a severity other than warning/info is an error.
40
+ * - sap-client <= 0.1.14 read checkruns severities from the wrong attribute
41
+ * (every `chkrun:type="E"` came back as `info`, text still XML-escaped,
42
+ * line 0) and always added one empty, uri-less message for the
43
+ * `<checkMessageList>` container. That empty message is the fingerprint of
44
+ * a result whose severities were lost: then every remaining non-warning
45
+ * message is treated as an error, so a broken program never passes as
46
+ * clean on the old pin. The empty artefact itself is dropped.
47
+ */
48
+ export function normaliseSyntaxResult(res) {
49
+ const all = (res.messages ?? []);
50
+ const severitiesLost = all.some((m) => !m.text && !m.uri);
51
+ const messages = all
52
+ .filter((m) => m.text || m.uri)
53
+ .map((m) => {
54
+ const severity = m.severity === 'warning' ? 'warning'
55
+ : m.severity === 'info' && !severitiesLost ? 'info'
56
+ : 'error';
57
+ return {
58
+ severity,
59
+ line: lineOf(m),
60
+ column: columnOf(m),
61
+ text: decodeEntities(m.text ?? ''),
62
+ ...(m.uri !== undefined ? { uri: m.uri } : {}),
63
+ };
64
+ });
65
+ if (res.hasErrors && !messages.some((m) => m.severity === 'error')) {
66
+ messages.unshift({ severity: 'error', line: 0, column: 0, text: 'SAP reported syntax errors (no message text returned)' });
67
+ }
68
+ return {
69
+ hasErrors: messages.some((m) => m.severity === 'error'),
70
+ hasWarnings: messages.some((m) => m.severity === 'warning'),
71
+ messages,
72
+ };
73
+ }
74
+ /**
75
+ * Final review A-I2 — the ONE syntax-check call every CLI consumer uses.
76
+ *
77
+ * Live S4H capture (test/fixtures/checkruns-s4h): for BDEF, DDLX, SRVD and
78
+ * TABL, sap-client 0.1.15's request (no version) is answered
79
+ * `chkrun:status="notProcessed"` ("Error while importing object … from the
80
+ * database") when the object has NO inactive version — e.g. right after the
81
+ * write was activated — and 0.1.15 throws "did not run". The same request
82
+ * with `chkrun:version="active"` is processed.
83
+ *
84
+ * So: on a notProcessed throw, and ONLY when the object is confirmed NOT in
85
+ * the inactive-objects list (then the active version is the current source),
86
+ * check once more with version="active" and require a processed report.
87
+ * Anything else — an inactive version exists, the list is unreadable, the
88
+ * retry is not processed — rethrows the original error (fail closed).
89
+ */
90
+ export async function checkSyntax(adt, type, name) {
91
+ try {
92
+ return await adt.syntaxCheck(type, name);
93
+ }
94
+ catch (err) {
95
+ if (!/did not run \(status notProcessed\)/i.test(String(err?.message ?? err)))
96
+ throw err;
97
+ const retried = await checkActiveVersion(adt, type, name).catch(() => undefined);
98
+ if (retried)
99
+ return retried;
100
+ throw err;
101
+ }
102
+ }
103
+ const connOf = (adt) => adt.connection;
104
+ const INACTIVE_URL = '/sap/bc/adt/activation/inactiveobjects';
105
+ /**
106
+ * Re-review of the final fix wave, item 2 — the published 0.1.15
107
+ * inactive-list parser returns [] when the object's name sits on a CHILD
108
+ * <ioc:ref> element (test/fixtures/inactive-objects), so "[] = no inactive
109
+ * version" cannot be trusted. Read the RAW body: does it mention this object
110
+ * (name, or its ADT uri, as a whole word)?
111
+ */
112
+ export function inactiveBodyMentions(body, type, name) {
113
+ const esc = (v) => v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
114
+ const upper = name.toUpperCase();
115
+ const byName = new RegExp(`(?<![A-Z0-9_/])${esc(upper)}(?![A-Z0-9_])`).test(body.toUpperCase());
116
+ let byUri = false;
117
+ try {
118
+ const uri = toObjectUrl(type, upper).toLowerCase();
119
+ byUri = new RegExp(`${esc(uri)}(?![a-z0-9_])`).test(body.toLowerCase());
120
+ }
121
+ catch { /* unknown type word: the name check stands */ }
122
+ return byName || byUri;
123
+ }
124
+ async function checkActiveVersion(adt, type, name) {
125
+ const upper = name.toUpperCase();
126
+ const conn = connOf(adt);
127
+ if (!conn || typeof conn.post !== 'function' || typeof conn.get !== 'function')
128
+ return undefined;
129
+ // Parser-independent guard: never check the old active source while an
130
+ // inactive version may exist.
131
+ const list = await conn.get(INACTIVE_URL);
132
+ if (list.status < 200 || list.status >= 300)
133
+ return undefined;
134
+ const body = list.body ?? '';
135
+ if (inactiveBodyMentions(body, type, upper))
136
+ return undefined;
137
+ const inactive = await adt.inactiveObjects();
138
+ if (inactive.some((o) => o.name.toUpperCase() === upper))
139
+ return undefined;
140
+ // Controller ruling: no "body has refs but parses to nothing" rule — with the
141
+ // 0.1.15 parser bug it refused the retry whenever the user had ANY other
142
+ // inactive object, re-blocking every clean BDEF/DDLX/SRVD/TABL write. The
143
+ // whole-word raw-body check above (plus non-2xx → refuse) is the guard.
144
+ const esc = (v) => v.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;');
145
+ const xml = '<?xml version="1.0" encoding="utf-8"?>'
146
+ + '<chkrun:checkObjectList xmlns:chkrun="http://www.sap.com/adt/checkrun" xmlns:adtcore="http://www.sap.com/adt/core">'
147
+ + `<chkrun:checkObject adtcore:uri="${esc(toObjectUrl(type, upper))}" chkrun:version="active"/>`
148
+ + '</chkrun:checkObjectList>';
149
+ const resp = await conn.post('/sap/bc/adt/checkruns?reporters=abapCheckRun', xml, 'application/vnd.sap.adt.checkobjects+xml; charset=utf-8', 'application/xml, */*');
150
+ if (resp.status < 200 || resp.status >= 300)
151
+ return undefined;
152
+ const report = /<(?:[\w-]+:)?checkReport(?![\w-])([^>]*)>/i.exec(resp.body ?? '');
153
+ const status = report ? /(?:^|\s)(?:[\w-]+:)?status\s*=\s*"([^"]*)"/.exec(report[1] ?? '')?.[1] : undefined;
154
+ if (!report || (status !== undefined && status.toLowerCase() !== 'processed'))
155
+ return undefined;
156
+ return xmlParser.parseSyntaxCheckResult(resp.body);
157
+ }
13
158
  /**
14
159
  * Run a syntax check and return a normalised VerifyResult.
15
160
  * Errors block activation; warnings are surfaced but do not block.
161
+ * Fails closed — see normaliseSyntaxResult.
16
162
  */
17
163
  export async function verifySyntax(adt, name, type) {
18
- const res = await adt.syntaxCheck(type, name);
164
+ // Review r7 I-4 — a check that did not run (HTTP error, aborted report,
165
+ // network) FAILS CLOSED: never syntax ✓, never activation_allowed.
166
+ let raw;
167
+ let didNotRun;
168
+ try {
169
+ raw = await checkSyntax(adt, type, name);
170
+ }
171
+ catch (err) {
172
+ didNotRun = String(err?.message ?? err).replace(/\s+/g, ' ').trim();
173
+ raw = { hasErrors: true, hasWarnings: false, messages: [{ severity: 'error', line: 0, column: 0,
174
+ text: /did not run/i.test(didNotRun) ? didNotRun : `Syntax check did not run: ${didNotRun}` }] };
175
+ }
176
+ const res = normaliseSyntaxResult(raw);
177
+ recordSyntaxCheck(type, name, res.hasErrors); // round 7 item 8e
178
+ const fmt = (m) => (m.line > 0 || m.uri ? `L${m.line}: ${m.text}` : m.text);
19
179
  return {
20
180
  ok: !res.hasErrors,
21
- errors: res.messages
22
- .filter((m) => m.severity === 'error')
23
- .map((m) => `L${m.line}: ${m.text}`),
24
- warnings: res.messages
25
- .filter((m) => m.severity === 'warning')
26
- .map((m) => `L${m.line}: ${m.text}`),
181
+ errors: res.messages.filter((m) => m.severity === 'error').map(fmt),
182
+ warnings: res.messages.filter((m) => m.severity === 'warning').map(fmt),
183
+ ...(didNotRun !== undefined ? { didNotRun } : {}),
27
184
  };
28
185
  }
29
186
  export async function verifyActive(adt, name, type) {
@@ -34,6 +191,25 @@ export async function verifyActive(adt, name, type) {
34
191
  catch (err) {
35
192
  return { active: false, verifyError: String(err?.message ?? err) };
36
193
  }
37
- const stillInactive = inactive.some((o) => o.name.toUpperCase() === name.toUpperCase() && o.type.toUpperCase() === type.toUpperCase());
194
+ // Re-review of the final fix wave, item 1 — the list carries ADT codes with
195
+ // a slash (PROG/P, CLAS/OC, DDLS/DF), so an exact type compare never matched
196
+ // and still-inactive objects read as active. Match by object NAME: a
197
+ // same-named object of another type only errs on the safe side.
198
+ let stillInactive = inactive.some((o) => o.name.toUpperCase() === name.toUpperCase());
199
+ // Re-review item 2 — parser-independent: the raw body mentioning the object
200
+ // also means still inactive (0.1.15 misses names on a child <ioc:ref>).
201
+ const conn = connOf(adt);
202
+ if (!stillInactive && conn && typeof conn.get === 'function') {
203
+ try {
204
+ const list = await conn.get(INACTIVE_URL);
205
+ if (list.status >= 200 && list.status < 300)
206
+ stillInactive = inactiveBodyMentions(list.body ?? '', type, name);
207
+ else
208
+ return { active: false, verifyError: `inactive-objects list answered HTTP ${list.status}` };
209
+ }
210
+ catch (err) {
211
+ return { active: false, verifyError: String(err?.message ?? err) };
212
+ }
213
+ }
38
214
  return { active: !stillInactive };
39
215
  }