@cspeach/cli 1.1.22 → 1.1.24

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 (54) hide show
  1. package/dist/agent/loop.js +124 -0
  2. package/dist/agent/tool-dispatch.js +4 -2
  3. package/dist/classifier/client.js +27 -2
  4. package/dist/cli.js +13 -0
  5. package/dist/commands/plan-audit-evidence.js +61 -4
  6. package/dist/commands/plan-audit.js +13 -1
  7. package/dist/commands/plan-continue.js +11 -1
  8. package/dist/commands/plan-resume.js +38 -1
  9. package/dist/commands/sap-link.js +52 -0
  10. package/dist/lane/app-chain.js +297 -0
  11. package/dist/lane/app-flow.js +55 -0
  12. package/dist/lane/card.js +148 -0
  13. package/dist/lane/chain-token.js +59 -0
  14. package/dist/lane/inputs.js +459 -0
  15. package/dist/lane/paths.js +21 -0
  16. package/dist/lane/resolve.js +109 -0
  17. package/dist/lane/roots.js +113 -0
  18. package/dist/lane/signals.js +80 -0
  19. package/dist/lane/store.js +232 -0
  20. package/dist/lane/types.js +1 -0
  21. package/dist/lib/shutdown-hooks.js +87 -0
  22. package/dist/one-shot.js +5 -0
  23. package/dist/projects/extract-plan.js +46 -6
  24. package/dist/projects/plan-lane.js +214 -0
  25. package/dist/projects/plan-run.js +5 -1
  26. package/dist/projects/plan-schema.js +12 -1
  27. package/dist/projects/promote-command.js +8 -2
  28. package/dist/projects/save-command.js +71 -25
  29. package/dist/projects/workspace.js +10 -0
  30. package/dist/renderer/tool-labels.js +6 -1
  31. package/dist/repl/credential-handover-gate.js +12 -6
  32. package/dist/repl/resume-standalone.js +3 -0
  33. package/dist/repl.js +27 -2
  34. package/dist/sap/connection-manager.js +30 -24
  35. package/dist/sap-link/policy.js +185 -0
  36. package/dist/sap-link/project.js +163 -0
  37. package/dist/sap-link/registry.js +259 -0
  38. package/dist/sap-link/server.js +351 -0
  39. package/dist/sap-link/upstream.js +367 -0
  40. package/dist/sap-link/write-log.js +60 -0
  41. package/dist/skill-catalog.js +14 -6
  42. package/dist/skills/bundled-skills.js +61 -54
  43. package/dist/tools/cap/_fetch-errors.js +20 -0
  44. package/dist/tools/cap/link-smoke.js +703 -0
  45. package/dist/tools/cap/metadata-import.js +325 -0
  46. package/dist/tools/cap/sap-link-tool.js +133 -0
  47. package/dist/tools/cap/service-catalog.js +248 -0
  48. package/dist/tools/fiori/preview/registry.js +30 -24
  49. package/dist/tools/lane/app-lane-resolve.js +329 -0
  50. package/dist/tools/local-build.js +15 -0
  51. package/dist/tools/subagent/_background-shared.js +59 -37
  52. package/dist/tools/subagent/background_run.js +9 -5
  53. package/dist/tools/tool-loading.js +2 -0
  54. package/package.json +121 -121
@@ -16,6 +16,9 @@
16
16
  * depends on), fiori_metadata_audit, fiori_draft_smoke
17
17
  * (L1-5b — a SAP write, approval-gated like every write),
18
18
  * fiori_sample_search, fiori_sample_get
19
+ * cap: cap_metadata_import (CAP phase 2 — writes srv/external/<API>.edmx),
20
+ * sap_service_catalog (read-only Gateway catalog, used in design),
21
+ * sap_link, cap_link_smoke (S/4 link check; its write leg is approval-gated)
19
22
  * extend: extend_model_insert (anchored CDS/DDLX edit — abap-extend-model)
20
23
  * subagent: agent_run (Task 7, 2026-07-03 — customers get subagent
21
24
  * dispatch when local_build is on; plan phases force its
@@ -71,6 +74,16 @@ export const LOCAL_BUILD_TOOLS = [
71
74
  'fiori_draft_smoke',
72
75
  'fiori_sample_search',
73
76
  'fiori_sample_get',
77
+ // CAP phase 2 (Task 10) — writes srv/external/<API>.edmx from a SAP $metadata.
78
+ 'cap_metadata_import',
79
+ // R25 (final wave) — Gateway catalog read for design; gated so non-CAP users' tool list is unchanged.
80
+ 'sap_service_catalog',
81
+ // CAP phase 2 (Task 8) — the SAP link: a local CAP app's [s4] profile reaches S/4 through it.
82
+ 'sap_link',
83
+ // CAP phase 2 (Task 11) — S/4 link check: live read vs direct S/4, dev-only update-then-restore.
84
+ 'cap_link_smoke',
85
+ // App lane routing (slice 1, Task 5) — reads the spec file like read_document; writes only .cspeach/lane + [app-lane].
86
+ 'app_lane_resolve',
74
87
  'extend_model_insert',
75
88
  'system_capability',
76
89
  'agent_run',
@@ -98,6 +111,8 @@ export const STANDALONE_FILE_TOOLS = [
98
111
  'file_edit',
99
112
  'glob',
100
113
  'grep',
114
+ // App lane routing — /abap-app in standalone mode decides the lane on declared facts.
115
+ 'app_lane_resolve',
101
116
  ];
102
117
  export function applyStandaloneFileTools(cwd) {
103
118
  enableToolFlags([...STANDALONE_FILE_TOOLS]);
@@ -15,11 +15,27 @@
15
15
  * spawned in.
16
16
  *
17
17
  * Exit handler installed exactly once via installExitHandler(). When
18
- * Node exits (normal or signal), every tracked child is SIGTERMd, then
19
- * SIGKILLd after KILL_GRACE_MS ms. Both timers .unref() so they don't
20
- * keep Node alive past the legitimate shutdown.
18
+ * Node exits (normal or signal), every tracked LIVE child is stopped:
19
+ * - Windows: the whole tree, synchronously, with the absolute taskkill
20
+ * `/T /F` shared with the Fiori preview registry. `child.kill()` there is
21
+ * TerminateProcess on the direct child only — and cross-spawn runs a
22
+ * `.cmd` shim (`cds.cmd`, `npm.cmd`) through cmd.exe, which creates no job
23
+ * object, so the real server (e.g. `cds watch`'s `watched` grandchild)
24
+ * kept the port (task 14c finding 3).
25
+ * If taskkill cannot run or fails (not exit 0 / 128), fall back to the
26
+ * direct kill below.
27
+ * - POSIX: SIGTERM to the direct child, then SIGKILL after KILL_GRACE_MS
28
+ * (timer .unref()d).
29
+ * Identity rule (same as preview): only a child handle this process still
30
+ * holds live, and only a pid > 1.
31
+ *
32
+ * The handler is a hook on lib/shutdown-hooks.ts, NOT its own process
33
+ * listeners: our own appended SIGINT/SIGTERM listeners used to stop Node's
34
+ * default "exit on signal", so SIGTERM no longer ended the CLI.
21
35
  */
22
36
  import { KILL_GRACE_MS } from '../_command-shared.js';
37
+ import { registerShutdownHook } from '../../lib/shutdown-hooks.js';
38
+ import { childIsLive, killablePid, taskkillTreeSync } from '../fiori/preview/registry.js';
23
39
  export const MAX_EVENTS_PER_BG = 10_000;
24
40
  const registry = new Map();
25
41
  let exitHandlerInstalled = false;
@@ -83,46 +99,52 @@ export function consumeEvents(bg_id, max) {
83
99
  signal: entry.signal,
84
100
  };
85
101
  }
102
+ let treeKillImpl = taskkillTreeSync;
103
+ /** Stop one entry's process tree, synchronously where it matters (Windows). */
104
+ function stopEntrySync(entry) {
105
+ const child = entry.child;
106
+ if (entry.closed || !childIsLive(child))
107
+ return;
108
+ if (process.platform === 'win32' && killablePid(child.pid)) {
109
+ // taskkill failed to run, timed out, or exited with an error → fall back
110
+ // to the direct kill so at least the child itself goes.
111
+ if (treeKillImpl(child.pid))
112
+ return;
113
+ }
114
+ try {
115
+ child.kill('SIGTERM');
116
+ }
117
+ catch { /* ignore */ }
118
+ const t = setTimeout(() => {
119
+ try {
120
+ if (childIsLive(child))
121
+ child.kill('SIGKILL');
122
+ }
123
+ catch { /* ignore */ }
124
+ }, KILL_GRACE_MS);
125
+ t.unref();
126
+ }
127
+ /** Stop every live background child (and, on Windows, its descendants). */
128
+ export function killAllBackgroundSync() {
129
+ for (const entry of registry.values()) {
130
+ try {
131
+ stopEntrySync(entry);
132
+ }
133
+ catch { /* best effort: one failure never blocks the rest */ }
134
+ }
135
+ }
86
136
  /** Idempotent. Subsequent calls are silent no-ops. */
87
137
  export function installExitHandler() {
88
138
  if (exitHandlerInstalled)
89
139
  return;
90
140
  exitHandlerInstalled = true;
91
- // 'exit' fires synchronously during Node shutdown. Best-effort SIGTERM
92
- // each tracked child; the SIGKILL escalation timer cannot fire from
93
- // inside an 'exit' handler (event-loop is shutting down) so we
94
- // additionally hook SIGINT/SIGTERM/SIGHUP below for graceful paths
95
- // where the loop is still alive.
96
- process.on('exit', () => {
97
- for (const entry of registry.values()) {
98
- if (!entry.closed) {
99
- try {
100
- entry.child.kill('SIGTERM');
101
- }
102
- catch { /* ignore */ }
103
- }
104
- }
105
- });
106
- for (const sig of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
107
- process.on(sig, () => {
108
- for (const entry of registry.values()) {
109
- if (!entry.closed) {
110
- try {
111
- entry.child.kill('SIGTERM');
112
- }
113
- catch { /* ignore */ }
114
- const t = setTimeout(() => {
115
- try {
116
- entry.child.kill('SIGKILL');
117
- }
118
- catch { /* ignore */ }
119
- }, KILL_GRACE_MS);
120
- t.unref();
121
- }
122
- }
123
- });
124
- }
141
+ // One shared exit/signal handler for every managed resource (runs on 'exit'
142
+ // and on SIGINT/SIGTERM/SIGHUP, and re-raises so the CLI still exits).
143
+ registerShutdownHook(killAllBackgroundSync);
125
144
  }
145
+ /** Test-only — replace / restore the Windows tree kill. */
146
+ export function __setTreeKillForTests(fn) { treeKillImpl = fn; }
147
+ export function __resetTreeKillForTests() { treeKillImpl = taskkillTreeSync; }
126
148
  /** Test-only — clears registry between cases. Does NOT uninstall the exit handler (handler is process-lifetime-scoped). */
127
149
  export function __resetRegistryForTests() {
128
150
  registry.clear();
@@ -8,9 +8,11 @@
8
8
  * Child stdout/stderr lines stream into the registry as BgEvents;
9
9
  * monitor_emit drains them.
10
10
  *
11
- * Child does NOT outlive the CLI process — the registry's exit
12
- * handler SIGTERMs every live child on Node exit and SIGKILLs after
13
- * KILL_GRACE_MS.
11
+ * Child does NOT outlive the CLI process. There is no per-job stop: when
12
+ * the CLI exits or gets SIGINT/SIGTERM/SIGHUP, the registry's shutdown hook
13
+ * stops every live child — on Windows the whole process tree (absolute
14
+ * taskkill /T /F, falling back to a direct kill), on POSIX SIGTERM to the
15
+ * direct child, then SIGKILL after KILL_GRACE_MS.
14
16
  *
15
17
  * Flag-gated: invisible to listTools() unless
16
18
  * CSPEACH_TOOL_BACKGROUND_RUN=on. isMutating: true — hooks the existing
@@ -135,14 +137,16 @@ export async function backgroundRunHandler(args, ctx) {
135
137
  `pid: ${child.pid ?? 'unknown'}\n` +
136
138
  `cwd: ${cwd}\n` +
137
139
  `note: child is running — call monitor_emit with this bg_id to drain stdout/stderr/exit events. ` +
138
- `child will be SIGTERMd on CLI exit (then SIGKILLd after grace).`,
140
+ `there is no per-job stop: the child runs until the CLI exits, which stops it ` +
141
+ `(on Windows the whole process tree; on POSIX SIGTERM to the child, SIGKILL after grace).`,
139
142
  };
140
143
  }
141
144
  registerTool({
142
145
  name: 'background_run',
143
146
  description: 'Spawn a safelisted command as a non-blocking background process. Returns a bg_id immediately; ' +
144
147
  'caller polls events via monitor_emit. Same safelist + argv-only + env scrub as shell_exec. ' +
145
- 'Child does NOT outlive the CLI process — SIGTERM on exit, SIGKILL after grace.',
148
+ 'No per-job stop: the child runs until the CLI exits or gets a signal, which stops it — ' +
149
+ 'the whole process tree on Windows; SIGTERM to the child (SIGKILL after grace) on POSIX.',
146
150
  isMutating: true,
147
151
  category: 'subagent',
148
152
  flagGated: true,
@@ -53,6 +53,8 @@ export const SKILL_STARTERS = Object.freeze({
53
53
  'abap-transport': TRANSPORT_FAMILY,
54
54
  'abap-transport-analysis': [...TRANSPORT_FAMILY, 'sap_atc_run', 'sap_usage_references'],
55
55
  'abap-cap': ['fiori_scaffold_fe', 'fiori_render_smoke', 'fiori_draft_smoke'],
56
+ // Both flag-gated (LOCAL_BUILD_TOOLS / STANDALONE_FILE_TOOLS): skipped when off.
57
+ 'abap-app': ['app_lane_resolve', 'read_document'],
56
58
  'abap-atc-fix': ['sap_atc_run'],
57
59
  'abap-cca': ['sap_atc_run', 'sap_usage_references', 'sap_api_state'],
58
60
  'abap-clean-core': ['sap_api_state', 'sap_atc_run', 'sap_usage_references'],
package/package.json CHANGED
@@ -1,121 +1,121 @@
1
- {
2
- "name": "@cspeach/cli",
3
- "version": "1.1.22",
4
- "description": "CSPeach — AI-assisted ABAP development CLI. Direct SAP access, 34 skills, safety gates.",
5
- "keywords": [
6
- "abap",
7
- "sap",
8
- "ai",
9
- "cli",
10
- "ai-assisted-development",
11
- "s4hana",
12
- "abap-development",
13
- "claude",
14
- "anthropic"
15
- ],
16
- "homepage": "https://cspeach.dev",
17
- "bugs": {
18
- "email": "laeeq.siddique@cremencing.com"
19
- },
20
- "author": "Laeeq Siddique (Cremencing Solutions)",
21
- "license": "SEE LICENSE IN LICENSE",
22
- "private": false,
23
- "publishConfig": {
24
- "access": "public"
25
- },
26
- "type": "module",
27
- "bin": {
28
- "cspeach": "dist/index.js"
29
- },
30
- "scripts": {
31
- "dev": "tsx src/index.ts",
32
- "prebuild": "tsx scripts/prebuild.ts",
33
- "build": "tsc && node scripts/make-bin-executable.js",
34
- "install:global": "tsx scripts/install-global.ts",
35
- "pretest": "tsx scripts/sync-signing-key.ts || node -e \"console.warn('WARN: sync-signing-key skipped — using stub')\"",
36
- "start": "node dist/index.js",
37
- "typecheck": "tsc --noEmit",
38
- "test": "vitest run",
39
- "test:watch": "vitest",
40
- "test:smoke-e2e": "vitest run --config vitest.smoke-e2e.config.ts",
41
- "adt:smoke": "tsx scripts/adt-smoke.ts",
42
- "smoke:all": "pnpm zcspeach:smoke && pnpm adt:smoke",
43
- "zcspeach:smoke": "tsx scripts/zcspeach-smoke.ts",
44
- "bench:models": "tsx scripts/bench-models.ts",
45
- "bench:audit": "tsx scripts/bench-audit-task.ts",
46
- "bench:replay": "tsx bench/replay/run.ts",
47
- "fiori": "tsx src/tools/fiori/bin.ts",
48
- "prepare": "husky",
49
- "prepublishOnly": "node -e \"const deps=require('./package.json').dependencies||{}; for (const n of ['@cspeach/sap-client','@cspeach/register-core']) { const d=deps[n]||''; if(d.startsWith('file:')||d.startsWith('link:')){console.error('publish blocked: '+n+' is a local link ('+d+') — point it at the published version before npm publish'); process.exit(1)} }\""
50
- },
51
- "engines": {
52
- "node": ">=20.0.0"
53
- },
54
- "dependencies": {
55
- "@anthropic-ai/sdk": "^0.90.0",
56
- "@cspeach/register-core": "0.1.0",
57
- "@cspeach/sap-client": "0.1.15",
58
- "@iarna/toml": "^2.2.5",
59
- "@inkjs/ui": "^2.0.0",
60
- "@inquirer/prompts": "^7.0.0",
61
- "@napi-rs/keyring": "2.1.0",
62
- "@noble/ed25519": "2.1.0",
63
- "@noble/hashes": "1.4.0",
64
- "@sap-ux/annotation-converter": "0.10.21",
65
- "@sap-ux/edmx-parser": "0.10.0",
66
- "@sap-ux/fe-fpm-writer": "0.43.7",
67
- "@sap-ux/fiori-elements-writer": "^3.0.39",
68
- "@sap-ux/fiori-freestyle-writer": "3.0.12",
69
- "@sap-ux/vocabularies-types": "0.15.0",
70
- "adm-zip": "0.5.17",
71
- "chalk": "^5.3.0",
72
- "cli-highlight": "^2.1.11",
73
- "cli-table3": "^0.6.5",
74
- "clipboardy": "^5.3.1",
75
- "cross-spawn": "^7.0.6",
76
- "diff": "^9.0.0",
77
- "ejs": "3.1.10",
78
- "fuse.js": "^7.0.0",
79
- "ink": "^5.0.0",
80
- "ink-text-input": "^6.0.0",
81
- "jose": "^5.9.0",
82
- "mammoth": "^1.8.0",
83
- "marked": "^11.2.0",
84
- "marked-terminal": "^6.2.0",
85
- "mem-fs": "2.1.0",
86
- "mem-fs-editor": "9.4.0",
87
- "node-machine-id": "^1.1.12",
88
- "openai": "^6.49.0",
89
- "puppeteer-core": "24.10.2",
90
- "react": "^18.3.0",
91
- "string-width": "^7.2.0",
92
- "turndown": "^7.2.0",
93
- "unpdf": "1.7.0",
94
- "zod": "^3.23.0"
95
- },
96
- "devDependencies": {
97
- "@sap-ux/ui5-middleware-fe-mockserver": "2.4.17",
98
- "@types/adm-zip": "0.5.8",
99
- "@types/cross-spawn": "^6.0.6",
100
- "@types/diff": "^7.0.2",
101
- "@types/ejs": "^3.1.5",
102
- "@types/node": "^20.17.0",
103
- "@types/react": "^18.3.0",
104
- "@types/turndown": "^5.0.5",
105
- "@ui5/builder": "4.3.2",
106
- "@ui5/fs": "4.0.6",
107
- "docx": "^9.0.2",
108
- "husky": "^9.1.7",
109
- "ink-testing-library": "^4.0.0",
110
- "pdf-lib": "^1.17.1",
111
- "strip-ansi": "6.0.1",
112
- "tsx": "^4.19.0",
113
- "typescript": "^5.7.0",
114
- "vitest": "^2.1.0"
115
- },
116
- "pnpm": {
117
- "onlyBuiltDependencies": [
118
- "esbuild"
119
- ]
120
- }
121
- }
1
+ {
2
+ "name": "@cspeach/cli",
3
+ "version": "1.1.24",
4
+ "description": "CSPeach — AI-assisted ABAP development CLI. Direct SAP access, 34 skills, safety gates.",
5
+ "keywords": [
6
+ "abap",
7
+ "sap",
8
+ "ai",
9
+ "cli",
10
+ "ai-assisted-development",
11
+ "s4hana",
12
+ "abap-development",
13
+ "claude",
14
+ "anthropic"
15
+ ],
16
+ "homepage": "https://cspeach.dev",
17
+ "bugs": {
18
+ "email": "laeeq.siddique@cremencing.com"
19
+ },
20
+ "author": "Laeeq Siddique (Cremencing Solutions)",
21
+ "license": "SEE LICENSE IN LICENSE",
22
+ "private": false,
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "type": "module",
27
+ "bin": {
28
+ "cspeach": "dist/index.js"
29
+ },
30
+ "scripts": {
31
+ "dev": "tsx src/index.ts",
32
+ "prebuild": "tsx scripts/prebuild.ts",
33
+ "build": "tsc && node scripts/make-bin-executable.js",
34
+ "install:global": "tsx scripts/install-global.ts",
35
+ "pretest": "tsx scripts/sync-signing-key.ts || node -e \"console.warn('WARN: sync-signing-key skipped — using stub')\"",
36
+ "start": "node dist/index.js",
37
+ "typecheck": "tsc --noEmit",
38
+ "test": "vitest run",
39
+ "test:watch": "vitest",
40
+ "test:smoke-e2e": "vitest run --config vitest.smoke-e2e.config.ts",
41
+ "adt:smoke": "tsx scripts/adt-smoke.ts",
42
+ "smoke:all": "pnpm zcspeach:smoke && pnpm adt:smoke",
43
+ "zcspeach:smoke": "tsx scripts/zcspeach-smoke.ts",
44
+ "bench:models": "tsx scripts/bench-models.ts",
45
+ "bench:audit": "tsx scripts/bench-audit-task.ts",
46
+ "bench:replay": "tsx bench/replay/run.ts",
47
+ "fiori": "tsx src/tools/fiori/bin.ts",
48
+ "prepare": "husky",
49
+ "prepublishOnly": "node -e \"const deps=require('./package.json').dependencies||{}; for (const n of ['@cspeach/sap-client','@cspeach/register-core']) { const d=deps[n]||''; if(d.startsWith('file:')||d.startsWith('link:')){console.error('publish blocked: '+n+' is a local link ('+d+') — point it at the published version before npm publish'); process.exit(1)} }\""
50
+ },
51
+ "engines": {
52
+ "node": ">=20.0.0"
53
+ },
54
+ "dependencies": {
55
+ "@anthropic-ai/sdk": "^0.90.0",
56
+ "@cspeach/register-core": "0.1.0",
57
+ "@cspeach/sap-client": "0.1.15",
58
+ "@iarna/toml": "^2.2.5",
59
+ "@inkjs/ui": "^2.0.0",
60
+ "@inquirer/prompts": "^7.0.0",
61
+ "@napi-rs/keyring": "2.1.0",
62
+ "@noble/ed25519": "2.1.0",
63
+ "@noble/hashes": "1.4.0",
64
+ "@sap-ux/annotation-converter": "0.10.21",
65
+ "@sap-ux/edmx-parser": "0.10.0",
66
+ "@sap-ux/fe-fpm-writer": "0.43.7",
67
+ "@sap-ux/fiori-elements-writer": "^3.0.39",
68
+ "@sap-ux/fiori-freestyle-writer": "3.0.12",
69
+ "@sap-ux/vocabularies-types": "0.15.0",
70
+ "adm-zip": "0.5.17",
71
+ "chalk": "^5.3.0",
72
+ "cli-highlight": "^2.1.11",
73
+ "cli-table3": "^0.6.5",
74
+ "clipboardy": "^5.3.1",
75
+ "cross-spawn": "^7.0.6",
76
+ "diff": "^9.0.0",
77
+ "ejs": "3.1.10",
78
+ "fuse.js": "^7.0.0",
79
+ "ink": "^5.0.0",
80
+ "ink-text-input": "^6.0.0",
81
+ "jose": "^5.9.0",
82
+ "mammoth": "^1.8.0",
83
+ "marked": "^11.2.0",
84
+ "marked-terminal": "^6.2.0",
85
+ "mem-fs": "2.1.0",
86
+ "mem-fs-editor": "9.4.0",
87
+ "node-machine-id": "^1.1.12",
88
+ "openai": "^6.49.0",
89
+ "puppeteer-core": "24.10.2",
90
+ "react": "^18.3.0",
91
+ "string-width": "^7.2.0",
92
+ "turndown": "^7.2.0",
93
+ "unpdf": "1.7.0",
94
+ "zod": "^3.23.0"
95
+ },
96
+ "devDependencies": {
97
+ "@sap-ux/ui5-middleware-fe-mockserver": "2.4.17",
98
+ "@types/adm-zip": "0.5.8",
99
+ "@types/cross-spawn": "^6.0.6",
100
+ "@types/diff": "^7.0.2",
101
+ "@types/ejs": "^3.1.5",
102
+ "@types/node": "^20.17.0",
103
+ "@types/react": "^18.3.0",
104
+ "@types/turndown": "^5.0.5",
105
+ "@ui5/builder": "4.3.2",
106
+ "@ui5/fs": "4.0.6",
107
+ "docx": "^9.0.2",
108
+ "husky": "^9.1.7",
109
+ "ink-testing-library": "^4.0.0",
110
+ "pdf-lib": "^1.17.1",
111
+ "strip-ansi": "6.0.1",
112
+ "tsx": "^4.19.0",
113
+ "typescript": "^5.7.0",
114
+ "vitest": "^2.1.0"
115
+ },
116
+ "pnpm": {
117
+ "onlyBuiltDependencies": [
118
+ "esbuild"
119
+ ]
120
+ }
121
+ }