@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.
Files changed (116) hide show
  1. package/bin/commands.ts +7 -3
  2. package/bin/init.test.ts +94 -0
  3. package/bin/init.ts +108 -2
  4. package/dist/bin/commands.d.ts +1 -0
  5. package/dist/bin/commands.js +6 -3
  6. package/dist/bin/init.d.ts +4 -0
  7. package/dist/bin/init.js +96 -2
  8. package/dist/server/agents/codexParse.js +31 -0
  9. package/dist/server/agents/detect.d.ts +18 -8
  10. package/dist/server/agents/detect.js +78 -13
  11. package/dist/server/agents/modelRejectionHint.js +1 -1
  12. package/dist/server/agents/prompt.d.ts +15 -1
  13. package/dist/server/agents/prompt.js +59 -37
  14. package/dist/server/agents/runManager.d.ts +23 -2
  15. package/dist/server/agents/runManager.js +36 -8
  16. package/dist/server/client.d.ts +1 -0
  17. package/dist/server/client.js +7 -2
  18. package/dist/server/index.js +208 -16
  19. package/dist/server/nodesPayload.d.ts +14 -1
  20. package/dist/server/nodesPayload.js +15 -2
  21. package/dist/server/projectMode.js +5 -2
  22. package/dist/server/runRegistry.d.ts +52 -1
  23. package/dist/server/runRegistry.js +170 -1
  24. package/dist/server/sourceNav.d.ts +77 -0
  25. package/dist/server/sourceNav.js +503 -0
  26. package/dist/server/subflowRunner.d.ts +48 -1
  27. package/dist/server/subflowRunner.js +34 -7
  28. package/dist/server/updateCheck.d.ts +68 -0
  29. package/dist/server/updateCheck.js +142 -0
  30. package/dist/src/engine/executor.js +4 -3
  31. package/dist/src/engine/registry.d.ts +27 -2
  32. package/dist/src/engine/registry.js +84 -2
  33. package/dist/src/nodes/index.d.ts +8 -2
  34. package/dist/src/nodes/index.js +7 -3
  35. package/dist/src/nodes/login.d.ts +3 -1
  36. package/dist/src/nodes/login.js +2 -2
  37. package/package.json +28 -7
  38. package/server/agentRoute.test.ts +20 -0
  39. package/server/agents/codexParse.test.ts +37 -0
  40. package/server/agents/codexParse.ts +34 -0
  41. package/server/agents/detect.test.ts +26 -7
  42. package/server/agents/detect.ts +82 -14
  43. package/server/agents/modelRejectionHint.ts +2 -1
  44. package/server/agents/prompt.test.ts +128 -0
  45. package/server/agents/prompt.ts +102 -3
  46. package/server/agents/runManager.test.ts +9 -0
  47. package/server/agents/runManager.ts +37 -7
  48. package/server/client.ts +10 -4
  49. package/server/index.ts +213 -15
  50. package/server/nodeRun.test.ts +189 -0
  51. package/server/nodesPayload.test.ts +38 -0
  52. package/server/nodesPayload.ts +28 -3
  53. package/server/projectMode.ts +5 -2
  54. package/server/runRegistry.ts +200 -3
  55. package/server/setupStatus.test.ts +3 -0
  56. package/server/sourceNav.test.ts +382 -0
  57. package/server/sourceNav.ts +644 -0
  58. package/server/sourceNavRoute.test.ts +163 -0
  59. package/server/stepDrill.test.ts +380 -0
  60. package/server/subflowRunner.ts +92 -11
  61. package/server/updateCheck.test.ts +209 -0
  62. package/server/updateCheck.ts +175 -0
  63. package/server/workflowTestRoute.test.ts +1 -1
  64. package/src/App.tsx +82 -2
  65. package/src/components/AgentConsole.tsx +7 -280
  66. package/src/components/AgentStream.test.tsx +88 -0
  67. package/src/components/AgentStream.tsx +303 -0
  68. package/src/components/CreateModal.tsx +43 -9
  69. package/src/components/Dock.tsx +1 -1
  70. package/src/components/EmptyState.test.tsx +49 -0
  71. package/src/components/EmptyState.tsx +61 -0
  72. package/src/components/EnvironmentDialog.tsx +4 -1
  73. package/src/components/EnvironmentPicker.tsx +8 -3
  74. package/src/components/EnvironmentsDialog.tsx +4 -1
  75. package/src/components/InfraPanel.tsx +30 -2
  76. package/src/components/InfrastructureDialog.test.tsx +97 -0
  77. package/src/components/InfrastructureDialog.tsx +111 -0
  78. package/src/components/Inspector.tsx +9 -26
  79. package/src/components/RunbookView.tsx +70 -6
  80. package/src/components/SettingsDialog.tsx +4 -59
  81. package/src/components/Sidebar.tsx +6 -26
  82. package/src/components/SourceNavigator.test.tsx +226 -0
  83. package/src/components/SourceNavigator.tsx +520 -0
  84. package/src/components/StatusBar.tsx +227 -26
  85. package/src/components/Toolbar.tsx +28 -16
  86. package/src/components/UpdateChip.test.tsx +31 -0
  87. package/src/components/WelcomeDialog.test.tsx +384 -13
  88. package/src/components/WelcomeDialog.tsx +996 -177
  89. package/src/engine/executor.ts +4 -3
  90. package/src/engine/registry.sourceRef.test.ts +112 -0
  91. package/src/engine/registry.ts +103 -2
  92. package/src/lib/guidedQuestions.test.ts +224 -0
  93. package/src/lib/guidedQuestions.ts +181 -0
  94. package/src/lib/runbookModel.ts +3 -3
  95. package/src/lib/runbookProjection.test.ts +43 -0
  96. package/src/lib/runbookProjection.ts +26 -6
  97. package/src/nodes/index.ts +10 -3
  98. package/src/nodes/login.ts +5 -2
  99. package/src/store/agentClient.ts +27 -8
  100. package/src/store/apiTree.ts +12 -0
  101. package/src/store/builderStore.test.ts +441 -99
  102. package/src/store/builderStore.ts +385 -314
  103. package/src/store/nodeMeta.ts +10 -2
  104. package/src/store/serverRunner.ts +56 -5
  105. package/src/store/setupClient.ts +7 -2
  106. package/src/store/sourceNavClient.ts +48 -0
  107. package/src/store/updateClient.ts +50 -0
  108. package/studio-dist/assets/index-BbzppDpt.js +65 -0
  109. package/studio-dist/assets/index-CLf6blcA.css +1 -0
  110. package/studio-dist/index.html +2 -2
  111. package/templates/skills/emberflow-basics/SKILL.md +29 -1
  112. package/templates/skills/emberflow-model-process/SKILL.md +92 -9
  113. package/templates/skills/emberflow-new-workflow/SKILL.md +8 -1
  114. package/templates/skills/emberflow-review-workflow/SKILL.md +64 -1
  115. package/studio-dist/assets/index-DNJwW-hM.css +0 -1
  116. package/studio-dist/assets/index-O26dKRjW.js +0 -65
@@ -1,7 +1,15 @@
1
1
  import type { NodeDefinition } from '../engine';
2
2
 
3
- /** A runner node definition plus its implementation source (for display). */
4
- export type NodeMeta = NodeDefinition & { source?: string };
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
- onNodeState(nodeId: string, state: NodeRunState): void;
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
- export async function stepServerRun(runId: string): Promise<boolean> {
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
- const { done } = (await response.json()) as { done: boolean };
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 };
@@ -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
- * WelcomeChecklist's per-row status logic. Powers the StatusBar setup chip;
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
+ }