@oharness/server 0.1.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/dist/analytics.d.ts +47 -0
- package/dist/analytics.js +323 -0
- package/dist/analytics.js.map +1 -0
- package/dist/artifacts.d.ts +53 -0
- package/dist/artifacts.js +129 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/canvas.d.ts +28 -0
- package/dist/canvas.js +646 -0
- package/dist/canvas.js.map +1 -0
- package/dist/changes.d.ts +54 -0
- package/dist/changes.js +154 -0
- package/dist/changes.js.map +1 -0
- package/dist/files.d.ts +48 -0
- package/dist/files.js +168 -0
- package/dist/files.js.map +1 -0
- package/dist/i18n.d.ts +15 -0
- package/dist/i18n.js +625 -0
- package/dist/i18n.js.map +1 -0
- package/dist/icons.d.ts +9 -0
- package/dist/icons.js +197 -0
- package/dist/icons.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +148 -0
- package/dist/main.js.map +1 -0
- package/dist/markdown.d.ts +10 -0
- package/dist/markdown.js +253 -0
- package/dist/markdown.js.map +1 -0
- package/dist/page.d.ts +1 -0
- package/dist/page.js +8591 -0
- package/dist/page.js.map +1 -0
- package/dist/pick.d.ts +62 -0
- package/dist/pick.js +215 -0
- package/dist/pick.js.map +1 -0
- package/dist/prefs.d.ts +59 -0
- package/dist/prefs.js +66 -0
- package/dist/prefs.js.map +1 -0
- package/dist/projects.d.ts +34 -0
- package/dist/projects.js +129 -0
- package/dist/projects.js.map +1 -0
- package/dist/server.d.ts +50 -0
- package/dist/server.js +2789 -0
- package/dist/server.js.map +1 -0
- package/package.json +36 -0
package/dist/markdown.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client-side script, kept as a template so the page stays one file.
|
|
3
|
+
*
|
|
4
|
+
* **Everything here builds DOM nodes and sets `textContent`; nothing assigns
|
|
5
|
+
* `innerHTML` with content from the model, a tool result or a file.** That is
|
|
6
|
+
* not stylistic. This page holds a token that drives an agent which can run
|
|
7
|
+
* shell commands, so a `<script>` in a file the agent happened to read would,
|
|
8
|
+
* with an innerHTML renderer, execute in exactly the context that can act on
|
|
9
|
+
* this machine. Building nodes makes the injection impossible rather than
|
|
10
|
+
* filtered.
|
|
11
|
+
*/
|
|
12
|
+
const RAW = String.raw `
|
|
13
|
+
const el = (tag, cls, text) => {
|
|
14
|
+
const node = document.createElement(tag);
|
|
15
|
+
if (cls) node.className = cls;
|
|
16
|
+
if (text !== undefined) node.textContent = text;
|
|
17
|
+
return node;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// --- markdown -------------------------------------------------------------
|
|
21
|
+
// A small subset: fences, headings, lists, quotes, and inline code/bold/italic
|
|
22
|
+
// /links. Anything unrecognised stays literal text, which is the safe default
|
|
23
|
+
// for a renderer fed by a language model.
|
|
24
|
+
|
|
25
|
+
function renderMarkdown(source) {
|
|
26
|
+
const root = el("div", "md");
|
|
27
|
+
const lines = source.split("\n");
|
|
28
|
+
let i = 0;
|
|
29
|
+
|
|
30
|
+
while (i < lines.length) {
|
|
31
|
+
const line = lines[i];
|
|
32
|
+
|
|
33
|
+
if (/^@@FENCE@@/.test(line)) {
|
|
34
|
+
const lang = line.slice(3).trim();
|
|
35
|
+
const body = [];
|
|
36
|
+
i++;
|
|
37
|
+
while (i < lines.length && !/^@@FENCE@@/.test(lines[i])) body.push(lines[i++]);
|
|
38
|
+
i++;
|
|
39
|
+
root.appendChild(codeBlock(body.join("\n"), lang));
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const heading = /^(#{1,4})\s+(.*)$/.exec(line);
|
|
44
|
+
if (heading) {
|
|
45
|
+
root.appendChild(inline(el("h" + (heading[1].length + 2), "md-h"), heading[2]));
|
|
46
|
+
i++;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (/^\s*>/.test(line)) {
|
|
51
|
+
const body = [];
|
|
52
|
+
while (i < lines.length && /^\s*>/.test(lines[i])) body.push(lines[i++].replace(/^\s*>\s?/, ""));
|
|
53
|
+
const quote = el("blockquote", "md-quote");
|
|
54
|
+
quote.appendChild(renderMarkdown(body.join("\n")));
|
|
55
|
+
root.appendChild(quote);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (/^\s*([-*+]|\d+\.)\s+/.test(line)) {
|
|
60
|
+
const ordered = /^\s*\d+\./.test(line);
|
|
61
|
+
const list = el(ordered ? "ol" : "ul", "md-list");
|
|
62
|
+
while (i < lines.length && /^\s*([-*+]|\d+\.)\s+/.test(lines[i])) {
|
|
63
|
+
const item = lines[i++].replace(/^\s*([-*+]|\d+\.)\s+/, "");
|
|
64
|
+
list.appendChild(inline(el("li"), item));
|
|
65
|
+
}
|
|
66
|
+
root.appendChild(list);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (line.trim() === "") {
|
|
71
|
+
i++;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const paragraph = [];
|
|
76
|
+
while (
|
|
77
|
+
i < lines.length &&
|
|
78
|
+
lines[i].trim() !== "" &&
|
|
79
|
+
!/^@@FENCE@@|^\s*>|^#{1,4}\s|^\s*([-*+]|\d+\.)\s+/.test(lines[i])
|
|
80
|
+
) {
|
|
81
|
+
paragraph.push(lines[i++]);
|
|
82
|
+
}
|
|
83
|
+
root.appendChild(inline(el("p", "md-p"), paragraph.join("\n")));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return root;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Inline spans, appended as nodes so no markup can come from the text. */
|
|
90
|
+
function inline(parent, text) {
|
|
91
|
+
const pattern = /(@@BT@@[^@@BT@@]+@@BT@@)|(\*\*[^*]+\*\*)|(\*[^*]+\*)|(\[[^\]]+\]\([^)]+\))/g;
|
|
92
|
+
let last = 0;
|
|
93
|
+
let match;
|
|
94
|
+
|
|
95
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
96
|
+
if (match.index > last) parent.appendChild(document.createTextNode(text.slice(last, match.index)));
|
|
97
|
+
const token = match[0];
|
|
98
|
+
|
|
99
|
+
if (token.startsWith("@@BT@@")) {
|
|
100
|
+
parent.appendChild(el("code", "md-code", token.slice(1, -1)));
|
|
101
|
+
} else if (token.startsWith("**")) {
|
|
102
|
+
parent.appendChild(el("strong", null, token.slice(2, -2)));
|
|
103
|
+
} else if (token.startsWith("*")) {
|
|
104
|
+
parent.appendChild(el("em", null, token.slice(1, -1)));
|
|
105
|
+
} else {
|
|
106
|
+
const label = token.slice(1, token.indexOf("]"));
|
|
107
|
+
const href = token.slice(token.indexOf("(") + 1, -1);
|
|
108
|
+
// Only http(s): a javascript: or data: URL from model output would run
|
|
109
|
+
// script in a page that can drive the agent.
|
|
110
|
+
if (/^https?:\/\//i.test(href)) {
|
|
111
|
+
const link = el("a", "md-link", label);
|
|
112
|
+
link.href = href;
|
|
113
|
+
link.target = "_blank";
|
|
114
|
+
link.rel = "noopener noreferrer";
|
|
115
|
+
parent.appendChild(link);
|
|
116
|
+
} else {
|
|
117
|
+
parent.appendChild(document.createTextNode(token));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
last = match.index + token.length;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (last < text.length) parent.appendChild(document.createTextNode(text.slice(last)));
|
|
124
|
+
return parent;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function codeBlock(source, lang) {
|
|
128
|
+
const wrap = el("div", "code-wrap");
|
|
129
|
+
const bar = el("div", "code-bar");
|
|
130
|
+
bar.appendChild(el("span", "code-lang", lang || "text"));
|
|
131
|
+
|
|
132
|
+
const copy = el("button", "code-copy", "copy");
|
|
133
|
+
copy.type = "button";
|
|
134
|
+
copy.addEventListener("click", () => {
|
|
135
|
+
navigator.clipboard?.writeText(source);
|
|
136
|
+
copy.textContent = "copied";
|
|
137
|
+
setTimeout(() => (copy.textContent = "copy"), 1200);
|
|
138
|
+
});
|
|
139
|
+
bar.appendChild(copy);
|
|
140
|
+
|
|
141
|
+
const pre = el("pre", "code");
|
|
142
|
+
pre.appendChild(highlight(source, lang));
|
|
143
|
+
wrap.appendChild(bar);
|
|
144
|
+
wrap.appendChild(pre);
|
|
145
|
+
return wrap;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// --- highlighting ---------------------------------------------------------
|
|
149
|
+
// Deliberately generic: one tokenizer for strings, comments, numbers and a
|
|
150
|
+
// shared keyword set. A per-language grammar would be more accurate and far
|
|
151
|
+
// more code to be wrong in; this reads well for the languages people paste.
|
|
152
|
+
|
|
153
|
+
const KEYWORDS = new Set((
|
|
154
|
+
"const let var function return if else for while class extends new await async " +
|
|
155
|
+
"import export from default try catch finally throw typeof instanceof interface " +
|
|
156
|
+
"type enum public private static void null undefined true false this super " +
|
|
157
|
+
"def lambda pass raise with as elif not and or in is None True False print " +
|
|
158
|
+
"fn impl struct trait mut pub use crate match Some None Ok Err " +
|
|
159
|
+
"package func range map chan go defer select case switch break continue"
|
|
160
|
+
).split(" "));
|
|
161
|
+
|
|
162
|
+
function highlight(source, lang) {
|
|
163
|
+
const code = el("code", "hl");
|
|
164
|
+
const pattern =
|
|
165
|
+
/("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|@@BT@@(?:[^@@BT@@\\]|\\.)*@@BT@@)|(\/\/[^\n]*|#[^\n]*|\/\*[\s\S]*?\*\/)|(\b\d[\d_.eE+-]*\b)|([A-Za-z_$][\w$]*)/g;
|
|
166
|
+
let last = 0;
|
|
167
|
+
let match;
|
|
168
|
+
|
|
169
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
170
|
+
if (match.index > last) code.appendChild(document.createTextNode(source.slice(last, match.index)));
|
|
171
|
+
const [token, str, comment, num, word] = match;
|
|
172
|
+
|
|
173
|
+
if (str) code.appendChild(el("span", "t-str", token));
|
|
174
|
+
else if (comment) code.appendChild(el("span", "t-com", token));
|
|
175
|
+
else if (num) code.appendChild(el("span", "t-num", token));
|
|
176
|
+
else if (word && KEYWORDS.has(word)) code.appendChild(el("span", "t-kw", token));
|
|
177
|
+
else code.appendChild(document.createTextNode(token));
|
|
178
|
+
|
|
179
|
+
last = match.index + token.length;
|
|
180
|
+
}
|
|
181
|
+
if (last < source.length) code.appendChild(document.createTextNode(source.slice(last)));
|
|
182
|
+
return code;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// --- search ---------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Whether an option matches a query.
|
|
189
|
+
*
|
|
190
|
+
* Every whitespace-separated word must appear somewhere in the label, the
|
|
191
|
+
* group or the trailing detail — so "qwen flash" finds qwen/qwen3.7-flash
|
|
192
|
+
* regardless of the order typed, and "anthropic opus" narrows by vendor and
|
|
193
|
+
* model at once. A substring match on the whole query would fail both.
|
|
194
|
+
*/
|
|
195
|
+
function matchesQuery(option, query) {
|
|
196
|
+
if (!query) return true;
|
|
197
|
+
const words = String(query).toLowerCase().split(/\s+/).filter(Boolean);
|
|
198
|
+
const hay = (
|
|
199
|
+
(option.label || "") + " " + (option.group || "") + " " + (option.sub || "")
|
|
200
|
+
).toLowerCase();
|
|
201
|
+
return words.every((word) => hay.includes(word));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// --- diffs ----------------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* A line diff for edit tool calls.
|
|
208
|
+
*
|
|
209
|
+
* Longest common subsequence rather than a naive line-by-line compare: without
|
|
210
|
+
* it, inserting one line at the top marks every following line as changed, and
|
|
211
|
+
* the reader cannot see what actually happened.
|
|
212
|
+
*/
|
|
213
|
+
function renderDiff(before, after) {
|
|
214
|
+
const a = before.split("\n");
|
|
215
|
+
const b = after.split("\n");
|
|
216
|
+
const table = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
|
|
217
|
+
|
|
218
|
+
for (let i = a.length - 1; i >= 0; i--) {
|
|
219
|
+
for (let j = b.length - 1; j >= 0; j--) {
|
|
220
|
+
table[i][j] = a[i] === b[j] ? table[i + 1][j + 1] + 1 : Math.max(table[i + 1][j], table[i][j + 1]);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const out = el("pre", "diff");
|
|
225
|
+
let i = 0;
|
|
226
|
+
let j = 0;
|
|
227
|
+
while (i < a.length && j < b.length) {
|
|
228
|
+
if (a[i] === b[j]) {
|
|
229
|
+
out.appendChild(el("div", "d-same", " " + a[i]));
|
|
230
|
+
i++;
|
|
231
|
+
j++;
|
|
232
|
+
} else if (table[i + 1][j] >= table[i][j + 1]) {
|
|
233
|
+
out.appendChild(el("div", "d-del", "- " + a[i++]));
|
|
234
|
+
} else {
|
|
235
|
+
out.appendChild(el("div", "d-add", "+ " + b[j++]));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
while (i < a.length) out.appendChild(el("div", "d-del", "- " + a[i++]));
|
|
239
|
+
while (j < b.length) out.appendChild(el("div", "d-add", "+ " + b[j++]));
|
|
240
|
+
return out;
|
|
241
|
+
}
|
|
242
|
+
`;
|
|
243
|
+
/**
|
|
244
|
+
* Backticks are written as placeholders and substituted here.
|
|
245
|
+
*
|
|
246
|
+
* The first version concatenated `String.raw` fragments around quoted
|
|
247
|
+
* backticks — which ends the raw template at the first `+`, so everything
|
|
248
|
+
* after it was an ordinary template literal and every `\n` in the client code
|
|
249
|
+
* became a real newline inside a string. The page parsed as far as that line
|
|
250
|
+
* and then died. One template, no concatenation, avoids the whole class.
|
|
251
|
+
*/
|
|
252
|
+
export const CLIENT_SCRIPT = RAW.replaceAll("@@FENCE@@", "```").replaceAll("@@BT@@", "`");
|
|
253
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsOrB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC"}
|
package/dist/page.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PAGE: string;
|