@nanobpm/nano-workforce 0.117.0 → 0.118.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/CHANGELOG.md +7 -0
- package/README.md +21 -0
- package/app/deliveryGraphText.ts +41 -0
- package/docs/agent-guide.md +173 -0
- package/openapi.yaml +166 -0
- package/operations/dispatchDeliveryGraph.test.ts +166 -0
- package/operations/dispatchDeliveryGraph.ts +113 -0
- package/operations/getAgentInstructions.test.ts +22 -0
- package/operations/previewDeliveryGraph.test.ts +74 -0
- package/operations/previewDeliveryGraph.ts +59 -0
- package/package.json +1 -1
- package/pages/_nav.json +1 -0
- package/pages/board.page.json +4 -0
- package/pages/cockpit.page.json +4 -0
- package/pages/delivery-graph-detail.page.json +114 -0
- package/pages/delivery-graphs.page.json +153 -0
- package/pages/epic-detail.page.json +4 -0
- package/pages/epic.page.json +4 -0
- package/pages/feature.page.json +4 -0
- package/pages/home.page.json +4 -0
- package/pages/lineage.page.json +4 -0
- package/pages/overview.page.json +6 -2
- package/pages/tasks.page.json +4 -0
- package/pages/velocity.page.json +4 -0
- package/scripts/pages-contract.test.ts +67 -0
package/pages/overview.page.json
CHANGED
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"label": "Feature",
|
|
30
30
|
"page": "feature"
|
|
31
31
|
},
|
|
32
|
+
{
|
|
33
|
+
"label": "Delivery Graphs",
|
|
34
|
+
"page": "delivery-graphs"
|
|
35
|
+
},
|
|
32
36
|
{
|
|
33
37
|
"label": "Tasks",
|
|
34
38
|
"page": "tasks",
|
|
@@ -66,7 +70,7 @@
|
|
|
66
70
|
"type": "text",
|
|
67
71
|
"id": "subtitle",
|
|
68
72
|
"props": {
|
|
69
|
-
"text": "Everything currently in flight across the
|
|
73
|
+
"text": "Everything currently in flight across the four dispatch surfaces \u2014 PR convergences, Epics, Feature runs, and Delivery Graphs. Each section lists only its active items, remembers whether you collapsed it, and shows a live count in its header. Follow any row to its detail page.",
|
|
70
74
|
"variant": "sub"
|
|
71
75
|
}
|
|
72
76
|
},
|
|
@@ -208,7 +212,7 @@
|
|
|
208
212
|
"filter": [{ "field": "status", "in": ["awaiting-approval", "running"] }]
|
|
209
213
|
},
|
|
210
214
|
"columns": [
|
|
211
|
-
{ "field": "title", "template": "{{title}}", "header": "Item", "subtitleField": "run_key", "truncate": true, "width": "30%" },
|
|
215
|
+
{ "field": "title", "template": "{{title}}", "header": "Item", "subtitleField": "run_key", "truncate": true, "width": "30%", "link": { "kind": "page", "page": "delivery-graph-detail", "keyField": "run_key" } },
|
|
212
216
|
{ "field": "status", "header": "Status", "link": { "kind": "processExplorer", "keyField": "process_key" } },
|
|
213
217
|
{ "field": "phase", "header": "Phase", "truncate": true, "width": "28%" },
|
|
214
218
|
{ "field": "updated_at", "header": "Updated", "width": "9rem", "format": "datetime" }
|
package/pages/tasks.page.json
CHANGED
package/pages/velocity.page.json
CHANGED
|
@@ -282,6 +282,9 @@ test("issue #205: overview is the landing page and first nav item", async () =>
|
|
|
282
282
|
},
|
|
283
283
|
plans: { field: "list_bucket", in: ["active"] },
|
|
284
284
|
feature_runs: { field: "status", in: ["running", "escalated", "awaiting_operator"] },
|
|
285
|
+
// The 4th dispatch surface (issue #386) — active delivery graphs. Both in-flight statuses
|
|
286
|
+
// (`awaiting-approval` parked at the gate, `running` dispatched) show here.
|
|
287
|
+
delivery_graph_runs: { field: "status", in: ["awaiting-approval", "running"] },
|
|
285
288
|
};
|
|
286
289
|
const grids = (overview.nodes ?? []).filter((n: Json) => n.type === "dataGrid");
|
|
287
290
|
for (const [table, { field, in: values }] of Object.entries(expected)) {
|
|
@@ -298,3 +301,67 @@ test("issue #205: overview is the landing page and first nav item", async () =>
|
|
|
298
301
|
}
|
|
299
302
|
});
|
|
300
303
|
|
|
304
|
+
|
|
305
|
+
test("issue #386: the human-facing Delivery Graphs surface is wired (nav tab, page, detail, overview)", async () => {
|
|
306
|
+
// 1) A `Delivery Graphs` nav tab in the single-source nav, pointing at the delivery-graphs page.
|
|
307
|
+
const nav = JSON.parse(readFileSync(`${ROOT}pages/_nav.json`, "utf8"));
|
|
308
|
+
const tab = (nav.props?.items ?? []).find(
|
|
309
|
+
(i: Json) => i.page === "delivery-graphs" && i.label === "Delivery Graphs",
|
|
310
|
+
);
|
|
311
|
+
assert(tab, "pages/_nav.json must carry a `Delivery Graphs` nav tab → the delivery-graphs page");
|
|
312
|
+
|
|
313
|
+
// 2) The Submit page exists with a Preview (compile) action and a Dispatch (start) action, plus an
|
|
314
|
+
// in-flight grid over the delivery_graph_runs aggregate that links to the per-graph detail page.
|
|
315
|
+
const page = JSON.parse(readFileSync(`${ROOT}pages/delivery-graphs.page.json`, "utf8"));
|
|
316
|
+
const forms = (page.nodes ?? []).filter((n: Json) => n.type === "actionForm");
|
|
317
|
+
const preview = forms.find((f: Json) => f.props?.action?.path === "/app/api/actions/delivery-graph/preview");
|
|
318
|
+
const dispatch = forms.find((f: Json) => f.props?.action?.path === "/app/api/actions/delivery-graph/dispatch");
|
|
319
|
+
assert(preview, "delivery-graphs page must have a Preview form posting to /app/api/actions/delivery-graph/preview");
|
|
320
|
+
assert(dispatch, "delivery-graphs page must have a Dispatch form posting to /app/api/actions/delivery-graph/dispatch");
|
|
321
|
+
// Both forms take the pasted graph JSON; Dispatch also carries the explicit approve gate.
|
|
322
|
+
assert(
|
|
323
|
+
(preview.props?.fields ?? []).some((fl: Json) => fl.key === "graphJson"),
|
|
324
|
+
"the Preview form must have a graphJson paste field",
|
|
325
|
+
);
|
|
326
|
+
assert(
|
|
327
|
+
(dispatch.props?.fields ?? []).some((fl: Json) => fl.key === "graphJson") &&
|
|
328
|
+
(dispatch.props?.fields ?? []).some((fl: Json) => fl.key === "approve"),
|
|
329
|
+
"the Dispatch form must have a graphJson paste field and an approve gate",
|
|
330
|
+
);
|
|
331
|
+
const grid = (page.nodes ?? []).find(
|
|
332
|
+
(n: Json) => n.type === "dataGrid" && n.props?.data?.table === "delivery_graph_runs",
|
|
333
|
+
);
|
|
334
|
+
assert(grid, "delivery-graphs page must have an in-flight grid over delivery_graph_runs");
|
|
335
|
+
const linkCol = (grid.props?.columns ?? []).find((c: Json) => c.link?.page === "delivery-graph-detail");
|
|
336
|
+
assert(
|
|
337
|
+
linkCol && linkCol.link?.keyField === "run_key",
|
|
338
|
+
"the in-flight grid must link a column to delivery-graph-detail by run_key",
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
// 3) The per-graph detail page reads the run aggregate scoped to the route param (run_key).
|
|
342
|
+
const detail = JSON.parse(readFileSync(`${ROOT}pages/delivery-graph-detail.page.json`, "utf8"));
|
|
343
|
+
const runGrid = (detail.nodes ?? []).find(
|
|
344
|
+
(n: Json) => n.type === "dataGrid" && n.props?.data?.table === "delivery_graph_runs",
|
|
345
|
+
);
|
|
346
|
+
assert(runGrid, "delivery-graph-detail must bind a grid to delivery_graph_runs");
|
|
347
|
+
assert(
|
|
348
|
+
(runGrid.props?.data?.filter ?? []).some((fl: Json) => fl.field === "run_key" && fl.eqParam === true),
|
|
349
|
+
"delivery-graph-detail must scope its run grid to the route param (run_key eqParam)",
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
// 4) The Overview no longer claims only three surfaces, and its 4th section links to the detail page.
|
|
353
|
+
const overview = JSON.parse(readFileSync(`${ROOT}pages/overview.page.json`, "utf8"));
|
|
354
|
+
const subtitle = (overview.nodes ?? []).find((n: Json) => n.id === "subtitle");
|
|
355
|
+
assert(
|
|
356
|
+
typeof subtitle?.props?.text === "string" && !subtitle.props.text.includes("three dispatch surfaces"),
|
|
357
|
+
"overview subtitle must no longer say 'three dispatch surfaces' (a delivery graph is a 4th)",
|
|
358
|
+
);
|
|
359
|
+
const ovGrid = (overview.nodes ?? []).find(
|
|
360
|
+
(n: Json) => n.type === "dataGrid" && n.props?.data?.table === "delivery_graph_runs",
|
|
361
|
+
);
|
|
362
|
+
const ovLink = (ovGrid?.props?.columns ?? []).find((c: Json) => c.link?.page === "delivery-graph-detail");
|
|
363
|
+
assert(
|
|
364
|
+
ovLink && ovLink.link?.keyField === "run_key",
|
|
365
|
+
"overview delivery-graphs section must link its item to delivery-graph-detail by run_key",
|
|
366
|
+
);
|
|
367
|
+
});
|