@xdelivered/emberflow 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/commands.ts +7 -3
- package/bin/init.test.ts +94 -0
- package/bin/init.ts +108 -2
- package/dist/bin/commands.d.ts +1 -0
- package/dist/bin/commands.js +6 -3
- package/dist/bin/init.d.ts +4 -0
- package/dist/bin/init.js +96 -2
- package/dist/server/agents/codexParse.js +31 -0
- package/dist/server/agents/detect.d.ts +18 -8
- package/dist/server/agents/detect.js +78 -13
- package/dist/server/agents/modelRejectionHint.js +1 -1
- package/dist/server/agents/prompt.d.ts +15 -1
- package/dist/server/agents/prompt.js +59 -37
- package/dist/server/agents/runManager.d.ts +23 -2
- package/dist/server/agents/runManager.js +36 -8
- package/dist/server/client.d.ts +1 -0
- package/dist/server/client.js +7 -2
- package/dist/server/index.js +208 -16
- package/dist/server/nodesPayload.d.ts +14 -1
- package/dist/server/nodesPayload.js +15 -2
- package/dist/server/projectMode.js +5 -2
- package/dist/server/runRegistry.d.ts +52 -1
- package/dist/server/runRegistry.js +170 -1
- package/dist/server/sourceNav.d.ts +77 -0
- package/dist/server/sourceNav.js +503 -0
- package/dist/server/subflowRunner.d.ts +48 -1
- package/dist/server/subflowRunner.js +34 -7
- package/dist/server/updateCheck.d.ts +68 -0
- package/dist/server/updateCheck.js +142 -0
- package/dist/src/engine/executor.js +4 -3
- package/dist/src/engine/registry.d.ts +27 -2
- package/dist/src/engine/registry.js +84 -2
- package/dist/src/nodes/index.d.ts +8 -2
- package/dist/src/nodes/index.js +7 -3
- package/dist/src/nodes/login.d.ts +3 -1
- package/dist/src/nodes/login.js +2 -2
- package/package.json +28 -7
- package/server/agentRoute.test.ts +20 -0
- package/server/agents/codexParse.test.ts +37 -0
- package/server/agents/codexParse.ts +34 -0
- package/server/agents/detect.test.ts +26 -7
- package/server/agents/detect.ts +82 -14
- package/server/agents/modelRejectionHint.ts +2 -1
- package/server/agents/prompt.test.ts +128 -0
- package/server/agents/prompt.ts +102 -3
- package/server/agents/runManager.test.ts +9 -0
- package/server/agents/runManager.ts +37 -7
- package/server/client.ts +10 -4
- package/server/index.ts +213 -15
- package/server/nodeRun.test.ts +189 -0
- package/server/nodesPayload.test.ts +38 -0
- package/server/nodesPayload.ts +28 -3
- package/server/projectMode.ts +5 -2
- package/server/runRegistry.ts +200 -3
- package/server/setupStatus.test.ts +3 -0
- package/server/sourceNav.test.ts +382 -0
- package/server/sourceNav.ts +644 -0
- package/server/sourceNavRoute.test.ts +163 -0
- package/server/stepDrill.test.ts +380 -0
- package/server/subflowRunner.ts +92 -11
- package/server/updateCheck.test.ts +209 -0
- package/server/updateCheck.ts +175 -0
- package/server/workflowTestRoute.test.ts +1 -1
- package/src/App.tsx +82 -2
- package/src/components/AgentConsole.tsx +7 -280
- package/src/components/AgentStream.test.tsx +88 -0
- package/src/components/AgentStream.tsx +303 -0
- package/src/components/CreateModal.tsx +43 -9
- package/src/components/Dock.tsx +1 -1
- package/src/components/EmptyState.test.tsx +49 -0
- package/src/components/EmptyState.tsx +61 -0
- package/src/components/EnvironmentDialog.tsx +4 -1
- package/src/components/EnvironmentPicker.tsx +8 -3
- package/src/components/EnvironmentsDialog.tsx +4 -1
- package/src/components/InfraPanel.tsx +30 -2
- package/src/components/InfrastructureDialog.test.tsx +97 -0
- package/src/components/InfrastructureDialog.tsx +111 -0
- package/src/components/Inspector.tsx +9 -26
- package/src/components/RunbookView.tsx +70 -6
- package/src/components/SettingsDialog.tsx +4 -59
- package/src/components/Sidebar.tsx +6 -26
- package/src/components/SourceNavigator.test.tsx +226 -0
- package/src/components/SourceNavigator.tsx +520 -0
- package/src/components/StatusBar.tsx +227 -26
- package/src/components/Toolbar.tsx +28 -16
- package/src/components/UpdateChip.test.tsx +31 -0
- package/src/components/WelcomeDialog.test.tsx +384 -13
- package/src/components/WelcomeDialog.tsx +996 -177
- package/src/engine/executor.ts +4 -3
- package/src/engine/registry.sourceRef.test.ts +112 -0
- package/src/engine/registry.ts +103 -2
- package/src/lib/guidedQuestions.test.ts +224 -0
- package/src/lib/guidedQuestions.ts +181 -0
- package/src/lib/runbookModel.ts +3 -3
- package/src/lib/runbookProjection.test.ts +43 -0
- package/src/lib/runbookProjection.ts +26 -6
- package/src/nodes/index.ts +10 -3
- package/src/nodes/login.ts +5 -2
- package/src/store/agentClient.ts +27 -8
- package/src/store/apiTree.ts +12 -0
- package/src/store/builderStore.test.ts +441 -99
- package/src/store/builderStore.ts +385 -314
- package/src/store/nodeMeta.ts +10 -2
- package/src/store/serverRunner.ts +56 -5
- package/src/store/setupClient.ts +7 -2
- package/src/store/sourceNavClient.ts +48 -0
- package/src/store/updateClient.ts +50 -0
- package/studio-dist/assets/index-BbzppDpt.js +65 -0
- package/studio-dist/assets/index-CLf6blcA.css +1 -0
- package/studio-dist/index.html +2 -2
- package/templates/skills/emberflow-basics/SKILL.md +29 -1
- package/templates/skills/emberflow-model-process/SKILL.md +92 -9
- package/templates/skills/emberflow-new-workflow/SKILL.md +8 -1
- package/templates/skills/emberflow-review-workflow/SKILL.md +64 -1
- package/studio-dist/assets/index-DNJwW-hM.css +0 -1
- package/studio-dist/assets/index-O26dKRjW.js +0 -65
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
3
|
+
import { NodeCodeView, SourceNavigator } from './SourceNavigator';
|
|
4
|
+
import type { SourceFileFetchResult, SourceFilePayload } from '../store/sourceNavClient';
|
|
5
|
+
|
|
6
|
+
// Props-driven fixtures: renderToStaticMarkup never runs effects, so the
|
|
7
|
+
// fetch cache is pre-populated via initialFiles and the fetcher is inert.
|
|
8
|
+
const neverFetch = () => new Promise<SourceFileFetchResult>(() => {});
|
|
9
|
+
|
|
10
|
+
const NODES_MJS: SourceFilePayload = {
|
|
11
|
+
path: 'nodes.mjs',
|
|
12
|
+
content: [
|
|
13
|
+
"import { deriveTrackingActual } from './shipment-logic.mjs';",
|
|
14
|
+
"import express from 'express';",
|
|
15
|
+
"import { createHash } from 'node:crypto';",
|
|
16
|
+
'const RATE = 1.2;',
|
|
17
|
+
'export function handler(input) {',
|
|
18
|
+
' return deriveTrackingActual(input) * RATE;',
|
|
19
|
+
'}',
|
|
20
|
+
].join('\n'),
|
|
21
|
+
language: 'js',
|
|
22
|
+
symbols: {
|
|
23
|
+
declarations: [
|
|
24
|
+
{ name: 'RATE', kind: 'const', line: 4, endLine: 4, exported: false },
|
|
25
|
+
{ name: 'handler', kind: 'fn', line: 5, endLine: 7, exported: true },
|
|
26
|
+
],
|
|
27
|
+
imports: [
|
|
28
|
+
{
|
|
29
|
+
name: 'deriveTrackingActual',
|
|
30
|
+
local: 'deriveTrackingActual',
|
|
31
|
+
from: './shipment-logic.mjs',
|
|
32
|
+
resolution: { kind: 'project', path: 'shipment-logic.mjs', line: 5 },
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'default',
|
|
36
|
+
local: 'express',
|
|
37
|
+
from: 'express',
|
|
38
|
+
resolution: { kind: 'external', package: 'express' },
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'createHash',
|
|
42
|
+
local: 'createHash',
|
|
43
|
+
from: 'node:crypto',
|
|
44
|
+
resolution: { kind: 'builtin' },
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'import()',
|
|
48
|
+
local: '',
|
|
49
|
+
from: 'x',
|
|
50
|
+
resolution: { kind: 'unresolved', reason: 'dynamic import target is computed' },
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: '*',
|
|
54
|
+
local: '',
|
|
55
|
+
from: './polyfill.mjs',
|
|
56
|
+
resolution: { kind: 'project', path: 'polyfill.mjs' },
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
reexports: [],
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const SHIPMENT_MJS: SourceFilePayload = {
|
|
64
|
+
path: 'shipment-logic.mjs',
|
|
65
|
+
content: 'export function deriveTrackingActual(input) { return input.actual; }',
|
|
66
|
+
language: 'js',
|
|
67
|
+
symbols: {
|
|
68
|
+
declarations: [
|
|
69
|
+
{ name: 'deriveTrackingActual', kind: 'fn', line: 1, endLine: 1, exported: true },
|
|
70
|
+
],
|
|
71
|
+
imports: [],
|
|
72
|
+
reexports: [],
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const files = (payload: SourceFilePayload): Record<string, SourceFileFetchResult> => ({
|
|
77
|
+
[payload.path]: { ok: true, payload },
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
/** Highlighting splits code across token spans; strip tags to assert on the raw text. */
|
|
81
|
+
const text = (html: string): string => html.replace(/<[^>]+>/g, '');
|
|
82
|
+
|
|
83
|
+
describe('SourceNavigator', () => {
|
|
84
|
+
it('renders the file content with local declarations linkified for same-file navigation', () => {
|
|
85
|
+
const out = renderToStaticMarkup(
|
|
86
|
+
<SourceNavigator
|
|
87
|
+
entryFile="nodes.mjs"
|
|
88
|
+
entryLine={5}
|
|
89
|
+
nodeType="DeriveShipmentActuals"
|
|
90
|
+
fetcher={neverFetch}
|
|
91
|
+
initialFiles={files(NODES_MJS)}
|
|
92
|
+
/>,
|
|
93
|
+
);
|
|
94
|
+
expect(out).toContain('deriveTrackingActual');
|
|
95
|
+
expect(out).toContain('RATE');
|
|
96
|
+
// Declaration + import identifiers render as link buttons (token linking).
|
|
97
|
+
expect(out).toContain('source-nav-link');
|
|
98
|
+
expect(out).toContain('Jump to line 5'); // handler declaration
|
|
99
|
+
expect(out).toContain('Open shipment-logic.mjs:5'); // project import token
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('renders a project import as a clickable path:line link in the Referenced code panel', () => {
|
|
103
|
+
const out = renderToStaticMarkup(
|
|
104
|
+
<SourceNavigator
|
|
105
|
+
entryFile="nodes.mjs"
|
|
106
|
+
nodeType="DeriveShipmentActuals"
|
|
107
|
+
fetcher={neverFetch}
|
|
108
|
+
initialFiles={files(NODES_MJS)}
|
|
109
|
+
/>,
|
|
110
|
+
);
|
|
111
|
+
expect(out).toContain('Referenced code');
|
|
112
|
+
expect(out).toContain('shipment-logic.mjs:5');
|
|
113
|
+
expect(out).toContain('project');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('badges external, builtin, and unresolved (with reason) references', () => {
|
|
117
|
+
const out = renderToStaticMarkup(
|
|
118
|
+
<SourceNavigator
|
|
119
|
+
entryFile="nodes.mjs"
|
|
120
|
+
nodeType="DeriveShipmentActuals"
|
|
121
|
+
fetcher={neverFetch}
|
|
122
|
+
initialFiles={files(NODES_MJS)}
|
|
123
|
+
/>,
|
|
124
|
+
);
|
|
125
|
+
expect(out).toContain('package: express');
|
|
126
|
+
expect(out).toContain('Node.js builtin');
|
|
127
|
+
expect(out).toContain('unresolved — dynamic import target is computed');
|
|
128
|
+
// Imports without a local binding are still listed: dynamic + side-effect.
|
|
129
|
+
expect(out).toContain('import()');
|
|
130
|
+
expect(out).toContain('(side-effect import)');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('shows the breadcrumb trail and a Back button at depth > 1', () => {
|
|
134
|
+
const out = renderToStaticMarkup(
|
|
135
|
+
<SourceNavigator
|
|
136
|
+
entryFile="nodes.mjs"
|
|
137
|
+
nodeType="DeriveShipmentActuals"
|
|
138
|
+
fetcher={neverFetch}
|
|
139
|
+
initialStack={[{ path: 'nodes.mjs', line: 5 }, { path: 'shipment-logic.mjs', line: 5 }]}
|
|
140
|
+
initialFiles={{ ...files(NODES_MJS), ...files(SHIPMENT_MJS) }}
|
|
141
|
+
/>,
|
|
142
|
+
);
|
|
143
|
+
expect(out).toContain('nodes.mjs');
|
|
144
|
+
expect(out).toContain('shipment-logic.mjs');
|
|
145
|
+
expect(out).toContain('›');
|
|
146
|
+
expect(out).toContain('Back');
|
|
147
|
+
// Current file's content is on screen, not the ancestor's.
|
|
148
|
+
expect(text(out)).toContain('return input.actual;');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('hides Back at depth 1', () => {
|
|
152
|
+
const out = renderToStaticMarkup(
|
|
153
|
+
<SourceNavigator
|
|
154
|
+
entryFile="nodes.mjs"
|
|
155
|
+
nodeType="DeriveShipmentActuals"
|
|
156
|
+
fetcher={neverFetch}
|
|
157
|
+
initialFiles={files(NODES_MJS)}
|
|
158
|
+
/>,
|
|
159
|
+
);
|
|
160
|
+
expect(out).not.toContain('Back');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('shows the resolver-unavailable banner while still rendering content', () => {
|
|
164
|
+
const degraded: SourceFilePayload = {
|
|
165
|
+
...SHIPMENT_MJS,
|
|
166
|
+
resolver: 'unavailable',
|
|
167
|
+
symbols: { declarations: [], imports: [], reexports: [] },
|
|
168
|
+
};
|
|
169
|
+
const out = renderToStaticMarkup(
|
|
170
|
+
<SourceNavigator
|
|
171
|
+
entryFile="shipment-logic.mjs"
|
|
172
|
+
nodeType="DeriveShipmentActuals"
|
|
173
|
+
fetcher={neverFetch}
|
|
174
|
+
initialFiles={files(degraded)}
|
|
175
|
+
/>,
|
|
176
|
+
);
|
|
177
|
+
expect(out).toContain('Symbol resolution unavailable (typescript not installed)');
|
|
178
|
+
expect(text(out)).toContain('return input.actual;');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('renders the fetch error text (denied / missing / runner down) instead of code', () => {
|
|
182
|
+
const out = renderToStaticMarkup(
|
|
183
|
+
<SourceNavigator
|
|
184
|
+
entryFile=".env"
|
|
185
|
+
nodeType="DeriveShipmentActuals"
|
|
186
|
+
fetcher={neverFetch}
|
|
187
|
+
initialFiles={{ '.env': { ok: false, error: 'Access denied: path not servable' } }}
|
|
188
|
+
/>,
|
|
189
|
+
);
|
|
190
|
+
expect(out).toContain('Access denied: path not servable');
|
|
191
|
+
expect(out).not.toContain('Referenced code');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('NodeCodeView (Inspector code dialog body)', () => {
|
|
196
|
+
it('without sourceRef renders exactly the legacy highlighter view — no Referenced code', () => {
|
|
197
|
+
const out = renderToStaticMarkup(
|
|
198
|
+
<NodeCodeView nodeType="Map" source="async (input) => input" fetcher={neverFetch} />,
|
|
199
|
+
);
|
|
200
|
+
expect(out).toContain('input');
|
|
201
|
+
expect(out).not.toContain('Referenced code');
|
|
202
|
+
expect(out).not.toContain('Built-in node');
|
|
203
|
+
expect(out).not.toContain('source-nav-link');
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('builtin nodes keep the legacy view plus a quiet Built-in node badge', () => {
|
|
207
|
+
const out = renderToStaticMarkup(
|
|
208
|
+
<NodeCodeView nodeType="Input" source="async () => ({})" builtin fetcher={neverFetch} />,
|
|
209
|
+
);
|
|
210
|
+
expect(out).toContain('Built-in node');
|
|
211
|
+
expect(out).not.toContain('Referenced code');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('with a sourceRef renders the SourceNavigator (breadcrumb + loading state pre-fetch)', () => {
|
|
215
|
+
const out = renderToStaticMarkup(
|
|
216
|
+
<NodeCodeView
|
|
217
|
+
nodeType="DeriveShipmentActuals"
|
|
218
|
+
source="ignored"
|
|
219
|
+
sourceRef={{ file: 'nodes.mjs', line: 4 }}
|
|
220
|
+
fetcher={neverFetch}
|
|
221
|
+
/>,
|
|
222
|
+
);
|
|
223
|
+
expect(out).toContain('nodes.mjs');
|
|
224
|
+
expect(out).toContain('Loading source…');
|
|
225
|
+
});
|
|
226
|
+
});
|