digital-workers 0.1.1 → 2.0.2

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 (83) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/CHANGELOG.md +17 -0
  3. package/README.md +290 -106
  4. package/dist/actions.d.ts +95 -0
  5. package/dist/actions.d.ts.map +1 -0
  6. package/dist/actions.js +437 -0
  7. package/dist/actions.js.map +1 -0
  8. package/dist/approve.d.ts +49 -0
  9. package/dist/approve.d.ts.map +1 -0
  10. package/dist/approve.js +235 -0
  11. package/dist/approve.js.map +1 -0
  12. package/dist/ask.d.ts +42 -0
  13. package/dist/ask.d.ts.map +1 -0
  14. package/dist/ask.js +227 -0
  15. package/dist/ask.js.map +1 -0
  16. package/dist/decide.d.ts +62 -0
  17. package/dist/decide.d.ts.map +1 -0
  18. package/dist/decide.js +245 -0
  19. package/dist/decide.js.map +1 -0
  20. package/dist/do.d.ts +63 -0
  21. package/dist/do.d.ts.map +1 -0
  22. package/dist/do.js +228 -0
  23. package/dist/do.js.map +1 -0
  24. package/dist/generate.d.ts +61 -0
  25. package/dist/generate.d.ts.map +1 -0
  26. package/dist/generate.js +299 -0
  27. package/dist/generate.js.map +1 -0
  28. package/dist/goals.d.ts +89 -0
  29. package/dist/goals.d.ts.map +1 -0
  30. package/dist/goals.js +206 -0
  31. package/dist/goals.js.map +1 -0
  32. package/dist/index.d.ts +68 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +69 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/is.d.ts +54 -0
  37. package/dist/is.d.ts.map +1 -0
  38. package/dist/is.js +318 -0
  39. package/dist/is.js.map +1 -0
  40. package/dist/kpis.d.ts +103 -0
  41. package/dist/kpis.d.ts.map +1 -0
  42. package/dist/kpis.js +271 -0
  43. package/dist/kpis.js.map +1 -0
  44. package/dist/notify.d.ts +47 -0
  45. package/dist/notify.d.ts.map +1 -0
  46. package/dist/notify.js +220 -0
  47. package/dist/notify.js.map +1 -0
  48. package/dist/role.d.ts +53 -0
  49. package/dist/role.d.ts.map +1 -0
  50. package/dist/role.js +111 -0
  51. package/dist/role.js.map +1 -0
  52. package/dist/team.d.ts +61 -0
  53. package/dist/team.d.ts.map +1 -0
  54. package/dist/team.js +131 -0
  55. package/dist/team.js.map +1 -0
  56. package/dist/transports.d.ts +164 -0
  57. package/dist/transports.d.ts.map +1 -0
  58. package/dist/transports.js +358 -0
  59. package/dist/transports.js.map +1 -0
  60. package/dist/types.d.ts +693 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/dist/types.js +72 -0
  63. package/dist/types.js.map +1 -0
  64. package/package.json +27 -61
  65. package/src/actions.ts +615 -0
  66. package/src/approve.ts +317 -0
  67. package/src/ask.ts +304 -0
  68. package/src/decide.ts +295 -0
  69. package/src/do.ts +275 -0
  70. package/src/generate.ts +364 -0
  71. package/src/goals.ts +220 -0
  72. package/src/index.ts +118 -0
  73. package/src/is.ts +372 -0
  74. package/src/kpis.ts +348 -0
  75. package/src/notify.ts +303 -0
  76. package/src/role.ts +116 -0
  77. package/src/team.ts +142 -0
  78. package/src/transports.ts +504 -0
  79. package/src/types.ts +843 -0
  80. package/test/actions.test.ts +546 -0
  81. package/test/standalone.test.ts +299 -0
  82. package/test/types.test.ts +460 -0
  83. package/tsconfig.json +9 -0
@@ -0,0 +1,460 @@
1
+ /**
2
+ * Type tests for digital-workers
3
+ */
4
+
5
+ import { describe, it, expect, expectTypeOf } from 'vitest'
6
+ import type {
7
+ Worker,
8
+ WorkerType,
9
+ WorkerStatus,
10
+ WorkerRef,
11
+ Team,
12
+ Contacts,
13
+ ContactChannel,
14
+ WorkerAction,
15
+ NotifyActionData,
16
+ AskActionData,
17
+ ApproveActionData,
18
+ DecideActionData,
19
+ DoActionData,
20
+ NotifyResult,
21
+ AskResult,
22
+ ApprovalResult,
23
+ DecideResult,
24
+ DoResult,
25
+ ActionTarget,
26
+ WorkerContext,
27
+ } from '../src/types.js'
28
+
29
+ describe('Worker Types', () => {
30
+ describe('Worker interface', () => {
31
+ it('should have required properties', () => {
32
+ const worker: Worker = {
33
+ id: 'worker_1',
34
+ name: 'Test Worker',
35
+ type: 'human',
36
+ status: 'available',
37
+ contacts: {},
38
+ }
39
+
40
+ expect(worker.id).toBe('worker_1')
41
+ expect(worker.name).toBe('Test Worker')
42
+ expect(worker.type).toBe('human')
43
+ expect(worker.status).toBe('available')
44
+ })
45
+
46
+ it('should support human type', () => {
47
+ const human: Worker = {
48
+ id: 'human_1',
49
+ name: 'Alice',
50
+ type: 'human',
51
+ status: 'available',
52
+ contacts: {
53
+ email: 'alice@company.com',
54
+ slack: { workspace: 'acme', user: 'U123' },
55
+ },
56
+ }
57
+
58
+ expect(human.type).toBe('human')
59
+ })
60
+
61
+ it('should support agent type', () => {
62
+ const agent: Worker = {
63
+ id: 'agent_1',
64
+ name: 'Code Reviewer',
65
+ type: 'agent',
66
+ status: 'available',
67
+ contacts: {
68
+ api: { endpoint: 'https://api.internal/agent', auth: 'bearer' },
69
+ },
70
+ }
71
+
72
+ expect(agent.type).toBe('agent')
73
+ })
74
+
75
+ it('should support all worker statuses', () => {
76
+ const statuses: WorkerStatus[] = ['available', 'busy', 'away', 'offline']
77
+ expect(statuses).toHaveLength(4)
78
+ })
79
+ })
80
+
81
+ describe('WorkerRef interface', () => {
82
+ it('should be a lightweight reference', () => {
83
+ const ref: WorkerRef = { id: 'worker_1' }
84
+ expect(ref.id).toBe('worker_1')
85
+ })
86
+
87
+ it('should support optional properties', () => {
88
+ const ref: WorkerRef = {
89
+ id: 'worker_1',
90
+ type: 'human',
91
+ name: 'Alice',
92
+ role: 'Engineer',
93
+ }
94
+
95
+ expect(ref.type).toBe('human')
96
+ expect(ref.name).toBe('Alice')
97
+ expect(ref.role).toBe('Engineer')
98
+ })
99
+ })
100
+
101
+ describe('Team interface', () => {
102
+ it('should group workers', () => {
103
+ const team: Team = {
104
+ id: 'team_1',
105
+ name: 'Engineering',
106
+ members: [{ id: 'alice' }, { id: 'bob' }],
107
+ contacts: { slack: '#engineering' },
108
+ }
109
+
110
+ expect(team.members).toHaveLength(2)
111
+ expect(team.contacts.slack).toBe('#engineering')
112
+ })
113
+
114
+ it('should support lead and goals', () => {
115
+ const team: Team = {
116
+ id: 'team_1',
117
+ name: 'Engineering',
118
+ members: [{ id: 'alice' }],
119
+ contacts: {},
120
+ lead: { id: 'alice' },
121
+ goals: ['Ship v2.0', 'Reduce tech debt'],
122
+ }
123
+
124
+ expect(team.lead?.id).toBe('alice')
125
+ expect(team.goals).toHaveLength(2)
126
+ })
127
+ })
128
+
129
+ describe('Contacts interface', () => {
130
+ it('should support string contacts', () => {
131
+ const contacts: Contacts = {
132
+ email: 'test@example.com',
133
+ slack: '@user',
134
+ phone: '+1-555-1234',
135
+ }
136
+
137
+ expect(contacts.email).toBe('test@example.com')
138
+ })
139
+
140
+ it('should support object contacts', () => {
141
+ const contacts: Contacts = {
142
+ email: { address: 'test@example.com', name: 'Test User' },
143
+ slack: { workspace: 'acme', user: 'U123', channel: '#general' },
144
+ phone: { number: '+1-555-1234', country: 'US', verified: true },
145
+ }
146
+
147
+ expect((contacts.email as { address: string }).address).toBe('test@example.com')
148
+ })
149
+
150
+ it('should support all channel types', () => {
151
+ const channels: ContactChannel[] = [
152
+ 'email', 'slack', 'teams', 'discord', 'phone',
153
+ 'sms', 'whatsapp', 'telegram', 'web', 'api', 'webhook',
154
+ ]
155
+ expect(channels).toHaveLength(11)
156
+ })
157
+ })
158
+ })
159
+
160
+ describe('Action Types', () => {
161
+ describe('WorkerAction', () => {
162
+ it('should support all action types', () => {
163
+ const actions: WorkerAction[] = ['notify', 'ask', 'approve', 'decide', 'do']
164
+ expect(actions).toHaveLength(5)
165
+ })
166
+ })
167
+
168
+ describe('NotifyActionData', () => {
169
+ it('should have required properties', () => {
170
+ const data: NotifyActionData = {
171
+ actor: 'system',
172
+ object: { id: 'alice' },
173
+ action: 'notify',
174
+ message: 'Hello',
175
+ }
176
+
177
+ expect(data.action).toBe('notify')
178
+ expect(data.message).toBe('Hello')
179
+ })
180
+
181
+ it('should support priority and via', () => {
182
+ const data: NotifyActionData = {
183
+ actor: 'system',
184
+ object: 'alice',
185
+ action: 'notify',
186
+ message: 'Urgent!',
187
+ priority: 'urgent',
188
+ via: 'slack',
189
+ }
190
+
191
+ expect(data.priority).toBe('urgent')
192
+ expect(data.via).toBe('slack')
193
+ })
194
+ })
195
+
196
+ describe('AskActionData', () => {
197
+ it('should have question property', () => {
198
+ const data: AskActionData = {
199
+ actor: 'system',
200
+ object: { id: 'alice' },
201
+ action: 'ask',
202
+ question: 'What is the status?',
203
+ }
204
+
205
+ expect(data.action).toBe('ask')
206
+ expect(data.question).toBe('What is the status?')
207
+ })
208
+
209
+ it('should support schema and timeout', () => {
210
+ const data: AskActionData = {
211
+ actor: 'system',
212
+ object: 'alice',
213
+ action: 'ask',
214
+ question: 'Priority?',
215
+ schema: { priority: 'low | normal | high' },
216
+ timeout: 60000,
217
+ }
218
+
219
+ expect(data.schema).toBeDefined()
220
+ expect(data.timeout).toBe(60000)
221
+ })
222
+ })
223
+
224
+ describe('ApproveActionData', () => {
225
+ it('should have request property', () => {
226
+ const data: ApproveActionData = {
227
+ actor: { id: 'alice' },
228
+ object: 'expense_123',
229
+ action: 'approve',
230
+ request: 'Expense: $500',
231
+ }
232
+
233
+ expect(data.action).toBe('approve')
234
+ expect(data.request).toBe('Expense: $500')
235
+ })
236
+ })
237
+
238
+ describe('DecideActionData', () => {
239
+ it('should have options property', () => {
240
+ const data: DecideActionData = {
241
+ actor: 'ai',
242
+ object: 'decision',
243
+ action: 'decide',
244
+ options: ['A', 'B', 'C'],
245
+ }
246
+
247
+ expect(data.action).toBe('decide')
248
+ expect(data.options).toHaveLength(3)
249
+ })
250
+
251
+ it('should support context and criteria', () => {
252
+ const data: DecideActionData = {
253
+ actor: 'ai',
254
+ object: 'decision',
255
+ action: 'decide',
256
+ options: ['React', 'Vue'],
257
+ context: 'Choosing a framework',
258
+ criteria: ['DX', 'Performance'],
259
+ }
260
+
261
+ expect(data.context).toBe('Choosing a framework')
262
+ expect(data.criteria).toHaveLength(2)
263
+ })
264
+ })
265
+
266
+ describe('DoActionData', () => {
267
+ it('should have instruction property', () => {
268
+ const data: DoActionData = {
269
+ actor: { id: 'agent_1' },
270
+ object: 'production',
271
+ action: 'do',
272
+ instruction: 'Deploy v2.0',
273
+ }
274
+
275
+ expect(data.action).toBe('do')
276
+ expect(data.instruction).toBe('Deploy v2.0')
277
+ })
278
+
279
+ it('should support timeout and maxRetries', () => {
280
+ const data: DoActionData = {
281
+ actor: 'agent_1',
282
+ object: 'production',
283
+ action: 'do',
284
+ instruction: 'Deploy',
285
+ timeout: 300000,
286
+ maxRetries: 3,
287
+ }
288
+
289
+ expect(data.timeout).toBe(300000)
290
+ expect(data.maxRetries).toBe(3)
291
+ })
292
+ })
293
+ })
294
+
295
+ describe('Result Types', () => {
296
+ describe('NotifyResult', () => {
297
+ it('should indicate send status', () => {
298
+ const result: NotifyResult = {
299
+ sent: true,
300
+ via: ['slack'],
301
+ messageId: 'msg_123',
302
+ }
303
+
304
+ expect(result.sent).toBe(true)
305
+ expect(result.via).toContain('slack')
306
+ })
307
+
308
+ it('should include delivery details', () => {
309
+ const result: NotifyResult = {
310
+ sent: true,
311
+ via: ['slack', 'email'],
312
+ sentAt: new Date(),
313
+ delivery: [
314
+ { channel: 'slack', status: 'sent' },
315
+ { channel: 'email', status: 'delivered' },
316
+ ],
317
+ }
318
+
319
+ expect(result.delivery).toHaveLength(2)
320
+ })
321
+ })
322
+
323
+ describe('AskResult', () => {
324
+ it('should contain answer', () => {
325
+ const result: AskResult<string> = {
326
+ answer: 'The status is good',
327
+ answeredAt: new Date(),
328
+ }
329
+
330
+ expect(result.answer).toBe('The status is good')
331
+ })
332
+
333
+ it('should support typed answers', () => {
334
+ interface Priority {
335
+ level: 'low' | 'normal' | 'high'
336
+ }
337
+
338
+ const result: AskResult<Priority> = {
339
+ answer: { level: 'high' },
340
+ answeredBy: { id: 'alice' },
341
+ answeredAt: new Date(),
342
+ via: 'slack',
343
+ }
344
+
345
+ expect(result.answer.level).toBe('high')
346
+ })
347
+ })
348
+
349
+ describe('ApprovalResult', () => {
350
+ it('should indicate approval status', () => {
351
+ const result: ApprovalResult = {
352
+ approved: true,
353
+ approvedBy: { id: 'manager' },
354
+ approvedAt: new Date(),
355
+ }
356
+
357
+ expect(result.approved).toBe(true)
358
+ })
359
+
360
+ it('should support notes', () => {
361
+ const result: ApprovalResult = {
362
+ approved: false,
363
+ notes: 'Budget exceeded',
364
+ via: 'email',
365
+ }
366
+
367
+ expect(result.approved).toBe(false)
368
+ expect(result.notes).toBe('Budget exceeded')
369
+ })
370
+ })
371
+
372
+ describe('DecideResult', () => {
373
+ it('should contain choice and reasoning', () => {
374
+ const result: DecideResult<string> = {
375
+ choice: 'React',
376
+ reasoning: 'Best ecosystem support',
377
+ confidence: 0.85,
378
+ }
379
+
380
+ expect(result.choice).toBe('React')
381
+ expect(result.confidence).toBe(0.85)
382
+ })
383
+
384
+ it('should support alternatives', () => {
385
+ const result: DecideResult<string> = {
386
+ choice: 'React',
387
+ reasoning: 'Best ecosystem',
388
+ confidence: 0.85,
389
+ alternatives: [
390
+ { option: 'Vue', score: 75 },
391
+ { option: 'Svelte', score: 65 },
392
+ ],
393
+ }
394
+
395
+ expect(result.alternatives).toHaveLength(2)
396
+ })
397
+ })
398
+
399
+ describe('DoResult', () => {
400
+ it('should indicate success and result', () => {
401
+ const result: DoResult<{ deployed: boolean }> = {
402
+ result: { deployed: true },
403
+ success: true,
404
+ duration: 5000,
405
+ }
406
+
407
+ expect(result.success).toBe(true)
408
+ expect(result.result.deployed).toBe(true)
409
+ })
410
+
411
+ it('should track steps', () => {
412
+ const result: DoResult = {
413
+ result: { done: true },
414
+ success: true,
415
+ steps: [
416
+ { action: 'start', result: {}, timestamp: new Date() },
417
+ { action: 'complete', result: { done: true }, timestamp: new Date() },
418
+ ],
419
+ }
420
+
421
+ expect(result.steps).toHaveLength(2)
422
+ })
423
+ })
424
+ })
425
+
426
+ describe('ActionTarget Type', () => {
427
+ it('should accept Worker', () => {
428
+ const worker: Worker = {
429
+ id: 'alice',
430
+ name: 'Alice',
431
+ type: 'human',
432
+ status: 'available',
433
+ contacts: {},
434
+ }
435
+ const target: ActionTarget = worker
436
+ expect(target).toBeDefined()
437
+ })
438
+
439
+ it('should accept Team', () => {
440
+ const team: Team = {
441
+ id: 'eng',
442
+ name: 'Engineering',
443
+ members: [],
444
+ contacts: {},
445
+ }
446
+ const target: ActionTarget = team
447
+ expect(target).toBeDefined()
448
+ })
449
+
450
+ it('should accept WorkerRef', () => {
451
+ const ref: WorkerRef = { id: 'alice' }
452
+ const target: ActionTarget = ref
453
+ expect(target).toBeDefined()
454
+ })
455
+
456
+ it('should accept string', () => {
457
+ const target: ActionTarget = 'alice'
458
+ expect(target).toBe('alice')
459
+ })
460
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
9
+ }