@fieldwangai/agentflow 0.1.135 → 0.1.137
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/lib/prd-workflow-collaboration.mjs +172 -17
- package/bin/lib/ui-server.mjs +869 -80
- package/bin/lib/workflow-report.mjs +357 -36
- package/builtin/web-ui/dist/assets/index-CQsrSc3u.css +1 -0
- package/builtin/web-ui/dist/assets/index-DQvqqAeQ.js +590 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/skills/agentflow-cli/SKILL.md +3 -1
- package/skills/agentflow-cli/scripts/agentflow-cli.mjs +55 -6
- package/skills/agentflow-cli/scripts/workflow-report-client.mjs +71 -0
- package/skills/agentflow-workflow-report/SKILL.md +40 -17
- package/skills/agentflow-workflow-report/references/protocol.md +529 -235
- package/builtin/web-ui/dist/assets/index-BFQVTav-.css +0 -1
- package/builtin/web-ui/dist/assets/index-CmpbCHAj.js +0 -420
|
@@ -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-
|
|
19
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
18
|
+
<script type="module" crossorigin src="/assets/index-DQvqqAeQ.js"></script>
|
|
19
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CQsrSc3u.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.
|
|
3
|
+
"version": "0.1.137",
|
|
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",
|
|
@@ -120,7 +120,9 @@ node skills/agentflow-cli/scripts/agentflow-cli.mjs display-outputs --flow-id Te
|
|
|
120
120
|
|
|
121
121
|
## Workflow reporting
|
|
122
122
|
|
|
123
|
-
The CLI
|
|
123
|
+
The reusable transport lives in `scripts/workflow-report-client.mjs`. The CLI exposes it through `workflow-access-sync`, `workflow-get`, `workflow-report`, and `workflow-artifact-publish`; their permission model, state model, extension contract, concurrency rules, and AI procedure belong to the separate [`agentflow-workflow-report`](../agentflow-workflow-report/SKILL.md) skill. Use that skill whenever synchronizing access or reading/mutating Workflow state; do not reconstruct the protocol from this general CLI guide.
|
|
124
|
+
|
|
125
|
+
Every write requires the real business adapter `source`. Put the key-level `expectedVersions` map in the JSON file; use `absent` for a new resource key. `--expected-revision` is retained only for legacy whole-Workflow locking and should not be used by new integrations.
|
|
124
126
|
|
|
125
127
|
## Workflow
|
|
126
128
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { createWorkflowReportClient } from "./workflow-report-client.mjs";
|
|
5
6
|
|
|
6
7
|
const DEFAULT_BASE_URL = "http://ai.mengma.bigo.inner/";
|
|
7
8
|
const DISPLAY_DEFINITION_KINDS = new Map([
|
|
@@ -41,7 +42,9 @@ Commands:
|
|
|
41
42
|
display-outputs --flow-id <id> [--flow-source user]
|
|
42
43
|
sync-workspace --workspace <id>
|
|
43
44
|
workflow-get --workflow tapd:<id> [--flow-id <id>] [--runtime-only]
|
|
44
|
-
workflow-
|
|
45
|
+
workflow-access-sync --workflow tapd:<id> --file <access.json>
|
|
46
|
+
workflow-report --workflow tapd:<id> --file <report.json> [--source <adapter>] [--expected-revision <revision>] [--idempotency-key <key>]
|
|
47
|
+
workflow-artifact-publish --workflow tapd:<id> --file <artifact.json> [--source <adapter>] [--expected-revision <revision>] [--idempotency-key <key>]
|
|
45
48
|
`;
|
|
46
49
|
}
|
|
47
50
|
|
|
@@ -387,31 +390,77 @@ async function main() {
|
|
|
387
390
|
const flowId = option(args, "flow-id") || option(args, "flow");
|
|
388
391
|
const flowSource = option(args, "flow-source") || "user";
|
|
389
392
|
const runtimeOnly = args["runtime-only"] === true || args.cached === true ? "1" : "";
|
|
390
|
-
|
|
393
|
+
const client = createWorkflowReportClient({ baseUrl: normalizedBaseUrl(args), token: authToken(args) });
|
|
394
|
+
printJson(await client.getState({
|
|
391
395
|
workflow: workflow.key,
|
|
392
396
|
flowId,
|
|
393
397
|
flowSource,
|
|
394
|
-
runtimeOnly,
|
|
395
|
-
})
|
|
398
|
+
runtimeOnly: runtimeOnly === "1",
|
|
399
|
+
}));
|
|
396
400
|
return;
|
|
397
401
|
}
|
|
398
402
|
|
|
399
403
|
if (command === "workflow-report") {
|
|
400
404
|
const body = readJsonFile(option(args, "file"));
|
|
401
|
-
const workflow = workflowReferenceFromArgs(args, false) || parseWorkflowReference(
|
|
405
|
+
const workflow = workflowReferenceFromArgs(args, false) || parseWorkflowReference(
|
|
406
|
+
typeof body?.workflow === "string" ? body.workflow : body?.workflow?.key || "",
|
|
407
|
+
);
|
|
402
408
|
if (!workflow && !(body?.workflow?.namespace && body?.workflow?.id)) {
|
|
403
409
|
throw new Error("Missing workflow reference. Pass --workflow namespace:id or include workflow.namespace and workflow.id in the JSON file.");
|
|
404
410
|
}
|
|
405
411
|
if (workflow) body.workflow = workflow;
|
|
406
412
|
const expectedRevision = option(args, "expected-revision");
|
|
407
413
|
const idempotencyKey = option(args, "idempotency-key");
|
|
414
|
+
const reportSource = option(args, "source");
|
|
408
415
|
const flowId = option(args, "flow-id") || option(args, "flow");
|
|
409
416
|
const flowSource = option(args, "flow-source");
|
|
410
417
|
if (expectedRevision) body.expectedRevision = expectedRevision;
|
|
411
418
|
if (idempotencyKey) body.idempotencyKey = idempotencyKey;
|
|
419
|
+
if (reportSource) body.source = reportSource;
|
|
420
|
+
if (!String(body.source || "").trim()) throw new Error("Missing Workflow report source. Pass --source <adapter> or include source in the JSON file.");
|
|
412
421
|
if (flowId) body.flowId = flowId;
|
|
413
422
|
if (flowSource) body.flowSource = flowSource;
|
|
414
|
-
|
|
423
|
+
const client = createWorkflowReportClient({ baseUrl: normalizedBaseUrl(args), token: authToken(args) });
|
|
424
|
+
printJson(await client.report(body));
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (command === "workflow-access-sync") {
|
|
429
|
+
const body = readJsonFile(option(args, "file"));
|
|
430
|
+
const workflow = workflowReferenceFromArgs(args, false) || parseWorkflowReference(
|
|
431
|
+
typeof body?.workflow === "string" ? body.workflow : body?.workflow?.key || "",
|
|
432
|
+
);
|
|
433
|
+
if (!workflow && !(body?.workflow?.namespace && body?.workflow?.id)) {
|
|
434
|
+
throw new Error("Missing workflow reference. Pass --workflow namespace:id or include workflow.namespace and workflow.id in the JSON file.");
|
|
435
|
+
}
|
|
436
|
+
if (workflow) body.workflow = workflow;
|
|
437
|
+
const client = createWorkflowReportClient({ baseUrl: normalizedBaseUrl(args), token: authToken(args) });
|
|
438
|
+
printJson(await client.syncAccess(body));
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (command === "workflow-artifact-publish") {
|
|
443
|
+
const body = readJsonFile(option(args, "file"));
|
|
444
|
+
const workflow = workflowReferenceFromArgs(args, false) || parseWorkflowReference(
|
|
445
|
+
typeof body?.workflow === "string" ? body.workflow : body?.workflow?.key || "",
|
|
446
|
+
);
|
|
447
|
+
if (!workflow && !(body?.workflow?.namespace && body?.workflow?.id)) {
|
|
448
|
+
throw new Error("Missing workflow reference. Pass --workflow namespace:id or include workflow.namespace and workflow.id in the JSON file.");
|
|
449
|
+
}
|
|
450
|
+
if (workflow) body.workflow = workflow;
|
|
451
|
+
const expectedRevision = option(args, "expected-revision");
|
|
452
|
+
const idempotencyKey = option(args, "idempotency-key");
|
|
453
|
+
const reportSource = option(args, "source");
|
|
454
|
+
const flowId = option(args, "flow-id") || option(args, "flow");
|
|
455
|
+
const flowSource = option(args, "flow-source");
|
|
456
|
+
if (flowId) body.flowId = flowId;
|
|
457
|
+
if (flowSource) body.flowSource = flowSource;
|
|
458
|
+
if (expectedRevision) body.expectedRevision = expectedRevision;
|
|
459
|
+
if (idempotencyKey) body.idempotencyKey = idempotencyKey;
|
|
460
|
+
if (reportSource) body.source = reportSource;
|
|
461
|
+
if (!String(body.source || "").trim()) throw new Error("Missing Workflow artifact source. Pass --source <adapter> or include source in the JSON file.");
|
|
462
|
+
const client = createWorkflowReportClient({ baseUrl: normalizedBaseUrl(args), token: authToken(args) });
|
|
463
|
+
printJson(await client.publishArtifact(body));
|
|
415
464
|
return;
|
|
416
465
|
}
|
|
417
466
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
function cleanBaseUrl(value) {
|
|
2
|
+
return String(value || "").trim().replace(/\/+$/, "");
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function workflowQuery(params = {}) {
|
|
6
|
+
const search = new URLSearchParams();
|
|
7
|
+
for (const [key, value] of Object.entries(params)) {
|
|
8
|
+
if (value === undefined || value === null || value === "") continue;
|
|
9
|
+
search.set(key, String(value));
|
|
10
|
+
}
|
|
11
|
+
const text = search.toString();
|
|
12
|
+
return text ? `?${text}` : "";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createWorkflowReportClient({ baseUrl, token, fetchImpl = globalThis.fetch } = {}) {
|
|
16
|
+
const origin = cleanBaseUrl(baseUrl);
|
|
17
|
+
const credential = String(token || "").trim();
|
|
18
|
+
if (!origin) throw new Error("Workflow Report client requires baseUrl");
|
|
19
|
+
if (!credential) throw new Error("Workflow Report client requires token");
|
|
20
|
+
if (typeof fetchImpl !== "function") throw new Error("Workflow Report client requires fetch");
|
|
21
|
+
|
|
22
|
+
const request = async (pathname, { method = "GET", body } = {}) => {
|
|
23
|
+
const url = new URL(pathname, `${origin}/`);
|
|
24
|
+
const headers = {
|
|
25
|
+
Accept: "application/json",
|
|
26
|
+
Authorization: `Bearer ${credential}`,
|
|
27
|
+
Cookie: `af_session=${encodeURIComponent(credential)}`,
|
|
28
|
+
};
|
|
29
|
+
if (body !== undefined) headers["Content-Type"] = "application/json";
|
|
30
|
+
const response = await fetchImpl(url, {
|
|
31
|
+
method,
|
|
32
|
+
headers,
|
|
33
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
34
|
+
});
|
|
35
|
+
const text = await response.text();
|
|
36
|
+
let data = null;
|
|
37
|
+
try {
|
|
38
|
+
data = text ? JSON.parse(text) : null;
|
|
39
|
+
} catch {
|
|
40
|
+
data = { text };
|
|
41
|
+
}
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
const message = data?.error || data?.message || text || `HTTP ${response.status}`;
|
|
44
|
+
const error = new Error(`${method} ${url.pathname} failed: ${message}`);
|
|
45
|
+
error.status = response.status;
|
|
46
|
+
error.data = data;
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
return data;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
getState({ workflow, flowId = "", flowSource = "user", runtimeOnly = false } = {}) {
|
|
54
|
+
return request(`/api/workflows/state${workflowQuery({
|
|
55
|
+
workflow,
|
|
56
|
+
flowId,
|
|
57
|
+
flowSource,
|
|
58
|
+
runtimeOnly: runtimeOnly ? "1" : "",
|
|
59
|
+
})}`);
|
|
60
|
+
},
|
|
61
|
+
syncAccess(body = {}) {
|
|
62
|
+
return request("/api/workflows/access/sync", { method: "POST", body });
|
|
63
|
+
},
|
|
64
|
+
report(body = {}) {
|
|
65
|
+
return request("/api/workflows/report", { method: "POST", body });
|
|
66
|
+
},
|
|
67
|
+
publishArtifact(body = {}) {
|
|
68
|
+
return request("/api/workflow-artifacts/publish", { method: "POST", body });
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agentflow-workflow-report
|
|
3
|
-
description: Safely read, merge, and report AgentFlow Workflow actions, artifacts, producer-owned global state, and generic timeline projections through the AgentFlow CLI and HTTP protocol. Use when an AI agent or producer such as prd-flow needs to integrate Workflow reporting, publish progress or evidence, update globalState, assign version/sprint/milestone timeline membership, clear projections, or resolve revision and idempotency conflicts.
|
|
3
|
+
description: Safely synchronize TAPD-derived Workflow access, then read, merge, and report AgentFlow Workflow actions, artifacts, producer-owned global state, and generic timeline projections through the AgentFlow CLI and HTTP protocol. Use when an AI agent or producer such as prd-flow needs to integrate Workflow reporting, map TAPD Owner and participants, publish progress or evidence, update globalState, assign version/sprint/milestone timeline membership, clear projections, or resolve revision and idempotency conflicts.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# AgentFlow Workflow Report
|
|
7
7
|
|
|
8
|
-
Treat Workflow reporting as
|
|
8
|
+
Treat Workflow reporting as one canonical producer-adapter protocol. The producer reports facts through `POST /api/workflows/report`; AgentFlow alone materializes and returns `snapshot`. Do not introduce producer-specific write endpoints for new integrations.
|
|
9
9
|
|
|
10
10
|
## Prerequisites
|
|
11
11
|
|
|
12
|
-
Use the
|
|
12
|
+
Use the Workflow Report client bundled with the sibling `agentflow-cli` skill. The CLI is its command-line wrapper for AI, scripts, and local verification:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
15
|
node skills/agentflow-cli/scripts/agentflow-cli.mjs <command> [options]
|
|
@@ -17,12 +17,13 @@ node skills/agentflow-cli/scripts/agentflow-cli.mjs <command> [options]
|
|
|
17
17
|
|
|
18
18
|
If the script is unavailable, install `agentflow-cli` beside this skill. Require `AGENTFLOW_TOKEN` or `AGENTFLOW_SESSION_TOKEN`; never print either token. Use `AGENTFLOW_BASE_URL` only when overriding the default service.
|
|
19
19
|
|
|
20
|
-
Read [references/protocol.md](references/protocol.md) completely before implementing a producer, changing the report contract,
|
|
20
|
+
Read [references/protocol.md](references/protocol.md) completely before implementing a producer, changing the report contract, constructing a payload, or answering questions about parameters, permissions, merge behavior, custom panels, and visible UI results.
|
|
21
21
|
|
|
22
22
|
## Required sequence
|
|
23
23
|
|
|
24
|
-
1. Resolve a canonical Workflow reference such as `tapd:1015046`.
|
|
25
|
-
2.
|
|
24
|
+
1. Resolve a canonical Workflow reference such as `tapd:1015046`. The report schema is producer-generic, but the current AgentFlow identity adapter accepts only the `tapd` namespace. Do not claim that arbitrary Workflow namespaces already work.
|
|
25
|
+
2. If the Adapter reads TAPD personnel, synchronize its authority snapshot with `POST /api/workflows/access/sync` before reporting: TAPD Owner becomes Workflow Owner and matched TAPD participants become derived Viewers. Keep this permission control-plane call separate from runtime report data.
|
|
26
|
+
3. Read the current materialized state and retain `snapshot.resourceVersions` for every resource key the operation will touch:
|
|
26
27
|
|
|
27
28
|
```bash
|
|
28
29
|
node skills/agentflow-cli/scripts/agentflow-cli.mjs workflow-get \
|
|
@@ -30,48 +31,70 @@ node skills/agentflow-cli/scripts/agentflow-cli.mjs workflow-get \
|
|
|
30
31
|
--runtime-only
|
|
31
32
|
```
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
4. Compute only the intended semantic update. Choose one stable lowercase `source` for the business adapter (for example `prd-flow` or `release-bot`). `agentflow-cli` is only transport and must not replace the real producer identity.
|
|
35
|
+
5. Preserve unrelated `globalState` fields. Never infer or rewrite a producer's private schema.
|
|
36
|
+
6. When timeline membership changes, derive the complete producer-owned `projections.timeline` slice. AgentFlow preserves entries owned by other sources; use `[]` to clear only the current source's memberships.
|
|
37
|
+
7. Put `expectedVersions` for every touched Action, Artifact, GlobalState path, Projection, Extension path, or Observation into the JSON payload. Use `"absent"` when creating a new key. Report it with a stable operation key:
|
|
37
38
|
|
|
38
39
|
```bash
|
|
39
40
|
node skills/agentflow-cli/scripts/agentflow-cli.mjs workflow-report \
|
|
40
41
|
--workflow tapd:1015046 \
|
|
41
42
|
--file workflow-report.json \
|
|
42
|
-
--expected-revision 'runtime:current-revision' \
|
|
43
43
|
--idempotency-key 'implementation-finished:android:issue-2:v1'
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
8. On HTTP 409, refresh only the resource keys listed in `conflict.conflicts`, recompute the intended update, and retry once with their new versions. Never send a client field named `snapshot`; use `observation.state` for a complete producer observation and treat returned `snapshot` as server output.
|
|
47
47
|
|
|
48
48
|
## Report selection
|
|
49
49
|
|
|
50
50
|
Include at least one capability:
|
|
51
51
|
|
|
52
|
+
- `observation`: report the producer's complete current observation when it computes a deterministic workflow view.
|
|
52
53
|
- `action`: report a stable progress or lifecycle event.
|
|
53
54
|
- `artifacts`: attach evidence; use stable artifact keys.
|
|
54
55
|
- `globalState`: merge producer-owned durable state or remove explicit paths.
|
|
55
56
|
- `projections`: replace generic derived indexes used by AgentFlow dashboards.
|
|
57
|
+
- `extensions`: report namespaced data for a registered specialized renderer, such as `extensions["prd-flow"].issues`.
|
|
58
|
+
|
|
59
|
+
Map data to the visible page deliberately:
|
|
60
|
+
|
|
61
|
+
- Global area: `observation.state`, incremental producer facts in `globalState`, and iteration membership in `projections.timeline`.
|
|
62
|
+
- Action timeline: stable `action.key` plus Action-scoped `artifacts`.
|
|
63
|
+
- Generic custom cards: use `globalState.sections` with built-in `text`, `user`, `chips`, `list`, and `link` field renderers.
|
|
64
|
+
- Specialized custom area: use namespaced `extensions` only when built-in renderers cannot express the layout. Saving an extension does not create a UI by itself; currently only `extensions["prd-flow"]` has a registered AI Docs / Issues renderer.
|
|
56
65
|
|
|
57
66
|
Use projection-only reports when the producer state is already current and only dashboard membership needs synchronization.
|
|
58
67
|
|
|
68
|
+
For local Markdown or other content that must become a browser URL, publish it first with `workflow-artifact-publish` (`POST /api/workflow-artifacts/publish`), then use the returned Artifact in the same Workflow. Do not use `/api/prd-workflow/review-link` for new integrations.
|
|
69
|
+
|
|
59
70
|
## Non-negotiable rules
|
|
60
71
|
|
|
61
72
|
- Keep `schemaVersion` at `1` unless the server advertises another version.
|
|
73
|
+
- Keep the runtime chain singular: producer adapter → Workflow Report client → AgentFlow. The Skill is guidance, not a transport hop.
|
|
62
74
|
- Give every action a stable `key`.
|
|
75
|
+
- Send a stable lowercase `source` on every report and Markdown publish; it is required. Action, idempotency, Artifact, Projection, Extension, Observation, and GlobalState ownership are isolated by source-aware resource keys.
|
|
63
76
|
- Give every timeline entry stable `kind` and `id` values.
|
|
64
77
|
- Treat `dimensions` as opaque facets; do not hardcode Android, iOS, version, or prd-flow fields into AgentFlow state.
|
|
65
78
|
- Treat `globalState` as the source of truth owned by the producer; treat projections as replaceable derived views.
|
|
66
|
-
- Send the complete current timeline
|
|
67
|
-
- Use `
|
|
79
|
+
- Send the complete current source-owned timeline slice whenever changing it. Omitting `projections` means no projection change.
|
|
80
|
+
- Use `expectedVersions` for key-level concurrency and a stable `idempotencyKey` for every logical operation. `expectedRevision` remains a whole-Workflow compatibility lock only when `expectedVersions` is absent.
|
|
68
81
|
- Do not include credentials, tokens, cookies, or private environment values in actions, artifacts, state, projections, or logs.
|
|
69
82
|
|
|
83
|
+
## Permissions and overwrite semantics
|
|
84
|
+
|
|
85
|
+
- Treat TAPD personnel as derived authority when the Adapter can read them: TAPD Owner maps to Workflow Owner and registered TAPD participants map to Viewer.
|
|
86
|
+
- Keep explicit grants separate from derived TAPD membership. Allow Owner and explicit Reporter writes. Treat TAPD participant Viewer, explicit Viewer, same-team Viewer, share-link Viewer, and admin review as read-only. Accept legacy `editor` only as a compatibility alias for Reporter.
|
|
87
|
+
- `observation.state` replaces the complete previous observation for the same `clientId`.
|
|
88
|
+
- `globalState.patch` recursively merges objects; arrays and scalars replace; `null` and `remove` delete explicit paths. The first reporting source to write a path owns it; another source cannot overwrite an owned path.
|
|
89
|
+
- Reusing an `action.key` updates the same semantic stage. Do not create a new key for refreshes or retries.
|
|
90
|
+
- `projections.timeline` replaces only the current source's entries; AgentFlow preserves other sources atomically.
|
|
91
|
+
- `extensions` can update only `extensions[source]`; objects recursively merge, arrays/scalars replace, and `null` deletes producer-owned fields.
|
|
92
|
+
- Publishing Markdown creates or updates a preview Artifact and review copy; it does not confirm a document or advance an Action.
|
|
93
|
+
|
|
70
94
|
## Failure handling
|
|
71
95
|
|
|
72
96
|
- Missing token: stop and ask the user to configure `AGENTFLOW_TOKEN`.
|
|
73
97
|
- HTTP 401/403: stop; do not retry with a token printed in a command or answer.
|
|
74
|
-
- HTTP 409: follow the single read-merge-retry sequence.
|
|
98
|
+
- HTTP 409: inspect `workflow-resource-conflict` or `workflow-resource-ownership-conflict`, refresh the listed keys, and follow the single read-merge-retry sequence.
|
|
75
99
|
- HTTP 400: fix the payload against the protocol reference; do not weaken validation.
|
|
76
|
-
- Replayed idempotency key
|
|
77
|
-
|
|
100
|
+
- Replayed idempotency key from the same `source`: accept `alreadyApplied: true` as success. Markdown publish returns the previously created preview instead of creating another copy.
|