@agentic-surfaces/cli 0.1.8 → 0.1.10
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/dist/index.js +89 -29
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync, readdirSync, existsSync } from "node:fs";
|
|
2
2
|
import { join, dirname, resolve } from "node:path";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
|
-
import { loadWorkflow, runWorkflowOnce, Scheduler, loadProjectConfig, buildWorkflowRunner, defaultRegistry } from "@agentic-surfaces/core";
|
|
4
|
+
import { loadWorkflow, runWorkflowOnce, Scheduler, loadProjectConfig, buildWorkflowRunner, defaultRegistry, parseAgentFile } from "@agentic-surfaces/core";
|
|
5
5
|
import { serve, StreamingObserver } from "@agentic-surfaces/server";
|
|
6
6
|
import { buildServices } from "./services.js";
|
|
7
7
|
const CONFIG = "agentic-surfaces.config.yaml";
|
|
@@ -33,14 +33,62 @@ function loadWorkflows(dir) {
|
|
|
33
33
|
}
|
|
34
34
|
return map;
|
|
35
35
|
}
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
function
|
|
36
|
+
// Load agents/<name>.md from the project into a name→AgentDefinition map.
|
|
37
|
+
// A bad agent file is reported and skipped (consistent with workflow loading).
|
|
38
|
+
function loadAgents(projectDir) {
|
|
39
|
+
const map = new Map();
|
|
40
|
+
const agentsDir = join(projectDir, "agents");
|
|
41
|
+
if (!existsSync(agentsDir))
|
|
42
|
+
return map;
|
|
43
|
+
for (const f of readdirSync(agentsDir).filter((f) => f.endsWith(".md"))) {
|
|
44
|
+
try {
|
|
45
|
+
const def = parseAgentFile(readFileSync(join(agentsDir, f), "utf8"), f.replace(/\.md$/, ""));
|
|
46
|
+
map.set(def.name, def);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error(`skipping agent ${f}:`, err instanceof Error ? err.message : String(err));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return map;
|
|
53
|
+
}
|
|
54
|
+
// Walk up to the directory that contains agentic-surfaces.config.yaml.
|
|
55
|
+
function findProjectDir(start) {
|
|
56
|
+
let dir = resolve(start);
|
|
57
|
+
for (;;) {
|
|
58
|
+
if (existsSync(join(dir, CONFIG)))
|
|
59
|
+
return dir;
|
|
60
|
+
const parent = dirname(dir);
|
|
61
|
+
if (parent === dir)
|
|
62
|
+
return undefined;
|
|
63
|
+
dir = parent;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// This package's version, shown in the dashboard. npm always ships package.json
|
|
67
|
+
// in the tarball, so it resolves both from source and when installed via npx.
|
|
68
|
+
const VERSION = (() => {
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return "unknown";
|
|
74
|
+
}
|
|
75
|
+
})();
|
|
76
|
+
// Launch THE dashboard — one full UI, used by every `--ui` path (bare `ui`,
|
|
77
|
+
// `run --ui`, `start --ui`). Always serves the workflow list, Run buttons,
|
|
78
|
+
// agents, config + version. There is no lite variant.
|
|
79
|
+
function launchUi(opts) {
|
|
39
80
|
const port = parseInt(process.env["FLOW_UI_PORT"] ?? "4000", 10);
|
|
40
|
-
const {
|
|
81
|
+
const { port: p } = serve({
|
|
82
|
+
port,
|
|
83
|
+
observer: opts.observer,
|
|
84
|
+
workflows: [...opts.workflows.values()],
|
|
85
|
+
agents: [...opts.agents.values()],
|
|
86
|
+
onRun: opts.onRun,
|
|
87
|
+
config: { dryRun: opts.dryRun, agent: opts.agentDefaults, version: VERSION },
|
|
88
|
+
});
|
|
41
89
|
const url = `http://127.0.0.1:${p}`;
|
|
42
90
|
openBrowser(url);
|
|
43
|
-
return
|
|
91
|
+
return url;
|
|
44
92
|
}
|
|
45
93
|
function openBrowser(url) {
|
|
46
94
|
if (process.env["FLOW_NO_OPEN"])
|
|
@@ -88,27 +136,24 @@ export async function run(argv) {
|
|
|
88
136
|
const pc = loadProjectConfig(dir);
|
|
89
137
|
const workflowsDir = pc?.workflows ? join(dir, pc.workflows) : dir;
|
|
90
138
|
const allWorkflows = loadWorkflows(workflowsDir);
|
|
139
|
+
const agents = loadAgents(dir);
|
|
91
140
|
const registry = defaultRegistry();
|
|
92
141
|
const observer = new StreamingObserver();
|
|
93
142
|
const services = buildServices({ projectConfig: pc });
|
|
94
|
-
const runWorkflowFn = buildWorkflowRunner({ workflows: allWorkflows, registry, services, observer });
|
|
95
|
-
const servicesWithRunner = { ...services, runWorkflow: runWorkflowFn };
|
|
143
|
+
const runWorkflowFn = buildWorkflowRunner({ workflows: allWorkflows, registry, services: { ...services, agents }, observer });
|
|
144
|
+
const servicesWithRunner = { ...services, agents, runWorkflow: runWorkflowFn };
|
|
96
145
|
// Cron-triggered workflows fire on schedule too.
|
|
97
146
|
const sched = new Scheduler(servicesWithRunner, registry, observer);
|
|
98
147
|
for (const [, w] of allWorkflows)
|
|
99
148
|
sched.add(w);
|
|
100
149
|
sched.start();
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
port,
|
|
104
|
-
observer,
|
|
105
|
-
workflows: [...allWorkflows.values()],
|
|
150
|
+
const url = launchUi({
|
|
151
|
+
observer, workflows: allWorkflows, agents,
|
|
106
152
|
onRun: (name) => runWorkflowFn(name, undefined),
|
|
107
|
-
|
|
153
|
+
dryRun: pc?.dryRun,
|
|
154
|
+
agentDefaults: { model: pc?.agent?.model, effort: pc?.agent?.effort },
|
|
108
155
|
});
|
|
109
|
-
|
|
110
|
-
openBrowser(url);
|
|
111
|
-
console.log(`\n▶ agentic-surfaces — ${url}`);
|
|
156
|
+
console.log(`\n▶ agentic-surfaces ${VERSION} — ${url}`);
|
|
112
157
|
console.log(` project: ${dir} · ${allWorkflows.size} workflow(s) · Ctrl-C to exit`);
|
|
113
158
|
await new Promise(() => { }); // serve until interrupted
|
|
114
159
|
return 0;
|
|
@@ -137,11 +182,18 @@ export async function run(argv) {
|
|
|
137
182
|
}
|
|
138
183
|
catch { /* skip unparseable */ }
|
|
139
184
|
}
|
|
185
|
+
const agents = loadAgents(findProjectDir(dirname(file)) ?? dir);
|
|
140
186
|
const registry = defaultRegistry();
|
|
141
|
-
const
|
|
142
|
-
const observer =
|
|
143
|
-
const runWorkflowFn = buildWorkflowRunner({ workflows: allWorkflows, registry, services, observer });
|
|
144
|
-
const servicesWithRunner = { ...services, runWorkflow: runWorkflowFn };
|
|
187
|
+
const ui = rest.includes("--ui");
|
|
188
|
+
const observer = ui ? new StreamingObserver() : undefined;
|
|
189
|
+
const runWorkflowFn = buildWorkflowRunner({ workflows: allWorkflows, registry, services: { ...services, agents }, observer });
|
|
190
|
+
const servicesWithRunner = { ...services, agents, runWorkflow: runWorkflowFn };
|
|
191
|
+
const url = ui ? launchUi({
|
|
192
|
+
observer: observer, workflows: allWorkflows, agents,
|
|
193
|
+
onRun: (name) => runWorkflowFn(name, undefined),
|
|
194
|
+
dryRun: pc?.dryRun,
|
|
195
|
+
agentDefaults: { model: pc?.agent?.model, effort: pc?.agent?.effort },
|
|
196
|
+
}) : undefined;
|
|
145
197
|
// A run error must NOT tear down the --ui server: the failure is already
|
|
146
198
|
// streamed to the dashboard (the failed node + run), so keep serving so it
|
|
147
199
|
// stays inspectable. Without --ui, an error still exits non-zero.
|
|
@@ -154,8 +206,8 @@ export async function run(argv) {
|
|
|
154
206
|
failed = true;
|
|
155
207
|
console.error("run failed:", err instanceof Error ? err.message : String(err));
|
|
156
208
|
}
|
|
157
|
-
if (
|
|
158
|
-
console.log(`\n▶
|
|
209
|
+
if (url) {
|
|
210
|
+
console.log(`\n▶ agentic-surfaces ${VERSION} — ${url} — Ctrl-C to exit${failed ? " (run failed — see the dashboard)" : ""}`);
|
|
159
211
|
await new Promise(() => { }); // keep the server up so the run stays viewable
|
|
160
212
|
}
|
|
161
213
|
return failed ? 1 : 0;
|
|
@@ -174,18 +226,26 @@ export async function run(argv) {
|
|
|
174
226
|
}
|
|
175
227
|
catch { /* skip unparseable */ }
|
|
176
228
|
}
|
|
229
|
+
const agents = loadAgents(dir);
|
|
177
230
|
const registry = defaultRegistry();
|
|
178
|
-
const
|
|
179
|
-
const observer =
|
|
180
|
-
const runWorkflowFn = buildWorkflowRunner({ workflows: allWorkflows, registry, services, observer });
|
|
181
|
-
const servicesWithRunner = { ...services, runWorkflow: runWorkflowFn };
|
|
231
|
+
const ui = rest.includes("--ui");
|
|
232
|
+
const observer = ui ? new StreamingObserver() : undefined;
|
|
233
|
+
const runWorkflowFn = buildWorkflowRunner({ workflows: allWorkflows, registry, services: { ...services, agents }, observer });
|
|
234
|
+
const servicesWithRunner = { ...services, agents, runWorkflow: runWorkflowFn };
|
|
182
235
|
const sched = new Scheduler(servicesWithRunner, registry, observer);
|
|
183
236
|
for (const [, w] of allWorkflows)
|
|
184
237
|
sched.add(w);
|
|
185
238
|
sched.start();
|
|
186
239
|
console.log("scheduler started; watching", workflowsDir);
|
|
187
|
-
if (
|
|
188
|
-
|
|
240
|
+
if (ui) {
|
|
241
|
+
const url = launchUi({
|
|
242
|
+
observer: observer, workflows: allWorkflows, agents,
|
|
243
|
+
onRun: (name) => runWorkflowFn(name, undefined),
|
|
244
|
+
dryRun: pc?.dryRun,
|
|
245
|
+
agentDefaults: { model: pc?.agent?.model, effort: pc?.agent?.effort },
|
|
246
|
+
});
|
|
247
|
+
console.log(`▶ agentic-surfaces ${VERSION} — ${url}`);
|
|
248
|
+
}
|
|
189
249
|
return 0;
|
|
190
250
|
}
|
|
191
251
|
console.error("usage: flow <validate|run|start> [workflow|projectDir] [--ui] [--fake]");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentic-surfaces/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"dist"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@agentic-surfaces/core": "0.1.
|
|
25
|
-
"@agentic-surfaces/agent": "0.1.
|
|
26
|
-
"@agentic-surfaces/server": "0.1.
|
|
24
|
+
"@agentic-surfaces/core": "0.1.10",
|
|
25
|
+
"@agentic-surfaces/agent": "0.1.10",
|
|
26
|
+
"@agentic-surfaces/server": "0.1.10"
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"build": "tsc -b",
|