@quintinshaw/pi-dynamic-workflows 1.7.1 → 1.9.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/README.md +6 -8
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/task-panel.d.ts +24 -0
- package/dist/task-panel.js +82 -0
- package/dist/workflow-commands.js +12 -0
- package/dist/workflow-manager.d.ts +3 -0
- package/dist/workflow-manager.js +3 -0
- package/dist/workflow-tool.js +4 -1
- package/dist/workflow-ui.d.ts +110 -0
- package/dist/workflow-ui.js +426 -0
- package/dist/workflow.d.ts +21 -0
- package/dist/workflow.js +54 -19
- package/extensions/workflow.ts +9 -3
- package/package.json +1 -1
- package/src/index.ts +11 -0
- package/src/task-panel.ts +103 -0
- package/src/workflow-commands.ts +12 -0
- package/src/workflow-manager.ts +5 -0
- package/src/workflow-tool.ts +4 -1
- package/src/workflow-ui.ts +496 -0
- package/src/workflow.ts +71 -27
package/README.md
CHANGED
|
@@ -51,7 +51,8 @@ Press `Esc` to cancel a running run; active subagents are aborted and surfaced a
|
|
|
51
51
|
Ask for a background workflow (the model passes `background: true`) and it runs without blocking your session. Manage it with the `/workflows` command:
|
|
52
52
|
|
|
53
53
|
```text
|
|
54
|
-
/workflows # list
|
|
54
|
+
/workflows # open the interactive navigator (plain list in print mode)
|
|
55
|
+
/workflows list # force the plain-text list
|
|
55
56
|
/workflows status <id> # watch a running run live (status bar), prints result when done
|
|
56
57
|
/workflows stop <id> # abort a running run
|
|
57
58
|
/workflows pause <id> # pause a running run
|
|
@@ -98,6 +99,7 @@ return { inventory, summary }
|
|
|
98
99
|
| `parallel(thunks)` | Run an array of `() => agent(...)` thunks concurrently. Results returned in input order. |
|
|
99
100
|
| `pipeline(items, ...stages)` | Fan items out through sequential stages. Each stage receives `(prev, original, index)`. |
|
|
100
101
|
| `phase(title)` | Mark the current phase for the live progress view. |
|
|
102
|
+
| `workflow(name, args)` | Run a saved workflow inline and return its result (one level deep; shares the global caps). |
|
|
101
103
|
| `log(message)` | Append a workflow-level log line. |
|
|
102
104
|
| `args` | Optional JSON value passed via the tool's `args` parameter. |
|
|
103
105
|
| `budget` | `{ total, spent(), remaining() }` token-budget tracker. |
|
|
@@ -146,21 +148,17 @@ Scripts run inside a Node `vm` sandbox. Intentionally unavailable: `Date.now()`,
|
|
|
146
148
|
- **Structured output** — JSON-Schema-validated subagent results
|
|
147
149
|
- **Real token & cost accounting** — read from each subagent's SDK session (input / output / total / cost), with a character estimate only as fallback when a provider reports no usage; `budget` gates on the real total
|
|
148
150
|
- **Real per-agent / per-phase model routing** — `opts.model` and `meta.phases[].model` actually select the model (resolved against your authed model registry), with graceful fallback
|
|
149
|
-
- **`/workflows`
|
|
151
|
+
- **`/workflows` interactive navigator** — `/workflows` opens a focused TUI you drill through with the keyboard (runs → phases → agents → agent detail): `↑/↓` (or `j/k`) select, `enter`/`→` open, `esc`/`←` back, `j/k` scroll detail, `p` pause/resume, `x` stop, `s` save, `q` quit. In print/RPC mode it falls back to plain text
|
|
152
|
+
- **Live task panel + background delivery** — while a `background: true` run is going, a "Workflows running" panel sits below the input (focus it and press `enter` to open the navigator); when the run finishes, its result is delivered back into the conversation so your paused task continues
|
|
150
153
|
- **Bundled `/deep-research` & `/adversarial-review`** — `/deep-research` runs real web searches (via built-in `web_search` / `web_fetch` tools), extracts claims, cross-checks them across sources, and reports only what survived; `/adversarial-review` investigates a task then has independent skeptics try to refute each finding, keeping only those that clear an agreement threshold
|
|
151
154
|
- **Saved workflows as `/<name>`** — save a run's script with `/workflows save <name>` and it becomes a reusable slash command; arguments are parsed (`key=value` and positionals) and passed through as `args`
|
|
155
|
+
- **Nested `workflow()`** — call `await workflow('saved-name', args)` inside a script to run a saved workflow inline; nesting is one level deep and shares the parent's concurrency limiter, agent counter, and token budget so the global caps hold
|
|
152
156
|
- **Resume** — each agent result is journaled by a deterministic call index; resuming replays the unchanged prefix from cache (no re-run, no tokens) and runs only new or edited calls live
|
|
153
157
|
- **Worktree isolation** — `isolation: "worktree"` runs an agent in its own git worktree on a throwaway branch, so parallel agents can edit the same files without conflict; the worktree is torn down after (results are not auto-merged), and it falls back to a logged no-op outside a git repo
|
|
154
158
|
- **Safety limits** — 1000-agent cap (`maxAgents`), per-agent timeout (`agentTimeoutMs`), recoverable-vs-fatal error classification
|
|
155
159
|
- **Live progress + token/cost display**, `Esc` to abort
|
|
156
160
|
- **Log persistence** to `.pi/workflows/runs/`
|
|
157
161
|
|
|
158
|
-
## Roadmap
|
|
159
|
-
|
|
160
|
-
Tracked toward closer parity with Claude Code dynamic workflows:
|
|
161
|
-
|
|
162
|
-
- **Nested `workflow()`** to compose saved workflows inline
|
|
163
|
-
|
|
164
162
|
## How it works
|
|
165
163
|
|
|
166
164
|
```text
|
package/dist/index.d.ts
CHANGED
|
@@ -20,8 +20,9 @@ export { createRunPersistence, generateRunId } from "./run-persistence.js";
|
|
|
20
20
|
export { parseCommandArgs, registerAllSavedWorkflows, registerSavedWorkflow, } from "./saved-commands.js";
|
|
21
21
|
export type { StructuredOutputCapture, StructuredOutputToolOptions } from "./structured-output.js";
|
|
22
22
|
export { createStructuredOutputTool } from "./structured-output.js";
|
|
23
|
+
export { installResultDelivery, installTaskPanel, type TaskPanelOptions } from "./task-panel.js";
|
|
23
24
|
export { createWebFetchTool, createWebSearchTool, createWebTools } from "./web-tools.js";
|
|
24
|
-
export type { AgentOptions, JournalEntry, WorkflowMeta, WorkflowMetaPhase, WorkflowRunOptions, WorkflowRunResult, } from "./workflow.js";
|
|
25
|
+
export type { AgentOptions, JournalEntry, SharedRuntime, WorkflowMeta, WorkflowMetaPhase, WorkflowRunOptions, WorkflowRunResult, } from "./workflow.js";
|
|
25
26
|
export { parseWorkflowScript, runWorkflow } from "./workflow.js";
|
|
26
27
|
export { registerWorkflowCommands } from "./workflow-commands.js";
|
|
27
28
|
export type { ManagedRun, WorkflowManagerOptions } from "./workflow-manager.js";
|
|
@@ -30,5 +31,6 @@ export type { SavedWorkflow, WorkflowStorage } from "./workflow-saved.js";
|
|
|
30
31
|
export { createWorkflowStorage } from "./workflow-saved.js";
|
|
31
32
|
export type { WorkflowToolInput, WorkflowToolOptions } from "./workflow-tool.js";
|
|
32
33
|
export { createWorkflowTool } from "./workflow-tool.js";
|
|
34
|
+
export { keyToAction, type NavAction, NavigatorModel, NavigatorState, openWorkflowNavigator, renderNavigator, type ViewKind, } from "./workflow-ui.js";
|
|
33
35
|
export type { Worktree } from "./worktree.js";
|
|
34
36
|
export { createWorktree, removeWorktree } from "./worktree.js";
|
package/dist/index.js
CHANGED
|
@@ -11,10 +11,12 @@ export { buildModelRoutingInstructions, parseModelRoutingFromMeta, resolveModelF
|
|
|
11
11
|
export { createRunPersistence, generateRunId } from "./run-persistence.js";
|
|
12
12
|
export { parseCommandArgs, registerAllSavedWorkflows, registerSavedWorkflow, } from "./saved-commands.js";
|
|
13
13
|
export { createStructuredOutputTool } from "./structured-output.js";
|
|
14
|
+
export { installResultDelivery, installTaskPanel } from "./task-panel.js";
|
|
14
15
|
export { createWebFetchTool, createWebSearchTool, createWebTools } from "./web-tools.js";
|
|
15
16
|
export { parseWorkflowScript, runWorkflow } from "./workflow.js";
|
|
16
17
|
export { registerWorkflowCommands } from "./workflow-commands.js";
|
|
17
18
|
export { WorkflowManager } from "./workflow-manager.js";
|
|
18
19
|
export { createWorkflowStorage } from "./workflow-saved.js";
|
|
19
20
|
export { createWorkflowTool } from "./workflow-tool.js";
|
|
21
|
+
export { keyToAction, NavigatorModel, NavigatorState, openWorkflowNavigator, renderNavigator, } from "./workflow-ui.js";
|
|
20
22
|
export { createWorktree, removeWorktree } from "./worktree.js";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background-run UX, mirroring Claude Code:
|
|
3
|
+
* - A live task panel below the input lists in-progress runs while you keep working.
|
|
4
|
+
* Focus it (↓) and press enter to open the full navigator.
|
|
5
|
+
* - When a background run finishes, its result is delivered back into the
|
|
6
|
+
* conversation so the paused task continues with the outcome.
|
|
7
|
+
*/
|
|
8
|
+
import type { ExtensionAPI, ExtensionUIContext } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import type { WorkflowManager } from "./workflow-manager.js";
|
|
10
|
+
import type { WorkflowStorage } from "./workflow-saved.js";
|
|
11
|
+
export interface TaskPanelOptions {
|
|
12
|
+
storage?: WorkflowStorage;
|
|
13
|
+
cwd?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Deliver a background run's result into the conversation when it completes or
|
|
17
|
+
* fails. Set up once per extension; idempotent via an internal guard.
|
|
18
|
+
*/
|
|
19
|
+
export declare function installResultDelivery(pi: ExtensionAPI, manager: WorkflowManager): void;
|
|
20
|
+
/**
|
|
21
|
+
* Install the live "workflows running" panel below the editor. Re-rendered on
|
|
22
|
+
* every manager event; focus + enter opens the navigator.
|
|
23
|
+
*/
|
|
24
|
+
export declare function installTaskPanel(pi: ExtensionAPI, manager: WorkflowManager, ui: ExtensionUIContext, opts?: TaskPanelOptions): void;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background-run UX, mirroring Claude Code:
|
|
3
|
+
* - A live task panel below the input lists in-progress runs while you keep working.
|
|
4
|
+
* Focus it (↓) and press enter to open the full navigator.
|
|
5
|
+
* - When a background run finishes, its result is delivered back into the
|
|
6
|
+
* conversation so the paused task continues with the outcome.
|
|
7
|
+
*/
|
|
8
|
+
import { parseKey } from "@earendil-works/pi-tui";
|
|
9
|
+
import { openWorkflowNavigator } from "./workflow-ui.js";
|
|
10
|
+
const RUN_EVENTS = ["agentStart", "agentEnd", "phase", "log", "complete", "error", "stopped", "paused", "resumed"];
|
|
11
|
+
function deliverText(run) {
|
|
12
|
+
const r = run.result?.result;
|
|
13
|
+
const body = r && typeof r.report === "string" && r.report.trim() ? r.report : JSON.stringify(run.result?.result, null, 2);
|
|
14
|
+
const tokens = run.result?.tokenUsage ? ` · ${run.result.tokenUsage.total.toLocaleString()} tokens` : "";
|
|
15
|
+
const agents = run.result?.agentCount ?? run.snapshot.agentCount;
|
|
16
|
+
return `✓ Workflow "${run.snapshot.name}" finished (${agents} agents${tokens}).\n\n${body}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Deliver a background run's result into the conversation when it completes or
|
|
20
|
+
* fails. Set up once per extension; idempotent via an internal guard.
|
|
21
|
+
*/
|
|
22
|
+
export function installResultDelivery(pi, manager) {
|
|
23
|
+
if (manager.__deliveryInstalled)
|
|
24
|
+
return;
|
|
25
|
+
manager.__deliveryInstalled = true;
|
|
26
|
+
manager.on("complete", ({ runId }) => {
|
|
27
|
+
const run = manager.getRun(runId);
|
|
28
|
+
if (run)
|
|
29
|
+
void pi.sendMessage({ customType: "workflow-result", content: deliverText(run), display: true });
|
|
30
|
+
});
|
|
31
|
+
manager.on("error", ({ runId, error }) => {
|
|
32
|
+
void pi.sendMessage({
|
|
33
|
+
customType: "workflow-result",
|
|
34
|
+
content: `✗ Workflow ${runId} failed: ${error?.message ?? "unknown error"}`,
|
|
35
|
+
display: true,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function renderPanel(manager, theme, focused) {
|
|
40
|
+
const active = manager.listRuns().filter((r) => r.status === "running" || r.status === "paused");
|
|
41
|
+
if (!active.length)
|
|
42
|
+
return [];
|
|
43
|
+
const rows = active.map((r) => {
|
|
44
|
+
const live = manager.getRun(r.runId);
|
|
45
|
+
const agents = live?.snapshot.agents ?? r.agents;
|
|
46
|
+
const done = agents.filter((a) => a.status === "done").length;
|
|
47
|
+
const icon = r.status === "paused" ? "⏸" : "◆";
|
|
48
|
+
const phase = live?.snapshot.currentPhase ? ` · ${live.snapshot.currentPhase}` : "";
|
|
49
|
+
return ` ${icon} ${r.workflowName} ${done}/${agents.length} agents${phase}`;
|
|
50
|
+
});
|
|
51
|
+
const hint = focused
|
|
52
|
+
? theme.fg("accent", " enter: open · esc: back")
|
|
53
|
+
: theme.fg("dim", " ↓ then enter, or /workflows, to open");
|
|
54
|
+
return [theme.bold(`Workflows running (${active.length}):`), ...rows, hint];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Install the live "workflows running" panel below the editor. Re-rendered on
|
|
58
|
+
* every manager event; focus + enter opens the navigator.
|
|
59
|
+
*/
|
|
60
|
+
export function installTaskPanel(pi, manager, ui, opts = {}) {
|
|
61
|
+
ui.setWidget("workflow-tasks", (tui, theme) => {
|
|
62
|
+
const onEvent = () => tui.requestRender();
|
|
63
|
+
for (const ev of RUN_EVENTS)
|
|
64
|
+
manager.on(ev, onEvent);
|
|
65
|
+
const comp = {
|
|
66
|
+
focused: false,
|
|
67
|
+
render: () => renderPanel(manager, theme, comp.focused ?? false),
|
|
68
|
+
handleInput: (data) => {
|
|
69
|
+
const key = parseKey(data);
|
|
70
|
+
if (key === "enter" || key === "return" || key === "right") {
|
|
71
|
+
void openWorkflowNavigator(pi, manager, ui, opts);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
invalidate: () => { },
|
|
75
|
+
dispose: () => {
|
|
76
|
+
for (const ev of RUN_EVENTS)
|
|
77
|
+
manager.off(ev, onEvent);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
return comp;
|
|
81
|
+
}, { placement: "belowEditor" });
|
|
82
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { recomputeWorkflowSnapshot, renderWorkflowText } from "./display.js";
|
|
6
6
|
import { registerSavedWorkflow } from "./saved-commands.js";
|
|
7
|
+
import { openWorkflowNavigator } from "./workflow-ui.js";
|
|
7
8
|
const STATUS_ICON = {
|
|
8
9
|
pending: "·",
|
|
9
10
|
running: "◆",
|
|
@@ -110,7 +111,18 @@ export function registerWorkflowCommands(pi, manager, opts = {}) {
|
|
|
110
111
|
const id = parts[1];
|
|
111
112
|
const print = (text) => pi.sendMessage({ customType: "workflows", content: text, display: true });
|
|
112
113
|
switch (sub) {
|
|
114
|
+
case "ui":
|
|
113
115
|
case "list": {
|
|
116
|
+
// Interactive navigator when a UI is available; plain text otherwise
|
|
117
|
+
// (print/RPC mode) or when the user explicitly asks for `list`.
|
|
118
|
+
if (sub !== "list" && ctx.hasUI) {
|
|
119
|
+
await openWorkflowNavigator(pi, manager, ctx.ui, { storage: opts.storage, cwd: opts.cwd });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (parts.length === 0 && ctx.hasUI) {
|
|
123
|
+
await openWorkflowNavigator(pi, manager, ctx.ui, { storage: opts.storage, cwd: opts.cwd });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
114
126
|
const runs = manager.listRuns();
|
|
115
127
|
if (!runs.length) {
|
|
116
128
|
await print("No workflow runs yet. Start one with a background workflow (background: true).");
|
|
@@ -23,12 +23,15 @@ export interface ManagedRun {
|
|
|
23
23
|
export interface WorkflowManagerOptions {
|
|
24
24
|
cwd?: string;
|
|
25
25
|
concurrency?: number;
|
|
26
|
+
/** Resolve a saved-workflow name to its script, enabling nested `workflow('name')`. */
|
|
27
|
+
loadSavedWorkflow?: (name: string) => string | undefined;
|
|
26
28
|
}
|
|
27
29
|
export declare class WorkflowManager extends EventEmitter {
|
|
28
30
|
private runs;
|
|
29
31
|
private persistence;
|
|
30
32
|
private cwd;
|
|
31
33
|
private concurrency;
|
|
34
|
+
private loadSavedWorkflow?;
|
|
32
35
|
constructor(options?: WorkflowManagerOptions);
|
|
33
36
|
/**
|
|
34
37
|
* Start a workflow in the background.
|
package/dist/workflow-manager.js
CHANGED
|
@@ -10,10 +10,12 @@ export class WorkflowManager extends EventEmitter {
|
|
|
10
10
|
persistence;
|
|
11
11
|
cwd;
|
|
12
12
|
concurrency;
|
|
13
|
+
loadSavedWorkflow;
|
|
13
14
|
constructor(options = {}) {
|
|
14
15
|
super();
|
|
15
16
|
this.cwd = options.cwd ?? process.cwd();
|
|
16
17
|
this.concurrency = options.concurrency ?? 8;
|
|
18
|
+
this.loadSavedWorkflow = options.loadSavedWorkflow;
|
|
17
19
|
this.persistence = createRunPersistence(this.cwd);
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
@@ -99,6 +101,7 @@ export class WorkflowManager extends EventEmitter {
|
|
|
99
101
|
args,
|
|
100
102
|
signal: managed.controller.signal,
|
|
101
103
|
concurrency: this.concurrency,
|
|
104
|
+
loadSavedWorkflow: this.loadSavedWorkflow,
|
|
102
105
|
resumeJournal,
|
|
103
106
|
resumeFromRunId: resumeJournal ? managed.runId : undefined,
|
|
104
107
|
onAgentJournal: (entry) => {
|
package/dist/workflow-tool.js
CHANGED
|
@@ -27,8 +27,9 @@ const workflowToolSchema = Type.Object({
|
|
|
27
27
|
})),
|
|
28
28
|
});
|
|
29
29
|
export function createWorkflowTool(options = {}) {
|
|
30
|
+
const storage = options.storage ?? createWorkflowStorage(options.cwd ?? process.cwd());
|
|
30
31
|
const manager = options.manager ?? new WorkflowManager({ cwd: options.cwd, concurrency: options.concurrency });
|
|
31
|
-
const
|
|
32
|
+
const loadSavedWorkflow = (name) => storage.load(name)?.script;
|
|
32
33
|
return defineTool({
|
|
33
34
|
name: "workflow",
|
|
34
35
|
label: "Workflow",
|
|
@@ -52,6 +53,7 @@ export function createWorkflowTool(options = {}) {
|
|
|
52
53
|
"For workflow, if agent() needs machine-readable output, pass a plain JSON Schema via opts.schema; agent() will return the validated object. Use JSON Schema syntax, not TypeScript or TypeBox constructors.",
|
|
53
54
|
"For workflow, do not assume the parent assistant has repository code context inside subagents; include enough task context and relevant paths in each agent prompt.",
|
|
54
55
|
"For workflow, set background: true to run asynchronously. The workflow will return immediately with a run ID that can be used to check status later.",
|
|
56
|
+
"For workflow, you may call `await workflow('saved-name', argsObject)` to run a saved workflow inline and use its result; nesting is one level deep only, and the global 16-concurrent / 1000-total caps hold across the nesting.",
|
|
55
57
|
],
|
|
56
58
|
parameters: workflowToolSchema,
|
|
57
59
|
prepareArguments(args) {
|
|
@@ -100,6 +102,7 @@ export function createWorkflowTool(options = {}) {
|
|
|
100
102
|
concurrency: options.concurrency,
|
|
101
103
|
maxAgents: params.maxAgents,
|
|
102
104
|
agentTimeoutMs: params.agentTimeoutMs,
|
|
105
|
+
loadSavedWorkflow,
|
|
103
106
|
onLog(message) {
|
|
104
107
|
snapshot.logs.push(message);
|
|
105
108
|
update();
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive `/workflows` navigator, modeled on Claude Code's view:
|
|
3
|
+
*
|
|
4
|
+
* runs ──enter──▶ phases ──enter──▶ agents ──enter──▶ agent detail
|
|
5
|
+
* ◀──esc─── ◀──esc──── ◀──esc────
|
|
6
|
+
*
|
|
7
|
+
* Keys: ↑/↓ (or j/k) select · enter/→ drill in · esc/← back (esc at top closes)
|
|
8
|
+
* p pause/resume · x stop · r restart · s save · q quit
|
|
9
|
+
*
|
|
10
|
+
* The state machine and line rendering are pure and unit-tested; the pi-tui
|
|
11
|
+
* Component shell (openWorkflowNavigator) wires them to live manager events.
|
|
12
|
+
*/
|
|
13
|
+
import type { ExtensionAPI, ExtensionUIContext } from "@earendil-works/pi-coding-agent";
|
|
14
|
+
import type { WorkflowAgentSnapshot } from "./display.js";
|
|
15
|
+
import type { WorkflowManager } from "./workflow-manager.js";
|
|
16
|
+
import type { WorkflowStorage } from "./workflow-saved.js";
|
|
17
|
+
/** Minimal theme surface so rendering is testable without the real Theme class. */
|
|
18
|
+
export interface ThemeLike {
|
|
19
|
+
fg(color: string, text: string): string;
|
|
20
|
+
bold(text: string): string;
|
|
21
|
+
}
|
|
22
|
+
export type ViewKind = "runs" | "phases" | "agents" | "detail";
|
|
23
|
+
interface RunRow {
|
|
24
|
+
runId: string;
|
|
25
|
+
name: string;
|
|
26
|
+
status: string;
|
|
27
|
+
done: number;
|
|
28
|
+
total: number;
|
|
29
|
+
tokens: number;
|
|
30
|
+
}
|
|
31
|
+
interface PhaseRow {
|
|
32
|
+
title: string;
|
|
33
|
+
done: number;
|
|
34
|
+
total: number;
|
|
35
|
+
tokens: number;
|
|
36
|
+
}
|
|
37
|
+
interface AgentRow {
|
|
38
|
+
id: number;
|
|
39
|
+
label: string;
|
|
40
|
+
status: string;
|
|
41
|
+
phase?: string;
|
|
42
|
+
tokens?: number;
|
|
43
|
+
}
|
|
44
|
+
/** Reads run/phase/agent data from the manager, preferring live snapshots. */
|
|
45
|
+
export declare class NavigatorModel {
|
|
46
|
+
private readonly manager;
|
|
47
|
+
constructor(manager: Pick<WorkflowManager, "listRuns" | "getRun">);
|
|
48
|
+
private snapshot;
|
|
49
|
+
runs(): RunRow[];
|
|
50
|
+
runName(runId: string): string;
|
|
51
|
+
runStatus(runId: string): string;
|
|
52
|
+
phases(runId: string): PhaseRow[];
|
|
53
|
+
agents(runId: string, phase: string): AgentRow[];
|
|
54
|
+
agentDetail(runId: string, agentId: number): WorkflowAgentSnapshot | undefined;
|
|
55
|
+
}
|
|
56
|
+
/** Navigation state machine: a stack of (view, cursor) frames plus detail scroll. */
|
|
57
|
+
export declare class NavigatorState {
|
|
58
|
+
private stack;
|
|
59
|
+
scroll: number;
|
|
60
|
+
private top;
|
|
61
|
+
get kind(): ViewKind;
|
|
62
|
+
get cursor(): number;
|
|
63
|
+
get runId(): string | undefined;
|
|
64
|
+
get phase(): string | undefined;
|
|
65
|
+
get agentId(): number | undefined;
|
|
66
|
+
get depth(): number;
|
|
67
|
+
/** Clamp the cursor to [0, count). */
|
|
68
|
+
clamp(count: number): void;
|
|
69
|
+
move(delta: number, count: number): void;
|
|
70
|
+
/** Drill into the selected item. Returns true if the view changed. */
|
|
71
|
+
drill(model: NavigatorModel): boolean;
|
|
72
|
+
/** Pop one level. Returns false when already at the top (caller should close). */
|
|
73
|
+
back(): boolean;
|
|
74
|
+
/** The runId the current view acts on (for pause/stop/save). */
|
|
75
|
+
activeRunId(model: NavigatorModel): string | undefined;
|
|
76
|
+
}
|
|
77
|
+
/** Build the lines for the current view. Pure: depends only on state + model + theme. */
|
|
78
|
+
export declare function renderNavigator(state: NavigatorState, model: NavigatorModel, width: number, theme?: ThemeLike): string[];
|
|
79
|
+
/** What a key press should do. Pure mapping from a parsed key id to an action. */
|
|
80
|
+
export type NavAction = {
|
|
81
|
+
type: "move";
|
|
82
|
+
delta: number;
|
|
83
|
+
} | {
|
|
84
|
+
type: "drill";
|
|
85
|
+
} | {
|
|
86
|
+
type: "back";
|
|
87
|
+
} | {
|
|
88
|
+
type: "close";
|
|
89
|
+
} | {
|
|
90
|
+
type: "pause";
|
|
91
|
+
} | {
|
|
92
|
+
type: "stop";
|
|
93
|
+
} | {
|
|
94
|
+
type: "restart";
|
|
95
|
+
} | {
|
|
96
|
+
type: "save";
|
|
97
|
+
} | {
|
|
98
|
+
type: "none";
|
|
99
|
+
};
|
|
100
|
+
export declare function keyToAction(keyId: string | undefined, kind: ViewKind): NavAction;
|
|
101
|
+
export interface NavigatorOptions {
|
|
102
|
+
storage?: WorkflowStorage;
|
|
103
|
+
cwd?: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Open the interactive `/workflows` navigator as a focused overlay. Resolves when
|
|
107
|
+
* the user closes it (esc at the top level, or `q`).
|
|
108
|
+
*/
|
|
109
|
+
export declare function openWorkflowNavigator(pi: ExtensionAPI, manager: WorkflowManager, ui: ExtensionUIContext, opts?: NavigatorOptions): Promise<void>;
|
|
110
|
+
export {};
|