wyrm-mcp 7.2.0 → 7.2.2
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/LICENSE +26 -667
- package/NOTICE +14 -33
- package/dist/activation.d.ts.map +1 -1
- package/dist/activation.js +1 -44
- package/dist/activation.js.map +1 -1
- package/dist/agent-daemon.js +4 -281
- package/dist/agent-loop.js +7 -332
- package/dist/analytics.js +13 -236
- package/dist/attribution.js +1 -49
- package/dist/audit.js +2 -457
- package/dist/auto-capture.js +3 -138
- package/dist/auto-orchestrator.js +1 -325
- package/dist/autoconfig.js +39 -840
- package/dist/buddy-runner.js +1 -109
- package/dist/buddy.js +14 -564
- package/dist/build-flags.js +1 -17
- package/dist/capabilities.js +3 -183
- package/dist/capture.js +1 -56
- package/dist/causality.js +6 -107
- package/dist/cli.js +20 -281
- package/dist/cloud/cli.js +5 -541
- package/dist/cloud/client.js +1 -221
- package/dist/cloud/crypto.js +1 -85
- package/dist/cloud/machine-id.js +2 -113
- package/dist/cloud/recovery.js +1 -60
- package/dist/cloud/sync-engine.js +7 -543
- package/dist/cloud-backup.js +5 -579
- package/dist/cloud-profile.js +1 -138
- package/dist/cloud-sync-entrypoint.js +1 -47
- package/dist/cloud-sync.js +2 -309
- package/dist/constellation.js +12 -168
- package/dist/context-build-budgeted.js +4 -144
- package/dist/context-ranking.js +1 -69
- package/dist/crypto.js +1 -179
- package/dist/daemon-write-endpoint.js +1 -290
- package/dist/daemon-writer.js +2 -406
- package/dist/database.js +43 -1110
- package/dist/deprecations.js +2 -162
- package/dist/design.js +13 -141
- package/dist/event-replication.js +1 -112
- package/dist/events-sse.js +7 -43
- package/dist/events.js +6 -238
- package/dist/failure-patterns.js +42 -659
- package/dist/federation.js +12 -236
- package/dist/goals.js +13 -101
- package/dist/golden.js +3 -355
- package/dist/handlers/agent.js +4 -165
- package/dist/handlers/alias-adapters.js +1 -129
- package/dist/handlers/aliases.js +1 -171
- package/dist/handlers/audit.js +1 -87
- package/dist/handlers/boundary.js +1 -221
- package/dist/handlers/capture.js +73 -1109
- package/dist/handlers/causality.js +7 -114
- package/dist/handlers/cloud.js +85 -382
- package/dist/handlers/companion.js +28 -459
- package/dist/handlers/datalake.js +7 -187
- package/dist/handlers/dispatch-context.js +0 -22
- package/dist/handlers/entity.js +25 -256
- package/dist/handlers/events.js +16 -335
- package/dist/handlers/failure.js +13 -340
- package/dist/handlers/goals.js +4 -296
- package/dist/handlers/intelligence.js +126 -674
- package/dist/handlers/invoicing.js +1 -70
- package/dist/handlers/mcpclient.js +6 -137
- package/dist/handlers/orchestration.js +40 -125
- package/dist/handlers/output-schemas.js +1 -24
- package/dist/handlers/presence.js +3 -99
- package/dist/handlers/project.js +28 -182
- package/dist/handlers/prompts.js +6 -157
- package/dist/handlers/quest.js +4 -224
- package/dist/handlers/recall.js +11 -218
- package/dist/handlers/registry.js +1 -167
- package/dist/handlers/resources.js +1 -288
- package/dist/handlers/review.js +11 -74
- package/dist/handlers/run.js +17 -487
- package/dist/handlers/search.js +15 -326
- package/dist/handlers/session.js +28 -615
- package/dist/handlers/share.js +8 -184
- package/dist/handlers/shims.js +1 -464
- package/dist/handlers/skill.js +67 -449
- package/dist/handlers/survivors.js +1 -120
- package/dist/handlers/symbols.js +8 -109
- package/dist/handlers/syncops.js +4 -302
- package/dist/handlers/types.js +1 -27
- package/dist/harvest.js +5 -191
- package/dist/hours.js +7 -156
- package/dist/http-auth.js +3 -321
- package/dist/http-fast.js +21 -1137
- package/dist/icons.js +1 -47
- package/dist/index.js +2 -924
- package/dist/indexer.js +4 -145
- package/dist/intelligence.js +31 -261
- package/dist/internal-dispatch.js +3 -212
- package/dist/keyset.js +1 -110
- package/dist/knowledge-graph.js +12 -176
- package/dist/license.d.ts +11 -0
- package/dist/license.d.ts.map +1 -1
- package/dist/license.js +2 -414
- package/dist/license.js.map +1 -1
- package/dist/logger.js +2 -199
- package/dist/maintenance.js +2 -148
- package/dist/mcp-client.js +6 -262
- package/dist/memory-artifacts.js +30 -449
- package/dist/migrate-prompt.js +2 -124
- package/dist/migrations.js +40 -655
- package/dist/performance.js +1 -228
- package/dist/presence.js +11 -140
- package/dist/priority-embed.js +5 -164
- package/dist/providers/embedding-provider.js +1 -196
- package/dist/readonly-gate.js +1 -29
- package/dist/rehydration.js +9 -157
- package/dist/reindex.js +1 -88
- package/dist/render-target.js +21 -514
- package/dist/render.js +4 -280
- package/dist/repl-guard.js +1 -173
- package/dist/replication-daemon-entrypoint.js +1 -31
- package/dist/replication-daemon.js +2 -262
- package/dist/resilience.js +1 -591
- package/dist/reverse-bridge.js +5 -360
- package/dist/security.js +1 -244
- package/dist/session-seen.js +3 -51
- package/dist/setup.js +1 -260
- package/dist/skill-author.js +5 -168
- package/dist/spec-kit.js +1 -191
- package/dist/sqlite-busy.js +1 -154
- package/dist/statusline.js +11 -315
- package/dist/sub-agent.js +13 -262
- package/dist/summarizer.js +13 -139
- package/dist/symbols.js +7 -283
- package/dist/sync.js +5 -359
- package/dist/tasks-dispatch.js +1 -84
- package/dist/tasks.js +1 -282
- package/dist/token-budget.js +1 -143
- package/dist/tool-analytics.js +7 -129
- package/dist/tool-annotations.js +1 -365
- package/dist/tool-manifest-v2.json +1 -1
- package/dist/tool-manifest.json +1 -1
- package/dist/tool-profiles.js +1 -75
- package/dist/trace-harvest.js +6 -244
- package/dist/types.js +1 -30
- package/dist/ui-dashboard.js +41 -50
- package/dist/ulid.js +1 -81
- package/dist/validate.js +1 -129
- package/dist/vault.js +1 -534
- package/dist/vectors.js +3 -184
- package/dist/version-check.js +4 -136
- package/dist/visibility.js +19 -155
- package/dist/wyrm-cli.js +98 -2451
- package/dist/wyrm-cli.js.map +1 -1
- package/dist/wyrm-guard.js +14 -424
- package/dist/wyrm-loop.js +3 -150
- package/dist/wyrm-manifest.json +1 -1
- package/dist/wyrm-statusline-daemon.js +1 -11
- package/dist/wyrm-statusline.js +4 -56
- package/dist/wyrm-ui.js +9 -77
- package/package.json +4 -2
package/dist/trace-harvest.js
CHANGED
|
@@ -1,244 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* WYRM_EXTRACT_MODEL / deterministic fallback, NEVER a cloud LLM, Article III):
|
|
8
|
-
*
|
|
9
|
-
* 1. Claude Code session JSONL — one JSON object per line, each
|
|
10
|
-
* { message: { role, content }, … } (the same shape
|
|
11
|
-
* scripts/hooks/wyrm-session-capture.mjs already parses). User prose +
|
|
12
|
-
* assistant text are kept; tool-result / system-reminder blocks dropped.
|
|
13
|
-
* 2. ~/.dragon/traces — the dragon-cli flywheel trace records. Tolerant of
|
|
14
|
-
* both line-delimited JSON and a top-level JSON array; each record's
|
|
15
|
-
* prompt/response/text/content fields are harvested.
|
|
16
|
-
* 3. WYRM_TRACE_TOOL_CALLS output — the `tool_call` Live Memory events the
|
|
17
|
-
* PostToolUse hook emits ({ kind:'tool_call', actor, payload, … }) or the
|
|
18
|
-
* raw stdin shape the hook reads ({ tool_name, tool_input, … }). Collapsed
|
|
19
|
-
* into a deterministic per-tool activity summary.
|
|
20
|
-
*
|
|
21
|
-
* SECRET REDACTION: every harvested segment passes through redactSecrets()
|
|
22
|
-
* BEFORE extraction, so an API key / bearer token / password that scrolled
|
|
23
|
-
* through a transcript never lands in the review queue. Deterministic, no
|
|
24
|
-
* network. Tool-call payloads are collapsed to keys (never values) for the same
|
|
25
|
-
* reason — a secret passed as a tool argument is summarized, not stored.
|
|
26
|
-
*
|
|
27
|
-
* Pure: parsing + redaction are total string functions (no I/O, no clock, no
|
|
28
|
-
* RNG). The MCP handler injects the DB writes + the extractor.
|
|
29
|
-
*
|
|
30
|
-
* @copyright 2026 Ghost Protocol (Pvt) Ltd.
|
|
31
|
-
* @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
|
|
32
|
-
*/
|
|
33
|
-
/** Control chars (ANSI/BEL/NUL) must never reach the review queue or a TUI. */
|
|
34
|
-
// eslint-disable-next-line no-control-regex
|
|
35
|
-
const CTRL = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
36
|
-
/**
|
|
37
|
-
* Redact common secret shapes from a string so they never enter the review
|
|
38
|
-
* queue. Deterministic + offline. Conservative (favours over-redaction): the
|
|
39
|
-
* goal is "a leaked credential is never stored", not perfect classification.
|
|
40
|
-
* Each rule replaces the SECRET portion with `[REDACTED]`, preserving
|
|
41
|
-
* surrounding prose so the candidate is still meaningful.
|
|
42
|
-
*/
|
|
43
|
-
export function redactSecrets(input) {
|
|
44
|
-
if (!input)
|
|
45
|
-
return '';
|
|
46
|
-
let s = input;
|
|
47
|
-
// High-entropy / vendor-prefixed token shapes (order matters — specific first).
|
|
48
|
-
const rules = [
|
|
49
|
-
// sk-... / sk-ant-api03-... / rk_live_... (OpenAI/Anthropic/Stripe-style);
|
|
50
|
-
// the token body may carry internal -/_ separators (sk-ant-api03-<rand>).
|
|
51
|
-
[/\b(?:sk|rk|pk)[-_][A-Za-z0-9][A-Za-z0-9_-]{14,}\b/g, '[REDACTED]'],
|
|
52
|
-
// GitHub tokens (ghp_/gho_/ghu_/ghs_/ghr_) + fine-grained github_pat_
|
|
53
|
-
[/\bgh[posru]_[A-Za-z0-9]{20,}\b/g, '[REDACTED]'],
|
|
54
|
-
[/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, '[REDACTED]'],
|
|
55
|
-
// AWS access key id
|
|
56
|
-
[/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g, '[REDACTED]'],
|
|
57
|
-
// Slack tokens
|
|
58
|
-
[/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, '[REDACTED]'],
|
|
59
|
-
// Google API key
|
|
60
|
-
[/\bAIza[A-Za-z0-9_-]{30,}\b/g, '[REDACTED]'],
|
|
61
|
-
// JWTs (three dot-separated base64url segments)
|
|
62
|
-
[/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g, '[REDACTED]'],
|
|
63
|
-
// Authorization: Bearer <token>
|
|
64
|
-
[/\b([Bb]earer)\s+[A-Za-z0-9._-]{12,}/g, '$1 [REDACTED]'],
|
|
65
|
-
// key=value / "key": "value" for secret-ish key names (api_key, token,
|
|
66
|
-
// password, secret, passwd, authorization, access_token, private_key).
|
|
67
|
-
[/((?:api[_-]?key|secret|token|password|passwd|auth(?:orization)?|access[_-]?token|private[_-]?key|client[_-]?secret)["']?\s*[:=]\s*["']?)([A-Za-z0-9._/+\-]{6,})/gi, '$1[REDACTED]'],
|
|
68
|
-
];
|
|
69
|
-
for (const [re, repl] of rules)
|
|
70
|
-
s = s.replace(re, repl);
|
|
71
|
-
return s;
|
|
72
|
-
}
|
|
73
|
-
/** Pull plain text out of a Claude/Anthropic message `content` (string or block array). */
|
|
74
|
-
function extractMessageText(content) {
|
|
75
|
-
if (content == null)
|
|
76
|
-
return '';
|
|
77
|
-
if (typeof content === 'string')
|
|
78
|
-
return content;
|
|
79
|
-
if (!Array.isArray(content))
|
|
80
|
-
return '';
|
|
81
|
-
const out = [];
|
|
82
|
-
for (const b of content) {
|
|
83
|
-
if (typeof b === 'string') {
|
|
84
|
-
out.push(b);
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (b && typeof b === 'object') {
|
|
88
|
-
const block = b;
|
|
89
|
-
if (block.type === 'text' && typeof block.text === 'string')
|
|
90
|
-
out.push(block.text);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return out.join('\n');
|
|
94
|
-
}
|
|
95
|
-
/** Tidy a candidate chunk: strip control chars, collapse whitespace, clip. */
|
|
96
|
-
function clean(text) {
|
|
97
|
-
return redactSecrets(text).replace(CTRL, '').replace(/[ \t]+/g, ' ').replace(/\n{3,}/g, '\n\n').trim().slice(0, 4000);
|
|
98
|
-
}
|
|
99
|
-
/** Parse a JSONL/array trace body into per-line JSON objects (tolerant). */
|
|
100
|
-
function parseRecords(raw) {
|
|
101
|
-
const trimmed = raw.trim();
|
|
102
|
-
if (!trimmed)
|
|
103
|
-
return [];
|
|
104
|
-
// Whole-body JSON array (dragon traces sometimes export one).
|
|
105
|
-
if (trimmed.startsWith('[')) {
|
|
106
|
-
try {
|
|
107
|
-
const arr = JSON.parse(trimmed);
|
|
108
|
-
if (Array.isArray(arr))
|
|
109
|
-
return arr.filter((x) => !!x && typeof x === 'object');
|
|
110
|
-
}
|
|
111
|
-
catch { /* fall through to line mode */ }
|
|
112
|
-
}
|
|
113
|
-
const out = [];
|
|
114
|
-
for (const line of trimmed.split('\n')) {
|
|
115
|
-
const t = line.trim();
|
|
116
|
-
if (!t || (t[0] !== '{' && t[0] !== '['))
|
|
117
|
-
continue;
|
|
118
|
-
try {
|
|
119
|
-
const obj = JSON.parse(t);
|
|
120
|
-
if (obj && typeof obj === 'object' && !Array.isArray(obj))
|
|
121
|
-
out.push(obj);
|
|
122
|
-
}
|
|
123
|
-
catch { /* skip non-JSON line */ }
|
|
124
|
-
}
|
|
125
|
-
return out;
|
|
126
|
-
}
|
|
127
|
-
/** Claude Code session JSONL → user/assistant prose segments. */
|
|
128
|
-
export function parseClaudeJsonl(raw) {
|
|
129
|
-
const out = [];
|
|
130
|
-
for (const obj of parseRecords(raw)) {
|
|
131
|
-
const msg = (obj.message && typeof obj.message === 'object' ? obj.message : obj);
|
|
132
|
-
const role = String(msg.role ?? obj.role ?? '');
|
|
133
|
-
if (role !== 'user' && role !== 'assistant')
|
|
134
|
-
continue;
|
|
135
|
-
const text = extractMessageText(msg.content).trim();
|
|
136
|
-
if (!text)
|
|
137
|
-
continue;
|
|
138
|
-
// Drop tool-result / system-reminder blocks (same rule as the capture hook).
|
|
139
|
-
if (role === 'user' && (text.startsWith('<') || text.startsWith('[{')))
|
|
140
|
-
continue;
|
|
141
|
-
const cleaned = clean(text);
|
|
142
|
-
if (cleaned.length >= 12)
|
|
143
|
-
out.push({ role, text: cleaned });
|
|
144
|
-
}
|
|
145
|
-
return out;
|
|
146
|
-
}
|
|
147
|
-
/** dragon-cli flywheel trace → prose segments (prompt/response/text/content). */
|
|
148
|
-
export function parseDragonTrace(raw) {
|
|
149
|
-
const out = [];
|
|
150
|
-
const fields = [['prompt', 'user'], ['input', 'user'], ['response', 'assistant'], ['output', 'assistant'], ['text', 'note'], ['content', 'note']];
|
|
151
|
-
for (const rec of parseRecords(raw)) {
|
|
152
|
-
for (const [field, role] of fields) {
|
|
153
|
-
const v = rec[field];
|
|
154
|
-
const text = typeof v === 'string' ? v : extractMessageText(v);
|
|
155
|
-
if (!text)
|
|
156
|
-
continue;
|
|
157
|
-
const cleaned = clean(text);
|
|
158
|
-
if (cleaned.length >= 12)
|
|
159
|
-
out.push({ role, text: cleaned });
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return out;
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* WYRM_TRACE_TOOL_CALLS output → ONE deterministic activity-summary segment.
|
|
166
|
-
*
|
|
167
|
-
* Accepts both the Live Memory `tool_call` event shape ({ kind:'tool_call',
|
|
168
|
-
* actor:<toolName>, payload }) and the raw PostToolUse stdin shape
|
|
169
|
-
* ({ tool_name, tool_input }). Payloads are collapsed to argument KEYS only
|
|
170
|
-
* (never values) so a secret passed as a tool argument is never stored. The
|
|
171
|
-
* order of first appearance is preserved (deterministic); counts are summed.
|
|
172
|
-
*/
|
|
173
|
-
export function parseToolCalls(raw) {
|
|
174
|
-
const counts = new Map();
|
|
175
|
-
const order = [];
|
|
176
|
-
for (const rec of parseRecords(raw)) {
|
|
177
|
-
const kind = String(rec.kind ?? '');
|
|
178
|
-
let tool = '';
|
|
179
|
-
if (kind === 'tool_call')
|
|
180
|
-
tool = String(rec.actor ?? rec.tool ?? '');
|
|
181
|
-
else if (typeof rec.tool_name === 'string')
|
|
182
|
-
tool = rec.tool_name;
|
|
183
|
-
else if (typeof rec.tool === 'string')
|
|
184
|
-
tool = rec.tool;
|
|
185
|
-
tool = tool.replace(CTRL, '').trim().slice(0, 80);
|
|
186
|
-
if (!tool)
|
|
187
|
-
continue;
|
|
188
|
-
if (!counts.has(tool))
|
|
189
|
-
order.push(tool);
|
|
190
|
-
counts.set(tool, (counts.get(tool) ?? 0) + 1);
|
|
191
|
-
}
|
|
192
|
-
if (order.length === 0)
|
|
193
|
-
return [];
|
|
194
|
-
const summary = order.map((t) => `${t}×${counts.get(t)}`).join(', ');
|
|
195
|
-
return [{ role: 'tool', text: `Tool activity in this run: ${summary}.` }];
|
|
196
|
-
}
|
|
197
|
-
/** Sniff the trace format from the content (best-effort, deterministic). */
|
|
198
|
-
export function detectTraceFormat(raw) {
|
|
199
|
-
const recs = parseRecords(raw).slice(0, 50);
|
|
200
|
-
if (recs.length === 0)
|
|
201
|
-
return 'claude-jsonl';
|
|
202
|
-
let toolish = 0, claudeish = 0;
|
|
203
|
-
for (const r of recs) {
|
|
204
|
-
if (r.kind === 'tool_call' || typeof r.tool_name === 'string')
|
|
205
|
-
toolish++;
|
|
206
|
-
const msg = (r.message && typeof r.message === 'object' ? r.message : r);
|
|
207
|
-
const role = msg.role ?? r.role;
|
|
208
|
-
if (role === 'user' || role === 'assistant' || role === 'system')
|
|
209
|
-
claudeish++;
|
|
210
|
-
}
|
|
211
|
-
if (toolish > 0 && toolish >= claudeish)
|
|
212
|
-
return 'tool-calls';
|
|
213
|
-
if (claudeish > 0)
|
|
214
|
-
return 'claude-jsonl';
|
|
215
|
-
return 'dragon';
|
|
216
|
-
}
|
|
217
|
-
/** Parse a trace body into normalized segments using the chosen (or sniffed) format. */
|
|
218
|
-
export function parseTrace(raw, format = 'auto') {
|
|
219
|
-
const fmt = format === 'auto' ? detectTraceFormat(raw) : format;
|
|
220
|
-
const segments = fmt === 'tool-calls' ? parseToolCalls(raw) :
|
|
221
|
-
fmt === 'dragon' ? parseDragonTrace(raw) :
|
|
222
|
-
parseClaudeJsonl(raw);
|
|
223
|
-
return { segments, format: fmt };
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Fold parsed segments into ONE prose blob for the extractor. Deterministic
|
|
227
|
-
* (preserves segment order); bounded so a huge transcript can't materialize an
|
|
228
|
-
* unbounded segment array downstream (the deterministic extractor splits the
|
|
229
|
-
* FULL text). Caps total chars; drops the tail past the cap rather than
|
|
230
|
-
* silently mangling.
|
|
231
|
-
*/
|
|
232
|
-
export function segmentsToText(segments, maxChars = 24_000) {
|
|
233
|
-
const parts = [];
|
|
234
|
-
let total = 0;
|
|
235
|
-
for (const s of segments) {
|
|
236
|
-
const line = s.text;
|
|
237
|
-
if (total + line.length > maxChars)
|
|
238
|
-
break;
|
|
239
|
-
parts.push(line);
|
|
240
|
-
total += line.length + 1;
|
|
241
|
-
}
|
|
242
|
-
return parts.join('\n');
|
|
243
|
-
}
|
|
244
|
-
//# sourceMappingURL=trace-harvest.js.map
|
|
1
|
+
const l=/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;function g(s){if(!s)return"";let o=s;const e=[[/\b(?:sk|rk|pk)[-_][A-Za-z0-9][A-Za-z0-9_-]{14,}\b/g,"[REDACTED]"],[/\bgh[posru]_[A-Za-z0-9]{20,}\b/g,"[REDACTED]"],[/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,"[REDACTED]"],[/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,"[REDACTED]"],[/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g,"[REDACTED]"],[/\bAIza[A-Za-z0-9_-]{30,}\b/g,"[REDACTED]"],[/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g,"[REDACTED]"],[/\b([Bb]earer)\s+[A-Za-z0-9._-]{12,}/g,"$1 [REDACTED]"],[/((?:api[_-]?key|secret|token|password|passwd|auth(?:orization)?|access[_-]?token|private[_-]?key|client[_-]?secret)["']?\s*[:=]\s*["']?)([A-Za-z0-9._/+\-]{6,})/gi,"$1[REDACTED]"]];for(const[r,t]of e)o=o.replace(r,t);return o}function u(s){if(s==null)return"";if(typeof s=="string")return s;if(!Array.isArray(s))return"";const o=[];for(const e of s){if(typeof e=="string"){o.push(e);continue}if(e&&typeof e=="object"){const r=e;r.type==="text"&&typeof r.text=="string"&&o.push(r.text)}}return o.join(`
|
|
2
|
+
`)}function p(s){return g(s).replace(l,"").replace(/[ \t]+/g," ").replace(/\n{3,}/g,`
|
|
3
|
+
|
|
4
|
+
`).trim().slice(0,4e3)}function i(s){const o=s.trim();if(!o)return[];if(o.startsWith("["))try{const r=JSON.parse(o);if(Array.isArray(r))return r.filter(t=>!!t&&typeof t=="object")}catch{}const e=[];for(const r of o.split(`
|
|
5
|
+
`)){const t=r.trim();if(!(!t||t[0]!=="{"&&t[0]!=="["))try{const c=JSON.parse(t);c&&typeof c=="object"&&!Array.isArray(c)&&e.push(c)}catch{}}return e}function A(s){const o=[];for(const e of i(s)){const r=e.message&&typeof e.message=="object"?e.message:e,t=String(r.role??e.role??"");if(t!=="user"&&t!=="assistant")continue;const c=u(r.content).trim();if(!c||t==="user"&&(c.startsWith("<")||c.startsWith("[{")))continue;const n=p(c);n.length>=12&&o.push({role:t,text:n})}return o}function m(s){const o=[],e=[["prompt","user"],["input","user"],["response","assistant"],["output","assistant"],["text","note"],["content","note"]];for(const r of i(s))for(const[t,c]of e){const n=r[t],a=typeof n=="string"?n:u(n);if(!a)continue;const f=p(a);f.length>=12&&o.push({role:c,text:f})}return o}function b(s){const o=new Map,e=[];for(const t of i(s)){const c=String(t.kind??"");let n="";c==="tool_call"?n=String(t.actor??t.tool??""):typeof t.tool_name=="string"?n=t.tool_name:typeof t.tool=="string"&&(n=t.tool),n=n.replace(l,"").trim().slice(0,80),n&&(o.has(n)||e.push(n),o.set(n,(o.get(n)??0)+1))}return e.length===0?[]:[{role:"tool",text:`Tool activity in this run: ${e.map(t=>`${t}\xD7${o.get(t)}`).join(", ")}.`}]}function x(s){const o=i(s).slice(0,50);if(o.length===0)return"claude-jsonl";let e=0,r=0;for(const t of o){(t.kind==="tool_call"||typeof t.tool_name=="string")&&e++;const n=(t.message&&typeof t.message=="object"?t.message:t).role??t.role;(n==="user"||n==="assistant"||n==="system")&&r++}return e>0&&e>=r?"tool-calls":r>0?"claude-jsonl":"dragon"}function y(s,o="auto"){const e=o==="auto"?x(s):o;return{segments:e==="tool-calls"?b(s):e==="dragon"?m(s):A(s),format:e}}function h(s,o=24e3){const e=[];let r=0;for(const t of s){const c=t.text;if(r+c.length>o)break;e.push(c),r+=c.length+1}return e.join(`
|
|
6
|
+
`)}export{x as detectTraceFormat,A as parseClaudeJsonl,m as parseDragonTrace,b as parseToolCalls,y as parseTrace,g as redactSecrets,h as segmentsToText};
|
package/dist/types.js
CHANGED
|
@@ -1,30 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Wyrm Types - Core type definitions
|
|
3
|
-
*
|
|
4
|
-
* @copyright 2026 Ghost Protocol (Pvt) Ltd.
|
|
5
|
-
* @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
|
|
6
|
-
* @module types
|
|
7
|
-
* @version 3.0.0
|
|
8
|
-
*/
|
|
9
|
-
export const DEFAULT_CONFIG = {
|
|
10
|
-
database: {
|
|
11
|
-
wal: true,
|
|
12
|
-
cacheSize: 64000,
|
|
13
|
-
},
|
|
14
|
-
encryption: {
|
|
15
|
-
enabled: false,
|
|
16
|
-
},
|
|
17
|
-
logging: {
|
|
18
|
-
level: 'info',
|
|
19
|
-
console: true,
|
|
20
|
-
},
|
|
21
|
-
http: {
|
|
22
|
-
port: 3333,
|
|
23
|
-
host: '127.0.0.1',
|
|
24
|
-
},
|
|
25
|
-
sync: {
|
|
26
|
-
autoImport: true,
|
|
27
|
-
autoExport: false,
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
//# sourceMappingURL=types.js.map
|
|
1
|
+
const e={database:{wal:!0,cacheSize:64e3},encryption:{enabled:!1},logging:{level:"info",console:!0},http:{port:3333,host:"127.0.0.1"},sync:{autoImport:!0,autoExport:!1}};export{e as DEFAULT_CONFIG};
|
package/dist/ui-dashboard.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Wyrm Visual Web Dashboard — Self-contained HTML SPA
|
|
3
|
-
*
|
|
4
|
-
* @copyright 2026 Ghost Protocol (Pvt) Ltd.
|
|
5
|
-
* @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
|
|
6
|
-
*/
|
|
7
|
-
export function getUIDashboardHTML() {
|
|
8
|
-
return `<!DOCTYPE html>
|
|
1
|
+
function e(){return`<!DOCTYPE html>
|
|
9
2
|
<html lang="en">
|
|
10
3
|
<head>
|
|
11
4
|
<meta charset="UTF-8">
|
|
@@ -261,7 +254,7 @@ main { padding: calc(var(--nav-h) + 24px) 24px 24px; max-width: 1200px; margin:
|
|
|
261
254
|
(function() {
|
|
262
255
|
'use strict';
|
|
263
256
|
|
|
264
|
-
//
|
|
257
|
+
// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
265
258
|
function el(tag, cls, text) {
|
|
266
259
|
const e = document.createElement(tag);
|
|
267
260
|
if (cls) e.className = cls;
|
|
@@ -313,7 +306,7 @@ async function apiPost(path) {
|
|
|
313
306
|
|
|
314
307
|
function truncate(s, n) {
|
|
315
308
|
if (!s) return '';
|
|
316
|
-
return s.length > n ? s.slice(0, n) + '
|
|
309
|
+
return s.length > n ? s.slice(0, n) + '\u2026' : s;
|
|
317
310
|
}
|
|
318
311
|
|
|
319
312
|
function clearEl(e) {
|
|
@@ -381,7 +374,7 @@ function staleBar(staleness) {
|
|
|
381
374
|
return wrap;
|
|
382
375
|
}
|
|
383
376
|
|
|
384
|
-
//
|
|
377
|
+
// \u2500\u2500 Router \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
385
378
|
const TABS = ['overview', 'impact', 'memories', 'quests', 'truths', 'skills', 'review'];
|
|
386
379
|
let currentTab = '';
|
|
387
380
|
// Set from GET /ui/account.readonly at boot (WYRM_UI_READONLY=1 on the server).
|
|
@@ -413,7 +406,7 @@ document.querySelectorAll('.tab-btn').forEach(btn => {
|
|
|
413
406
|
});
|
|
414
407
|
window.addEventListener('hashchange', router);
|
|
415
408
|
|
|
416
|
-
//
|
|
409
|
+
// \u2500\u2500 Overview \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
417
410
|
async function loadOverview() {
|
|
418
411
|
const pane = document.getElementById('pane-overview');
|
|
419
412
|
clearEl(pane);
|
|
@@ -456,13 +449,13 @@ async function loadOverview() {
|
|
|
456
449
|
card.replaceChild(vEl, skel);
|
|
457
450
|
}
|
|
458
451
|
});
|
|
459
|
-
// Recent sessions
|
|
452
|
+
// Recent sessions \u2014 remove skeleton list, then insert real data
|
|
460
453
|
pane.querySelector('.list')?.remove();
|
|
461
454
|
const sl = el('div', 'sessions-list');
|
|
462
455
|
const sessions = data.recent_sessions || [];
|
|
463
456
|
if (sessions.length === 0) {
|
|
464
457
|
const em = el('div', 'empty');
|
|
465
|
-
em.appendChild(el('div', 'empty-icon', '
|
|
458
|
+
em.appendChild(el('div', 'empty-icon', '\u{1F4ED}'));
|
|
466
459
|
em.appendChild(el('div', null, 'No sessions yet'));
|
|
467
460
|
sl.appendChild(em);
|
|
468
461
|
} else {
|
|
@@ -477,7 +470,7 @@ async function loadOverview() {
|
|
|
477
470
|
} catch(e) { showToast(String(e), 'error'); }
|
|
478
471
|
}
|
|
479
472
|
|
|
480
|
-
//
|
|
473
|
+
// \u2500\u2500 Memories \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
481
474
|
let memPage = 1, memKind = '', memSearch = '', memDebounce = null;
|
|
482
475
|
|
|
483
476
|
async function loadMemories(page, kind, search) {
|
|
@@ -503,7 +496,7 @@ async function loadMemories(page, kind, search) {
|
|
|
503
496
|
const newList = el('div', 'list');
|
|
504
497
|
if (!data.items || data.items.length === 0) {
|
|
505
498
|
const em = el('div', 'empty');
|
|
506
|
-
em.appendChild(el('div', 'empty-icon', '
|
|
499
|
+
em.appendChild(el('div', 'empty-icon', '\u{1F9E0}'));
|
|
507
500
|
em.appendChild(el('div', null, 'No memory artifacts found'));
|
|
508
501
|
newList.appendChild(em);
|
|
509
502
|
} else {
|
|
@@ -551,7 +544,7 @@ function initMemoriesPane() {
|
|
|
551
544
|
const filters = el('div', 'filters');
|
|
552
545
|
const si = el('input', 'filter-input');
|
|
553
546
|
si.type = 'search';
|
|
554
|
-
si.placeholder = 'Search memories
|
|
547
|
+
si.placeholder = 'Search memories\u2026';
|
|
555
548
|
si.addEventListener('input', () => {
|
|
556
549
|
memSearch = si.value;
|
|
557
550
|
clearTimeout(memDebounce);
|
|
@@ -578,7 +571,7 @@ function initMemoriesPane() {
|
|
|
578
571
|
pane.insertBefore(filters, pane.firstChild);
|
|
579
572
|
}
|
|
580
573
|
|
|
581
|
-
//
|
|
574
|
+
// \u2500\u2500 Quests \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
582
575
|
async function loadQuests() {
|
|
583
576
|
const pane = document.getElementById('pane-quests');
|
|
584
577
|
clearEl(pane);
|
|
@@ -590,7 +583,7 @@ async function loadQuests() {
|
|
|
590
583
|
const col = el('div', 'kanban-col');
|
|
591
584
|
const hdr = el('div', 'kanban-header');
|
|
592
585
|
hdr.appendChild(el('span', 'kanban-title', colLabels[status]));
|
|
593
|
-
const cnt = el('span', 'kanban-count', '
|
|
586
|
+
const cnt = el('span', 'kanban-count', '\u2026');
|
|
594
587
|
hdr.appendChild(cnt);
|
|
595
588
|
col.appendChild(hdr);
|
|
596
589
|
col.dataset.status = status;
|
|
@@ -627,7 +620,7 @@ async function loadQuests() {
|
|
|
627
620
|
} catch(e) { showToast(String(e), 'error'); }
|
|
628
621
|
}
|
|
629
622
|
|
|
630
|
-
//
|
|
623
|
+
// \u2500\u2500 Truths \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
631
624
|
let truthPage = 1;
|
|
632
625
|
|
|
633
626
|
async function loadTruths(page) {
|
|
@@ -646,7 +639,7 @@ async function loadTruths(page) {
|
|
|
646
639
|
const list = el('div', 'list');
|
|
647
640
|
if (!data.items || data.items.length === 0) {
|
|
648
641
|
const em = el('div', 'empty');
|
|
649
|
-
em.appendChild(el('div', 'empty-icon', '
|
|
642
|
+
em.appendChild(el('div', 'empty-icon', '\u{1F4DA}'));
|
|
650
643
|
em.appendChild(el('div', null, 'No ground truths yet'));
|
|
651
644
|
list.appendChild(em);
|
|
652
645
|
} else {
|
|
@@ -656,7 +649,7 @@ async function loadTruths(page) {
|
|
|
656
649
|
row1.appendChild(el('span', 'truth-cat', t.category));
|
|
657
650
|
row1.appendChild(el('span', 'truth-key', t.key));
|
|
658
651
|
if (t.staleness != null && t.staleness > 0.7) {
|
|
659
|
-
row1.appendChild(el('span', null, '
|
|
652
|
+
row1.appendChild(el('span', null, '\u26A0\uFE0F'));
|
|
660
653
|
}
|
|
661
654
|
item.appendChild(row1);
|
|
662
655
|
item.appendChild(el('div', 'truth-value', truncate(t.value, 150)));
|
|
@@ -689,7 +682,7 @@ async function loadTruths(page) {
|
|
|
689
682
|
} catch(e) { showToast(String(e), 'error'); }
|
|
690
683
|
}
|
|
691
684
|
|
|
692
|
-
//
|
|
685
|
+
// \u2500\u2500 Review \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
693
686
|
async function loadReview() {
|
|
694
687
|
const pane = document.getElementById('pane-review');
|
|
695
688
|
clearEl(pane);
|
|
@@ -701,7 +694,7 @@ async function loadReview() {
|
|
|
701
694
|
const items = data.items || [];
|
|
702
695
|
if (items.length === 0) {
|
|
703
696
|
const em = el('div', 'empty');
|
|
704
|
-
em.appendChild(el('div', 'empty-icon', '
|
|
697
|
+
em.appendChild(el('div', 'empty-icon', '\u2705'));
|
|
705
698
|
em.appendChild(el('div', null, 'Review queue is empty'));
|
|
706
699
|
pane.appendChild(em);
|
|
707
700
|
return;
|
|
@@ -719,8 +712,8 @@ async function loadReview() {
|
|
|
719
712
|
// Approve/reject mutate the queue, withheld in read-only/public view.
|
|
720
713
|
if (!READONLY) {
|
|
721
714
|
const actions = el('div', 'review-actions');
|
|
722
|
-
const approveBtn = el('button', 'btn btn-approve', '
|
|
723
|
-
const rejectBtn = el('button', 'btn btn-reject', '
|
|
715
|
+
const approveBtn = el('button', 'btn btn-approve', '\u2713 Approve');
|
|
716
|
+
const rejectBtn = el('button', 'btn btn-reject', '\u2715 Reject');
|
|
724
717
|
approveBtn.addEventListener('click', async () => {
|
|
725
718
|
try {
|
|
726
719
|
await apiPost('/ui/review/' + m.id + '/approve');
|
|
@@ -729,7 +722,7 @@ async function loadReview() {
|
|
|
729
722
|
if (list.querySelectorAll('.review-item').length === 0) {
|
|
730
723
|
list.remove();
|
|
731
724
|
const em = el('div', 'empty');
|
|
732
|
-
em.appendChild(el('div', 'empty-icon', '
|
|
725
|
+
em.appendChild(el('div', 'empty-icon', '\u2705'));
|
|
733
726
|
em.appendChild(el('div', null, 'Review queue is empty'));
|
|
734
727
|
pane.appendChild(em);
|
|
735
728
|
}
|
|
@@ -743,7 +736,7 @@ async function loadReview() {
|
|
|
743
736
|
if (list.querySelectorAll('.review-item').length === 0) {
|
|
744
737
|
list.remove();
|
|
745
738
|
const em = el('div', 'empty');
|
|
746
|
-
em.appendChild(el('div', 'empty-icon', '
|
|
739
|
+
em.appendChild(el('div', 'empty-icon', '\u2705'));
|
|
747
740
|
em.appendChild(el('div', null, 'Review queue is empty'));
|
|
748
741
|
pane.appendChild(em);
|
|
749
742
|
}
|
|
@@ -759,7 +752,7 @@ async function loadReview() {
|
|
|
759
752
|
} catch(e) { showToast(String(e), 'error'); }
|
|
760
753
|
}
|
|
761
754
|
|
|
762
|
-
//
|
|
755
|
+
// \u2500\u2500 Skills \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
763
756
|
async function loadSkills() {
|
|
764
757
|
const pane = document.getElementById('pane-skills');
|
|
765
758
|
clearEl(pane);
|
|
@@ -770,7 +763,7 @@ async function loadSkills() {
|
|
|
770
763
|
const items = data.items || [];
|
|
771
764
|
if (items.length === 0) {
|
|
772
765
|
const em = el('div', 'empty');
|
|
773
|
-
em.appendChild(el('div', 'empty-icon', '
|
|
766
|
+
em.appendChild(el('div', 'empty-icon', '\u{1F9E9}'));
|
|
774
767
|
em.appendChild(el('div', null, 'No skills registered yet'));
|
|
775
768
|
pane.appendChild(em);
|
|
776
769
|
return;
|
|
@@ -798,7 +791,7 @@ async function loadSkills() {
|
|
|
798
791
|
} catch(e) { showToast(String(e), 'error'); }
|
|
799
792
|
}
|
|
800
793
|
|
|
801
|
-
//
|
|
794
|
+
// \u2500\u2500 Impact \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
802
795
|
function fmtNum(n) {
|
|
803
796
|
if (n >= 1000) return (n / 1000).toFixed(n >= 10000 ? 0 : 1).replace(/\\.0$/, '') + 'k';
|
|
804
797
|
return String(n || 0);
|
|
@@ -857,15 +850,15 @@ async function loadImpact() {
|
|
|
857
850
|
} catch(e) { showToast(String(e), 'error'); }
|
|
858
851
|
}
|
|
859
852
|
|
|
860
|
-
//
|
|
853
|
+
// \u2500\u2500 Memory detail modal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
861
854
|
let modalReq = 0;
|
|
862
855
|
async function openMemoryModal(id) {
|
|
863
856
|
const myReq = ++modalReq;
|
|
864
857
|
const ov = document.getElementById('modal-overlay');
|
|
865
858
|
const card = document.getElementById('modal-card');
|
|
866
859
|
clearEl(card);
|
|
867
|
-
const close = el('span', 'modal-close', '
|
|
868
|
-
card.appendChild(el('div', 'item-sub', 'Loading
|
|
860
|
+
const close = el('span', 'modal-close', '\u2715'); close.onclick = closeModal; card.appendChild(close);
|
|
861
|
+
card.appendChild(el('div', 'item-sub', 'Loading\u2026'));
|
|
869
862
|
ov.classList.add('open');
|
|
870
863
|
try {
|
|
871
864
|
const d = await apiFetch('/ui/memory?id=' + id);
|
|
@@ -873,7 +866,7 @@ async function openMemoryModal(id) {
|
|
|
873
866
|
if (myReq !== modalReq || !ov.classList.contains('open')) return;
|
|
874
867
|
const it = d.item;
|
|
875
868
|
clearEl(card);
|
|
876
|
-
const cl = el('span', 'modal-close', '
|
|
869
|
+
const cl = el('span', 'modal-close', '\u2715'); cl.onclick = closeModal; card.appendChild(cl);
|
|
877
870
|
if (!it) { card.appendChild(el('div', 'item-sub', 'Memory not found.')); return; }
|
|
878
871
|
const row = el('div', 'item-row');
|
|
879
872
|
if (it.kind) row.appendChild(kindBadge(it.kind));
|
|
@@ -902,12 +895,12 @@ async function openMemoryModal(id) {
|
|
|
902
895
|
const used = (it.access_count || 0), reused = (it.reuse_count || 0);
|
|
903
896
|
// "Surfaced" = times recalled (auto); "Confirmed helpful" = times an agent
|
|
904
897
|
// called wyrm_feedback after applying it. 0 here means no feedback yet, not broken.
|
|
905
|
-
card.appendChild(el('div', 'item-sub', 'Surfaced ' + used + '
|
|
898
|
+
card.appendChild(el('div', 'item-sub', 'Surfaced ' + used + '\xD7 \xB7 confirmed helpful ' + reused + '\xD7'));
|
|
906
899
|
} catch(e) { if (myReq === modalReq) closeModal(); }
|
|
907
900
|
}
|
|
908
901
|
function closeModal() { const ov = document.getElementById('modal-overlay'); if (ov) ov.classList.remove('open'); }
|
|
909
902
|
|
|
910
|
-
//
|
|
903
|
+
// \u2500\u2500 Account badge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
911
904
|
async function loadAccount() {
|
|
912
905
|
const box = document.getElementById('acct');
|
|
913
906
|
if (!box) return;
|
|
@@ -927,14 +920,14 @@ async function loadAccount() {
|
|
|
927
920
|
box.classList.add('ro');
|
|
928
921
|
box.title = 'Read-only public view';
|
|
929
922
|
} else {
|
|
930
|
-
box.appendChild(el('span', 'acct-caret', '
|
|
923
|
+
box.appendChild(el('span', 'acct-caret', '\u25BE'));
|
|
931
924
|
box.title = 'Click to switch account / home';
|
|
932
925
|
box.onclick = toggleAcctMenu;
|
|
933
926
|
}
|
|
934
927
|
} catch(e) { /* badge stays empty on failure */ }
|
|
935
928
|
}
|
|
936
929
|
|
|
937
|
-
//
|
|
930
|
+
// \u2500\u2500 Account switcher dropdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
938
931
|
let acctMenuOpen = false;
|
|
939
932
|
async function toggleAcctMenu(ev) {
|
|
940
933
|
if (ev) ev.stopPropagation();
|
|
@@ -943,7 +936,7 @@ async function toggleAcctMenu(ev) {
|
|
|
943
936
|
if (acctMenuOpen) { menu.classList.remove('open'); acctMenuOpen = false; return; }
|
|
944
937
|
clearEl(menu);
|
|
945
938
|
menu.appendChild(el('div', 'acct-menu-label', 'Switch account / home'));
|
|
946
|
-
menu.appendChild(el('div', 'acct-menu-label', 'Loading
|
|
939
|
+
menu.appendChild(el('div', 'acct-menu-label', 'Loading\u2026'));
|
|
947
940
|
menu.classList.add('open'); acctMenuOpen = true;
|
|
948
941
|
try {
|
|
949
942
|
const r = await fetch('/ui/homes');
|
|
@@ -956,9 +949,9 @@ async function toggleAcctMenu(ev) {
|
|
|
956
949
|
const it = el('div', 'acct-menu-item' + (h.active ? ' active' : ''));
|
|
957
950
|
const a = el('div', 'ai-acct');
|
|
958
951
|
a.appendChild(el('span', null, h.account || h.name));
|
|
959
|
-
if (h.active) a.appendChild(el('span', 'ai-check', '
|
|
952
|
+
if (h.active) a.appendChild(el('span', 'ai-check', '\u25CF active'));
|
|
960
953
|
it.appendChild(a);
|
|
961
|
-
it.appendChild(el('div', 'ai-meta', (h.tier || 'free') + '
|
|
954
|
+
it.appendChild(el('div', 'ai-meta', (h.tier || 'free') + ' \xB7 ' + h.name));
|
|
962
955
|
if (!h.active) it.addEventListener('click', () => switchHome(h.dbPath));
|
|
963
956
|
menu.appendChild(it);
|
|
964
957
|
});
|
|
@@ -990,22 +983,22 @@ document.getElementById('modal-overlay').addEventListener('click', (e) => {
|
|
|
990
983
|
});
|
|
991
984
|
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeModal(); });
|
|
992
985
|
|
|
993
|
-
//
|
|
986
|
+
// \u2500\u2500 Pagination helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
994
987
|
function buildPagination(current, total, onPage) {
|
|
995
988
|
const pgn = el('div', 'pagination');
|
|
996
|
-
const prev = el('button', 'page-btn', '
|
|
989
|
+
const prev = el('button', 'page-btn', '\u2190 Prev');
|
|
997
990
|
prev.disabled = current <= 1;
|
|
998
991
|
prev.addEventListener('click', () => onPage(current - 1));
|
|
999
992
|
pgn.appendChild(prev);
|
|
1000
993
|
pgn.appendChild(el('span', 'page-info', 'Page ' + current + ' of ' + total));
|
|
1001
|
-
const next = el('button', 'page-btn', 'Next
|
|
994
|
+
const next = el('button', 'page-btn', 'Next \u2192');
|
|
1002
995
|
next.disabled = current >= total;
|
|
1003
996
|
next.addEventListener('click', () => onPage(current + 1));
|
|
1004
997
|
pgn.appendChild(next);
|
|
1005
998
|
return pgn;
|
|
1006
999
|
}
|
|
1007
1000
|
|
|
1008
|
-
//
|
|
1001
|
+
// \u2500\u2500 Tab loader \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1009
1002
|
function loadTab(name) {
|
|
1010
1003
|
if (name === 'overview') loadOverview();
|
|
1011
1004
|
else if (name === 'impact') loadImpact();
|
|
@@ -1021,8 +1014,6 @@ function loadTab(name) {
|
|
|
1021
1014
|
// so the Review pane knows whether to show approve/reject controls.
|
|
1022
1015
|
loadAccount().then(router);
|
|
1023
1016
|
})();
|
|
1024
|
-
|
|
1017
|
+
<\/script>
|
|
1025
1018
|
</body>
|
|
1026
|
-
</html
|
|
1027
|
-
}
|
|
1028
|
-
//# sourceMappingURL=ui-dashboard.js.map
|
|
1019
|
+
</html>`}export{e as getUIDashboardHTML};
|