@cspeach/cli 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/agent/__tests__/crash-recover.integration.test.js +254 -0
  2. package/dist/agent/__tests__/loop-save-hook.test.js +188 -0
  3. package/dist/agent/__tests__/maybe-build-project-context.test.js +247 -0
  4. package/dist/agent/__tests__/project-context-injection.test.js +161 -0
  5. package/dist/agent/__tests__/repair-partial.test.js +79 -0
  6. package/dist/agent/__tests__/retry-key.test.js +77 -0
  7. package/dist/agent/__tests__/sap-connection-adapter.test.js +132 -0
  8. package/dist/agent/__tests__/skill-checkpoint.test.js +154 -0
  9. package/dist/agent/__tests__/turn-assistant-text.test.js +73 -0
  10. package/dist/agent/__tests__/turn-error-ux.test.js +145 -0
  11. package/dist/agent/__tests__/turn-stream.test.js +100 -0
  12. package/dist/agent/__tests__/turn-watchdog.test.js +126 -0
  13. package/dist/agent/providers/__tests__/ai-hub-provider.test.js +30 -0
  14. package/dist/agent/providers/__tests__/byok-provider.test.js +32 -0
  15. package/dist/agent/providers/__tests__/factory.test.js +33 -0
  16. package/dist/agent/providers/__tests__/local-provider.test.js +55 -0
  17. package/dist/approvals/__tests__/advisory-prompt.test.js +57 -0
  18. package/dist/approvals/__tests__/advisory-render.test.js +54 -0
  19. package/dist/auth/__tests__/auth-file.test.js +42 -0
  20. package/dist/auth/__tests__/me.test.js +43 -0
  21. package/dist/classifier/__tests__/client.test.js +70 -0
  22. package/dist/commands/__tests__/config-set-write-mode.test.js +14 -0
  23. package/dist/commands/__tests__/login.test.js +152 -0
  24. package/dist/commands/__tests__/logout.test.js +39 -0
  25. package/dist/commands/__tests__/project-context-impact.test.js +173 -0
  26. package/dist/commands/__tests__/spec-gap-status.test.js +31 -0
  27. package/dist/commands/__tests__/whoami.test.js +91 -0
  28. package/dist/config/__tests__/llm-config.test.js +28 -0
  29. package/dist/config/__tests__/shell-exec-config.test.js +76 -0
  30. package/dist/config/__tests__/write-mode.test.js +36 -0
  31. package/dist/doctor/__tests__/check-forge-rules.test.js +134 -0
  32. package/dist/doctor/__tests__/check-llm-mode.test.js +21 -0
  33. package/dist/doctor/__tests__/check-write-mode.test.js +34 -0
  34. package/dist/index.js +0 -0
  35. package/dist/project-context/__tests__/conventions.test.js +221 -0
  36. package/dist/project-context/__tests__/detect.test.js +177 -0
  37. package/dist/project-context/__tests__/domain-abap-cloud.test.js +119 -0
  38. package/dist/project-context/__tests__/domain-abapgit.test.js +161 -0
  39. package/dist/project-context/__tests__/domain-cap.test.js +168 -0
  40. package/dist/project-context/__tests__/domain-fiori.test.js +282 -0
  41. package/dist/project-context/__tests__/git.test.js +131 -0
  42. package/dist/project-context/__tests__/index-files.test.js +195 -0
  43. package/dist/project-context/__tests__/index.test.js +133 -0
  44. package/dist/project-context/__tests__/render.test.js +322 -0
  45. package/dist/project-context/__tests__/types.test.js +73 -0
  46. package/dist/projects/__tests__/build.test.js +52 -0
  47. package/dist/projects/__tests__/canonicalize.test.js +47 -0
  48. package/dist/projects/__tests__/email-template.test.js +71 -0
  49. package/dist/projects/__tests__/expand-text-attachments.test.js +105 -0
  50. package/dist/projects/__tests__/extract-cca.test.js +141 -0
  51. package/dist/projects/__tests__/extract-design.test.js +62 -0
  52. package/dist/projects/__tests__/extract-estimate.test.js +58 -0
  53. package/dist/projects/__tests__/extract-modernize.test.js +127 -0
  54. package/dist/projects/__tests__/extract-spec-gap.test.js +122 -0
  55. package/dist/projects/__tests__/extract-test-coverage.test.js +133 -0
  56. package/dist/projects/__tests__/filename.test.js +32 -0
  57. package/dist/projects/__tests__/promote-command.test.js +170 -0
  58. package/dist/projects/__tests__/promote.test.js +181 -0
  59. package/dist/projects/__tests__/save-command.test.js +216 -0
  60. package/dist/projects/__tests__/save.test.js +41 -0
  61. package/dist/projects/__tests__/status.test.js +208 -0
  62. package/dist/projects/__tests__/types.test.js +41 -0
  63. package/dist/projects/__tests__/validate.test.js +165 -0
  64. package/dist/projects/__tests__/workspace.test.js +337 -0
  65. package/dist/repl/__tests__/current-transport.test.js +43 -0
  66. package/dist/repl/__tests__/diff-display.test.js +59 -0
  67. package/dist/repl/__tests__/file-picker.test.js +97 -0
  68. package/dist/repl/__tests__/rule8-detector.test.js +114 -0
  69. package/dist/repl/__tests__/safety-confirm.test.js +130 -0
  70. package/dist/repl/__tests__/safety-mode-state.test.js +42 -0
  71. package/dist/sap/__tests__/system-info.test.js +344 -0
  72. package/dist/session/__tests__/store-discovery.test.js +114 -0
  73. package/dist/session/__tests__/time-ago.test.js +53 -0
  74. package/dist/skills/__tests__/canonical.test.js +20 -0
  75. package/dist/skills/__tests__/manifest-client.test.js +88 -0
  76. package/dist/skills/__tests__/promotion-dispatch.test.js +28 -0
  77. package/dist/skills/__tests__/source-managed.test.js +60 -0
  78. package/dist/tools/__tests__/_background-shared.test.js +69 -0
  79. package/dist/tools/__tests__/_command-shared.test.js +59 -0
  80. package/dist/tools/__tests__/_filesystem-shared.test.js +42 -0
  81. package/dist/tools/__tests__/_flag.test.js +66 -0
  82. package/dist/tools/__tests__/_helpers.js +17 -0
  83. package/dist/tools/__tests__/_web-shared.test.js +143 -0
  84. package/dist/tools/__tests__/agent_run.test.js +166 -0
  85. package/dist/tools/__tests__/approval-advisory.test.js +66 -0
  86. package/dist/tools/__tests__/background_run.test.js +113 -0
  87. package/dist/tools/__tests__/convention_get.test.js +53 -0
  88. package/dist/tools/__tests__/file-edit.test.js +72 -0
  89. package/dist/tools/__tests__/file-read.test.js +81 -0
  90. package/dist/tools/__tests__/file-write.test.js +68 -0
  91. package/dist/tools/__tests__/glob.test.js +128 -0
  92. package/dist/tools/__tests__/grep.test.js +71 -0
  93. package/dist/tools/__tests__/monitor_emit.test.js +96 -0
  94. package/dist/tools/__tests__/playbook_get.test.js +109 -0
  95. package/dist/tools/__tests__/project_context_get.test.js +71 -0
  96. package/dist/tools/__tests__/registry-category.test.js +60 -0
  97. package/dist/tools/__tests__/sap-read-extras.test.js +196 -0
  98. package/dist/tools/__tests__/sap-write-extras.test.js +573 -0
  99. package/dist/tools/__tests__/schedule_create.test.js +85 -0
  100. package/dist/tools/__tests__/shell_exec.test.js +135 -0
  101. package/dist/tools/__tests__/transport-safety.test.js +106 -0
  102. package/dist/tools/__tests__/update-method-intercept.test.js +128 -0
  103. package/dist/tools/__tests__/web_fetch.test.js +329 -0
  104. package/dist/tools/__tests__/web_search.test.js +215 -0
  105. package/dist/tools/__tests__/write-mode.test.js +32 -0
  106. package/dist/ui/__tests__/login-banner.test.js +69 -0
  107. package/package.json +82 -83
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Tests for the 8 additional read-only SAP tools added in Phase 3-Lite A.4:
3
+ * sap_class_includes, sap_inactive_objects, sap_syntax_check, sap_diff,
4
+ * sap_preview_change, sap_run_unit_test, sap_odata_test, sap_badi_list
5
+ *
6
+ * Pattern: partial mock as `{ method: vi.fn() } as unknown as AdtClient`.
7
+ * Each tool gets a happy-path test and an error-path test (16 tests total).
8
+ */
9
+ import '../sap-read.js'; // triggers registration side-effect
10
+ import { getTool } from '../index.js';
11
+ import { describe, it, expect, vi } from 'vitest';
12
+ // ---------------------------------------------------------------------------
13
+ // Helper: build a minimal ToolContext stub
14
+ // ---------------------------------------------------------------------------
15
+ function makeCtx(adt) {
16
+ return {
17
+ adt: adt,
18
+ sapAlias: 'dev',
19
+ session: {},
20
+ cwd: '.',
21
+ };
22
+ }
23
+ // ---------------------------------------------------------------------------
24
+ // 11. sap_class_includes
25
+ // ---------------------------------------------------------------------------
26
+ describe('sap_class_includes', () => {
27
+ it('returns JSON array when no includeType is given', async () => {
28
+ const adt = {
29
+ classIncludes: vi.fn().mockResolvedValue([{ name: 'definitions' }, { name: 'implementations' }]),
30
+ };
31
+ const tool = getTool('sap_class_includes');
32
+ const result = await tool.handler({ className: 'ZCL_FOO' }, makeCtx(adt));
33
+ expect(adt.classIncludes).toHaveBeenCalledWith('ZCL_FOO', undefined);
34
+ expect(JSON.parse(result.content)).toEqual([{ name: 'definitions' }, { name: 'implementations' }]);
35
+ });
36
+ it('propagates error when classIncludes throws', async () => {
37
+ const adt = {
38
+ classIncludes: vi.fn().mockRejectedValue(new Error('ADT 404')),
39
+ };
40
+ const tool = getTool('sap_class_includes');
41
+ await expect(tool.handler({ className: 'ZCL_MISSING' }, makeCtx(adt))).rejects.toThrow('ADT 404');
42
+ });
43
+ });
44
+ // ---------------------------------------------------------------------------
45
+ // 12. sap_inactive_objects
46
+ // ---------------------------------------------------------------------------
47
+ describe('sap_inactive_objects', () => {
48
+ it('returns JSON list of inactive objects', async () => {
49
+ const adt = {
50
+ inactiveObjects: vi.fn().mockResolvedValue([{ name: 'ZCL_FOO', type: 'CLAS' }]),
51
+ };
52
+ const tool = getTool('sap_inactive_objects');
53
+ const result = await tool.handler({}, makeCtx(adt));
54
+ expect(adt.inactiveObjects).toHaveBeenCalledWith();
55
+ expect(JSON.parse(result.content)).toEqual([{ name: 'ZCL_FOO', type: 'CLAS' }]);
56
+ });
57
+ it('propagates error when inactiveObjects throws', async () => {
58
+ const adt = {
59
+ inactiveObjects: vi.fn().mockRejectedValue(new Error('ADT 503')),
60
+ };
61
+ const tool = getTool('sap_inactive_objects');
62
+ await expect(tool.handler({}, makeCtx(adt))).rejects.toThrow('ADT 503');
63
+ });
64
+ });
65
+ // ---------------------------------------------------------------------------
66
+ // 13. sap_syntax_check
67
+ // ---------------------------------------------------------------------------
68
+ describe('sap_syntax_check', () => {
69
+ it('calls syntaxCheck with type first and returns JSON result', async () => {
70
+ const fakeSyntaxResult = { hasErrors: false, messages: [] };
71
+ const adt = {
72
+ syntaxCheck: vi.fn().mockResolvedValue(fakeSyntaxResult),
73
+ };
74
+ const tool = getTool('sap_syntax_check');
75
+ const result = await tool.handler({ type: 'CLAS', name: 'ZCL_FOO' }, makeCtx(adt));
76
+ expect(adt.syntaxCheck).toHaveBeenCalledWith('CLAS', 'ZCL_FOO');
77
+ expect(JSON.parse(result.content)).toEqual(fakeSyntaxResult);
78
+ });
79
+ it('propagates error when syntaxCheck throws', async () => {
80
+ const adt = {
81
+ syntaxCheck: vi.fn().mockRejectedValue(new Error('connection refused')),
82
+ };
83
+ const tool = getTool('sap_syntax_check');
84
+ await expect(tool.handler({ type: 'CLAS', name: 'ZCL_FOO' }, makeCtx(adt))).rejects.toThrow('connection refused');
85
+ });
86
+ });
87
+ // ---------------------------------------------------------------------------
88
+ // 14. sap_diff
89
+ // ---------------------------------------------------------------------------
90
+ describe('sap_diff', () => {
91
+ it('calls diff with type first and returns JSON result', async () => {
92
+ const fakeDiff = { unified: '--- a\n+++ b\n@@ -1 +1 @@\n-old\n+new' };
93
+ const adt = {
94
+ diff: vi.fn().mockResolvedValue(fakeDiff),
95
+ };
96
+ const tool = getTool('sap_diff');
97
+ const result = await tool.handler({ type: 'PROG', name: 'ZTEST', version1: 'old', version2: 'new' }, makeCtx(adt));
98
+ expect(adt.diff).toHaveBeenCalledWith('PROG', 'ZTEST', 'old', 'new');
99
+ expect(JSON.parse(result.content)).toEqual(fakeDiff);
100
+ });
101
+ it('propagates error when diff throws', async () => {
102
+ const adt = {
103
+ diff: vi.fn().mockRejectedValue(new Error('ADT 401')),
104
+ };
105
+ const tool = getTool('sap_diff');
106
+ await expect(tool.handler({ type: 'PROG', name: 'ZTEST' }, makeCtx(adt))).rejects.toThrow('ADT 401');
107
+ });
108
+ });
109
+ // ---------------------------------------------------------------------------
110
+ // 15. sap_preview_change
111
+ // ---------------------------------------------------------------------------
112
+ describe('sap_preview_change', () => {
113
+ it('calls previewChange with type first and returns JSON result', async () => {
114
+ const fakeDiff = { unified: '@@ -1 +1 @@\n-old\n+new' };
115
+ const adt = {
116
+ previewChange: vi.fn().mockResolvedValue(fakeDiff),
117
+ };
118
+ const tool = getTool('sap_preview_change');
119
+ const result = await tool.handler({ type: 'CLAS', name: 'ZCL_FOO', newSource: 'CLASS ZCL_FOO...' }, makeCtx(adt));
120
+ expect(adt.previewChange).toHaveBeenCalledWith('CLAS', 'ZCL_FOO', 'CLASS ZCL_FOO...');
121
+ expect(JSON.parse(result.content)).toEqual(fakeDiff);
122
+ });
123
+ it('propagates error when previewChange throws', async () => {
124
+ const adt = {
125
+ previewChange: vi.fn().mockRejectedValue(new Error('object locked')),
126
+ };
127
+ const tool = getTool('sap_preview_change');
128
+ await expect(tool.handler({ type: 'CLAS', name: 'ZCL_FOO', newSource: 'x' }, makeCtx(adt))).rejects.toThrow('object locked');
129
+ });
130
+ });
131
+ // ---------------------------------------------------------------------------
132
+ // 16. sap_run_unit_test
133
+ // ---------------------------------------------------------------------------
134
+ describe('sap_run_unit_test', () => {
135
+ it('calls runUnitTest with type first and returns JSON result', async () => {
136
+ const fakeResult = { passed: 3, failed: 0, errors: 0, testClasses: [] };
137
+ const adt = {
138
+ runUnitTest: vi.fn().mockResolvedValue(fakeResult),
139
+ };
140
+ const tool = getTool('sap_run_unit_test');
141
+ const result = await tool.handler({ type: 'CLAS', name: 'ZCL_ORDER' }, makeCtx(adt));
142
+ expect(adt.runUnitTest).toHaveBeenCalledWith('CLAS', 'ZCL_ORDER');
143
+ expect(JSON.parse(result.content)).toEqual(fakeResult);
144
+ });
145
+ it('propagates error when runUnitTest throws', async () => {
146
+ const adt = {
147
+ runUnitTest: vi.fn().mockRejectedValue(new Error('ADT 500')),
148
+ };
149
+ const tool = getTool('sap_run_unit_test');
150
+ await expect(tool.handler({ type: 'CLAS', name: 'ZCL_ORDER' }, makeCtx(adt))).rejects.toThrow('ADT 500');
151
+ });
152
+ });
153
+ // ---------------------------------------------------------------------------
154
+ // 17. sap_odata_test
155
+ // ---------------------------------------------------------------------------
156
+ describe('sap_odata_test', () => {
157
+ it('calls odataTest with correct args and returns JSON result', async () => {
158
+ const fakeResult = { status: 200, body: '<service/>' };
159
+ const adt = {
160
+ odataTest: vi.fn().mockResolvedValue(fakeResult),
161
+ };
162
+ const tool = getTool('sap_odata_test');
163
+ const result = await tool.handler({ servicePath: '/sap/opu/odata/sap/ZSALES_SRV', entity: 'SalesOrder', method: 'GET' }, makeCtx(adt));
164
+ expect(adt.odataTest).toHaveBeenCalledWith('/sap/opu/odata/sap/ZSALES_SRV', 'SalesOrder', 'GET');
165
+ expect(JSON.parse(result.content)).toEqual(fakeResult);
166
+ });
167
+ it('propagates error when odataTest throws', async () => {
168
+ const adt = {
169
+ odataTest: vi.fn().mockRejectedValue(new Error('service not found')),
170
+ };
171
+ const tool = getTool('sap_odata_test');
172
+ await expect(tool.handler({ servicePath: '/sap/opu/odata/sap/ZMISSING_SRV' }, makeCtx(adt))).rejects.toThrow('service not found');
173
+ });
174
+ });
175
+ // ---------------------------------------------------------------------------
176
+ // 18. sap_badi_list
177
+ // ---------------------------------------------------------------------------
178
+ describe('sap_badi_list', () => {
179
+ it('calls badiList with correct args and returns JSON result', async () => {
180
+ const fakeResult = { badiDefinitions: [{ name: 'MD_PURCH_REQ_SAVE' }], enhancementSpots: [] };
181
+ const adt = {
182
+ badiList: vi.fn().mockResolvedValue(fakeResult),
183
+ };
184
+ const tool = getTool('sap_badi_list');
185
+ const result = await tool.handler({ query: 'MD_PURCH*', enhancementSpot: 'ES_MD_PURCH', maxResults: 25 }, makeCtx(adt));
186
+ expect(adt.badiList).toHaveBeenCalledWith('MD_PURCH*', 'ES_MD_PURCH', 25);
187
+ expect(JSON.parse(result.content)).toEqual(fakeResult);
188
+ });
189
+ it('propagates error when badiList throws', async () => {
190
+ const adt = {
191
+ badiList: vi.fn().mockRejectedValue(new Error('ADT 403')),
192
+ };
193
+ const tool = getTool('sap_badi_list');
194
+ await expect(tool.handler({ query: 'ZBADI*' }, makeCtx(adt))).rejects.toThrow('ADT 403');
195
+ });
196
+ });