@ai-setting/roy-plugin-task-show 2.5.11 → 2.5.13

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.
Files changed (46) hide show
  1. package/dist/chat-markdown-renderer.d.ts +63 -0
  2. package/dist/chat-markdown-renderer.d.ts.map +1 -0
  3. package/dist/chat-markdown-renderer.js +123 -0
  4. package/dist/chat-markdown-renderer.js.map +1 -0
  5. package/dist/collector.d.ts +11 -0
  6. package/dist/collector.d.ts.map +1 -1
  7. package/dist/collector.js +37 -12
  8. package/dist/collector.js.map +1 -1
  9. package/dist/file-tree.d.ts +57 -1
  10. package/dist/file-tree.d.ts.map +1 -1
  11. package/dist/file-tree.js +22 -2
  12. package/dist/file-tree.js.map +1 -1
  13. package/dist/file-viewer-utils.d.ts +76 -0
  14. package/dist/file-viewer-utils.d.ts.map +1 -0
  15. package/dist/file-viewer-utils.js +215 -0
  16. package/dist/file-viewer-utils.js.map +1 -0
  17. package/dist/logger.d.ts +59 -0
  18. package/dist/logger.d.ts.map +1 -0
  19. package/dist/logger.js +181 -0
  20. package/dist/logger.js.map +1 -0
  21. package/dist/mermaid-zoom-guardian.d.ts +77 -0
  22. package/dist/mermaid-zoom-guardian.d.ts.map +1 -0
  23. package/dist/mermaid-zoom-guardian.js +176 -0
  24. package/dist/mermaid-zoom-guardian.js.map +1 -0
  25. package/dist/plugin.d.ts +24 -10
  26. package/dist/plugin.d.ts.map +1 -1
  27. package/dist/plugin.js +79 -33
  28. package/dist/plugin.js.map +1 -1
  29. package/dist/server.d.ts +25 -1
  30. package/dist/server.d.ts.map +1 -1
  31. package/dist/server.js +134 -8
  32. package/dist/server.js.map +1 -1
  33. package/dist/task-session-store.js +7 -0
  34. package/dist/task-session-store.js.map +1 -1
  35. package/dist/tool-call-detail.d.ts +18 -0
  36. package/dist/tool-call-detail.d.ts.map +1 -1
  37. package/dist/tool-call-detail.js +115 -7
  38. package/dist/tool-call-detail.js.map +1 -1
  39. package/package.json +2 -2
  40. package/plugin.json +2 -2
  41. package/public/app.js +18 -0
  42. package/public/index.html +7 -0
  43. package/public/markdown-preprocessor.js +89 -0
  44. package/public/markdown-renderer.js +29 -1
  45. package/public/mermaid-zoom-guardian.js +137 -0
  46. package/public/style.css +109 -0
@@ -0,0 +1,215 @@
1
+ /**
2
+ * @fileoverview File viewer rendering utilities (Task #2952).
3
+ *
4
+ * The right-hand tool-call detail panel on the task page renders
5
+ * differently depending on the tool name:
6
+ *
7
+ * - **write_file / write / create_file** → render the FULL content
8
+ * of the file as the user just wrote it (line-numbered, no
9
+ * truncation). Previously the panel mounted a Monaco placeholder
10
+ * that fetched the file from disk via /api/file-content — which
11
+ * could be truncated for large files and never reflected the
12
+ * content the tool call actually wrote.
13
+ *
14
+ * - **edit_file / edit / edit_file_v2 / multi_edit_file / multi_edit
15
+ * / apply_patch** → render a git-style diff between
16
+ * `old_string` and `new_string` (LCS-based +/- lines). For these
17
+ * tools we want to highlight what changed, not show the entire
18
+ * resulting file again.
19
+ *
20
+ * Both renderers produce XSS-safe HTML — every user-controlled string
21
+ * passes through {@link escapeHtml} before being injected.
22
+ */
23
+ // ---------------------------------------------------------------------------
24
+ // Public renderers
25
+ // ---------------------------------------------------------------------------
26
+ /**
27
+ * Render a write_file tool call's full content as line-numbered HTML.
28
+ *
29
+ * Returns a `<div class="file-viewer write-file">` containing:
30
+ * - a header with the file path + line/byte counts
31
+ * - a `<pre class="code-block">` with every line (no truncation)
32
+ *
33
+ * The renderer escapes HTML; long lines are preserved verbatim.
34
+ */
35
+ export function renderWriteFileFull(opts) {
36
+ const lines = opts.content.split("\n");
37
+ // If the content ends with \n, split() produces a trailing "" entry.
38
+ // We keep it (matches editor display) but flag the count accurately.
39
+ const totalChars = opts.content.length;
40
+ const lineNumbered = lines
41
+ .map((line, i) => {
42
+ const num = String(i + 1).padStart(4, " ");
43
+ const escaped = escapeHtml(line);
44
+ return `<div class="code-line"><span class="ln">${num}</span><span class="content">${escaped}</span></div>`;
45
+ })
46
+ .join("");
47
+ return `<div class="file-viewer write-file" data-file-path="${escapeHtmlAttr(opts.path)}">
48
+ <div class="file-header">
49
+ <span class="file-icon">📝</span>
50
+ <span class="file-path">${escapeHtml(opts.path)}</span>
51
+ <span class="file-meta">${lines.length} lines · ${totalChars} bytes</span>
52
+ </div>
53
+ <pre class="code-block">${lineNumbered}</pre>
54
+ </div>`;
55
+ }
56
+ /**
57
+ * Render an edit_file tool call as a git-style unified diff.
58
+ *
59
+ * Returns a `<div class="file-viewer edit-file">` containing:
60
+ * - a header with the file path + line counts
61
+ * - a `<ol class="diff-body">` with LCS-derived +/- / context lines
62
+ * (legacy contract — pre-v2.5.12 callers look for `class="diff-body"`
63
+ * and `diff-line-(added|removed|context)` markers).
64
+ *
65
+ * If `old_string` and `new_string` are identical the result is just
66
+ * the context lines (no +/- markers).
67
+ *
68
+ * The wrapper also carries `data-diff="<json>"` so the client
69
+ * hydrator can rebuild the diff on click without re-parsing the DOM.
70
+ */
71
+ export function renderEditFileDiff(opts) {
72
+ const oldLines = splitLines(opts.old_string);
73
+ const newLines = splitLines(opts.new_string);
74
+ const ops = computeLineDiff(oldLines, newLines);
75
+ const rendered = ops
76
+ .map((op) => {
77
+ const escaped = escapeHtml(op.line);
78
+ // v2.5.12: dual-class — legacy `diff-line-added/removed/context`
79
+ // (consumed by .diff-body CSS + v2.0.0 client tests) AND the new
80
+ // `add/remove/context` short forms (consumed by .file-viewer CSS).
81
+ // The legacy class MUST be the second token so the regex
82
+ // `class="diff-line diff-line-(added|removed|context)"` continues
83
+ // to match (used by RED-INT3 in
84
+ // test/tool-call-detail-server-integration.test.ts).
85
+ const legacyCls = op.type === "add"
86
+ ? "diff-line-added"
87
+ : op.type === "remove"
88
+ ? "diff-line-removed"
89
+ : "diff-line-context";
90
+ const newCls = op.type; // "add" | "remove" | "context"
91
+ const marker = op.type === "add" ? "+" : op.type === "remove" ? "-" : " ";
92
+ return `<li class="diff-line ${legacyCls}" data-kind="${newCls}" data-line="${escapeHtmlAttr(String(op.lineNum))}"><span class="diff-gutter">${escapeHtml(marker)}</span><span class="diff-text">${escaped}</span></li>`;
93
+ })
94
+ .join("");
95
+ const removedCount = ops.filter((o) => o.type === "remove").length;
96
+ const addedCount = ops.filter((o) => o.type === "add").length;
97
+ const dataDiff = JSON.stringify(ops.map((o) => ({
98
+ kind: o.type === "add" ? "added" : o.type === "remove" ? "removed" : "context",
99
+ text: o.line,
100
+ lineNum: o.lineNum,
101
+ })));
102
+ return `<div class="file-viewer edit-file" data-file-path="${escapeHtmlAttr(opts.path)}">
103
+ <div class="file-header">
104
+ <span class="file-icon">✏️</span>
105
+ <span class="file-path">${escapeHtml(opts.path)}</span>
106
+ <span class="file-meta">-${removedCount} +${addedCount} lines (${oldLines.length} → ${newLines.length})</span>
107
+ </div>
108
+ <ol class="diff-body" data-diff="${escapeHtmlAttr(dataDiff)}">${rendered}</ol>
109
+ </div>`;
110
+ }
111
+ // ---------------------------------------------------------------------------
112
+ // LCS-based line diff
113
+ // ---------------------------------------------------------------------------
114
+ /**
115
+ * Compute a line-level diff using LCS (Longest Common Subsequence).
116
+ *
117
+ * Algorithm: classic O(N*M) DP table, then a single backtrack to
118
+ * emit the ops in order. For inputs up to a few thousand lines this
119
+ * is well within budget; for pathological inputs we accept the cost
120
+ * (Task #2952 callers are user-authored file edits, not bulk
121
+ * transforms).
122
+ *
123
+ * Output: ordered array of `{type, line, lineNum}` matching how an
124
+ * editor would display them.
125
+ */
126
+ export function computeLineDiff(oldLines, newLines) {
127
+ const m = oldLines.length;
128
+ const n = newLines.length;
129
+ if (m === 0 && n === 0)
130
+ return [];
131
+ // dp[i+1][j+1] = LCS length of oldLines[0..i] vs newLines[0..j]
132
+ const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
133
+ for (let i = 0; i < m; i++) {
134
+ const oldLine = oldLines[i];
135
+ const row = dp[i + 1];
136
+ const prev = dp[i];
137
+ for (let j = 0; j < n; j++) {
138
+ if (oldLine === newLines[j]) {
139
+ row[j + 1] = (prev[j] ?? 0) + 1;
140
+ }
141
+ else {
142
+ row[j + 1] = Math.max(prev[j + 1] ?? 0, row[j] ?? 0);
143
+ }
144
+ }
145
+ }
146
+ // Backtrack to produce the ops in reverse order.
147
+ const reversed = [];
148
+ let i = m;
149
+ let j = n;
150
+ while (i > 0 && j > 0) {
151
+ if (oldLines[i - 1] === newLines[j - 1]) {
152
+ reversed.push({ type: "context", line: oldLines[i - 1], lineNum: j });
153
+ i--;
154
+ j--;
155
+ }
156
+ else if ((dp[i - 1]?.[j] ?? 0) >= (dp[i]?.[j - 1] ?? 0)) {
157
+ reversed.push({ type: "remove", line: oldLines[i - 1], lineNum: i });
158
+ i--;
159
+ }
160
+ else {
161
+ reversed.push({ type: "add", line: newLines[j - 1], lineNum: j });
162
+ j--;
163
+ }
164
+ }
165
+ while (i > 0) {
166
+ reversed.push({ type: "remove", line: oldLines[i - 1], lineNum: i });
167
+ i--;
168
+ }
169
+ while (j > 0) {
170
+ reversed.push({ type: "add", line: newLines[j - 1], lineNum: j });
171
+ j--;
172
+ }
173
+ reversed.reverse();
174
+ return reversed;
175
+ }
176
+ // ---------------------------------------------------------------------------
177
+ // Helpers
178
+ // ---------------------------------------------------------------------------
179
+ /**
180
+ * Split a string into lines. We split on `\n` and drop a single
181
+ * trailing empty element from a final `\n` (matching how `git diff`
182
+ * and most editors present the result). Empty input → `[]`.
183
+ */
184
+ function splitLines(s) {
185
+ if (s === "")
186
+ return [];
187
+ const parts = s.split("\n");
188
+ if (parts.length > 0 && parts[parts.length - 1] === "")
189
+ parts.pop();
190
+ return parts;
191
+ }
192
+ /**
193
+ * Escape user-controlled strings for HTML body context. Mirrors
194
+ * `escapeHtml()` in `src/tool-call-detail.ts` so the two renderers
195
+ * stay consistent.
196
+ */
197
+ function escapeHtml(input) {
198
+ if (input === undefined || input === null)
199
+ return "";
200
+ const s = typeof input === "string" ? input : JSON.stringify(input);
201
+ return s
202
+ .replace(/&/g, "&amp;")
203
+ .replace(/</g, "&lt;")
204
+ .replace(/>/g, "&gt;")
205
+ .replace(/"/g, "&quot;")
206
+ .replace(/'/g, "&#39;");
207
+ }
208
+ /**
209
+ * Attribute-context escape. Same algorithm as {@link escapeHtml} but
210
+ * the separate name makes the intent clear at the call site.
211
+ */
212
+ function escapeHtmlAttr(input) {
213
+ return escapeHtml(input);
214
+ }
215
+ //# sourceMappingURL=file-viewer-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-viewer-utils.js","sourceRoot":"","sources":["../src/file-viewer-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAWH,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAGnC;IACC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvC,qEAAqE;IACrE,qEAAqE;IACrE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IACvC,MAAM,YAAY,GAAG,KAAK;SACvB,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACf,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO,2CAA2C,GAAG,gCAAgC,OAAO,eAAe,CAAC;IAC9G,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO,uDAAuD,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;;;8BAG3D,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;8BACrB,KAAK,CAAC,MAAM,YAAY,UAAU;;4BAEpC,YAAY;OACjC,CAAC;AACR,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAIlC;IACC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEhD,MAAM,QAAQ,GAAG,GAAG;SACjB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;QACV,MAAM,OAAO,GAAG,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACpC,iEAAiE;QACjE,iEAAiE;QACjE,mEAAmE;QACnE,yDAAyD;QACzD,kEAAkE;QAClE,gCAAgC;QAChC,qDAAqD;QACrD,MAAM,SAAS,GACb,EAAE,CAAC,IAAI,KAAK,KAAK;YACf,CAAC,CAAC,iBAAiB;YACnB,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,QAAQ;gBACpB,CAAC,CAAC,mBAAmB;gBACrB,CAAC,CAAC,mBAAmB,CAAC;QAC5B,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,+BAA+B;QACvD,MAAM,MAAM,GACV,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAC7D,OAAO,wBAAwB,SAAS,gBAAgB,MAAM,gBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,+BAA+B,UAAU,CAAC,MAAM,CAAC,kCAAkC,OAAO,cAAc,CAAC;IAC3N,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IACnE,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAC7B,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACd,IAAI,EAAE,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QAC9E,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;KACnB,CAAC,CAAC,CACJ,CAAC;IAEF,OAAO,sDAAsD,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;;;8BAG1D,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;+BACpB,YAAY,KAAK,UAAU,WAAW,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC,MAAM;;qCAEpE,cAAc,CAAC,QAAQ,CAAC,KAAK,QAAQ;OACnE,CAAC;AACR,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAkB,EAClB,QAAkB;IAElB,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC1B,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC1B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,gEAAgE;IAChE,MAAM,EAAE,GAAe,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,CACxD,IAAI,KAAK,CAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACjC,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;QACvB,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAE,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,IAAI,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5B,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAClC,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,IAAI,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;YACvE,CAAC,EAAE,CAAC;YACJ,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC1D,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;YACtE,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;YACnE,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACb,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QACtE,CAAC,EAAE,CAAC;IACN,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACb,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QACnE,CAAC,EAAE,CAAC;IACN,CAAC;IAED,QAAQ,CAAC,OAAO,EAAE,CAAC;IACnB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,UAAU,CAAC,CAAS;IAC3B,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;QAAE,KAAK,CAAC,GAAG,EAAE,CAAC;IACpE,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAC,KAAc;IAChC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IACrD,MAAM,CAAC,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACpE,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @fileoverview Plugin-internal unified logger (Task #2961).
3
+ *
4
+ * User feedback: "用 logger.info 走日志系统,不污染 stdout/stderr".
5
+ *
6
+ * The plugin is intentionally zero-runtime-dep (no `@ai-setting/roy-agent-core`,
7
+ * no `pino`/`winston`). To route diagnostic output through a unified logger
8
+ * WITHOUT polluting stdout/stderr, we ship a small, self-contained logger
9
+ * here that mirrors the host agent's `createLogger` semantics:
10
+ *
11
+ * - `info` / `warn` / `error` / `debug` methods on every logger instance.
12
+ * - Quiet-by-default mode: when `quietMode === true` (the default), all
13
+ * log calls go to a per-category log file under
14
+ * `${XDG_DATA_HOME:-~/.local/share}/roy-agent/logs/roy-plugin-task-show-<name>.log`,
15
+ * and DO NOT touch `console.log` / `console.warn` / `console.error`.
16
+ * - Console output is only enabled when an operator explicitly calls
17
+ * `setQuietMode(false)`. The env var `TASK_SHOW_DEBUG=1` no longer
18
+ * re-enables console output — it is intentionally ignored (was the
19
+ * previous band-aid in Task #2953).
20
+ * - The log file path is created on first write (mkdir -p).
21
+ * - Writes are synchronous append (`appendFileSync`) so the log is
22
+ * durable even when the process exits immediately (subprocess shutdown).
23
+ *
24
+ * Why a new file instead of inlining in `plugin.ts`? Tests pin the
25
+ * `createPluginLogger` symbol (RED-3 / RED-4 / RED-5) and the chat
26
+ * subprocess test imports it from `../src/logger.js`. Co-locating the
27
+ * logger means `server.ts`, `collector.ts`, and `plugin.ts` all import
28
+ * the same `createPluginLogger` — one sink, one set of gates.
29
+ *
30
+ * NOTE: this logger is intentionally minimal. If the host agent ever
31
+ * exposes a `createPluginLogger` factory in `@ai-setting/roy-agent-core`,
32
+ * this file can be replaced with a thin re-export.
33
+ */
34
+ export declare function isQuietMode(): boolean;
35
+ export declare function setQuietMode(enabled: boolean): void;
36
+ export interface PluginLogger {
37
+ /** Log to file unconditionally. Console only when un-quiet. */
38
+ info(message: string, data?: unknown): void;
39
+ warn(message: string, data?: unknown): void;
40
+ error(message: string, data?: unknown): void;
41
+ debug(message: string, data?: unknown): void;
42
+ /**
43
+ * Whether this logger currently routes to the console. True when
44
+ * quiet mode is off AND the env says console output is allowed.
45
+ * Tests use this to assert the default behaviour without spying on
46
+ * `console.*` directly.
47
+ */
48
+ readonly consoleEnabled: boolean;
49
+ }
50
+ /**
51
+ * Create (or fetch from cache) a plugin logger under the given category
52
+ * prefix. The prefix appears in the log file name and in each formatted
53
+ * line so operators can grep for it.
54
+ *
55
+ * @param prefix A short identifier for the subsystem
56
+ * (e.g. `"plugin"`, `"server"`, `"collector"`).
57
+ */
58
+ export declare function createPluginLogger(prefix: string): PluginLogger;
59
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAqBH,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEnD;AAgDD,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AA+CD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CA4C/D"}
package/dist/logger.js ADDED
@@ -0,0 +1,181 @@
1
+ /**
2
+ * @fileoverview Plugin-internal unified logger (Task #2961).
3
+ *
4
+ * User feedback: "用 logger.info 走日志系统,不污染 stdout/stderr".
5
+ *
6
+ * The plugin is intentionally zero-runtime-dep (no `@ai-setting/roy-agent-core`,
7
+ * no `pino`/`winston`). To route diagnostic output through a unified logger
8
+ * WITHOUT polluting stdout/stderr, we ship a small, self-contained logger
9
+ * here that mirrors the host agent's `createLogger` semantics:
10
+ *
11
+ * - `info` / `warn` / `error` / `debug` methods on every logger instance.
12
+ * - Quiet-by-default mode: when `quietMode === true` (the default), all
13
+ * log calls go to a per-category log file under
14
+ * `${XDG_DATA_HOME:-~/.local/share}/roy-agent/logs/roy-plugin-task-show-<name>.log`,
15
+ * and DO NOT touch `console.log` / `console.warn` / `console.error`.
16
+ * - Console output is only enabled when an operator explicitly calls
17
+ * `setQuietMode(false)`. The env var `TASK_SHOW_DEBUG=1` no longer
18
+ * re-enables console output — it is intentionally ignored (was the
19
+ * previous band-aid in Task #2953).
20
+ * - The log file path is created on first write (mkdir -p).
21
+ * - Writes are synchronous append (`appendFileSync`) so the log is
22
+ * durable even when the process exits immediately (subprocess shutdown).
23
+ *
24
+ * Why a new file instead of inlining in `plugin.ts`? Tests pin the
25
+ * `createPluginLogger` symbol (RED-3 / RED-4 / RED-5) and the chat
26
+ * subprocess test imports it from `../src/logger.js`. Co-locating the
27
+ * logger means `server.ts`, `collector.ts`, and `plugin.ts` all import
28
+ * the same `createPluginLogger` — one sink, one set of gates.
29
+ *
30
+ * NOTE: this logger is intentionally minimal. If the host agent ever
31
+ * exposes a `createPluginLogger` factory in `@ai-setting/roy-agent-core`,
32
+ * this file can be replaced with a thin re-export.
33
+ */
34
+ import * as fs from "node:fs";
35
+ import * as os from "node:os";
36
+ import * as path from "node:path";
37
+ // ============================================================================
38
+ // Module-level quiet mode (mirrors @ai-setting/roy-agent-core quietMode)
39
+ // ============================================================================
40
+ /**
41
+ * Quiet mode = "log to file only, do not touch console". When false, log
42
+ * calls also forward to the matching `console.*` method.
43
+ *
44
+ * Defaults to `true` so the plugin never pollutes the parent process's
45
+ * stdout / stderr unless the operator explicitly asks for it. The env
46
+ * var `TASK_SHOW_DEBUG=1` (legacy band-aid from Task #2953) is ignored
47
+ * — see `envSaysConsoleEnabled()` for the rationale.
48
+ */
49
+ let quietMode = true;
50
+ export function isQuietMode() {
51
+ return quietMode;
52
+ }
53
+ export function setQuietMode(enabled) {
54
+ quietMode = enabled;
55
+ }
56
+ /**
57
+ * v2.5.12 (Task #2961): the env flags are intentionally NOT consulted.
58
+ * The user's explicit feedback was "用 logger.info 走日志系统,不污染
59
+ * stdout/stderr". Honouring that means the default behaviour must NEVER
60
+ * touch console, regardless of legacy debug env vars. Operators who
61
+ * want console output for live debugging should call `setQuietMode(false)`
62
+ * directly — this keeps the env variable surface narrow and predictable.
63
+ */
64
+ function envSaysConsoleEnabled() {
65
+ return false;
66
+ }
67
+ // ============================================================================
68
+ // Log file path
69
+ // ============================================================================
70
+ /**
71
+ * Resolve the log directory every call so tests that flip
72
+ * `XDG_DATA_HOME` between cases pick up the new path. The cost is a
73
+ * couple of `path.join` calls per log write — negligible.
74
+ */
75
+ function getLogDir() {
76
+ const xdg = process.env?.XDG_DATA_HOME;
77
+ const base = xdg && xdg.length > 0
78
+ ? xdg
79
+ : path.join(os.homedir(), ".local", "share");
80
+ const dir = path.join(base, "roy-agent", "logs");
81
+ try {
82
+ fs.mkdirSync(dir, { recursive: true });
83
+ }
84
+ catch {
85
+ // ignore — fall through; writeToFile will no-op on error.
86
+ }
87
+ return dir;
88
+ }
89
+ function getLogFilePath(category) {
90
+ // Sanitize the category to avoid path traversal — keep alnum + dash/underscore.
91
+ const safe = category.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
92
+ return path.join(getLogDir(), `roy-plugin-task-show-${safe}.log`);
93
+ }
94
+ const TAG = "roy-plugin-task-show";
95
+ function formatLine(level, prefix, message, data) {
96
+ const ts = new Date().toISOString();
97
+ const tail = data !== undefined ? ` ${safeStringify(data)}` : "";
98
+ return `${ts} [${level.toUpperCase()}] [${TAG}:${prefix}] ${message}${tail}`;
99
+ }
100
+ function safeStringify(data) {
101
+ try {
102
+ const s = JSON.stringify(data);
103
+ return s === undefined ? String(data) : s;
104
+ }
105
+ catch {
106
+ return String(data);
107
+ }
108
+ }
109
+ function writeToFile(line, category) {
110
+ try {
111
+ const file = getLogFilePath(category);
112
+ fs.appendFileSync(file, line + "\n", "utf-8");
113
+ }
114
+ catch {
115
+ // Swallow — the plugin must never crash on log I/O.
116
+ }
117
+ }
118
+ /**
119
+ * Compute the current console-enabled state. Called on every log
120
+ * call so that toggling `quietMode` at runtime takes effect immediately.
121
+ */
122
+ function computeConsoleEnabled() {
123
+ return !quietMode || envSaysConsoleEnabled();
124
+ }
125
+ // ============================================================================
126
+ // Logger factory
127
+ // ============================================================================
128
+ const cache = new Map();
129
+ /**
130
+ * Create (or fetch from cache) a plugin logger under the given category
131
+ * prefix. The prefix appears in the log file name and in each formatted
132
+ * line so operators can grep for it.
133
+ *
134
+ * @param prefix A short identifier for the subsystem
135
+ * (e.g. `"plugin"`, `"server"`, `"collector"`).
136
+ */
137
+ export function createPluginLogger(prefix) {
138
+ const cached = cache.get(prefix);
139
+ if (cached)
140
+ return cached;
141
+ const logger = {
142
+ get consoleEnabled() {
143
+ return computeConsoleEnabled();
144
+ },
145
+ info(message, data) {
146
+ const line = formatLine("info", prefix, message, data);
147
+ writeToFile(line, prefix);
148
+ if (computeConsoleEnabled()) {
149
+ // eslint-disable-next-line no-console
150
+ console.log(line);
151
+ }
152
+ },
153
+ warn(message, data) {
154
+ const line = formatLine("warn", prefix, message, data);
155
+ writeToFile(line, prefix);
156
+ if (computeConsoleEnabled()) {
157
+ // eslint-disable-next-line no-console
158
+ console.warn(line);
159
+ }
160
+ },
161
+ error(message, data) {
162
+ const line = formatLine("error", prefix, message, data);
163
+ writeToFile(line, prefix);
164
+ if (computeConsoleEnabled()) {
165
+ // eslint-disable-next-line no-console
166
+ console.error(line);
167
+ }
168
+ },
169
+ debug(message, data) {
170
+ const line = formatLine("debug", prefix, message, data);
171
+ writeToFile(line, prefix);
172
+ if (computeConsoleEnabled()) {
173
+ // eslint-disable-next-line no-console
174
+ console.debug(line);
175
+ }
176
+ },
177
+ };
178
+ cache.set(prefix, logger);
179
+ return logger;
180
+ }
181
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @fileoverview Mermaid zoom-stage guardian (v2.5.12 / Task #2951).
3
+ *
4
+ * Why this module exists
5
+ * ----------------------
6
+ * The Mermaid controller (`public/mermaid-renderer.js`) wraps every
7
+ * freshly-rendered SVG in a `.mermaid-zoom-stage` div that carries
8
+ * the pan/zoom CSS transform and the pointer-drag handlers. Without
9
+ * that wrapper the user can neither pan nor zoom the lifecycle
10
+ * diagram.
11
+ *
12
+ * Mermaid's library auto-runs `mermaid.run({nodes})` once
13
+ * `startOnLoad: true` is set in `mermaid.initialize`. We DO set
14
+ * `startOnLoad: true` in the SSR template (server.ts line ~2041) so
15
+ * the initial paint works for hosts that don't ship our controller.
16
+ * The auto-runner scans the DOM for `.mermaid` elements that are not
17
+ * already marked `data-processed` and replaces their innerHTML with a
18
+ * freshly-rendered SVG.
19
+ *
20
+ * Even after our controller's `update()` has set `data-processed="true"`
21
+ * and wrapped the SVG, Mermaid's auto-runner fires roughly 1.5–3s
22
+ * later (observed via Playwright trace on 2026-08-12) and replaces
23
+ * the contents of the `.mermaid` element with a fresh, bare SVG. The
24
+ * bare SVG is not wrapped in `.mermaid-zoom-stage`, so the pan/zoom
25
+ * UI silently breaks for the rest of the page lifetime.
26
+ *
27
+ * What this module does
28
+ * ---------------------
29
+ * `ensureMermaidZoomStage(container)` — one-shot helper that walks
30
+ * the container and wraps any existing `<svg>` in a
31
+ * `.mermaid-zoom-stage` div. Idempotent: calling it twice keeps ONE
32
+ * wrapper.
33
+ *
34
+ * `MermaidZoomGuardian` — a long-lived `MutationObserver` that
35
+ * detects when something (Mermaid's late `mermaid.run()`, an SSE
36
+ * patch, etc.) replaces the SVG and re-applies the wrapper. The
37
+ * guardian stops observing after `stop()` is called.
38
+ *
39
+ * Both helpers are deliberately framework-free so they can be unit-
40
+ * tested in happy-dom / jsdom without a full browser.
41
+ */
42
+ /**
43
+ * Wrap any existing SVG inside `container` in a single
44
+ * `.mermaid-zoom-stage` div. Idempotent.
45
+ *
46
+ * @returns the (possibly newly-created) stage element, or `null`
47
+ * when the container has no SVG to wrap.
48
+ */
49
+ export declare function ensureMermaidZoomStage(container: Element): HTMLElement | null;
50
+ /**
51
+ * v2.5.12 (Task #2951): the MermaidZoomGuardian watches a container
52
+ * and re-wraps any replacement SVG in `.mermaid-zoom-stage`. Use
53
+ * this for diagrams that survive past the initial render — e.g. the
54
+ * lifecycle mermaid on the per-task page, where Mermaid's late
55
+ * `mermaid.run()` otherwise destroys the wrapper.
56
+ *
57
+ * Lifecycle:
58
+ * const g = new MermaidZoomGuardian(container);
59
+ * g.start();
60
+ * // ...later, when the page is torn down:
61
+ * g.stop();
62
+ */
63
+ export declare class MermaidZoomGuardian {
64
+ private readonly container;
65
+ private observer;
66
+ private scheduled;
67
+ constructor(container: Element);
68
+ start(): void;
69
+ stop(): void;
70
+ }
71
+ /**
72
+ * Export the constants so tests can reference them without hardcoding.
73
+ */
74
+ export declare const MERMAID_STAGE_CLASS = "mermaid-zoom-stage";
75
+ export declare const MERMAID_TOOLBAR_CLASS = "mermaid-zoom-toolbar";
76
+ export declare const MERMAID_CONTAINER_CLASS = "mermaid";
77
+ //# sourceMappingURL=mermaid-zoom-guardian.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mermaid-zoom-guardian.d.ts","sourceRoot":"","sources":["../src/mermaid-zoom-guardian.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAgBH;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAsC7E;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,EAAE,OAAO;IAI9B,KAAK,IAAI,IAAI;IAwCb,IAAI,IAAI,IAAI;CAOb;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,uBAAc,CAAC;AAC/C,eAAO,MAAM,qBAAqB,yBAAgB,CAAC;AACnD,eAAO,MAAM,uBAAuB,YAAgB,CAAC"}