@tagma/sdk 0.7.4 → 0.7.6

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 (191) 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 +4 -4
  42. package/dist/validate-raw.d.ts.map +1 -1
  43. package/dist/validate-raw.js +45 -52
  44. package/dist/validate-raw.js.map +1 -1
  45. package/package.json +11 -24
  46. package/dist/adapters/stdin-approval.d.ts +0 -2
  47. package/dist/adapters/stdin-approval.d.ts.map +0 -1
  48. package/dist/adapters/stdin-approval.js +0 -2
  49. package/dist/adapters/stdin-approval.js.map +0 -1
  50. package/dist/adapters/websocket-approval.d.ts +0 -2
  51. package/dist/adapters/websocket-approval.d.ts.map +0 -1
  52. package/dist/adapters/websocket-approval.js +0 -2
  53. package/dist/adapters/websocket-approval.js.map +0 -1
  54. package/dist/core/dataflow.d.ts +0 -23
  55. package/dist/core/dataflow.d.ts.map +0 -1
  56. package/dist/core/dataflow.js +0 -99
  57. package/dist/core/dataflow.js.map +0 -1
  58. package/dist/core/log-prune.d.ts +0 -16
  59. package/dist/core/log-prune.d.ts.map +0 -1
  60. package/dist/core/log-prune.js +0 -34
  61. package/dist/core/log-prune.js.map +0 -1
  62. package/dist/core/preflight.d.ts +0 -13
  63. package/dist/core/preflight.d.ts.map +0 -1
  64. package/dist/core/preflight.js +0 -61
  65. package/dist/core/preflight.js.map +0 -1
  66. package/dist/core/run-context.d.ts +0 -55
  67. package/dist/core/run-context.d.ts.map +0 -1
  68. package/dist/core/run-context.js +0 -158
  69. package/dist/core/run-context.js.map +0 -1
  70. package/dist/core/run-state.d.ts +0 -25
  71. package/dist/core/run-state.d.ts.map +0 -1
  72. package/dist/core/run-state.js +0 -93
  73. package/dist/core/run-state.js.map +0 -1
  74. package/dist/core/scheduler.d.ts +0 -13
  75. package/dist/core/scheduler.d.ts.map +0 -1
  76. package/dist/core/scheduler.js +0 -35
  77. package/dist/core/scheduler.js.map +0 -1
  78. package/dist/core/task-executor.d.ts +0 -13
  79. package/dist/core/task-executor.d.ts.map +0 -1
  80. package/dist/core/task-executor.js +0 -610
  81. package/dist/core/task-executor.js.map +0 -1
  82. package/dist/core/trigger-errors.d.ts +0 -9
  83. package/dist/core/trigger-errors.d.ts.map +0 -1
  84. package/dist/core/trigger-errors.js +0 -15
  85. package/dist/core/trigger-errors.js.map +0 -1
  86. package/dist/dag.d.ts +0 -45
  87. package/dist/dag.d.ts.map +0 -1
  88. package/dist/dag.js +0 -177
  89. package/dist/dag.js.map +0 -1
  90. package/dist/hooks.d.ts +0 -73
  91. package/dist/hooks.d.ts.map +0 -1
  92. package/dist/hooks.js +0 -106
  93. package/dist/hooks.js.map +0 -1
  94. package/dist/pipeline-definition.d.ts +0 -3
  95. package/dist/pipeline-definition.d.ts.map +0 -1
  96. package/dist/pipeline-definition.js +0 -4
  97. package/dist/pipeline-definition.js.map +0 -1
  98. package/dist/ports.d.ts +0 -196
  99. package/dist/ports.d.ts.map +0 -1
  100. package/dist/ports.js +0 -688
  101. package/dist/ports.js.map +0 -1
  102. package/dist/prompt-doc.d.ts +0 -70
  103. package/dist/prompt-doc.d.ts.map +0 -1
  104. package/dist/prompt-doc.js +0 -154
  105. package/dist/prompt-doc.js.map +0 -1
  106. package/dist/registry.d.ts +0 -3
  107. package/dist/registry.d.ts.map +0 -1
  108. package/dist/registry.js +0 -2
  109. package/dist/registry.js.map +0 -1
  110. package/dist/task-ref.d.ts +0 -55
  111. package/dist/task-ref.d.ts.map +0 -1
  112. package/dist/task-ref.js +0 -103
  113. package/dist/task-ref.js.map +0 -1
  114. package/dist/utils.d.ts +0 -13
  115. package/dist/utils.d.ts.map +0 -1
  116. package/dist/utils.js +0 -177
  117. package/dist/utils.js.map +0 -1
  118. package/src/adapters/stdin-approval.ts +0 -1
  119. package/src/adapters/websocket-approval.ts +0 -1
  120. package/src/approval.ts +0 -9
  121. package/src/bootstrap.ts +0 -55
  122. package/src/completions/exit-code.ts +0 -34
  123. package/src/completions/file-exists.ts +0 -66
  124. package/src/completions/output-check.test.ts +0 -50
  125. package/src/completions/output-check.ts +0 -92
  126. package/src/config-ops.test.ts +0 -70
  127. package/src/config-ops.ts +0 -328
  128. package/src/config.ts +0 -26
  129. package/src/core/dataflow.test.ts +0 -166
  130. package/src/core/dataflow.ts +0 -161
  131. package/src/core/log-prune.test.ts +0 -58
  132. package/src/core/log-prune.ts +0 -43
  133. package/src/core/preflight.test.ts +0 -49
  134. package/src/core/preflight.ts +0 -89
  135. package/src/core/run-context.test.ts +0 -291
  136. package/src/core/run-context.ts +0 -211
  137. package/src/core/run-state.test.ts +0 -98
  138. package/src/core/run-state.ts +0 -122
  139. package/src/core/scheduler.test.ts +0 -83
  140. package/src/core/scheduler.ts +0 -42
  141. package/src/core/task-executor.ts +0 -752
  142. package/src/core/trigger-errors.ts +0 -15
  143. package/src/dag.test.ts +0 -56
  144. package/src/dag.ts +0 -245
  145. package/src/drivers/opencode.ts +0 -410
  146. package/src/engine-ports-mixed.test.ts +0 -182
  147. package/src/engine-ports.test.ts +0 -210
  148. package/src/engine-task-type.test.ts +0 -56
  149. package/src/engine.ts +0 -32
  150. package/src/hooks.ts +0 -193
  151. package/src/index.ts +0 -31
  152. package/src/logger.ts +0 -2
  153. package/src/middlewares/static-context.ts +0 -49
  154. package/src/package-split.test.ts +0 -15
  155. package/src/pipeline-definition.ts +0 -5
  156. package/src/pipeline-runner.test.ts +0 -144
  157. package/src/pipeline-runner.ts +0 -194
  158. package/src/plugin-registry.test.ts +0 -448
  159. package/src/plugins.ts +0 -21
  160. package/src/ports.test.ts +0 -678
  161. package/src/ports.ts +0 -925
  162. package/src/prompt-doc.test.ts +0 -174
  163. package/src/prompt-doc.ts +0 -169
  164. package/src/registry.ts +0 -7
  165. package/src/runner.test.ts +0 -142
  166. package/src/runner.ts +0 -1
  167. package/src/runtime/adapters/stdin-approval.ts +0 -1
  168. package/src/runtime/adapters/websocket-approval.ts +0 -1
  169. package/src/runtime/bun-process-runner.ts +0 -1
  170. package/src/runtime-adapters.test.ts +0 -10
  171. package/src/runtime.ts +0 -12
  172. package/src/schema-ports.test.ts +0 -172
  173. package/src/schema.test.ts +0 -213
  174. package/src/schema.ts +0 -379
  175. package/src/tagma.test.ts +0 -317
  176. package/src/tagma.ts +0 -67
  177. package/src/task-ref.test.ts +0 -401
  178. package/src/task-ref.ts +0 -121
  179. package/src/triggers/file.test.ts +0 -79
  180. package/src/triggers/file.ts +0 -131
  181. package/src/triggers/manual.ts +0 -86
  182. package/src/types.ts +0 -18
  183. package/src/utils-api.ts +0 -8
  184. package/src/utils.test.ts +0 -28
  185. package/src/utils.ts +0 -203
  186. package/src/validate-raw-plugin-types.test.ts +0 -60
  187. package/src/validate-raw-ports.test.ts +0 -136
  188. package/src/validate-raw.ts +0 -852
  189. package/src/yaml-compiler.test.ts +0 -108
  190. package/src/yaml-compiler.ts +0 -110
  191. 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';