@ai-setting/roy-plugin-task-show 0.8.4 → 0.8.7

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.
@@ -0,0 +1,193 @@
1
+ /**
2
+ * @fileoverview TaskSessionStore — process-scoped registry of tasks
3
+ * observed through the `task:after.create` hook.
4
+ *
5
+ * v0.8.7 introduced this store so the home page can render an
6
+ * *ancestor chain* (the latest "leaf" task plus the chain of
7
+ * `parent_task_id` links up to the root) instead of the full
8
+ * cross-host task tree. Tracking only this-process tasks also keeps
9
+ * the home page quiet until the plugin actually does work, which
10
+ * makes the visualization a more accurate reflection of what the
11
+ * agent is doing right now.
12
+ *
13
+ * Design notes:
14
+ * - Pure in-memory; no I/O, no globals. The plugin owns a single
15
+ * instance and disposes it via {@link TaskSessionStore.clear} when
16
+ * the plugin is torn down.
17
+ * - The fetcher for parent tasks is **injected** so tests can mock
18
+ * the CLI call without spawning a real subprocess.
19
+ * - The store is tolerant: a broken parent link, a cycle, or a
20
+ * missing fetcher all degrade gracefully (the chain stops at the
21
+ * first unverifiable link rather than throwing).
22
+ * - `buildAncestorChain` always returns tasks in **root-first** order
23
+ * (`[root, …, leaf]`) so the UI can render the chain linearly
24
+ * from top to bottom without having to reverse it.
25
+ */
26
+ import { execFile } from "node:child_process";
27
+ import { promisify } from "node:util";
28
+ const execFileAsync = promisify(execFile);
29
+ // ---------------------------------------------------------------------------
30
+ // Store
31
+ // ---------------------------------------------------------------------------
32
+ /**
33
+ * Process-scoped registry of tasks observed via the
34
+ * `task:after.create` hook.
35
+ */
36
+ export class TaskSessionStore {
37
+ /** In-memory metadata, keyed by task id. */
38
+ tasks = new Map();
39
+ /** Insertion order (Map preserves it). We keep a snapshot for tests. */
40
+ insertionOrder = [];
41
+ /**
42
+ * Record a task. Re-recording an existing id overwrites the cached
43
+ * metadata (this is the contract: the latest hook payload wins).
44
+ */
45
+ record(task) {
46
+ if (!Number.isFinite(task.id) || task.id <= 0)
47
+ return;
48
+ const isNew = !this.tasks.has(task.id);
49
+ this.tasks.set(task.id, { ...task });
50
+ if (isNew)
51
+ this.insertionOrder.push(task.id);
52
+ }
53
+ /** Return the most recently recorded task id, or `null` if empty. */
54
+ getLatestLeafId() {
55
+ if (this.insertionOrder.length === 0)
56
+ return null;
57
+ return this.insertionOrder[this.insertionOrder.length - 1] ?? null;
58
+ }
59
+ /** Return the cached metadata for `id`, or `null` if unknown. */
60
+ getRecordedTask(id) {
61
+ return this.tasks.get(id) ?? null;
62
+ }
63
+ /** Return the recorded task ids in insertion order. */
64
+ getRecordedTaskIds() {
65
+ return [...this.insertionOrder];
66
+ }
67
+ /** Drop everything. Used by tests + on plugin disposal. */
68
+ clear() {
69
+ this.tasks.clear();
70
+ this.insertionOrder.length = 0;
71
+ }
72
+ /**
73
+ * Walk `parent_task_id` from `leafId` up to the root, using
74
+ * `fetcher` to resolve any ancestors not already in the in-memory
75
+ * cache. Returns the chain in **root-first** order
76
+ * (`[root, …, leaf]`).
77
+ *
78
+ * Guarantees:
79
+ * - Always returns at least the leaf task if the leaf is known
80
+ * (from cache or via fetcher).
81
+ * - Cycle-safe: a task already in the chain stops the walk.
82
+ * - Depth-bounded by `options.maxDepth` (default 32).
83
+ * - Never throws: a broken parent link just ends the chain early.
84
+ */
85
+ async buildAncestorChain(leafId, fetcher, options = {}) {
86
+ if (!Number.isFinite(leafId) || leafId <= 0)
87
+ return [];
88
+ const maxDepth = Math.max(1, options.maxDepth ?? 32);
89
+ // Walk leaf → root, then reverse at the end. We collect into an
90
+ // array in walk order so cycles / missing ancestors are easy to
91
+ // detect.
92
+ const walked = [];
93
+ const seen = new Set();
94
+ let currentId = leafId;
95
+ for (let depth = 0; depth < maxDepth; depth++) {
96
+ if (seen.has(currentId))
97
+ break;
98
+ seen.add(currentId);
99
+ const cached = this.tasks.get(currentId);
100
+ const task = cached ?? await safeFetch(fetcher, currentId);
101
+ if (!task)
102
+ break;
103
+ walked.push(task);
104
+ const parentId = task.parent_task_id;
105
+ if (parentId === null || parentId === undefined)
106
+ break;
107
+ if (!Number.isFinite(parentId) || parentId <= 0)
108
+ break;
109
+ currentId = parentId;
110
+ }
111
+ return walked.reverse();
112
+ }
113
+ }
114
+ /**
115
+ * Run `fetcher(id)` and swallow any rejection. A failed fetch
116
+ * (network / parse / CLI error) should not crash the chain walk —
117
+ * we just stop at the last known task.
118
+ */
119
+ async function safeFetch(fetcher, id) {
120
+ try {
121
+ return await fetcher(id);
122
+ }
123
+ catch {
124
+ return null;
125
+ }
126
+ }
127
+ // ---------------------------------------------------------------------------
128
+ // Default CLI-backed fetcher
129
+ // ---------------------------------------------------------------------------
130
+ /**
131
+ * Build a {@link TaskMetaFetcher} that shells out to the host's
132
+ * `roy-agent` CLI. Intended for production use; tests should pass a
133
+ * stub.
134
+ *
135
+ * args: [cliPath, "tasks", "get", "<id>", "--json"]
136
+ * stdout: { task: { id, title, status, priority, type,
137
+ * parent_task_id, createdAt, updatedAt, tags,
138
+ * project_path }, ... }
139
+ *
140
+ * The returned fetcher:
141
+ * - Spawns the CLI as a discrete arg array (no shell string).
142
+ * - Enforces a 5-second wall-clock timeout.
143
+ * - Locates the first `{` in stdout (the CLI prints INFO lines
144
+ * before the JSON envelope).
145
+ * - Returns `null` on any failure (non-zero exit, timeout, parse
146
+ * error, schema mismatch).
147
+ */
148
+ export function makeCliTaskMetaFetcher(cliPath) {
149
+ return async (id) => {
150
+ if (!Number.isInteger(id) || id <= 0)
151
+ return null;
152
+ const args = [cliPath, "tasks", "get", String(id), "--json"];
153
+ let stdout = "";
154
+ try {
155
+ const result = await execFileAsync(cliPath, args.slice(1), {
156
+ timeout: 5000,
157
+ maxBuffer: 4 * 1024 * 1024,
158
+ windowsHide: true,
159
+ });
160
+ stdout = result.stdout ?? "";
161
+ }
162
+ catch {
163
+ return null;
164
+ }
165
+ const jsonStart = stdout.indexOf("{");
166
+ if (jsonStart < 0)
167
+ return null;
168
+ const envelopeText = stdout.slice(jsonStart);
169
+ let envelope;
170
+ try {
171
+ envelope = JSON.parse(envelopeText);
172
+ }
173
+ catch {
174
+ return null;
175
+ }
176
+ const t = envelope?.task;
177
+ if (!t || typeof t.id !== "number")
178
+ return null;
179
+ return {
180
+ id: t.id,
181
+ title: typeof t.title === "string" ? t.title : "",
182
+ status: typeof t.status === "string" ? t.status : undefined,
183
+ priority: typeof t.priority === "string" ? t.priority : undefined,
184
+ type: typeof t.type === "string" ? t.type : undefined,
185
+ parent_task_id: typeof t.parent_task_id === "number" ? t.parent_task_id : null,
186
+ createdAt: typeof t.createdAt === "string" ? t.createdAt : undefined,
187
+ updatedAt: typeof t.updatedAt === "string" ? t.updatedAt : undefined,
188
+ tags: Array.isArray(t.tags) ? t.tags.filter((x) => typeof x === "string") : undefined,
189
+ projectPath: typeof t.project_path === "string" ? t.project_path : undefined,
190
+ };
191
+ };
192
+ }
193
+ //# sourceMappingURL=task-session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-session-store.js","sourceRoot":"","sources":["../src/task-session-store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-setting/roy-plugin-task-show",
3
- "version": "0.8.4",
3
+ "version": "0.8.7",
4
4
  "description": "roy-agent plugin: visualize task solving process via tool call flow on a local web service",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/plugin.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@ai-setting/roy-plugin-task-show",
3
- "version": "0.8.4",
3
+ "version": "0.8.7",
4
4
  "type": "tool-plugin",
5
- "description": "Visualize the tool call chain of a task on a local web service with real-time SSE updates. v0.5.0+: page refreshes stream over GET /api/events (Server-Sent Events). Subscribes to tool:before.execute, tool:after.execute, task:before.create, task:after.create, task:after.complete (preferred, 2026-07-10+), and task:after.update (legacy fallback). v0.6.11: Mermaid re-rendering is delegated to a self-contained controller (public/mermaid-renderer.js) that prevents the SVG→raw-source regression on async updates and surfaces recoverable .mermaid-error states. v0.6.12: Task lifecycle pipeline (operations timeline) server now emits data-task-id on the pipeline section; client preserves it on swap, so the page actually fetches /api/tasks/<id>/operations and renders the 7-op timeline (previously silently bailed). v0.7.0: Home page redesigned as a hierarchical task tree (driven by `roy-agent tasks tree --json`); new /api/tasks/tree endpoint with status / priority / type / root-id filters, expand/collapse UI, search, and live 30s polling. v0.8.0: per-task page Mermaid area now renders the hierarchical 'Task lifecycle + tools' view — each operation record owns a subgraph that nests its tool calls, with click callbacks (`window.__toolClick`) that scroll-into-view + highlight + auto-expand the matching row in the tool-call table below. Operation record descriptions (`description` + `processDescription`) are now always rendered inline (no `<details>` collapse) so the user sees the lifecycle state at a glance; a fallback `<details>` kicks in only for descriptions longer than 600 chars. v0.8.1: hotfix for two pre-existing bugs in v0.8.0 (browser smoke test surfaced after merge). (a) Mermaid click directives were emitted as `click t1 __toolClick(1)` (missing `call` keyword) — Mermaid 10's parser rejects this with `got 'PS'`. Fixed to `click t1 call __toolClick(1)` (the v10 grammar requires `call` to invoke a callback with arguments). (b) `buildMermaidSource` lived inside the `attachTaskPageTimeline` IIFE but was also called from a listener in the `attachToolClickBridge` IIFE — sibling IIFEs cannot see each other's locals, so the listener threw `ReferenceError: buildMermaidSource is not defined` and the Mermaid diagram silently failed to re-render after `task-show:lifecycle-ops-loaded`. Fixed by hoisting the function (and its three helpers) to script top-level so both IIFEs can see it via the script-wide closure; the function is also exposed on `window.buildMermaidSource` for tests + tooling. v0.8.3: tree-display fix (Task #2426). The home page used to look like a flat list of root tasks because `autoExpandFirstLevels(..., 2)` only opened the first 2 levels — 30/47 roots were leaf nodes and the remaining 17 collapsed to one level so grandchildren were never visible. Default expand depth is now 3 (root + child + grandchild + great-grandchild are visible on first paint), the summary line now shows per-depth count pills (root / child / grandchild / great-grandchild / level-N), each `tree-row` carries a `data-depth` attribute so CSS can paint coloured left rails per level, and the duplicated 'Live tool-call sessions (legacy view)' panel that made the page look like both a flat table AND a tree is now hidden behind `#legacy-sessions[hidden]` (kept for future debug-toggle restoration).",
5
+ "description": "Visualize the tool call chain of a task on a local web service with real-time SSE updates. v0.5.0+: page refreshes stream over GET /api/events (Server-Sent Events). Subscribes to tool:before.execute, tool:after.execute, task:before.create, task:after.create, task:after.complete (preferred, 2026-07-10+), and task:after.update (legacy fallback). v0.6.11: Mermaid re-rendering is delegated to a self-contained controller (public/mermaid-renderer.js) that prevents the SVG→raw-source regression on async updates and surfaces recoverable .mermaid-error states. v0.6.12: Task lifecycle pipeline (operations timeline) server now emits data-task-id on the pipeline section; client preserves it on swap, so the page actually fetches /api/tasks/<id>/operations and renders the 7-op timeline (previously silently bailed). v0.7.0: Home page redesigned as a hierarchical task tree (driven by `roy-agent tasks tree --json`); new /api/tasks/tree endpoint with status / priority / type / root-id filters, expand/collapse UI, search, and live 30s polling. v0.8.0: per-task page Mermaid area now renders the hierarchical 'Task lifecycle + tools' view — each operation record owns a subgraph that nests its tool calls, with click callbacks (`window.__toolClick`) that scroll-into-view + highlight + auto-expand the matching row in the tool-call table below. Operation record descriptions (`description` + `processDescription`) are now always rendered inline (no `<details>` collapse) so the user sees the lifecycle state at a glance; a fallback `<details>` kicks in only for descriptions longer than 600 chars. v0.8.1: hotfix for two pre-existing bugs in v0.8.0 (browser smoke test surfaced after merge). (a) Mermaid click directives were emitted as `click t1 __toolClick(1)` (missing `call` keyword) — Mermaid 10's parser rejects this with `got 'PS'`. Fixed to `click t1 call __toolClick(1)` (the v10 grammar requires `call` to invoke a callback with arguments). (b) `buildMermaidSource` lived inside the `attachTaskPageTimeline` IIFE but was also called from a listener in the `attachToolClickBridge` IIFE — sibling IIFEs cannot see each other's locals, so the listener threw `ReferenceError: buildMermaidSource is not defined` and the Mermaid diagram silently failed to re-render after `task-show:lifecycle-ops-loaded`. Fixed by hoisting the function (and its three helpers) to script top-level so both IIFEs can see it via the script-wide closure; the function is also exposed on `window.buildMermaidSource` for tests + tooling. v0.8.3: tree-display fix (Task #2426). The home page used to look like a flat list of root tasks because `autoExpandFirstLevels(..., 2)` only opened the first 2 levels — 30/47 roots were leaf nodes and the remaining 17 collapsed to one level so grandchildren were never visible. Default expand depth is now 3 (root + child + grandchild + great-grandchild are visible on first paint), the summary line now shows per-depth count pills (root / child / grandchild / great-grandchild / level-N), each `tree-row` carries a `data-depth` attribute so CSS can paint coloured left rails per level, and the duplicated 'Live tool-call sessions (legacy view)' panel that made the page look like both a flat table AND a tree is now hidden behind `#legacy-sessions[hidden]` (kept for future debug-toggle restoration). v0.8.4: cli-eacces-compat hotfix (Task #2499). The CLI bundle `packages/cli/dist/bin/roy-agent.js` ships with `-rw-rw-r--` (no execute bit); the plugin now invokes `roy-agent` via `node <path>` from the resolved CLI path so EACCES is avoided even when the script lacks the executable bit. Resolution order: explicit `cfg.royAgentCliPath` override → `$ROY_AGENT_CLI` env → sibling-repo .js → monorepo .js → bare `roy-agent` (PATH). v0.8.5: CLI resolution priority fix. v0.8.4's resolution order preferred sibling-repo / monorepo `.js` files over the globally-installed `roy-agent` binary, which meant stale scripts in a sibling checkout could shadow a freshly-updated global install. v0.8.5 flips the order: explicit override → `$ROY_AGENT_CLI` env → **`roy-agent` on PATH** (looked up via `which`/`where`) → sibling-repo .js (dev) → monorepo .js (dev) → literal `roy-agent`. The lookup is exported as a free function `resolveRoyAgentCliPath()` (plus a `findRoyAgentOnPath()` helper) so the new priority order can be unit-tested in isolation. v0.8.7: home page redesigned around a process-scoped ancestor chain. The plugin now records every `task:after.create` payload into a `TaskSessionStore`, exposes it via a new `/api/tasks/ancestor-chain?leafId=N` endpoint, and renders the home page in a fixed top-to-bottom order: (1) ancestor chain — root → leaf, each link tagged with its parent_task_id and status, (2) Task lifecycle + tools — Mermaid diagram of the leaf's tool calls, (3) Task lifecycle pipeline — operations timeline placeholder, (4) a help/legend section that intentionally follows the pipeline so the pipeline is never the trailing element. When no leaf has been recorded yet, the home page falls back to the v0.8.x cross-host tasks tree so the page is never blank.",
6
6
  "main": "dist/index.js",
7
7
  "hooks": [
8
8
  {