@tagma/sdk 0.7.4 → 0.7.5

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 (190) hide show
  1. package/README.md +60 -53
  2. package/dist/completions/file-exists.js +1 -1
  3. package/dist/completions/file-exists.js.map +1 -1
  4. package/dist/completions/output-check.d.ts.map +1 -1
  5. package/dist/completions/output-check.js +17 -4
  6. package/dist/completions/output-check.js.map +1 -1
  7. package/dist/config.d.ts +4 -4
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +2 -2
  10. package/dist/config.js.map +1 -1
  11. package/dist/dataflow.d.ts +3 -0
  12. package/dist/dataflow.d.ts.map +1 -0
  13. package/dist/dataflow.js +2 -0
  14. package/dist/dataflow.js.map +1 -0
  15. package/dist/drivers/opencode.d.ts.map +1 -1
  16. package/dist/drivers/opencode.js +23 -71
  17. package/dist/drivers/opencode.js.map +1 -1
  18. package/dist/middlewares/static-context.d.ts.map +1 -1
  19. package/dist/middlewares/static-context.js +1 -2
  20. package/dist/middlewares/static-context.js.map +1 -1
  21. package/dist/pipeline-runner.d.ts.map +1 -1
  22. package/dist/pipeline-runner.js +2 -2
  23. package/dist/pipeline-runner.js.map +1 -1
  24. package/dist/schema.d.ts.map +1 -1
  25. package/dist/schema.js +3 -4
  26. package/dist/schema.js.map +1 -1
  27. package/dist/triggers/file.d.ts.map +1 -1
  28. package/dist/triggers/file.js +1 -2
  29. package/dist/triggers/file.js.map +1 -1
  30. package/dist/triggers/manual.d.ts.map +1 -1
  31. package/dist/triggers/manual.js +1 -2
  32. package/dist/triggers/manual.js.map +1 -1
  33. package/dist/types.d.ts +1 -2
  34. package/dist/types.d.ts.map +1 -1
  35. package/dist/types.js +1 -12
  36. package/dist/types.js.map +1 -1
  37. package/dist/utils-api.d.ts +1 -1
  38. package/dist/utils-api.d.ts.map +1 -1
  39. package/dist/utils-api.js +1 -1
  40. package/dist/utils-api.js.map +1 -1
  41. package/dist/validate-raw.d.ts.map +1 -1
  42. package/dist/validate-raw.js +5 -12
  43. package/dist/validate-raw.js.map +1 -1
  44. package/package.json +11 -24
  45. package/dist/adapters/stdin-approval.d.ts +0 -2
  46. package/dist/adapters/stdin-approval.d.ts.map +0 -1
  47. package/dist/adapters/stdin-approval.js +0 -2
  48. package/dist/adapters/stdin-approval.js.map +0 -1
  49. package/dist/adapters/websocket-approval.d.ts +0 -2
  50. package/dist/adapters/websocket-approval.d.ts.map +0 -1
  51. package/dist/adapters/websocket-approval.js +0 -2
  52. package/dist/adapters/websocket-approval.js.map +0 -1
  53. package/dist/core/dataflow.d.ts +0 -23
  54. package/dist/core/dataflow.d.ts.map +0 -1
  55. package/dist/core/dataflow.js +0 -99
  56. package/dist/core/dataflow.js.map +0 -1
  57. package/dist/core/log-prune.d.ts +0 -16
  58. package/dist/core/log-prune.d.ts.map +0 -1
  59. package/dist/core/log-prune.js +0 -34
  60. package/dist/core/log-prune.js.map +0 -1
  61. package/dist/core/preflight.d.ts +0 -13
  62. package/dist/core/preflight.d.ts.map +0 -1
  63. package/dist/core/preflight.js +0 -61
  64. package/dist/core/preflight.js.map +0 -1
  65. package/dist/core/run-context.d.ts +0 -55
  66. package/dist/core/run-context.d.ts.map +0 -1
  67. package/dist/core/run-context.js +0 -158
  68. package/dist/core/run-context.js.map +0 -1
  69. package/dist/core/run-state.d.ts +0 -25
  70. package/dist/core/run-state.d.ts.map +0 -1
  71. package/dist/core/run-state.js +0 -93
  72. package/dist/core/run-state.js.map +0 -1
  73. package/dist/core/scheduler.d.ts +0 -13
  74. package/dist/core/scheduler.d.ts.map +0 -1
  75. package/dist/core/scheduler.js +0 -35
  76. package/dist/core/scheduler.js.map +0 -1
  77. package/dist/core/task-executor.d.ts +0 -13
  78. package/dist/core/task-executor.d.ts.map +0 -1
  79. package/dist/core/task-executor.js +0 -610
  80. package/dist/core/task-executor.js.map +0 -1
  81. package/dist/core/trigger-errors.d.ts +0 -9
  82. package/dist/core/trigger-errors.d.ts.map +0 -1
  83. package/dist/core/trigger-errors.js +0 -15
  84. package/dist/core/trigger-errors.js.map +0 -1
  85. package/dist/dag.d.ts +0 -45
  86. package/dist/dag.d.ts.map +0 -1
  87. package/dist/dag.js +0 -177
  88. package/dist/dag.js.map +0 -1
  89. package/dist/hooks.d.ts +0 -73
  90. package/dist/hooks.d.ts.map +0 -1
  91. package/dist/hooks.js +0 -106
  92. package/dist/hooks.js.map +0 -1
  93. package/dist/pipeline-definition.d.ts +0 -3
  94. package/dist/pipeline-definition.d.ts.map +0 -1
  95. package/dist/pipeline-definition.js +0 -4
  96. package/dist/pipeline-definition.js.map +0 -1
  97. package/dist/ports.d.ts +0 -196
  98. package/dist/ports.d.ts.map +0 -1
  99. package/dist/ports.js +0 -688
  100. package/dist/ports.js.map +0 -1
  101. package/dist/prompt-doc.d.ts +0 -70
  102. package/dist/prompt-doc.d.ts.map +0 -1
  103. package/dist/prompt-doc.js +0 -154
  104. package/dist/prompt-doc.js.map +0 -1
  105. package/dist/registry.d.ts +0 -3
  106. package/dist/registry.d.ts.map +0 -1
  107. package/dist/registry.js +0 -2
  108. package/dist/registry.js.map +0 -1
  109. package/dist/task-ref.d.ts +0 -55
  110. package/dist/task-ref.d.ts.map +0 -1
  111. package/dist/task-ref.js +0 -103
  112. package/dist/task-ref.js.map +0 -1
  113. package/dist/utils.d.ts +0 -13
  114. package/dist/utils.d.ts.map +0 -1
  115. package/dist/utils.js +0 -177
  116. package/dist/utils.js.map +0 -1
  117. package/src/adapters/stdin-approval.ts +0 -1
  118. package/src/adapters/websocket-approval.ts +0 -1
  119. package/src/approval.ts +0 -9
  120. package/src/bootstrap.ts +0 -55
  121. package/src/completions/exit-code.ts +0 -34
  122. package/src/completions/file-exists.ts +0 -66
  123. package/src/completions/output-check.test.ts +0 -50
  124. package/src/completions/output-check.ts +0 -92
  125. package/src/config-ops.test.ts +0 -70
  126. package/src/config-ops.ts +0 -328
  127. package/src/config.ts +0 -26
  128. package/src/core/dataflow.test.ts +0 -166
  129. package/src/core/dataflow.ts +0 -161
  130. package/src/core/log-prune.test.ts +0 -58
  131. package/src/core/log-prune.ts +0 -43
  132. package/src/core/preflight.test.ts +0 -49
  133. package/src/core/preflight.ts +0 -89
  134. package/src/core/run-context.test.ts +0 -291
  135. package/src/core/run-context.ts +0 -211
  136. package/src/core/run-state.test.ts +0 -98
  137. package/src/core/run-state.ts +0 -122
  138. package/src/core/scheduler.test.ts +0 -83
  139. package/src/core/scheduler.ts +0 -42
  140. package/src/core/task-executor.ts +0 -752
  141. package/src/core/trigger-errors.ts +0 -15
  142. package/src/dag.test.ts +0 -56
  143. package/src/dag.ts +0 -245
  144. package/src/drivers/opencode.ts +0 -410
  145. package/src/engine-ports-mixed.test.ts +0 -182
  146. package/src/engine-ports.test.ts +0 -210
  147. package/src/engine-task-type.test.ts +0 -56
  148. package/src/engine.ts +0 -32
  149. package/src/hooks.ts +0 -193
  150. package/src/index.ts +0 -31
  151. package/src/logger.ts +0 -2
  152. package/src/middlewares/static-context.ts +0 -49
  153. package/src/package-split.test.ts +0 -15
  154. package/src/pipeline-definition.ts +0 -5
  155. package/src/pipeline-runner.test.ts +0 -144
  156. package/src/pipeline-runner.ts +0 -194
  157. package/src/plugin-registry.test.ts +0 -448
  158. package/src/plugins.ts +0 -21
  159. package/src/ports.test.ts +0 -678
  160. package/src/ports.ts +0 -925
  161. package/src/prompt-doc.test.ts +0 -174
  162. package/src/prompt-doc.ts +0 -169
  163. package/src/registry.ts +0 -7
  164. package/src/runner.test.ts +0 -142
  165. package/src/runner.ts +0 -1
  166. package/src/runtime/adapters/stdin-approval.ts +0 -1
  167. package/src/runtime/adapters/websocket-approval.ts +0 -1
  168. package/src/runtime/bun-process-runner.ts +0 -1
  169. package/src/runtime-adapters.test.ts +0 -10
  170. package/src/runtime.ts +0 -12
  171. package/src/schema-ports.test.ts +0 -172
  172. package/src/schema.test.ts +0 -213
  173. package/src/schema.ts +0 -379
  174. package/src/tagma.test.ts +0 -317
  175. package/src/tagma.ts +0 -67
  176. package/src/task-ref.test.ts +0 -401
  177. package/src/task-ref.ts +0 -121
  178. package/src/triggers/file.test.ts +0 -79
  179. package/src/triggers/file.ts +0 -131
  180. package/src/triggers/manual.ts +0 -86
  181. package/src/types.ts +0 -18
  182. package/src/utils-api.ts +0 -8
  183. package/src/utils.test.ts +0 -28
  184. package/src/utils.ts +0 -203
  185. package/src/validate-raw-plugin-types.test.ts +0 -60
  186. package/src/validate-raw-ports.test.ts +0 -136
  187. package/src/validate-raw.ts +0 -852
  188. package/src/yaml-compiler.test.ts +0 -108
  189. package/src/yaml-compiler.ts +0 -110
  190. package/src/yaml.ts +0 -11
@@ -1,448 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { PluginRegistry } from './registry';
3
- import { bootstrapBuiltins } from './bootstrap';
4
- import { runPipeline } from './engine';
5
- import type { DriverPlugin, TriggerPlugin, PipelineConfig, TagmaRuntime, TaskResult } from './types';
6
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
7
- import { tmpdir } from 'node:os';
8
- import { join } from 'node:path';
9
- import type { TagmaPlugin } from './types';
10
-
11
- function makeDriver(name: string, marker: string[]): DriverPlugin {
12
- return {
13
- name,
14
- capabilities: { sessionResume: false, systemPrompt: false, outputFormat: false },
15
- async buildCommand() {
16
- marker.push(`buildCommand:${name}`);
17
- return { args: ['echo', 'noop'] };
18
- },
19
- };
20
- }
21
-
22
- function makeTrigger(name: string, marker: string[]): TriggerPlugin {
23
- return {
24
- name,
25
- async watch() {
26
- marker.push(`watch:${name}`);
27
- },
28
- };
29
- }
30
-
31
- function taskResult(stdout = 'ok\n'): TaskResult {
32
- return {
33
- exitCode: 0,
34
- stdout,
35
- stderr: '',
36
- stdoutPath: null,
37
- stderrPath: null,
38
- stdoutBytes: stdout.length,
39
- stderrBytes: 0,
40
- durationMs: 1,
41
- sessionId: null,
42
- normalizedOutput: null,
43
- failureKind: null,
44
- };
45
- }
46
-
47
- function fakeRuntime(): TagmaRuntime {
48
- return {
49
- async runCommand() {
50
- return taskResult();
51
- },
52
- async runSpawn() {
53
- return taskResult();
54
- },
55
- async ensureDir() {
56
- /* no-op */
57
- },
58
- async fileExists() {
59
- return false;
60
- },
61
- async *watch() {
62
- /* no-op */
63
- },
64
- logStore: {
65
- openRunLog({ runId }) {
66
- return {
67
- path: `mem://${runId}/pipeline.log`,
68
- dir: `mem://${runId}`,
69
- append() {
70
- /* memory sink */
71
- },
72
- close() {
73
- /* memory sink */
74
- },
75
- };
76
- },
77
- taskOutputPath({ runId, taskId, stream }) {
78
- return `mem://${runId}/${taskId}.${stream}`;
79
- },
80
- logsDir() {
81
- return 'mem://logs';
82
- },
83
- },
84
- now: () => new Date('2026-04-26T00:00:00.000Z'),
85
- sleep: () => Promise.resolve(),
86
- };
87
- }
88
-
89
- describe('PluginRegistry — instance isolation', () => {
90
- test('two registries do not share drivers registered under the same type', () => {
91
- const regA = new PluginRegistry();
92
- const regB = new PluginRegistry();
93
- const markerA: string[] = [];
94
- const markerB: string[] = [];
95
-
96
- regA.registerPlugin('drivers', 'mock', makeDriver('mockA', markerA));
97
- regB.registerPlugin('drivers', 'mock', makeDriver('mockB', markerB));
98
-
99
- expect(regA.getHandler<DriverPlugin>('drivers', 'mock').name).toBe('mockA');
100
- expect(regB.getHandler<DriverPlugin>('drivers', 'mock').name).toBe('mockB');
101
-
102
- expect(regA.hasHandler('drivers', 'mock')).toBe(true);
103
- expect(regB.hasHandler('drivers', 'mock')).toBe(true);
104
- expect(regA.hasHandler('triggers', 'mock')).toBe(false);
105
- });
106
-
107
- test('unregistering in one registry does not affect the other', () => {
108
- const regA = new PluginRegistry();
109
- const regB = new PluginRegistry();
110
- regA.registerPlugin('drivers', 'mock', makeDriver('mockA', []));
111
- regB.registerPlugin('drivers', 'mock', makeDriver('mockB', []));
112
-
113
- expect(regA.unregisterPlugin('drivers', 'mock')).toBe(true);
114
- expect(regA.hasHandler('drivers', 'mock')).toBe(false);
115
- expect(regB.hasHandler('drivers', 'mock')).toBe(true);
116
- });
117
-
118
- test('listRegistered is scoped per instance', () => {
119
- const regA = new PluginRegistry();
120
- const regB = new PluginRegistry();
121
- regA.registerPlugin('triggers', 'a-only', makeTrigger('a-only', []));
122
- regB.registerPlugin('triggers', 'b-only', makeTrigger('b-only', []));
123
-
124
- expect(regA.listRegistered('triggers')).toEqual(['a-only']);
125
- expect(regB.listRegistered('triggers')).toEqual(['b-only']);
126
- });
127
-
128
- test('registering the same instance twice returns unchanged', () => {
129
- const reg = new PluginRegistry();
130
- const driver = makeDriver('same', []);
131
- expect(reg.registerPlugin('drivers', 'mock', driver)).toBe('registered');
132
- expect(reg.registerPlugin('drivers', 'mock', driver)).toBe('unchanged');
133
- });
134
-
135
- test('replacing with a different handler returns replaced', () => {
136
- const reg = new PluginRegistry();
137
- expect(reg.registerPlugin('drivers', 'mock', makeDriver('one', []))).toBe('registered');
138
- expect(reg.registerPlugin('drivers', 'mock', makeDriver('two', []))).toBe('replaced');
139
- expect(reg.getHandler<DriverPlugin>('drivers', 'mock').name).toBe('two');
140
- });
141
-
142
- test('bootstrapBuiltins(target) populates a specific instance', () => {
143
- const fresh = new PluginRegistry();
144
- expect(fresh.hasHandler('drivers', 'opencode')).toBe(false);
145
-
146
- bootstrapBuiltins(fresh);
147
-
148
- expect(fresh.hasHandler('drivers', 'opencode')).toBe(true);
149
- expect(fresh.hasHandler('triggers', 'file')).toBe(true);
150
- expect(fresh.hasHandler('triggers', 'manual')).toBe(true);
151
- expect(fresh.hasHandler('completions', 'exit_code')).toBe(true);
152
- expect(fresh.hasHandler('middlewares', 'static_context')).toBe(true);
153
-
154
- // Default registry's state is independent of `fresh` — if the default
155
- // happens to have opencode (because another test bootstrapped it), that
156
- // is fine; the guarantee is that `fresh.unregister` does not leak.
157
- fresh.unregisterPlugin('drivers', 'opencode');
158
- expect(fresh.hasHandler('drivers', 'opencode')).toBe(false);
159
- });
160
- });
161
-
162
- describe('PluginRegistry — capability plugins', () => {
163
- test('registerTagmaPlugin registers multiple capabilities from one package', () => {
164
- const reg = new PluginRegistry();
165
- const driver = makeDriver('cap-driver', []);
166
- const trigger = makeTrigger('cap-trigger', []);
167
- const plugin: TagmaPlugin = {
168
- name: 'tagma-plugin-multi',
169
- capabilities: {
170
- drivers: { cap_driver: driver },
171
- triggers: { cap_trigger: trigger },
172
- },
173
- };
174
-
175
- expect(reg.registerTagmaPlugin(plugin)).toEqual([
176
- { category: 'drivers', type: 'cap_driver', result: 'registered' },
177
- { category: 'triggers', type: 'cap_trigger', result: 'registered' },
178
- ]);
179
- expect(reg.getHandler<DriverPlugin>('drivers', 'cap_driver')).toBe(driver);
180
- expect(reg.getHandler<TriggerPlugin>('triggers', 'cap_trigger')).toBe(trigger);
181
- });
182
-
183
- test('registerTagmaPlugin keeps replacement warnings from the registry path', () => {
184
- const reg = new PluginRegistry();
185
- const originalWarn = console.warn;
186
- const warnings: string[] = [];
187
- console.warn = (message?: unknown) => {
188
- warnings.push(String(message));
189
- };
190
- try {
191
- reg.registerPlugin('drivers', 'mock', makeDriver('first', []));
192
- const result = reg.registerTagmaPlugin({
193
- name: 'tagma-plugin-replacement',
194
- capabilities: {
195
- drivers: { mock: makeDriver('second', []) },
196
- },
197
- });
198
-
199
- expect(result).toEqual([{ category: 'drivers', type: 'mock', result: 'replaced' }]);
200
- expect(warnings).toContain(
201
- '[tagma-sdk] registerPlugin: replaced existing drivers/mock - check for duplicate plugin packages claiming the same type.',
202
- );
203
- } finally {
204
- console.warn = originalWarn;
205
- }
206
- });
207
-
208
- test('loadPlugins accepts capability plugin default exports', async () => {
209
- const dir = mkdtempSync(join(tmpdir(), 'tagma-capability-plugin-'));
210
- const pluginDir = join(dir, 'node_modules', 'tagma-plugin-capability');
211
- mkdirSync(pluginDir, { recursive: true });
212
- writeFileSync(
213
- join(pluginDir, 'package.json'),
214
- JSON.stringify({ name: 'tagma-plugin-capability', version: '1.0.0', type: 'module', main: './index.js' }),
215
- 'utf-8',
216
- );
217
- writeFileSync(
218
- join(pluginDir, 'index.js'),
219
- [
220
- 'const driver = {',
221
- " name: 'cap-driver',",
222
- ' capabilities: { sessionResume: false, systemPrompt: false, outputFormat: false },',
223
- " async buildCommand() { return { args: ['echo', 'cap'] }; },",
224
- '};',
225
- 'const trigger = {',
226
- " name: 'cap-trigger',",
227
- ' async watch() {}',
228
- '};',
229
- 'export default {',
230
- " name: 'tagma-plugin-capability',",
231
- ' capabilities: {',
232
- ' drivers: { cap_driver: driver },',
233
- ' triggers: { cap_trigger: trigger },',
234
- ' },',
235
- '};',
236
- '',
237
- ].join('\n'),
238
- 'utf-8',
239
- );
240
-
241
- try {
242
- const reg = new PluginRegistry();
243
- await reg.loadPlugins(['tagma-plugin-capability'], dir);
244
- expect(reg.hasHandler('drivers', 'cap_driver')).toBe(true);
245
- expect(reg.hasHandler('triggers', 'cap_trigger')).toBe(true);
246
- } finally {
247
- rmSync(dir, { recursive: true, force: true });
248
- }
249
- });
250
-
251
- test('loadPlugins rejects legacy plugin module exports', async () => {
252
- const dir = mkdtempSync(join(tmpdir(), 'tagma-legacy-plugin-'));
253
- const pluginDir = join(dir, 'node_modules', 'tagma-plugin-legacy');
254
- mkdirSync(pluginDir, { recursive: true });
255
- writeFileSync(
256
- join(pluginDir, 'package.json'),
257
- JSON.stringify({ name: 'tagma-plugin-legacy', version: '1.0.0', type: 'module', main: './index.js' }),
258
- 'utf-8',
259
- );
260
- writeFileSync(
261
- join(pluginDir, 'index.js'),
262
- [
263
- "export const pluginCategory = 'drivers';",
264
- "export const pluginType = 'legacy';",
265
- 'export default {',
266
- " name: 'legacy',",
267
- ' capabilities: { sessionResume: false, systemPrompt: false, outputFormat: false },',
268
- " async buildCommand() { return { args: ['echo', 'legacy'] }; },",
269
- '};',
270
- '',
271
- ].join('\n'),
272
- 'utf-8',
273
- );
274
-
275
- try {
276
- const reg = new PluginRegistry();
277
- await expect(reg.loadPlugins(['tagma-plugin-legacy'], dir)).rejects.toThrow(
278
- /must default-export a TagmaPlugin/,
279
- );
280
- } finally {
281
- rmSync(dir, { recursive: true, force: true });
282
- }
283
- });
284
- });
285
-
286
- describe('PluginRegistry — validation', () => {
287
- test('rejects unknown category', () => {
288
- const reg = new PluginRegistry();
289
- expect(() =>
290
- reg.registerPlugin(
291
- 'nope' as 'drivers',
292
- 'x',
293
- makeDriver('x', []),
294
- ),
295
- ).toThrow(/Unknown plugin category/);
296
- });
297
-
298
- test('rejects driver missing buildCommand', () => {
299
- const reg = new PluginRegistry();
300
- expect(() =>
301
- reg.registerPlugin(
302
- 'drivers',
303
- 'broken',
304
- // deliberately bad: no buildCommand
305
- { name: 'broken', capabilities: { sessionResume: false, systemPrompt: false, outputFormat: false } } as unknown as DriverPlugin,
306
- ),
307
- ).toThrow(/must export buildCommand/);
308
- });
309
-
310
- test('rejects handler with missing name', () => {
311
- const reg = new PluginRegistry();
312
- expect(() =>
313
- reg.registerPlugin(
314
- 'drivers',
315
- 'x',
316
- // deliberately bad: no name
317
- { capabilities: { sessionResume: false, systemPrompt: false, outputFormat: false }, buildCommand: async () => ({ args: [] }) } as unknown as DriverPlugin,
318
- ),
319
- ).toThrow(/non-empty "name"/);
320
- });
321
-
322
- test('rejects plugin type identifiers that are not YAML-safe ids', () => {
323
- const reg = new PluginRegistry();
324
- expect(() =>
325
- reg.registerPlugin(
326
- 'drivers',
327
- '../evil',
328
- makeDriver('evil', []),
329
- ),
330
- ).toThrow(/Plugin type .* must match/);
331
- });
332
-
333
- test('middleware install hint uses singular middleware package name', () => {
334
- const reg = new PluginRegistry();
335
- expect(() => reg.getHandler('middlewares', 'audit')).toThrow(
336
- /bun add @tagma\/middleware-audit/,
337
- );
338
- });
339
-
340
- test('rejects middleware without enhanceDoc', () => {
341
- const reg = new PluginRegistry();
342
- expect(() =>
343
- reg.registerPlugin('middlewares', 'old', {
344
- name: 'old',
345
- async enhance(prompt: string) {
346
- return prompt;
347
- },
348
- } as never),
349
- ).toThrow(/must export enhanceDoc/);
350
- });
351
- });
352
-
353
- describe('runPipeline — options.registry isolation', () => {
354
- test('concurrent runs with different registries see their own drivers', async () => {
355
- const regA = new PluginRegistry();
356
- const regB = new PluginRegistry();
357
- const seenA: string[] = [];
358
- const seenB: string[] = [];
359
-
360
- bootstrapBuiltins(regA);
361
- bootstrapBuiltins(regB);
362
-
363
- regA.registerPlugin('drivers', 'mock', makeDriver('mockA', seenA));
364
- regB.registerPlugin('drivers', 'mock', makeDriver('mockB', seenB));
365
-
366
- // Command-only pipeline exercises the preflight path (which uses the
367
- // registry) plus the run-loop path without requiring a real driver
368
- // invocation. We verify isolation by asserting that preflight with a
369
- // registry missing `mock` rejects, while the matching registry accepts.
370
- const config: PipelineConfig = {
371
- name: 'isolation-test',
372
- tracks: [
373
- {
374
- id: 't',
375
- name: 'T',
376
- tasks: [{ id: 'only', name: 'only', command: 'echo hi' }],
377
- },
378
- ],
379
- };
380
-
381
- const tmpA = mkdtempSync(join(tmpdir(), 'tagma-regA-'));
382
- const tmpB = mkdtempSync(join(tmpdir(), 'tagma-regB-'));
383
- try {
384
- const [resA, resB] = await Promise.all([
385
- runPipeline(config, tmpA, {
386
- registry: regA,
387
- runtime: fakeRuntime(),
388
- skipPluginLoading: true,
389
- }),
390
- runPipeline(config, tmpB, {
391
- registry: regB,
392
- runtime: fakeRuntime(),
393
- skipPluginLoading: true,
394
- }),
395
- ]);
396
- expect(resA.success).toBe(true);
397
- expect(resB.success).toBe(true);
398
- expect(resA.runId).not.toBe(resB.runId);
399
- } finally {
400
- rmSync(tmpA, { recursive: true, force: true });
401
- rmSync(tmpB, { recursive: true, force: true });
402
- }
403
- });
404
-
405
- test('preflight fails when referenced driver is missing from the passed registry', async () => {
406
- const regNoOpencode = new PluginRegistry();
407
- // Deliberately do NOT bootstrap builtins — opencode is not registered.
408
- const config: PipelineConfig = {
409
- name: 'preflight-miss',
410
- tracks: [
411
- {
412
- id: 't',
413
- name: 'T',
414
- tasks: [{ id: 'x', name: 'x', prompt: 'hello' }],
415
- },
416
- ],
417
- };
418
- const tmp = mkdtempSync(join(tmpdir(), 'tagma-miss-'));
419
- try {
420
- await expect(
421
- runPipeline(config, tmp, { registry: regNoOpencode, skipPluginLoading: true }),
422
- ).rejects.toThrow(/driver "opencode" not registered/);
423
- } finally {
424
- rmSync(tmp, { recursive: true, force: true });
425
- }
426
- });
427
-
428
- test('runPipeline rejects missing explicit registry', async () => {
429
- const config: PipelineConfig = {
430
- name: 'missing-registry',
431
- tracks: [
432
- {
433
- id: 't',
434
- name: 'T',
435
- tasks: [{ id: 'only', name: 'only', command: 'echo hi' }],
436
- },
437
- ],
438
- };
439
- const tmp = mkdtempSync(join(tmpdir(), 'tagma-default-'));
440
- try {
441
- await expect(
442
- runPipeline(config, tmp, { skipPluginLoading: true } as never),
443
- ).rejects.toThrow(/requires options\.registry/);
444
- } finally {
445
- rmSync(tmp, { recursive: true, force: true });
446
- }
447
- });
448
- });
package/src/plugins.ts DELETED
@@ -1,21 +0,0 @@
1
- export { bootstrapBuiltins } from './bootstrap';
2
- export {
3
- PluginRegistry,
4
- isValidPluginName,
5
- PLUGIN_NAME_RE,
6
- readPluginManifest,
7
- } from '@tagma/core';
8
- export type { RegisteredCapability, RegisterResult } from '@tagma/core';
9
- export type {
10
- CapabilityHandler,
11
- PluginCategory,
12
- PluginCapabilities,
13
- PluginModule,
14
- PluginManifest,
15
- PluginSetupContext,
16
- TagmaPlugin,
17
- DriverPlugin,
18
- TriggerPlugin,
19
- CompletionPlugin,
20
- MiddlewarePlugin,
21
- } from './types';