@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,174 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import {
3
- appendContext,
4
- prependContext,
5
- promptDocumentFromString,
6
- renderInputsBlock,
7
- renderOutputSchemaBlock,
8
- serializePromptDocument,
9
- } from './prompt-doc';
10
- import type { PortDef, PromptContextBlock, PromptDocument } from './types';
11
-
12
- // ─── renderInputsBlock ────────────────────────────────────────────────
13
-
14
- describe('renderInputsBlock', () => {
15
- test('returns null when no inputs declared', () => {
16
- expect(renderInputsBlock(undefined, {})).toBeNull();
17
- expect(renderInputsBlock([], { any: 'x' })).toBeNull();
18
- });
19
-
20
- test('returns null when declared inputs have no resolved values', () => {
21
- const ports: PortDef[] = [{ name: 'city', type: 'string' }];
22
- // values missing entirely — block is noise, omit it
23
- expect(renderInputsBlock(ports, {})).toBeNull();
24
- });
25
-
26
- test('renders name: value per declared input', () => {
27
- const ports: PortDef[] = [
28
- { name: 'city', type: 'string' },
29
- { name: 'id', type: 'number' },
30
- ];
31
- const block = renderInputsBlock(ports, { city: 'Shanghai', id: 42 });
32
- expect(block).not.toBeNull();
33
- expect(block!.label).toBe('Inputs');
34
- expect(block!.content).toBe('city: "Shanghai"\nid: 42');
35
- });
36
-
37
- test('appends # description comment when provided', () => {
38
- const ports: PortDef[] = [
39
- { name: 'city', type: 'string', description: 'Target city' },
40
- ];
41
- const block = renderInputsBlock(ports, { city: 'Shanghai' })!;
42
- expect(block.content).toBe('city: "Shanghai" # Target city');
43
- });
44
-
45
- test('preserves declaration order, not input-map iteration order', () => {
46
- const ports: PortDef[] = [
47
- { name: 'b', type: 'string' },
48
- { name: 'a', type: 'string' },
49
- ];
50
- // Values object has 'a' first, 'b' second — block should still emit 'b' first.
51
- const block = renderInputsBlock(ports, { a: 'x', b: 'y' })!;
52
- expect(block.content).toBe('b: "y"\na: "x"');
53
- });
54
-
55
- test('skips ports whose values were not resolved', () => {
56
- const ports: PortDef[] = [
57
- { name: 'a', type: 'string' },
58
- { name: 'b', type: 'string' },
59
- ];
60
- const block = renderInputsBlock(ports, { a: 'x' })!;
61
- expect(block.content).toBe('a: "x"');
62
- });
63
-
64
- test('JSON-encodes non-primitive values', () => {
65
- const ports: PortDef[] = [{ name: 'payload', type: 'json' }];
66
- const block = renderInputsBlock(ports, { payload: { a: 1, b: [2, 3] } })!;
67
- expect(block.content).toBe('payload: {"a":1,"b":[2,3]}');
68
- });
69
-
70
- test('booleans render verbatim, not quoted', () => {
71
- const ports: PortDef[] = [{ name: 'flag', type: 'boolean' }];
72
- const block = renderInputsBlock(ports, { flag: true })!;
73
- expect(block.content).toBe('flag: true');
74
- });
75
- });
76
-
77
- // ─── renderOutputSchemaBlock ──────────────────────────────────────────
78
-
79
- describe('renderOutputSchemaBlock', () => {
80
- test('returns null when no outputs declared', () => {
81
- expect(renderOutputSchemaBlock(undefined)).toBeNull();
82
- expect(renderOutputSchemaBlock([])).toBeNull();
83
- });
84
-
85
- test('instructs the model to emit final-line JSON', () => {
86
- const ports: PortDef[] = [{ name: 'city', type: 'string' }];
87
- const block = renderOutputSchemaBlock(ports)!;
88
- expect(block.label).toBe('Output Format');
89
- expect(block.content).toMatch(/final line/i);
90
- });
91
-
92
- test('lists each port with its type', () => {
93
- const ports: PortDef[] = [
94
- { name: 'city', type: 'string', description: 'Target city' },
95
- { name: 'temp', type: 'number' },
96
- ];
97
- const block = renderOutputSchemaBlock(ports)!;
98
- expect(block.content).toContain('- city (string): Target city');
99
- expect(block.content).toContain('- temp (number)');
100
- });
101
-
102
- test('includes enum values in the type hint', () => {
103
- const ports: PortDef[] = [
104
- { name: 'color', type: 'enum', enum: ['red', 'green', 'blue'] },
105
- ];
106
- const block = renderOutputSchemaBlock(ports)!;
107
- expect(block.content).toContain('color (enum (one of: "red", "green", "blue"))');
108
- });
109
-
110
- test('example object uses declared defaults when present', () => {
111
- const ports: PortDef[] = [
112
- { name: 'score', type: 'number', default: 0.5 },
113
- { name: 'note', type: 'string', default: 'n/a' },
114
- ];
115
- const block = renderOutputSchemaBlock(ports)!;
116
- // The example line is `Example final line: {"score":0.5,"note":"n/a"}`.
117
- expect(block.content).toContain('"score":0.5');
118
- expect(block.content).toContain('"note":"n/a"');
119
- });
120
-
121
- test('example uses type-appropriate placeholders when no default', () => {
122
- const ports: PortDef[] = [
123
- { name: 's', type: 'string' },
124
- { name: 'n', type: 'number' },
125
- { name: 'b', type: 'boolean' },
126
- { name: 'j', type: 'json' },
127
- ];
128
- const block = renderOutputSchemaBlock(ports)!;
129
- expect(block.content).toContain('"s":"..."');
130
- expect(block.content).toContain('"n":0');
131
- expect(block.content).toContain('"b":false');
132
- expect(block.content).toContain('"j":null');
133
- });
134
-
135
- test('example uses first enum value when present', () => {
136
- const ports: PortDef[] = [
137
- { name: 'tier', type: 'enum', enum: ['low', 'high'] },
138
- ];
139
- const block = renderOutputSchemaBlock(ports)!;
140
- expect(block.content).toContain('"tier":"low"');
141
- });
142
- });
143
-
144
- // ─── prependContext / appendContext ──────────────────────────────────
145
-
146
- describe('prependContext / appendContext', () => {
147
- const block: PromptContextBlock = { label: 'X', content: 'x' };
148
-
149
- test('prependContext puts block at front without mutating input', () => {
150
- const doc: PromptDocument = { contexts: [{ label: 'Y', content: 'y' }], task: 't' };
151
- const next = prependContext(doc, block);
152
- expect(next.contexts.map((c) => c.label)).toEqual(['X', 'Y']);
153
- // Original untouched — immutability is part of the contract for
154
- // middleware safety (the engine compares doc identity to detect
155
- // changes in some paths).
156
- expect(doc.contexts).toHaveLength(1);
157
- expect(doc.contexts[0]!.label).toBe('Y');
158
- expect(next.task).toBe('t');
159
- });
160
-
161
- test('appendContext puts block at end without mutating input', () => {
162
- const doc: PromptDocument = { contexts: [{ label: 'Y', content: 'y' }], task: 't' };
163
- const next = appendContext(doc, block);
164
- expect(next.contexts.map((c) => c.label)).toEqual(['Y', 'X']);
165
- expect(doc.contexts).toHaveLength(1);
166
- });
167
-
168
- test('prepend + serialize produces [X] block above the task', () => {
169
- const doc = promptDocumentFromString('do the thing');
170
- const next = prependContext(doc, { label: 'Inputs', content: 'city: "Shanghai"' });
171
- const text = serializePromptDocument(next);
172
- expect(text).toBe('[Inputs]\ncity: "Shanghai"\n\ndo the thing');
173
- });
174
- });
package/src/prompt-doc.ts DELETED
@@ -1,169 +0,0 @@
1
- import type { PortDef, PromptContextBlock, PromptDocument } from './types';
2
-
3
- /**
4
- * Build a fresh `PromptDocument` from a raw task string.
5
- * Middlewares receive this from the engine and push context blocks onto
6
- * `contexts`. `task` is the user's original prompt and should not be
7
- * rewritten by middlewares (translation middlewares are the rare exception).
8
- */
9
- export function promptDocumentFromString(task: string): PromptDocument {
10
- return { contexts: [], task };
11
- }
12
-
13
- /**
14
- * Serialize a `PromptDocument` to the default string form consumed by
15
- * drivers that read `task.prompt` instead of `ctx.promptDoc`.
16
- *
17
- * Format:
18
- *
19
- * [<label1>]
20
- * <content1>
21
- *
22
- * [<label2>]
23
- * <content2>
24
- *
25
- * <task>
26
- *
27
- * Each context block is separated from the next (and from `task`) by a
28
- * single blank line. No implicit `[Task]` header is emitted — that framing
29
- * is the driver's responsibility (e.g. opencode's `agent_profile` wrapping).
30
- * Emitting one here would compose incorrectly with any driver that also
31
- * adds a `[Task]` header, producing a double header that some models
32
- * (observed with `opencode/big-pickle`) misread as a cut-off message.
33
- */
34
- export function serializePromptDocument(doc: PromptDocument): string {
35
- if (doc.contexts.length === 0) return doc.task;
36
- const blocks = doc.contexts.map((c) => `[${c.label}]\n${c.content}`);
37
- return `${blocks.join('\n\n')}\n\n${doc.task}`;
38
- }
39
-
40
- /**
41
- * Helper for middlewares: return a new document with the given block
42
- * appended to `contexts`, preserving immutability of `doc`.
43
- */
44
- export function appendContext(
45
- doc: PromptDocument,
46
- block: PromptContextBlock,
47
- ): PromptDocument {
48
- return { contexts: [...doc.contexts, block], task: doc.task };
49
- }
50
-
51
- /**
52
- * Helper: return a new document with the given block PREPENDED. The
53
- * engine uses this to place port-related context blocks (`[Inputs]`,
54
- * `[Output Format]`) at the top of the document so middlewares that
55
- * assemble retrieval context against the task's inputs see them.
56
- */
57
- export function prependContext(
58
- doc: PromptDocument,
59
- block: PromptContextBlock,
60
- ): PromptDocument {
61
- return { contexts: [block, ...doc.contexts], task: doc.task };
62
- }
63
-
64
- /**
65
- * Build an `[Inputs]` context block from a map of resolved port inputs.
66
- * Each input is rendered on its own line as `name: <value>` with an
67
- * optional trailing `# <description>` comment so the model has both the
68
- * value and the reason it matters.
69
- *
70
- * The block is *only* useful for AI tasks; command tasks consume inputs
71
- * through `{{inputs.X}}` substitution in their command line and do not
72
- * need this context.
73
- *
74
- * Returns null when there are no inputs to render — callers can forward
75
- * that nullish value to `prependContext` via an `if (block)` check so
76
- * empty-input tasks don't grow a noise block in their prompt.
77
- */
78
- export function renderInputsBlock(
79
- inputsDecl: readonly PortDef[] | undefined,
80
- values: Readonly<Record<string, unknown>>,
81
- ): PromptContextBlock | null {
82
- if (!inputsDecl || inputsDecl.length === 0) return null;
83
- const lines: string[] = [];
84
- for (const port of inputsDecl) {
85
- if (!(port.name in values)) continue;
86
- const raw = values[port.name];
87
- const rendered = renderInputValue(raw);
88
- const descr = port.description?.trim();
89
- lines.push(descr ? `${port.name}: ${rendered} # ${descr}` : `${port.name}: ${rendered}`);
90
- }
91
- if (lines.length === 0) return null;
92
- return { label: 'Inputs', content: lines.join('\n') };
93
- }
94
-
95
- function renderInputValue(value: unknown): string {
96
- if (value === null || value === undefined) return '';
97
- if (typeof value === 'string') return JSON.stringify(value);
98
- if (typeof value === 'number' || typeof value === 'boolean') return String(value);
99
- try {
100
- return JSON.stringify(value);
101
- } catch {
102
- return String(value);
103
- }
104
- }
105
-
106
- /**
107
- * Build an `[Output Format]` context block from a task's declared output
108
- * ports. The block instructs the model to emit a final-line JSON object
109
- * matching the declared schema so `extractTaskOutputs` can pick it up
110
- * without fragile heuristics. Returns null when the task declares no
111
- * outputs.
112
- *
113
- * The instruction is deliberately short and explicit — a terse "emit
114
- * this object as JSON on the final line" beats a long schema dump
115
- * because shorter prompts compose better with downstream middlewares.
116
- */
117
- export function renderOutputSchemaBlock(
118
- outputsDecl: readonly PortDef[] | undefined,
119
- ): PromptContextBlock | null {
120
- if (!outputsDecl || outputsDecl.length === 0) return null;
121
- const lines: string[] = [];
122
- lines.push(
123
- 'After your response, emit a single JSON object on the FINAL line with these keys:',
124
- );
125
- for (const port of outputsDecl) {
126
- const descr = port.description?.trim();
127
- const enumHint =
128
- port.type === 'enum' && port.enum?.length
129
- ? ` (one of: ${port.enum.map((v) => JSON.stringify(v)).join(', ')})`
130
- : '';
131
- lines.push(
132
- descr
133
- ? ` - ${port.name} (${port.type}${enumHint}): ${descr}`
134
- : ` - ${port.name} (${port.type}${enumHint})`,
135
- );
136
- }
137
- const example = buildExampleObject(outputsDecl);
138
- lines.push('');
139
- lines.push(`Example final line: ${JSON.stringify(example)}`);
140
- return { label: 'Output Format', content: lines.join('\n') };
141
- }
142
-
143
- function buildExampleObject(outputsDecl: readonly PortDef[]): Record<string, unknown> {
144
- const example: Record<string, unknown> = {};
145
- for (const port of outputsDecl) {
146
- if (port.default !== undefined) {
147
- example[port.name] = port.default;
148
- continue;
149
- }
150
- switch (port.type) {
151
- case 'string':
152
- example[port.name] = '...';
153
- break;
154
- case 'number':
155
- example[port.name] = 0;
156
- break;
157
- case 'boolean':
158
- example[port.name] = false;
159
- break;
160
- case 'enum':
161
- example[port.name] = port.enum?.[0] ?? '...';
162
- break;
163
- case 'json':
164
- default:
165
- example[port.name] = null;
166
- }
167
- }
168
- return example;
169
- }
package/src/registry.ts DELETED
@@ -1,7 +0,0 @@
1
- export {
2
- isValidPluginName,
3
- PluginRegistry,
4
- PLUGIN_NAME_RE,
5
- readPluginManifest,
6
- } from '@tagma/core';
7
- export type { RegisteredCapability, RegisterResult } from '@tagma/core';
@@ -1,142 +0,0 @@
1
- import { test, expect } from 'bun:test';
2
- import { mkdtempSync, readFileSync, rmSync, statSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
- import { runSpawn } from './runner';
6
-
7
- // Portable output producer — node is guaranteed in the bun dev env. Using a
8
- // known runtime avoids shell-quoting differences between platforms.
9
- function nodeArg(script: string): string[] {
10
- return ['node', '-e', script];
11
- }
12
-
13
- test('runSpawn: small output is returned whole, persisted byte-identical', async () => {
14
- const tmp = mkdtempSync(join(tmpdir(), 'tagma-runner-small-'));
15
- const stdoutPath = join(tmp, 'out');
16
- const stderrPath = join(tmp, 'err');
17
- try {
18
- const result = await runSpawn(
19
- { args: nodeArg('process.stdout.write("hello world"); process.stderr.write("oops")') },
20
- null,
21
- { stdoutPath, stderrPath },
22
- );
23
- expect(result.exitCode).toBe(0);
24
- expect(result.stdout).toBe('hello world');
25
- expect(result.stderr).toBe('oops');
26
- expect(result.stdoutBytes).toBe(11);
27
- expect(result.stderrBytes).toBe(4);
28
- expect(result.stdoutPath).toBe(stdoutPath);
29
- expect(result.stderrPath).toBe(stderrPath);
30
- expect(readFileSync(stdoutPath, 'utf8')).toBe('hello world');
31
- expect(readFileSync(stderrPath, 'utf8')).toBe('oops');
32
- } finally {
33
- rmSync(tmp, { recursive: true, force: true });
34
- }
35
- });
36
-
37
- test('runSpawn: oversized output — bounded tail in memory, full bytes on disk', async () => {
38
- const tmp = mkdtempSync(join(tmpdir(), 'tagma-runner-big-'));
39
- const stdoutPath = join(tmp, 'out');
40
- try {
41
- // Produce 3 MB of output against a 512 KB cap. The child writes in one
42
- // shot; the runner should slice the single chunk's tail rather than
43
- // evicting (the "pathological one-chunk-over-cap" branch).
44
- const cap = 512 * 1024;
45
- const totalBytes = 3 * 1024 * 1024;
46
- const result = await runSpawn(
47
- {
48
- args: nodeArg(
49
- `process.stdout.write("a".repeat(${totalBytes}))`,
50
- ),
51
- },
52
- null,
53
- { stdoutPath, maxStdoutTailBytes: cap },
54
- );
55
- expect(result.exitCode).toBe(0);
56
- // Total bytes reported match reality
57
- expect(result.stdoutBytes).toBe(totalBytes);
58
- // In-memory tail bounded above (tail + truncation marker header is a
59
- // couple hundred bytes at most; give it slack). No lower bound — chunk
60
- // boundaries are platform-dependent so the exact retained size varies.
61
- expect(result.stdout.length).toBeLessThan(cap + 1024);
62
- // Truncation breadcrumb present and points at the full output
63
- expect(result.stdout).toContain('truncated from head');
64
- expect(result.stdout).toContain(stdoutPath);
65
- // The tail ends with the trailing bytes the child wrote ('a')
66
- expect(result.stdout.endsWith('a')).toBe(true);
67
- // Disk copy is byte-exact and full-length
68
- const onDiskBytes = statSync(stdoutPath).size;
69
- expect(onDiskBytes).toBe(totalBytes);
70
- } finally {
71
- rmSync(tmp, { recursive: true, force: true });
72
- }
73
- });
74
-
75
- test('runSpawn: chunked output — tail eviction keeps retained <= cap', async () => {
76
- const tmp = mkdtempSync(join(tmpdir(), 'tagma-runner-chunked-'));
77
- const stdoutPath = join(tmp, 'out');
78
- try {
79
- // Emit 8 chunks × 64 KB with sync drains between them, so the runner
80
- // receives them as distinct chunks rather than one blob. Cap at 128 KB
81
- // forces eviction of older chunks.
82
- const cap = 128 * 1024;
83
- const chunkSize = 64 * 1024;
84
- const nChunks = 8;
85
- const script = `
86
- const chunk = 'b'.repeat(${chunkSize});
87
- (async () => {
88
- for (let i = 0; i < ${nChunks}; i++) {
89
- process.stdout.write(chunk);
90
- await new Promise(r => setImmediate(r));
91
- }
92
- })();
93
- `;
94
- const result = await runSpawn(
95
- { args: nodeArg(script) },
96
- null,
97
- { stdoutPath, maxStdoutTailBytes: cap },
98
- );
99
- expect(result.exitCode).toBe(0);
100
- expect(result.stdoutBytes).toBe(nChunks * chunkSize);
101
- // Retained tail should be strictly bounded by cap (eviction case, no
102
- // single-chunk slice). Allow small overhead for the truncation marker.
103
- expect(result.stdout.length).toBeLessThan(cap + 1024);
104
- expect(result.stdout).toContain('truncated from head');
105
- // Full stream on disk
106
- expect(statSync(stdoutPath).size).toBe(nChunks * chunkSize);
107
- } finally {
108
- rmSync(tmp, { recursive: true, force: true });
109
- }
110
- });
111
-
112
- test('runSpawn: no path configured — memory-only tail, returns null paths', async () => {
113
- const result = await runSpawn(
114
- { args: nodeArg('process.stdout.write("inline only")') },
115
- null,
116
- {},
117
- );
118
- expect(result.exitCode).toBe(0);
119
- expect(result.stdout).toBe('inline only');
120
- expect(result.stdoutPath).toBeNull();
121
- expect(result.stderrPath).toBeNull();
122
- });
123
-
124
- test('runSpawn: pre-spawn failure (bad executable) — no paths leak on disk', async () => {
125
- const tmp = mkdtempSync(join(tmpdir(), 'tagma-runner-bad-'));
126
- const stdoutPath = join(tmp, 'out');
127
- try {
128
- const result = await runSpawn(
129
- { args: ['this-command-definitely-does-not-exist-xyz123'] },
130
- null,
131
- { stdoutPath },
132
- );
133
- expect(result.exitCode).toBe(-1);
134
- expect(result.failureKind).toBe('spawn_error');
135
- // On pre-spawn failure the runner never opened the file, so stdoutPath
136
- // is null (not the unopened path). Callers can rely on this to decide
137
- // whether a disk file exists to read.
138
- expect(result.stdoutPath).toBeNull();
139
- } finally {
140
- rmSync(tmp, { recursive: true, force: true });
141
- }
142
- });
package/src/runner.ts DELETED
@@ -1 +0,0 @@
1
- export { runCommand, runSpawn } from '@tagma/runtime-bun';
@@ -1 +0,0 @@
1
- export * from '@tagma/runtime-bun/adapters/stdin-approval';
@@ -1 +0,0 @@
1
- export * from '@tagma/runtime-bun/adapters/websocket-approval';
@@ -1 +0,0 @@
1
- export { runCommand, runSpawn } from '@tagma/runtime-bun';
@@ -1,10 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { attachStdinApprovalAdapter } from './runtime/adapters/stdin-approval';
3
- import { attachWebSocketApprovalAdapter } from './runtime/adapters/websocket-approval';
4
-
5
- describe('runtime approval adapters', () => {
6
- test('approval adapters live under the runtime boundary', () => {
7
- expect(typeof attachStdinApprovalAdapter).toBe('function');
8
- expect(typeof attachWebSocketApprovalAdapter).toBe('function');
9
- });
10
- });
package/src/runtime.ts DELETED
@@ -1,12 +0,0 @@
1
- export * from '@tagma/runtime-bun';
2
- export type {
3
- OpenRunLogOptions,
4
- PruneLogOptions,
5
- RunOptions,
6
- RuntimeLogSink,
7
- RuntimeLogStore,
8
- RuntimeWatchEvent,
9
- RuntimeWatchOptions,
10
- TagmaRuntime,
11
- TaskOutputPathOptions,
12
- } from '@tagma/core';