@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
package/src/store/nodeMeta.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import type { NodeDefinition } from '../engine';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* A runner node definition plus its implementation source (for display) and
|
|
5
|
+
* provenance: `sourceRef` (repo-relative registering file + line) when the
|
|
6
|
+
* node is project-owned, `builtin: true` when registered from the package.
|
|
7
|
+
*/
|
|
8
|
+
export type NodeMeta = NodeDefinition & {
|
|
9
|
+
source?: string;
|
|
10
|
+
sourceRef?: { file: string; line?: number };
|
|
11
|
+
builtin?: boolean;
|
|
12
|
+
};
|
|
5
13
|
|
|
6
14
|
/**
|
|
7
15
|
* Fetch the runner's node metadata (GET /api/nodes, same-origin via the
|
|
@@ -14,7 +14,10 @@ export interface ErrorHandlerTag {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface ServerRunHandlers {
|
|
17
|
-
|
|
17
|
+
/** `workflowId` is the flow the node belongs to: the root flow for parent
|
|
18
|
+
* nodes, a child flow's id for nodes executed inside a drilled subflow
|
|
19
|
+
* (stepped runs stream child states on the root run's SSE). */
|
|
20
|
+
onNodeState(workflowId: string, nodeId: string, state: NodeRunState): void;
|
|
18
21
|
onLog(line: LogLine): void;
|
|
19
22
|
onFinished(run: WorkflowRun, errorHandler?: ErrorHandlerTag): void;
|
|
20
23
|
onError(message: string): void;
|
|
@@ -336,11 +339,58 @@ export async function startServerRun(
|
|
|
336
339
|
return runId;
|
|
337
340
|
}
|
|
338
341
|
|
|
339
|
-
|
|
342
|
+
/** Request to run a single node in isolation on the runner (POST /node-run). */
|
|
343
|
+
export interface NodeRunRequest {
|
|
344
|
+
type: string;
|
|
345
|
+
input: Record<string, unknown>;
|
|
346
|
+
config?: Record<string, unknown>;
|
|
347
|
+
environment?: string;
|
|
348
|
+
safeMode?: boolean;
|
|
349
|
+
/** Required to equal `environment` when running unsafe against a protected env. */
|
|
350
|
+
confirm?: string;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** The runner's isolated node-run result (output redacted, logs captured). */
|
|
354
|
+
export interface NodeRunResult {
|
|
355
|
+
output?: unknown;
|
|
356
|
+
error?: string;
|
|
357
|
+
logs: LogLine[];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Run one node in isolation on the runner: the runner resolves the environment's
|
|
362
|
+
* secrets/vars, honours safe mode, executes the node's implementation in-process
|
|
363
|
+
* and redacts the output. Throws on transport failure (runner offline) and on a
|
|
364
|
+
* non-2xx response (unknown type → 404, bad request → 400).
|
|
365
|
+
*/
|
|
366
|
+
export async function runNodeOnServer(req: NodeRunRequest): Promise<NodeRunResult> {
|
|
367
|
+
const response = await fetch(`${BASE}/node-run`, {
|
|
368
|
+
method: 'POST',
|
|
369
|
+
headers: { 'content-type': 'application/json' },
|
|
370
|
+
body: JSON.stringify(req),
|
|
371
|
+
});
|
|
372
|
+
if (!response.ok) {
|
|
373
|
+
const body = (await response.json().catch(() => ({}))) as { error?: string };
|
|
374
|
+
throw new Error(body.error ?? `Node run failed (HTTP ${response.status})`);
|
|
375
|
+
}
|
|
376
|
+
return (await response.json()) as NodeRunResult;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** One step of a stepped run. `done` mirrors the old boolean contract;
|
|
380
|
+
* stepping onto a Subflow node reports `entered` (the child flow's id plus
|
|
381
|
+
* the PARENT's Subflow node id — the entered step itself executes no child
|
|
382
|
+
* node), and completing a drilled child reports `exited` (which can co-occur
|
|
383
|
+
* with `done` when the child was the last node, or when the child failed). */
|
|
384
|
+
export interface StepResult {
|
|
385
|
+
done: boolean;
|
|
386
|
+
entered?: { workflowId: string; nodeId: string };
|
|
387
|
+
exited?: true;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export async function stepServerRun(runId: string): Promise<StepResult> {
|
|
340
391
|
const response = await fetch(`${BASE}/runs/${runId}/step`, { method: 'POST' });
|
|
341
392
|
if (!response.ok) throw new Error(`Step failed (HTTP ${response.status})`);
|
|
342
|
-
|
|
343
|
-
return done;
|
|
393
|
+
return (await response.json()) as StepResult;
|
|
344
394
|
}
|
|
345
395
|
|
|
346
396
|
export async function cancelServerRun(runId: string): Promise<void> {
|
|
@@ -353,10 +403,11 @@ export function subscribeServerRun(runId: string, handlers: ServerRunHandlers):
|
|
|
353
403
|
|
|
354
404
|
source.addEventListener('nodeState', (event) => {
|
|
355
405
|
const data = JSON.parse((event as MessageEvent).data) as {
|
|
406
|
+
workflowId: string;
|
|
356
407
|
nodeId: string;
|
|
357
408
|
state: NodeRunState;
|
|
358
409
|
};
|
|
359
|
-
handlers.onNodeState(data.nodeId, data.state);
|
|
410
|
+
handlers.onNodeState(data.workflowId, data.nodeId, data.state);
|
|
360
411
|
});
|
|
361
412
|
source.addEventListener('log', (event) => {
|
|
362
413
|
const data = JSON.parse((event as MessageEvent).data) as { line: LogLine };
|
package/src/store/setupClient.ts
CHANGED
|
@@ -14,6 +14,9 @@ const BASE = '/api';
|
|
|
14
14
|
|
|
15
15
|
export interface SetupStatus {
|
|
16
16
|
agents: DetectedAgent[];
|
|
17
|
+
/** Whether the project root is inside a git repo — agent features snapshot
|
|
18
|
+
* changes with git, so the checklist requires this before enabling them. */
|
|
19
|
+
git: { repo: boolean };
|
|
17
20
|
environments: {
|
|
18
21
|
configured: boolean;
|
|
19
22
|
count: number;
|
|
@@ -30,14 +33,16 @@ export interface SetupStatus {
|
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
35
|
* Progress across the Welcome checklist's rows, mirrored from
|
|
33
|
-
*
|
|
36
|
+
* deriveChecklist's per-row status logic. Powers the StatusBar setup chip;
|
|
34
37
|
* keep in step if rows are added or their completion rules change.
|
|
35
38
|
*/
|
|
36
39
|
export function setupProgress(status: SetupStatus): { done: number; total: number } {
|
|
40
|
+
// NOTE: secrets & auth deliberately have no row (matches deriveChecklist) —
|
|
41
|
+
// they live in the Manage Environment dialog, not onboarding.
|
|
37
42
|
const rows = [
|
|
43
|
+
status.git.repo,
|
|
38
44
|
status.agents.length > 0,
|
|
39
45
|
status.environments.configured,
|
|
40
|
-
status.environments.configured && status.environments.anyAuthConfigured,
|
|
41
46
|
status.skills.claude || status.skills.codex,
|
|
42
47
|
status.infrastructure.present,
|
|
43
48
|
status.ops.count > 1,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client for the runner's source navigator (GET /source-file), reached through
|
|
3
|
+
* the Vite proxy at /api → 127.0.0.1:8092, same-origin as setupClient.ts.
|
|
4
|
+
* Powers the Inspector's source-reference navigation (SourceNavigator).
|
|
5
|
+
*
|
|
6
|
+
* Types are imported TYPE-ONLY from server/sourceNav.ts — erased at build, so
|
|
7
|
+
* the browser bundle never pulls server code, and the shapes can't drift.
|
|
8
|
+
*/
|
|
9
|
+
import type { SourceFilePayload } from '../../server/sourceNav';
|
|
10
|
+
|
|
11
|
+
export type {
|
|
12
|
+
SourceFilePayload,
|
|
13
|
+
SourceDeclaration,
|
|
14
|
+
SourceImport,
|
|
15
|
+
SourceReexport,
|
|
16
|
+
Resolution,
|
|
17
|
+
} from '../../server/sourceNav';
|
|
18
|
+
|
|
19
|
+
/** A fetch outcome the navigator can render either way — payload or error text. */
|
|
20
|
+
export type SourceFileFetchResult =
|
|
21
|
+
| { ok: true; payload: SourceFilePayload }
|
|
22
|
+
| { ok: false; error: string };
|
|
23
|
+
|
|
24
|
+
const BASE = '/api';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* GET /source-file?path=<repo-relative>. Never throws — errors come back as
|
|
28
|
+
* `{ok:false}` with status-aware text: 400 → denied, 404 → missing, network
|
|
29
|
+
* failure → runner unreachable.
|
|
30
|
+
*/
|
|
31
|
+
export async function fetchSourceFile(path: string): Promise<SourceFileFetchResult> {
|
|
32
|
+
try {
|
|
33
|
+
const response = await fetch(`${BASE}/source-file?${new URLSearchParams({ path })}`);
|
|
34
|
+
if (response.ok) {
|
|
35
|
+
return { ok: true, payload: (await response.json()) as SourceFilePayload };
|
|
36
|
+
}
|
|
37
|
+
const body = (await response.json().catch(() => ({}))) as { error?: string };
|
|
38
|
+
if (response.status === 400) {
|
|
39
|
+
return { ok: false, error: `Access denied: ${body.error ?? 'path not servable'}` };
|
|
40
|
+
}
|
|
41
|
+
if (response.status === 404) {
|
|
42
|
+
return { ok: false, error: `File not found: ${path}` };
|
|
43
|
+
}
|
|
44
|
+
return { ok: false, error: body.error ?? `Source fetch failed (HTTP ${response.status})` };
|
|
45
|
+
} catch {
|
|
46
|
+
return { ok: false, error: 'Runner unreachable — start the runner to view source' };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client for the package update notifier (GET /update-status) and one-click
|
|
3
|
+
* updater (POST /update), reached through the Vite proxy at /api →
|
|
4
|
+
* 127.0.0.1:8092 — same-origin pattern as setupClient.ts.
|
|
5
|
+
*
|
|
6
|
+
* Shapes mirror server/index.ts's /update-status and /update responses by
|
|
7
|
+
* hand (the browser bundle can't import from server/).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const BASE = '/api';
|
|
11
|
+
|
|
12
|
+
export interface UpdateStatus {
|
|
13
|
+
current: string;
|
|
14
|
+
/** Absent when the registry check was unavailable. */
|
|
15
|
+
latest?: string;
|
|
16
|
+
updateAvailable: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UpdateResult {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
/** True after a successful install — the runner must restart to pick it up. */
|
|
22
|
+
restartRequired?: boolean;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** GET /update-status — null when the runner is unreachable or errors. */
|
|
27
|
+
export async function fetchUpdateStatus(): Promise<UpdateStatus | null> {
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetch(`${BASE}/update-status`);
|
|
30
|
+
if (!response.ok) return null;
|
|
31
|
+
return (await response.json()) as UpdateStatus;
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** POST /update — runs npm install on the runner. Never throws. */
|
|
38
|
+
export async function postUpdate(): Promise<UpdateResult> {
|
|
39
|
+
try {
|
|
40
|
+
const response = await fetch(`${BASE}/update`, { method: 'POST' });
|
|
41
|
+
const body = (await response.json().catch(() => ({}))) as UpdateResult;
|
|
42
|
+
return {
|
|
43
|
+
ok: response.ok && body.ok === true,
|
|
44
|
+
...(body.restartRequired !== undefined ? { restartRequired: body.restartRequired } : {}),
|
|
45
|
+
...(body.error !== undefined ? { error: body.error } : {}),
|
|
46
|
+
};
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return { ok: false, error: err instanceof Error ? err.message : 'Update request failed' };
|
|
49
|
+
}
|
|
50
|
+
}
|