@fieldwangai/agentflow 0.1.105 → 0.1.107

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.
@@ -15,8 +15,8 @@
15
15
  href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0"
16
16
  rel="stylesheet"
17
17
  />
18
- <script type="module" crossorigin src="/assets/index-DuSU9kCW.js"></script>
19
- <link rel="stylesheet" crossorigin href="/assets/index-CC1ceU6X.css">
18
+ <script type="module" crossorigin src="/assets/index-Ds1YW25U.js"></script>
19
+ <link rel="stylesheet" crossorigin href="/assets/index-BZMWrBdo.css">
20
20
  </head>
21
21
  <body>
22
22
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fieldwangai/agentflow",
3
- "version": "0.1.105",
3
+ "version": "0.1.107",
4
4
  "description": "Orchestration system for long-running complex agent tasks using Cursor, OpenCode, Claude Code, or Codex as execution backends",
5
5
  "type": "module",
6
6
  "main": "bin/agentflow.mjs",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agentflow-cli
3
- description: Direct AgentFlow platform operation through a bundled token-backed CLI, without MCP. Use when Codex needs to list AgentFlow workspaces or flows, start a flow run, inspect run status/logs, or fetch display outputs through AgentFlow HTTP APIs using AGENTFLOW_TOKEN from env or .env. Default AgentFlow base URL is http://ai.mengma.bigo.inner/.
3
+ description: Direct AgentFlow platform operation through a bundled token-backed CLI, without MCP. Use when Codex needs to list AgentFlow workspaces or flows, start or inspect runs, fetch display outputs, or read and report Workflow actions, artifacts, and global state through AgentFlow HTTP APIs using AGENTFLOW_TOKEN from env or .env. Default AgentFlow base URL is http://ai.mengma.bigo.inner/.
4
4
  ---
5
5
 
6
6
  # AgentFlow CLI
@@ -118,16 +118,87 @@ Extract display outputs from a flow:
118
118
  node skills/agentflow-cli/scripts/agentflow-cli.mjs display-outputs --flow-id TestNodes --flow-source user
119
119
  ```
120
120
 
121
+ Read the current materialized Workflow before making an incremental update:
122
+
123
+ ```bash
124
+ node skills/agentflow-cli/scripts/agentflow-cli.mjs workflow-get \
125
+ --workflow tapd:1015046 \
126
+ --runtime-only
127
+ ```
128
+
129
+ Report an action, its artifacts, and/or a global-state patch:
130
+
131
+ ```bash
132
+ node skills/agentflow-cli/scripts/agentflow-cli.mjs workflow-report \
133
+ --workflow tapd:1015046 \
134
+ --file workflow-report.json \
135
+ --expected-revision 'runtime:replace-with-current-revision' \
136
+ --idempotency-key 'implementation-finished:android:issue-2:v1'
137
+ ```
138
+
139
+ `workflow-report.json` uses one general model. Include at least one of `action`, `artifacts`, or `globalState`:
140
+
141
+ ```json
142
+ {
143
+ "action": {
144
+ "key": "implementation-finished",
145
+ "title": "实现完成",
146
+ "detail": "Remote Config 拉取频控已实现",
147
+ "status": "done",
148
+ "group": "development",
149
+ "scope": "firebase-remote-config-fetch-control-android",
150
+ "platform": "android",
151
+ "issueKey": "issue-2",
152
+ "tags": ["remote-config"]
153
+ },
154
+ "artifacts": [
155
+ {
156
+ "key": "implementation-mr",
157
+ "type": "gitlab-mr",
158
+ "title": "Android 实现 MR",
159
+ "url": "https://git.example.test/group/project/-/merge_requests/123",
160
+ "scope": "action",
161
+ "status": "ready"
162
+ }
163
+ ],
164
+ "globalState": {
165
+ "mode": "merge",
166
+ "patch": {
167
+ "status": { "label": "开发中" },
168
+ "sections": {
169
+ "android": {
170
+ "title": "Android",
171
+ "fields": {
172
+ "owner": { "label": "负责人", "type": "user", "value": "alice" },
173
+ "tags": { "label": "Tag", "type": "chips", "value": ["remote-config"] },
174
+ "rules": { "label": "实现规则", "type": "list", "value": ["仅允许国家注册 listener"] }
175
+ }
176
+ }
177
+ }
178
+ },
179
+ "remove": []
180
+ }
181
+ }
182
+ ```
183
+
184
+ Artifact `scope` is `action` or `global`. Action-scoped artifacts appear with the timeline action; global artifacts appear in the related-artifacts area. Use stable `key` values so later reports update an existing item instead of duplicating it.
185
+
186
+ Supported global-state field types are `text`, `user`, `chips`, `list`, and `link`. The model does not require Android/iOS sections; section and field keys are application-defined.
187
+
121
188
  ## Workflow
122
189
 
123
190
  1. Check token availability with `config`.
124
191
  2. Use `list-workspace` or `list-flows` to discover targets.
125
192
  3. Use `run` to start the flow. If the task needs the generated page/text, inspect returned `displayOutputs` or call `display-outputs`.
126
193
  4. Use `status`, `list-run-by-workspace`, and `logs` when a run is active, failed, or needs debugging.
194
+ 5. Before changing Workflow global state, call `workflow-get` and retain `snapshot.runtimeRevision`.
195
+ 6. Merge the intended semantic change into the current state; do not replace unrelated fields.
196
+ 7. Call `workflow-report` with `--expected-revision` and a stable `--idempotency-key`. If the API returns a revision conflict, fetch again, re-apply the intended patch, and retry once with a new revision.
127
197
 
128
198
  ## Failure Handling
129
199
 
130
200
  - If the CLI says the token is missing, ask the user to set `AGENTFLOW_TOKEN` in env or `.env`.
131
201
  - If the API returns 401/403, do not retry with a printed token. Ask the user to refresh the token.
132
202
  - If `run` fails because a flow is already running, call `status` and `list-run-by-workspace` before retrying.
203
+ - If `workflow-report` returns a revision conflict, do not blindly overwrite remote state. Read the returned snapshot or call `workflow-get`, merge the intended fields, and retry with its revision.
133
204
  - If local debugging is needed, override `AGENTFLOW_BASE_URL`; otherwise keep the default internal URL.
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: "AgentFlow CLI"
3
- short_description: "Directly call AgentFlow APIs with a token-backed CLI."
4
- default_prompt: "Use the bundled AgentFlow CLI to list workspaces or flows, run a flow, inspect run logs, and fetch display outputs. Use AGENTFLOW_TOKEN from env or .env and default the base URL to the internal AgentFlow service."
3
+ short_description: "Run flows and report Workflow state through AgentFlow APIs"
4
+ default_prompt: "Use $agentflow-cli to operate AgentFlow and report Workflow actions, artifacts, or global state with the bundled token-backed CLI."
@@ -40,6 +40,8 @@ Commands:
40
40
  logs --run-id <id>
41
41
  display-outputs --flow-id <id> [--flow-source user]
42
42
  sync-workspace --workspace <id>
43
+ workflow-get --workflow tapd:<id> [--flow-id <id>] [--runtime-only]
44
+ workflow-report --workflow tapd:<id> --file <report.json> [--expected-revision <revision>]
43
45
  `;
44
46
  }
45
47
 
@@ -227,6 +229,51 @@ function requireFlowId(args) {
227
229
  return flowId;
228
230
  }
229
231
 
232
+ function parseWorkflowReference(value) {
233
+ const text = String(value || "").trim();
234
+ if (!text) return null;
235
+ const separator = text.indexOf(":");
236
+ if (separator <= 0 || separator === text.length - 1) {
237
+ throw new Error(`Invalid workflow reference "${text}". Expected namespace:id, for example tapd:1015046.`);
238
+ }
239
+ const namespace = text.slice(0, separator).trim().toLowerCase();
240
+ const id = text.slice(separator + 1).trim();
241
+ if (!namespace || !id) {
242
+ throw new Error(`Invalid workflow reference "${text}". Expected namespace:id.`);
243
+ }
244
+ return { namespace, id, key: `${namespace}:${id}` };
245
+ }
246
+
247
+ function workflowReferenceFromArgs(args, required = true) {
248
+ const explicit = option(args, "workflow");
249
+ if (explicit) return parseWorkflowReference(explicit);
250
+ const tapdId = option(args, "tapd-id") || option(args, "tapd");
251
+ if (tapdId) return { namespace: "tapd", id: tapdId, key: `tapd:${tapdId}` };
252
+ if (required) throw new Error("Missing --workflow namespace:id.");
253
+ return null;
254
+ }
255
+
256
+ function readJsonFile(filePath) {
257
+ const requested = String(filePath || "").trim();
258
+ if (!requested) throw new Error("Missing --file <report.json>.");
259
+ const resolved = path.resolve(requested);
260
+ let source;
261
+ try {
262
+ source = fs.readFileSync(resolved, "utf8");
263
+ } catch (error) {
264
+ throw new Error(`Cannot read JSON file ${resolved}: ${error?.message || String(error)}`);
265
+ }
266
+ try {
267
+ const value = JSON.parse(source);
268
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
269
+ throw new Error("top-level value must be an object");
270
+ }
271
+ return value;
272
+ } catch (error) {
273
+ throw new Error(`Invalid JSON file ${resolved}: ${error?.message || String(error)}`);
274
+ }
275
+ }
276
+
230
277
  async function main() {
231
278
  loadEnvFiles();
232
279
  const args = parseArgv(process.argv.slice(2));
@@ -332,6 +379,42 @@ async function main() {
332
379
  return;
333
380
  }
334
381
 
382
+ if (command === "workflow-get") {
383
+ const workflow = workflowReferenceFromArgs(args);
384
+ if (workflow.namespace !== "tapd") {
385
+ throw new Error(`Unsupported workflow namespace: ${workflow.namespace}`);
386
+ }
387
+ const flowId = option(args, "flow-id") || option(args, "flow");
388
+ const flowSource = option(args, "flow-source") || "user";
389
+ const runtimeOnly = args["runtime-only"] === true || args.cached === true ? "1" : "";
390
+ printJson(await httpJson(args, `/api/workflows/state${query({
391
+ workflow: workflow.key,
392
+ flowId,
393
+ flowSource,
394
+ runtimeOnly,
395
+ })}`));
396
+ return;
397
+ }
398
+
399
+ if (command === "workflow-report") {
400
+ const body = readJsonFile(option(args, "file"));
401
+ const workflow = workflowReferenceFromArgs(args, false) || parseWorkflowReference(body?.workflow?.key || "");
402
+ if (!workflow && !(body?.workflow?.namespace && body?.workflow?.id)) {
403
+ throw new Error("Missing workflow reference. Pass --workflow namespace:id or include workflow.namespace and workflow.id in the JSON file.");
404
+ }
405
+ if (workflow) body.workflow = workflow;
406
+ const expectedRevision = option(args, "expected-revision");
407
+ const idempotencyKey = option(args, "idempotency-key");
408
+ const flowId = option(args, "flow-id") || option(args, "flow");
409
+ const flowSource = option(args, "flow-source");
410
+ if (expectedRevision) body.expectedRevision = expectedRevision;
411
+ if (idempotencyKey) body.idempotencyKey = idempotencyKey;
412
+ if (flowId) body.flowId = flowId;
413
+ if (flowSource) body.flowSource = flowSource;
414
+ printJson(await httpJson(args, "/api/workflows/report", { method: "POST", body }));
415
+ return;
416
+ }
417
+
335
418
  throw new Error(`Unknown command: ${command}\n\n${usage()}`);
336
419
  }
337
420