@ai-setting/roy-plugin-task-show 0.8.10 → 0.9.6
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/dist/cli-tasks-adapter.d.ts +5 -0
- package/dist/cli-tasks-adapter.d.ts.map +1 -1
- package/dist/cli-tasks-adapter.js +9 -0
- package/dist/cli-tasks-adapter.js.map +1 -1
- package/dist/cli-tasks-tree-adapter.d.ts +5 -0
- package/dist/cli-tasks-tree-adapter.d.ts.map +1 -1
- package/dist/cli-tasks-tree-adapter.js +5 -0
- package/dist/cli-tasks-tree-adapter.js.map +1 -1
- package/dist/plugin.d.ts +8 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +99 -0
- package/dist/plugin.js.map +1 -1
- package/dist/server.d.ts +15 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +46 -10
- package/dist/server.js.map +1 -1
- package/dist/task-detail-mermaid.d.ts +9 -0
- package/dist/task-detail-mermaid.d.ts.map +1 -1
- package/dist/task-detail-mermaid.js +43 -3
- package/dist/task-detail-mermaid.js.map +1 -1
- package/dist/task-metadata.d.ts +21 -0
- package/dist/task-metadata.d.ts.map +1 -0
- package/dist/task-metadata.js +50 -0
- package/dist/task-metadata.js.map +1 -0
- package/dist/task-session-store.d.ts +70 -0
- package/dist/task-session-store.d.ts.map +1 -0
- package/dist/task-session-store.js +177 -0
- package/dist/task-session-store.js.map +1 -0
- package/dist/tracing/decorator.d.ts +48 -0
- package/dist/tracing/decorator.d.ts.map +1 -0
- package/dist/tracing/decorator.js +310 -0
- package/dist/tracing/decorator.js.map +1 -0
- package/package.json +1 -1
- package/plugin.json +2 -2
- package/public/app.js +45 -1
- package/public/index.html +3 -0
- package/public/session-forest.js +97 -0
- package/public/style.css +64 -0
- package/public/task-operations.js +7 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { TracedAs, withTraceSync } from "./tracing/decorator.js";
|
|
8
|
+
import { formatTaskMetadata } from "./task-metadata.js";
|
|
9
|
+
export class TaskSessionStore {
|
|
10
|
+
opts;
|
|
11
|
+
latestLeafId = null;
|
|
12
|
+
constructor(opts) {
|
|
13
|
+
this.opts = {
|
|
14
|
+
sessionStartedAt: opts.sessionStartedAt,
|
|
15
|
+
maxAncestors: opts.maxAncestors ?? 32,
|
|
16
|
+
listTasks: opts.listTasks,
|
|
17
|
+
taskFetcher: opts.taskFetcher ?? (async () => null),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Returns the id of the most recently recorded leaf task in this session,
|
|
22
|
+
* or undefined if no task has been recorded yet. The v0.9.0 home page
|
|
23
|
+
* highlights this task with a `data-leaf="1"` attribute.
|
|
24
|
+
*/
|
|
25
|
+
getLatestLeafId() {
|
|
26
|
+
return this.latestLeafId ?? undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Record a leaf task id (called by the host plugin as new tasks appear).
|
|
30
|
+
* Idempotent — only the most recent call wins.
|
|
31
|
+
*/
|
|
32
|
+
recordLeaf(taskId) {
|
|
33
|
+
this.latestLeafId = taskId;
|
|
34
|
+
}
|
|
35
|
+
async buildSessionForest() {
|
|
36
|
+
const cutoff = Date.parse(this.opts.sessionStartedAt);
|
|
37
|
+
const raw = await this.opts.listTasks({ sinceIso: this.opts.sessionStartedAt });
|
|
38
|
+
const tasks = raw.filter((t) => {
|
|
39
|
+
const ts = Date.parse(t.createdAt);
|
|
40
|
+
return Number.isFinite(ts) && ts >= cutoff;
|
|
41
|
+
});
|
|
42
|
+
const byId = new Map();
|
|
43
|
+
for (const t of tasks)
|
|
44
|
+
byId.set(t.id, t);
|
|
45
|
+
const children = new Map();
|
|
46
|
+
for (const t of tasks) {
|
|
47
|
+
if (t.parent_task_id === undefined || t.parent_task_id === null)
|
|
48
|
+
continue;
|
|
49
|
+
const arr = children.get(t.parent_task_id) ?? [];
|
|
50
|
+
arr.push(t);
|
|
51
|
+
children.set(t.parent_task_id, arr);
|
|
52
|
+
}
|
|
53
|
+
// v0.9.0: bounded BFS for external ancestors. For every in-session
|
|
54
|
+
// task whose parent is not in `byId`, BFS up the parent chain,
|
|
55
|
+
// fetching each ancestor through `taskFetcher` and inserting it
|
|
56
|
+
// (deduplicated) into `byId` and `children` until we run out of
|
|
57
|
+
// ancestors or hit `maxAncestors`.
|
|
58
|
+
const maxAncestors = this.opts.maxAncestors;
|
|
59
|
+
let fetchedAncestors = 0;
|
|
60
|
+
// FIFO queue of parent_ids we still need to look up.
|
|
61
|
+
const queue = [];
|
|
62
|
+
const queued = new Set();
|
|
63
|
+
for (const t of tasks) {
|
|
64
|
+
if (t.parent_task_id === undefined || t.parent_task_id === null)
|
|
65
|
+
continue;
|
|
66
|
+
if (byId.has(t.parent_task_id))
|
|
67
|
+
continue;
|
|
68
|
+
if (queued.has(t.parent_task_id))
|
|
69
|
+
continue;
|
|
70
|
+
queue.push(t.parent_task_id);
|
|
71
|
+
queued.add(t.parent_task_id);
|
|
72
|
+
}
|
|
73
|
+
while (queue.length > 0 && fetchedAncestors < maxAncestors) {
|
|
74
|
+
const id = queue.shift();
|
|
75
|
+
const fetched = await this.opts.taskFetcher(id);
|
|
76
|
+
if (!fetched)
|
|
77
|
+
continue;
|
|
78
|
+
byId.set(fetched.id, fetched);
|
|
79
|
+
fetchedAncestors += 1;
|
|
80
|
+
// Index as a child of its own parent (so the tree walks correctly).
|
|
81
|
+
if (fetched.parent_task_id !== undefined && fetched.parent_task_id !== null) {
|
|
82
|
+
const arr = children.get(fetched.parent_task_id) ?? [];
|
|
83
|
+
arr.push(fetched);
|
|
84
|
+
children.set(fetched.parent_task_id, arr);
|
|
85
|
+
if (!byId.has(fetched.parent_task_id) && !queued.has(fetched.parent_task_id) && fetchedAncestors + queue.length < maxAncestors) {
|
|
86
|
+
queue.push(fetched.parent_task_id);
|
|
87
|
+
queued.add(fetched.parent_task_id);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Assemble roots: any task (in-session or fetched) whose parent is
|
|
92
|
+
// not present in byId becomes a root.
|
|
93
|
+
const roots = [];
|
|
94
|
+
for (const t of byId.values()) {
|
|
95
|
+
if (t.parent_task_id === undefined || t.parent_task_id === null || !byId.has(t.parent_task_id)) {
|
|
96
|
+
roots.push(t);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const buildChildren = (parentId, depth = 0) => {
|
|
100
|
+
const arr = children.get(parentId) ?? [];
|
|
101
|
+
const out = [];
|
|
102
|
+
for (const t of arr) {
|
|
103
|
+
if (depth > maxAncestors + 4)
|
|
104
|
+
break; // hard ceiling for defensive recursion
|
|
105
|
+
out.push({ task: t, children: buildChildren(t.id, depth + 1) });
|
|
106
|
+
}
|
|
107
|
+
out.sort((a, b) => a.task.id - b.task.id);
|
|
108
|
+
return out;
|
|
109
|
+
};
|
|
110
|
+
return roots
|
|
111
|
+
.sort((a, b) => a.id - b.id)
|
|
112
|
+
.map((t) => ({ task: t, children: buildChildren(t.id, 0) }));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
__decorate([
|
|
116
|
+
TracedAs("session.forest.build", { recordParams: false, recordResult: false })
|
|
117
|
+
], TaskSessionStore.prototype, "buildSessionForest", null);
|
|
118
|
+
function esc(s) {
|
|
119
|
+
const str = s === undefined || s === null ? "" : String(s);
|
|
120
|
+
return str
|
|
121
|
+
.replace(/&/g, "&")
|
|
122
|
+
.replace(/</g, "<")
|
|
123
|
+
.replace(/>/g, ">")
|
|
124
|
+
.replace(/"/g, """)
|
|
125
|
+
.replace(/'/g, "'");
|
|
126
|
+
}
|
|
127
|
+
export function renderSessionForestPage(args) {
|
|
128
|
+
return withTraceSync("html.session-forest.render", () => _renderSessionForestPageImpl(args));
|
|
129
|
+
}
|
|
130
|
+
function _renderSessionForestPageImpl(args) {
|
|
131
|
+
const rows = [];
|
|
132
|
+
const walk = (node, depth) => {
|
|
133
|
+
const t = node.task;
|
|
134
|
+
const checked = t.id === args.leafTaskId ? ' data-leaf="1"' : "";
|
|
135
|
+
rows.push(`<li class="session-row" data-depth="${depth}"${checked}>
|
|
136
|
+
<a class="session-title" href="/task/${t.id}">#${t.id} ${esc(t.title)}</a>
|
|
137
|
+
<button type="button" class="session-toggle" data-toggle="${t.id}">显示全部栏位</button>
|
|
138
|
+
<details class="session-details" data-details="${t.id}">
|
|
139
|
+
<summary>metadata</summary>
|
|
140
|
+
<dl>
|
|
141
|
+
<dt>project_path</dt><dd>${esc(t.project_path)}</dd>
|
|
142
|
+
<dt>context</dt><dd><pre class="metadata-json">${esc(formatTaskMetadata(t.context))}</pre></dd>
|
|
143
|
+
<dt>description</dt><dd>${esc(t.description)}</dd>
|
|
144
|
+
<dt>goals</dt><dd><pre class="metadata-text">${esc(formatTaskMetadata(t.goals_and_expected_deliverables))}</pre></dd>
|
|
145
|
+
<dt>tags</dt><dd>${esc((t.tags ?? []).join(", "))}</dd>
|
|
146
|
+
<dt>createdAt</dt><dd>${esc(t.createdAt)}</dd>
|
|
147
|
+
<dt>updatedAt</dt><dd>${esc(t.updatedAt)}</dd>
|
|
148
|
+
</dl>
|
|
149
|
+
</details>
|
|
150
|
+
<ul class="session-operations" data-task-operations="${t.id}"></ul>
|
|
151
|
+
</li>`);
|
|
152
|
+
for (const child of node.children)
|
|
153
|
+
walk(child, depth + 1);
|
|
154
|
+
};
|
|
155
|
+
for (const node of args.forest)
|
|
156
|
+
walk(node, 0);
|
|
157
|
+
const forestHtml = `<section class="session-forest" data-session-forest="1"><h2>本会话任务</h2><ul>${rows.join("")}</ul></section>`;
|
|
158
|
+
return `<!DOCTYPE html>
|
|
159
|
+
<html lang="zh-CN">
|
|
160
|
+
<head>
|
|
161
|
+
<meta charset="utf-8">
|
|
162
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
163
|
+
<title>roy-plugin-task-show · session forest</title>
|
|
164
|
+
<link rel="stylesheet" href="/static/style.css">
|
|
165
|
+
</head>
|
|
166
|
+
<body data-live-refresh data-view="session-forest">
|
|
167
|
+
<header class="topbar">
|
|
168
|
+
<h1>🌳 roy-plugin-task-show · 本会话任务</h1>
|
|
169
|
+
<p class="meta">只显示插件加载后创建的任务及其必要祖先;展开每行可查看完整 metadata。</p>
|
|
170
|
+
</header>
|
|
171
|
+
${forestHtml}
|
|
172
|
+
<script src="/static/task-operations.js"></script>
|
|
173
|
+
<script src="/static/session-forest.js"></script>
|
|
174
|
+
</body>
|
|
175
|
+
</html>`;
|
|
176
|
+
}
|
|
177
|
+
//# 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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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface TracedAsOptions {
|
|
2
|
+
recordParams?: boolean;
|
|
3
|
+
recordResult?: boolean;
|
|
4
|
+
recordError?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* @TracedAs(name, options) decorator factory.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* @TracedAs("server.home.render", { recordParams: false, recordResult: false })
|
|
11
|
+
* private async sendIndex(res: http.ServerResponse): Promise<void> { ... }
|
|
12
|
+
*
|
|
13
|
+
* If the spans.db is unreachable (no host, no env, schema mismatch),
|
|
14
|
+
* the decorator becomes a transparent passthrough — the wrapped
|
|
15
|
+
* function is called with its original `this` and arguments.
|
|
16
|
+
*/
|
|
17
|
+
export declare function TracedAs(name: string, _options?: TracedAsOptions): <T extends (...args: any[]) => any>(_target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T>;
|
|
18
|
+
/**
|
|
19
|
+
* For tests: reset the module-level db cache so test fixtures
|
|
20
|
+
* can simulate a fresh host install. Not used in production.
|
|
21
|
+
*/
|
|
22
|
+
export declare function __resetTracedAsCacheForTests(): void;
|
|
23
|
+
/**
|
|
24
|
+
* For tests: returns the resolved spans.db path or null. Allows
|
|
25
|
+
* tests to assert the decorator located the host DB.
|
|
26
|
+
*/
|
|
27
|
+
export declare function __getResolvedSpansDbPathForTests(): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Ensure the parent dir of a candidate spans.db path exists
|
|
30
|
+
* (used by tests that point at a temp file). Best-effort.
|
|
31
|
+
*/
|
|
32
|
+
export declare function __ensureSpansDbDirForTests(path: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* `withTrace(name, fn)` — manual instrumentation helper for free
|
|
35
|
+
* functions (which TS decorators cannot decorate). Runs `fn` and
|
|
36
|
+
* records a span around the invocation. Mirrors the @TracedAs
|
|
37
|
+
* contract: never throws, no-ops when spans.db is unavailable.
|
|
38
|
+
*
|
|
39
|
+
* Used by `renderSessionForestPage` and `encodeMermaidLabelText`
|
|
40
|
+
* (top-level exports that cannot carry a class-method decorator).
|
|
41
|
+
*/
|
|
42
|
+
export declare function withTrace<T>(name: string, fn: () => Promise<T> | T): Promise<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Synchronous variant of `withTrace`. Used for top-level
|
|
45
|
+
* non-async exports.
|
|
46
|
+
*/
|
|
47
|
+
export declare function withTraceSync<T>(name: string, fn: () => T): T;
|
|
48
|
+
//# sourceMappingURL=decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorator.d.ts","sourceRoot":"","sources":["../../src/tracing/decorator.ts"],"names":[],"mappings":"AAqDA,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA8HD;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,eAAe,IAC9C,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAChD,SAAS,GAAG,EACZ,aAAa,MAAM,EACnB,YAAY,uBAAuB,CAAC,CAAC,CAAC,KACrC,uBAAuB,CAAC,CAAC,CAAC,CAyD9B;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAUnD;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,IAAI,MAAM,GAAG,IAAI,CAEhE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAM7D;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAgBZ;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAgB7D"}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview @TracedAs decorator stub for the roy-plugin-task-show v0.9.0.
|
|
3
|
+
*
|
|
4
|
+
* The plugin is a standalone npm package with `dependencies: {}`, so it
|
|
5
|
+
* cannot import the host's `roy-agent-core` tracing module statically.
|
|
6
|
+
* This module provides a minimal local `@TracedAs(name, options)`
|
|
7
|
+
* decorator that:
|
|
8
|
+
*
|
|
9
|
+
* 1. At module load, locates a writable `spans.db` (SQLite) using:
|
|
10
|
+
* a. `process.env.ROY_TRACE_DB` if set
|
|
11
|
+
* b. `~/.config/roy-agent/spans.db` (host default)
|
|
12
|
+
* If none of these resolve to a writable file, the decorator
|
|
13
|
+
* degrades to a no-op that just calls the wrapped function.
|
|
14
|
+
*
|
|
15
|
+
* 2. Wraps the target method so that every invocation writes a
|
|
16
|
+
* single row to the `spans` table mirroring the host's
|
|
17
|
+
* OpenTelemetry-compatible schema:
|
|
18
|
+
*
|
|
19
|
+
* trace_id (16 bytes hex)
|
|
20
|
+
* span_id (8 bytes hex, unique per row)
|
|
21
|
+
* parent_span_id (always NULL for top-level spans)
|
|
22
|
+
* name (the span_name passed to @TracedAs)
|
|
23
|
+
* kind (always "internal")
|
|
24
|
+
* status ("ok" or "error")
|
|
25
|
+
* start_time (Unix epoch ms)
|
|
26
|
+
* end_time (Unix epoch ms)
|
|
27
|
+
* duration_ms (end - start)
|
|
28
|
+
* created_at (now)
|
|
29
|
+
*
|
|
30
|
+
* If the DB write throws (locked, missing schema, permission
|
|
31
|
+
* denied), the error is swallowed — the decorator must never
|
|
32
|
+
* break the wrapped function. This is critical for tests,
|
|
33
|
+
* CI, and any environment where the host spans.db is absent.
|
|
34
|
+
*
|
|
35
|
+
* 3. Generates a process-lifetime `trace_id` (16 bytes hex) at
|
|
36
|
+
* module init. The host's spans.db queries by `name`, so a
|
|
37
|
+
* shared trace_id is sufficient.
|
|
38
|
+
*
|
|
39
|
+
* The plugin runs in the Bun runtime (declared in `package.json
|
|
40
|
+
* engines.bun`), so we use `bun:sqlite` for the writer. If Bun is
|
|
41
|
+
* not available, the decorator degrades to no-op (tests don't
|
|
42
|
+
* need to write spans to pass).
|
|
43
|
+
*
|
|
44
|
+
* Why not import from `@ai-setting/roy-agent-core`? See the
|
|
45
|
+
* plan doc §3.1 / review op #20182: keeping the plugin zero-dep
|
|
46
|
+
* is a hard contract. A 90-line local stub is cheaper than
|
|
47
|
+
* carrying a runtime dep that may not exist in every install
|
|
48
|
+
* target (e.g. the plugin's own test suite).
|
|
49
|
+
*/
|
|
50
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
51
|
+
import { dirname, join } from "node:path";
|
|
52
|
+
import { homedir } from "node:os";
|
|
53
|
+
let cachedDb = null;
|
|
54
|
+
let resolvedSpansDbPath = null;
|
|
55
|
+
/**
|
|
56
|
+
* Process-lifetime trace_id (16 random bytes hex). The host's
|
|
57
|
+
* trace_check queries spans by `name`, so a single trace_id per
|
|
58
|
+
* process is sufficient and matches the host's per-process model.
|
|
59
|
+
*/
|
|
60
|
+
const PROCESS_TRACE_ID = (() => {
|
|
61
|
+
const bytes = new Uint8Array(16);
|
|
62
|
+
const c = globalThis.crypto;
|
|
63
|
+
if (c && typeof c.getRandomValues === "function") {
|
|
64
|
+
c.getRandomValues(bytes);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
for (let i = 0; i < bytes.length; i += 1)
|
|
68
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
69
|
+
}
|
|
70
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
71
|
+
})();
|
|
72
|
+
/**
|
|
73
|
+
* Generate a unique 8-byte hex span_id per call.
|
|
74
|
+
*/
|
|
75
|
+
function newSpanId() {
|
|
76
|
+
const bytes = new Uint8Array(8);
|
|
77
|
+
const c = globalThis.crypto;
|
|
78
|
+
if (c && typeof c.getRandomValues === "function") {
|
|
79
|
+
c.getRandomValues(bytes);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
for (let i = 0; i < bytes.length; i += 1)
|
|
83
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
84
|
+
}
|
|
85
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Locate the spans.db path. Returns null if no candidate exists
|
|
89
|
+
* or is writable. The lookup is cached after the first successful
|
|
90
|
+
* resolution.
|
|
91
|
+
*/
|
|
92
|
+
function resolveSpansDbPath() {
|
|
93
|
+
if (resolvedSpansDbPath !== null)
|
|
94
|
+
return resolvedSpansDbPath;
|
|
95
|
+
const candidates = [];
|
|
96
|
+
if (process.env.ROY_TRACE_DB)
|
|
97
|
+
candidates.push(process.env.ROY_TRACE_DB);
|
|
98
|
+
if (process.env.ROY_AGENT_DATA) {
|
|
99
|
+
candidates.push(join(process.env.ROY_AGENT_DATA, "spans.db"));
|
|
100
|
+
}
|
|
101
|
+
candidates.push(join(homedir(), ".config", "roy-agent", "spans.db"));
|
|
102
|
+
for (const c of candidates) {
|
|
103
|
+
if (c && existsSync(c)) {
|
|
104
|
+
resolvedSpansDbPath = c;
|
|
105
|
+
return c;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Lazily open the spans.db. Returns null if Bun is not available,
|
|
112
|
+
* the file cannot be opened, or the `spans` table does not exist.
|
|
113
|
+
*/
|
|
114
|
+
function getDb() {
|
|
115
|
+
if (cachedDb)
|
|
116
|
+
return cachedDb;
|
|
117
|
+
if (typeof globalThis.Bun === "undefined")
|
|
118
|
+
return null;
|
|
119
|
+
const path = resolveSpansDbPath();
|
|
120
|
+
if (!path)
|
|
121
|
+
return null;
|
|
122
|
+
try {
|
|
123
|
+
const { Database } = require("bun:sqlite");
|
|
124
|
+
const db = new Database(path);
|
|
125
|
+
try {
|
|
126
|
+
db.exec("SELECT 1 FROM span LIMIT 0");
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
db.close();
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
cachedDb = db;
|
|
133
|
+
return cachedDb;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Write a single span row. Never throws — decorator must not
|
|
141
|
+
* break the wrapped function.
|
|
142
|
+
*/
|
|
143
|
+
function writeSpan(row) {
|
|
144
|
+
const db = getDb();
|
|
145
|
+
if (!db)
|
|
146
|
+
return;
|
|
147
|
+
const spanId = newSpanId();
|
|
148
|
+
const durationMs = row.endTime - row.startTime;
|
|
149
|
+
try {
|
|
150
|
+
db.prepare(`INSERT INTO span (trace_id, span_id, parent_span_id, name, kind, status, start_time, end_time, attributes, time_created)
|
|
151
|
+
VALUES (?, ?, NULL, ?, 'internal', ?, ?, ?, ?, ?)`).run(PROCESS_TRACE_ID, spanId, row.name, row.status, row.startTime, row.endTime, JSON.stringify({ duration_ms: durationMs, ...(row.errorMessage ? { error: row.errorMessage } : {}) }), Date.now());
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Swallow — see file header.
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* @TracedAs(name, options) decorator factory.
|
|
159
|
+
*
|
|
160
|
+
* Usage:
|
|
161
|
+
* @TracedAs("server.home.render", { recordParams: false, recordResult: false })
|
|
162
|
+
* private async sendIndex(res: http.ServerResponse): Promise<void> { ... }
|
|
163
|
+
*
|
|
164
|
+
* If the spans.db is unreachable (no host, no env, schema mismatch),
|
|
165
|
+
* the decorator becomes a transparent passthrough — the wrapped
|
|
166
|
+
* function is called with its original `this` and arguments.
|
|
167
|
+
*/
|
|
168
|
+
export function TracedAs(name, _options) {
|
|
169
|
+
return function (_target, propertyKey, descriptor) {
|
|
170
|
+
const originalFn = descriptor.value;
|
|
171
|
+
if (!originalFn)
|
|
172
|
+
return descriptor;
|
|
173
|
+
const spanName = name || propertyKey;
|
|
174
|
+
const wrapped = function (...args) {
|
|
175
|
+
const startTime = Date.now();
|
|
176
|
+
let result;
|
|
177
|
+
try {
|
|
178
|
+
result = originalFn.apply(this, args);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
const endTime = Date.now();
|
|
182
|
+
writeSpan({
|
|
183
|
+
name: spanName,
|
|
184
|
+
status: "error",
|
|
185
|
+
startTime,
|
|
186
|
+
endTime,
|
|
187
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
188
|
+
});
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
191
|
+
if (result && typeof result.then === "function") {
|
|
192
|
+
return Promise.resolve(result).then((value) => {
|
|
193
|
+
writeSpan({
|
|
194
|
+
name: spanName,
|
|
195
|
+
status: "ok",
|
|
196
|
+
startTime,
|
|
197
|
+
endTime: Date.now(),
|
|
198
|
+
});
|
|
199
|
+
return value;
|
|
200
|
+
}, (err) => {
|
|
201
|
+
writeSpan({
|
|
202
|
+
name: spanName,
|
|
203
|
+
status: "error",
|
|
204
|
+
startTime,
|
|
205
|
+
endTime: Date.now(),
|
|
206
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
207
|
+
});
|
|
208
|
+
throw err;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
writeSpan({
|
|
212
|
+
name: spanName,
|
|
213
|
+
status: "ok",
|
|
214
|
+
startTime,
|
|
215
|
+
endTime: Date.now(),
|
|
216
|
+
});
|
|
217
|
+
return result;
|
|
218
|
+
};
|
|
219
|
+
wrapped.__tracedAsName = spanName;
|
|
220
|
+
return {
|
|
221
|
+
...descriptor,
|
|
222
|
+
value: wrapped,
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* For tests: reset the module-level db cache so test fixtures
|
|
228
|
+
* can simulate a fresh host install. Not used in production.
|
|
229
|
+
*/
|
|
230
|
+
export function __resetTracedAsCacheForTests() {
|
|
231
|
+
if (cachedDb) {
|
|
232
|
+
try {
|
|
233
|
+
cachedDb.close();
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
// ignore
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
cachedDb = null;
|
|
240
|
+
resolvedSpansDbPath = null;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* For tests: returns the resolved spans.db path or null. Allows
|
|
244
|
+
* tests to assert the decorator located the host DB.
|
|
245
|
+
*/
|
|
246
|
+
export function __getResolvedSpansDbPathForTests() {
|
|
247
|
+
return resolveSpansDbPath();
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Ensure the parent dir of a candidate spans.db path exists
|
|
251
|
+
* (used by tests that point at a temp file). Best-effort.
|
|
252
|
+
*/
|
|
253
|
+
export function __ensureSpansDbDirForTests(path) {
|
|
254
|
+
try {
|
|
255
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// ignore
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* `withTrace(name, fn)` — manual instrumentation helper for free
|
|
263
|
+
* functions (which TS decorators cannot decorate). Runs `fn` and
|
|
264
|
+
* records a span around the invocation. Mirrors the @TracedAs
|
|
265
|
+
* contract: never throws, no-ops when spans.db is unavailable.
|
|
266
|
+
*
|
|
267
|
+
* Used by `renderSessionForestPage` and `encodeMermaidLabelText`
|
|
268
|
+
* (top-level exports that cannot carry a class-method decorator).
|
|
269
|
+
*/
|
|
270
|
+
export async function withTrace(name, fn) {
|
|
271
|
+
const startTime = Date.now();
|
|
272
|
+
try {
|
|
273
|
+
const result = await fn();
|
|
274
|
+
writeSpan({ name, status: "ok", startTime, endTime: Date.now() });
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
writeSpan({
|
|
279
|
+
name,
|
|
280
|
+
status: "error",
|
|
281
|
+
startTime,
|
|
282
|
+
endTime: Date.now(),
|
|
283
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
284
|
+
});
|
|
285
|
+
throw err;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Synchronous variant of `withTrace`. Used for top-level
|
|
290
|
+
* non-async exports.
|
|
291
|
+
*/
|
|
292
|
+
export function withTraceSync(name, fn) {
|
|
293
|
+
const startTime = Date.now();
|
|
294
|
+
try {
|
|
295
|
+
const result = fn();
|
|
296
|
+
writeSpan({ name, status: "ok", startTime, endTime: Date.now() });
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
writeSpan({
|
|
301
|
+
name,
|
|
302
|
+
status: "error",
|
|
303
|
+
startTime,
|
|
304
|
+
endTime: Date.now(),
|
|
305
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
306
|
+
});
|
|
307
|
+
throw err;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorator.js","sourceRoot":"","sources":["../../src/tracing/decorator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-setting/roy-plugin-task-show",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.6",
|
|
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). v0.8.10: bug-fix release (Task #2537 + Task #2534). (a) Heap-bounded plugin caches: OperationsCache and TasksTreeCache now enforce a hard maxEntries cap (default 256 / 64). Oldest stale entries are evicted before inserting a new one, so long-lived roy-agent sessions (BackgroundTaskManager + MemorySessionStore) no longer leak Map entries through the plugin's per-task caches — see Task #2537 for the heap-unbounded-state RED→GREEN repro. (b) Mermaid CJK font-family: server.ts renderTaskPage now configures mermaid.initialize({ themeVariables: { fontFamily: '\"PingFang SC\", \"Microsoft YaHei\", \"Noto Sans CJK SC\", \"Source Han Sans CN\", \"WenQuanYi Micro Hei\", sans-serif' } }) so Chinese node labels render correctly in browsers that have at least one of those fonts installed (see Task #2534).",
|
|
5
|
+
"description": "Visualize the tool call chain of a task on a local web service with real-time SSE updates. v0.9.0: Session-scoped home page (only show tasks created after plugin load + their external ancestors), with per-row 「显示全部栏位」 toggle and lazy-loaded operations timeline; per-task Mermaid labels now correctly render CJK / mixed-Latin / emoji text (encoded as \\uXXXX before emission, decoded by the browser); detail page layout reordered to lifecycle → pipeline → stats → toolcalls → rawjson. 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.10: bug-fix release (Task #2537 + Task #2534). (a) Heap-bounded plugin caches: OperationsCache and TasksTreeCache now enforce a hard maxEntries cap (default 256 / 64). Oldest stale entries are evicted before inserting a new one, so long-lived roy-agent sessions (BackgroundTaskManager + MemorySessionStore) no longer leak Map entries through the plugin's per-task caches — see Task #2537 for the heap-unbounded-state RED→GREEN repro. (b) Mermaid CJK font-family: server.ts renderTaskPage now configures mermaid.initialize({ themeVariables: { fontFamily: '\"PingFang SC\", \"Microsoft YaHei\", \"Noto Sans CJK SC\", \"Source Han Sans CN\", \"WenQuanYi Micro Hei\", sans-serif' } }) so Chinese node labels render correctly in browsers that have at least one of those fonts installed (see Task #2534). v0.9.6: preserve task context/goals end-to-end with safe structured rendering, and ship a complete packaged session-home shell with reliable CSS/controller assets.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"hooks": [
|
|
8
8
|
{
|