@lifeaitools/rdc-skills 0.24.37 → 0.24.39
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/.claude/settings.json +15 -15
- package/.claude-plugin/marketplace.json +21 -21
- package/.claude-plugin/plugin.json +1371 -1371
- package/.github/workflows/publish.yml +34 -34
- package/.github/workflows/self-test.yml +58 -58
- package/CHANGELOG.md +310 -310
- package/LICENSE +21 -21
- package/MANIFEST.md +221 -221
- package/README.md +377 -377
- package/README.sandbox.md +3 -3
- package/assets/watcher/viewer.html +164 -164
- package/bin/rdc-skills-mcp.mjs +316 -316
- package/commands/build.md +183 -183
- package/commands/collab.md +180 -180
- package/commands/deploy.md +152 -152
- package/commands/design.md +31 -31
- package/commands/edit.md +28 -28
- package/commands/fixit.md +124 -124
- package/commands/handoff.md +173 -173
- package/commands/help.md +95 -95
- package/commands/overnight.md +220 -220
- package/commands/plan.md +158 -158
- package/commands/preplan.md +131 -131
- package/commands/prototype.md +145 -145
- package/commands/release.md +49 -49
- package/commands/report.md +99 -99
- package/commands/review.md +120 -120
- package/commands/self-test.md +113 -113
- package/commands/status.md +86 -86
- package/commands/watch.md +98 -98
- package/commands/workitems.md +137 -137
- package/git-sha.json +1 -1
- package/guides/agent-bootstrap.md +295 -295
- package/guides/agents/backend.md +104 -104
- package/guides/agents/content.md +94 -94
- package/guides/agents/cs2.md +56 -56
- package/guides/agents/data.md +87 -87
- package/guides/agents/design.md +77 -77
- package/guides/agents/frontend.md +92 -92
- package/guides/agents/infrastructure.md +81 -81
- package/guides/agents/setup.md +281 -281
- package/guides/agents/verify.md +151 -151
- package/guides/agents/viz.md +106 -106
- package/guides/backend.md +146 -146
- package/guides/content.md +147 -147
- package/guides/cs2.md +190 -190
- package/guides/data.md +123 -123
- package/guides/design.md +116 -116
- package/guides/engineering-behavior.md +43 -43
- package/guides/escalation-protocol.md +125 -125
- package/guides/frontend.md +151 -151
- package/guides/history-md-spec.md +297 -297
- package/guides/infrastructure.md +179 -179
- package/guides/lessons-learned-spec.md +153 -153
- package/guides/output-contract.md +108 -108
- package/guides/publish-md-spec.md +289 -289
- package/guides/rdc-skills-startup.md +30 -30
- package/guides/verify.md +11 -11
- package/hooks/check-cwd.js +31 -31
- package/hooks/check-rdc-environment.js +164 -164
- package/hooks/check-services.js +6 -6
- package/hooks/check-stale-work-items.js +19 -19
- package/hooks/foreground-process-gate.js +128 -128
- package/hooks/gate-watchdog-selfcheck.js +257 -257
- package/hooks/hook-logger.js +25 -25
- package/hooks/lib/run-evidence-gate.mjs +241 -241
- package/hooks/no-stop-open-epics.js +127 -127
- package/hooks/post-tool-batch-gate.js +203 -203
- package/hooks/post-work-check.js +21 -21
- package/hooks/postcompact-log.js +13 -13
- package/hooks/precompact-log.js +13 -13
- package/hooks/rate-limit-retry.js +46 -46
- package/hooks/rdc-invocation-marker.js +157 -157
- package/hooks/rdc-output-contract-gate.js +94 -94
- package/hooks/require-work-item-on-commit.js +294 -294
- package/hooks/restart-brief.js +19 -19
- package/hooks/run-hidden-hook.ps1 +47 -47
- package/hooks/task-completed-gate.js +274 -274
- package/hooks/work-item-exit-gate.js +944 -944
- package/lib/catalog.mjs +236 -236
- package/lib/cloud-rewrite.mjs +155 -155
- package/package.json +56 -56
- package/rules/work-items-rpc.md +520 -520
- package/scaffold/templates/HISTORY.md.template +39 -39
- package/scaffold/templates/PUBLISH.md.template +21 -21
- package/scaffold/templates/brochure-studio-default.html +70 -70
- package/scripts/acceptance.mjs +502 -502
- package/scripts/fixtures/guides/bad-guide.md +15 -15
- package/scripts/fixtures/guides-clean/good-guide.md +16 -16
- package/scripts/install-rdc-skills.js +1289 -1289
- package/scripts/install.ps1 +202 -202
- package/scripts/install.sh +132 -132
- package/scripts/lib/assertions.mjs +287 -287
- package/scripts/lib/manifest-schema.mjs +754 -754
- package/scripts/lib/runner.mjs +465 -465
- package/scripts/lib/sandbox.mjs +435 -435
- package/scripts/prepack.mjs +32 -32
- package/scripts/rdc-brochure.mjs +464 -464
- package/scripts/rdc-design-cli.mjs +134 -134
- package/scripts/rebuild-mcp.mjs +107 -107
- package/scripts/self-test.mjs +1460 -1460
- package/scripts/stamp-git-sha.mjs +29 -29
- package/scripts/test-guide-validator.mjs +196 -196
- package/scripts/test-rdc-hooks.mjs +145 -145
- package/scripts/uninstall.ps1 +77 -77
- package/scripts/uninstall.sh +69 -69
- package/scripts/update.ps1 +43 -43
- package/scripts/update.sh +43 -43
- package/scripts/validate-place-histories.js +461 -461
- package/scripts/validate-publish-manifests.js +424 -424
- package/scripts/watch-init.mjs +100 -100
- package/skills/brochure/SKILL.md +107 -107
- package/skills/build/SKILL.md +563 -554
- package/skills/channel-formatter/SKILL.md +533 -533
- package/skills/co-develop/SKILL.md +196 -196
- package/skills/collab/SKILL.md +239 -239
- package/skills/convert/SKILL.md +140 -140
- package/skills/deploy/SKILL.md +541 -541
- package/skills/design/SKILL.md +211 -211
- package/skills/design/reference/ownership.md +16 -16
- package/skills/design/reference/rampa.md +92 -92
- package/skills/design/reference/studio-model.md +153 -153
- package/skills/edit/SKILL.md +98 -98
- package/skills/fixit/SKILL.md +165 -165
- package/skills/fs-mcp/SKILL.md +148 -148
- package/skills/handoff/SKILL.md +236 -200
- package/skills/help/SKILL.md +143 -143
- package/skills/housekeeping/SKILL.md +189 -189
- package/skills/lifeai-brochure-author/SKILL.md +340 -340
- package/skills/overnight/SKILL.md +251 -251
- package/skills/plan/SKILL.md +345 -314
- package/skills/preplan/SKILL.md +90 -90
- package/skills/prototype/SKILL.md +150 -150
- package/skills/rdc-brochurify/SKILL.md +245 -245
- package/skills/rdc-extract-verifier-rules/SKILL.md +191 -191
- package/skills/release/SKILL.md +140 -140
- package/skills/report/SKILL.md +100 -100
- package/skills/review/SKILL.md +152 -152
- package/skills/rpms-filemap/SKILL.cloud.md +111 -111
- package/skills/rpms-filemap/SKILL.md +111 -111
- package/skills/self-test/SKILL.md +132 -132
- package/skills/status/SKILL.md +99 -99
- package/skills/terminal-config/SKILL.md +62 -62
- package/skills/tests/MATRIX.md +54 -54
- package/skills/tests/README.md +47 -47
- package/skills/tests/rdc-brochure.test.json +34 -34
- package/skills/tests/rdc-build.test.json +36 -36
- package/skills/tests/rdc-channel-formatter.test.json +45 -45
- package/skills/tests/rdc-co-develop.test.json +29 -29
- package/skills/tests/rdc-collab.test.json +29 -29
- package/skills/tests/rdc-convert.test.json +35 -35
- package/skills/tests/rdc-deploy.test.json +30 -30
- package/skills/tests/rdc-design.test.json +27 -27
- package/skills/tests/rdc-edit.test.json +29 -29
- package/skills/tests/rdc-fixit.test.json +36 -36
- package/skills/tests/rdc-fs-mcp.test.json +36 -36
- package/skills/tests/rdc-handoff.test.json +28 -28
- package/skills/tests/rdc-help.test.json +29 -29
- package/skills/tests/rdc-housekeeping.test.json +31 -31
- package/skills/tests/rdc-lifeai-brochure-author.test.json +35 -35
- package/skills/tests/rdc-overnight.test.json +37 -37
- package/skills/tests/rdc-plan.test.json +27 -27
- package/skills/tests/rdc-preplan.test.json +31 -31
- package/skills/tests/rdc-prototype.test.json +28 -28
- package/skills/tests/rdc-rdc-brochurify.test.json +23 -23
- package/skills/tests/rdc-rdc-extract-verifier-rules.test.json +34 -34
- package/skills/tests/rdc-release.test.json +29 -29
- package/skills/tests/rdc-report.test.json +28 -28
- package/skills/tests/rdc-review.test.json +29 -29
- package/skills/tests/rdc-rpms-filemap.test.json +28 -28
- package/skills/tests/rdc-self-test.test.json +24 -24
- package/skills/tests/rdc-status.test.json +29 -29
- package/skills/tests/rdc-terminal-config.test.json +29 -29
- package/skills/tests/rdc-watch.test.json +24 -24
- package/skills/tests/rdc-workitems.test.json +27 -27
- package/skills/watch/SKILL.md +97 -97
- package/skills/workitems/SKILL.md +151 -151
- package/tests/acceptance.test.mjs +59 -59
- package/tests/channel-formatter.contract.test.mjs +251 -251
- package/tests/curl-surface.test.mjs +289 -289
- package/tests/harness-gates.test.mjs +325 -325
- package/tests/help-surface.test.mjs +61 -61
- package/tests/install-rdc-skills.test.mjs +49 -49
- package/tests/manifest-contract-fields.test.mjs +78 -78
- package/tests/mcp.test.mjs +271 -271
- package/tests/require-work-item-on-commit.test.mjs +162 -162
- package/tests/run-evidence-gate.test.mjs +82 -82
- package/tests/skill-test-matrix.test.mjs +66 -66
- package/tests/validate-skills.js +27 -27
- package/tests/work-item-exit-gate-l2.test.mjs +368 -368
- package/tests/work-item-exit-gate-l3.test.mjs +197 -197
package/README.sandbox.md
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
# Sandbox
|
|
2
|
-
|
|
3
|
-
Hello world
|
|
1
|
+
# Sandbox
|
|
2
|
+
|
|
3
|
+
Hello world
|
|
@@ -1,164 +1,164 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<title>rdc:watch — session log</title>
|
|
6
|
-
<style>
|
|
7
|
-
:root {
|
|
8
|
-
--bg: #0b0f0b;
|
|
9
|
-
--fg: #c8f0c8;
|
|
10
|
-
--dim: #6a7a6a;
|
|
11
|
-
--bar: #111a11;
|
|
12
|
-
--bar-stall: #3a2f00;
|
|
13
|
-
--dispatch: #6aa9ff;
|
|
14
|
-
--commit: #58d06a;
|
|
15
|
-
--test: #e6c84a;
|
|
16
|
-
--error: #ff6060;
|
|
17
|
-
--note: #8a8a8a;
|
|
18
|
-
--banner: #ffffff;
|
|
19
|
-
}
|
|
20
|
-
* { box-sizing: border-box; }
|
|
21
|
-
html, body { margin: 0; padding: 0; height: 100%; background: var(--bg); color: var(--fg); font-family: ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace; font-size: 13px; }
|
|
22
|
-
body { display: flex; flex-direction: column; }
|
|
23
|
-
header {
|
|
24
|
-
background: var(--bar);
|
|
25
|
-
border-bottom: 1px solid #1d2a1d;
|
|
26
|
-
padding: 8px 14px;
|
|
27
|
-
display: flex;
|
|
28
|
-
gap: 18px;
|
|
29
|
-
flex-wrap: wrap;
|
|
30
|
-
font-size: 12px;
|
|
31
|
-
color: var(--dim);
|
|
32
|
-
}
|
|
33
|
-
header.stalled { background: var(--bar-stall); color: #ffe08a; }
|
|
34
|
-
header b { color: var(--fg); font-weight: 600; }
|
|
35
|
-
header.stalled b { color: #ffe08a; }
|
|
36
|
-
#log {
|
|
37
|
-
flex: 1;
|
|
38
|
-
overflow-y: auto;
|
|
39
|
-
padding: 10px 14px 40px;
|
|
40
|
-
white-space: pre-wrap;
|
|
41
|
-
word-break: break-word;
|
|
42
|
-
}
|
|
43
|
-
.line { padding: 1px 0; line-height: 1.45; }
|
|
44
|
-
.ts { color: var(--dim); margin-right: 8px; }
|
|
45
|
-
.kind {
|
|
46
|
-
display: inline-block;
|
|
47
|
-
min-width: 70px;
|
|
48
|
-
margin-right: 8px;
|
|
49
|
-
text-transform: uppercase;
|
|
50
|
-
font-size: 11px;
|
|
51
|
-
letter-spacing: 0.05em;
|
|
52
|
-
}
|
|
53
|
-
.dispatch .kind, .dispatch .msg { color: var(--dispatch); }
|
|
54
|
-
.commit .kind, .commit .msg { color: var(--commit); }
|
|
55
|
-
.test .kind, .test .msg { color: var(--test); }
|
|
56
|
-
.error .kind, .error .msg { color: var(--error); }
|
|
57
|
-
.note .kind, .note .msg { color: var(--note); }
|
|
58
|
-
.banner .kind, .banner .msg { color: var(--banner); font-weight: 700; }
|
|
59
|
-
</style>
|
|
60
|
-
</head>
|
|
61
|
-
<body>
|
|
62
|
-
<header id="bar">
|
|
63
|
-
<div>session <b id="sid">—</b></div>
|
|
64
|
-
<div>started <b id="started">—</b></div>
|
|
65
|
-
<div>events <b id="count">0</b></div>
|
|
66
|
-
<div>updated <b id="updated">—</b></div>
|
|
67
|
-
<div id="status"></div>
|
|
68
|
-
</header>
|
|
69
|
-
<div id="log"></div>
|
|
70
|
-
<script>
|
|
71
|
-
(function () {
|
|
72
|
-
const LOG_URL = "./current.log";
|
|
73
|
-
const POLL_MS = 2000;
|
|
74
|
-
const logEl = document.getElementById("log");
|
|
75
|
-
const bar = document.getElementById("bar");
|
|
76
|
-
const sidEl = document.getElementById("sid");
|
|
77
|
-
const startedEl = document.getElementById("started");
|
|
78
|
-
const countEl = document.getElementById("count");
|
|
79
|
-
const updatedEl = document.getElementById("updated");
|
|
80
|
-
const statusEl = document.getElementById("status");
|
|
81
|
-
|
|
82
|
-
let lastLen = 0;
|
|
83
|
-
let count = 0;
|
|
84
|
-
let sessionSet = false;
|
|
85
|
-
|
|
86
|
-
const LINE_RE = /^\[([^\]]+)\]\s*\[([^\]]+)\]\s*(.*)$/;
|
|
87
|
-
const KINDS = new Set(["dispatch", "commit", "test", "error", "note", "banner"]);
|
|
88
|
-
|
|
89
|
-
function isAtBottom() {
|
|
90
|
-
return logEl.scrollHeight - logEl.scrollTop - logEl.clientHeight < 40;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function renderLine(raw) {
|
|
94
|
-
const m = raw.match(LINE_RE);
|
|
95
|
-
let ts = "", kind = "note", msg = raw;
|
|
96
|
-
if (m) {
|
|
97
|
-
ts = m[1];
|
|
98
|
-
kind = KINDS.has(m[2].toLowerCase()) ? m[2].toLowerCase() : "note";
|
|
99
|
-
msg = m[3];
|
|
100
|
-
}
|
|
101
|
-
const div = document.createElement("div");
|
|
102
|
-
div.className = "line " + kind;
|
|
103
|
-
const tsSpan = document.createElement("span");
|
|
104
|
-
tsSpan.className = "ts";
|
|
105
|
-
tsSpan.textContent = ts;
|
|
106
|
-
const kSpan = document.createElement("span");
|
|
107
|
-
kSpan.className = "kind";
|
|
108
|
-
kSpan.textContent = kind;
|
|
109
|
-
const mSpan = document.createElement("span");
|
|
110
|
-
mSpan.className = "msg";
|
|
111
|
-
mSpan.textContent = msg;
|
|
112
|
-
div.appendChild(tsSpan);
|
|
113
|
-
div.appendChild(kSpan);
|
|
114
|
-
div.appendChild(mSpan);
|
|
115
|
-
logEl.appendChild(div);
|
|
116
|
-
|
|
117
|
-
if (kind === "banner" && !sessionSet) {
|
|
118
|
-
const idMatch = msg.match(/Session started:\s*(\S+)/);
|
|
119
|
-
if (idMatch) sidEl.textContent = idMatch[1];
|
|
120
|
-
if (ts) startedEl.textContent = ts;
|
|
121
|
-
sessionSet = true;
|
|
122
|
-
}
|
|
123
|
-
count += 1;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async function poll() {
|
|
127
|
-
try {
|
|
128
|
-
const res = await fetch(LOG_URL + "?t=" + Date.now(), { cache: "no-store" });
|
|
129
|
-
if (!res.ok) throw new Error("http " + res.status);
|
|
130
|
-
const text = await res.text();
|
|
131
|
-
if (text.length < lastLen) {
|
|
132
|
-
// File shrank — reset (new session).
|
|
133
|
-
logEl.innerHTML = "";
|
|
134
|
-
lastLen = 0;
|
|
135
|
-
count = 0;
|
|
136
|
-
sessionSet = false;
|
|
137
|
-
}
|
|
138
|
-
if (text.length > lastLen) {
|
|
139
|
-
const stick = isAtBottom();
|
|
140
|
-
const chunk = text.slice(lastLen);
|
|
141
|
-
lastLen = text.length;
|
|
142
|
-
const lines = chunk.split(/\r?\n/);
|
|
143
|
-
for (const line of lines) {
|
|
144
|
-
if (line.trim().length === 0) continue;
|
|
145
|
-
renderLine(line);
|
|
146
|
-
}
|
|
147
|
-
countEl.textContent = String(count);
|
|
148
|
-
updatedEl.textContent = new Date().toLocaleTimeString();
|
|
149
|
-
if (stick) logEl.scrollTop = logEl.scrollHeight;
|
|
150
|
-
}
|
|
151
|
-
bar.classList.remove("stalled");
|
|
152
|
-
statusEl.textContent = "";
|
|
153
|
-
} catch (e) {
|
|
154
|
-
bar.classList.add("stalled");
|
|
155
|
-
statusEl.textContent = "stalled — retrying";
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
poll();
|
|
160
|
-
setInterval(poll, POLL_MS);
|
|
161
|
-
})();
|
|
162
|
-
</script>
|
|
163
|
-
</body>
|
|
164
|
-
</html>
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>rdc:watch — session log</title>
|
|
6
|
+
<style>
|
|
7
|
+
:root {
|
|
8
|
+
--bg: #0b0f0b;
|
|
9
|
+
--fg: #c8f0c8;
|
|
10
|
+
--dim: #6a7a6a;
|
|
11
|
+
--bar: #111a11;
|
|
12
|
+
--bar-stall: #3a2f00;
|
|
13
|
+
--dispatch: #6aa9ff;
|
|
14
|
+
--commit: #58d06a;
|
|
15
|
+
--test: #e6c84a;
|
|
16
|
+
--error: #ff6060;
|
|
17
|
+
--note: #8a8a8a;
|
|
18
|
+
--banner: #ffffff;
|
|
19
|
+
}
|
|
20
|
+
* { box-sizing: border-box; }
|
|
21
|
+
html, body { margin: 0; padding: 0; height: 100%; background: var(--bg); color: var(--fg); font-family: ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace; font-size: 13px; }
|
|
22
|
+
body { display: flex; flex-direction: column; }
|
|
23
|
+
header {
|
|
24
|
+
background: var(--bar);
|
|
25
|
+
border-bottom: 1px solid #1d2a1d;
|
|
26
|
+
padding: 8px 14px;
|
|
27
|
+
display: flex;
|
|
28
|
+
gap: 18px;
|
|
29
|
+
flex-wrap: wrap;
|
|
30
|
+
font-size: 12px;
|
|
31
|
+
color: var(--dim);
|
|
32
|
+
}
|
|
33
|
+
header.stalled { background: var(--bar-stall); color: #ffe08a; }
|
|
34
|
+
header b { color: var(--fg); font-weight: 600; }
|
|
35
|
+
header.stalled b { color: #ffe08a; }
|
|
36
|
+
#log {
|
|
37
|
+
flex: 1;
|
|
38
|
+
overflow-y: auto;
|
|
39
|
+
padding: 10px 14px 40px;
|
|
40
|
+
white-space: pre-wrap;
|
|
41
|
+
word-break: break-word;
|
|
42
|
+
}
|
|
43
|
+
.line { padding: 1px 0; line-height: 1.45; }
|
|
44
|
+
.ts { color: var(--dim); margin-right: 8px; }
|
|
45
|
+
.kind {
|
|
46
|
+
display: inline-block;
|
|
47
|
+
min-width: 70px;
|
|
48
|
+
margin-right: 8px;
|
|
49
|
+
text-transform: uppercase;
|
|
50
|
+
font-size: 11px;
|
|
51
|
+
letter-spacing: 0.05em;
|
|
52
|
+
}
|
|
53
|
+
.dispatch .kind, .dispatch .msg { color: var(--dispatch); }
|
|
54
|
+
.commit .kind, .commit .msg { color: var(--commit); }
|
|
55
|
+
.test .kind, .test .msg { color: var(--test); }
|
|
56
|
+
.error .kind, .error .msg { color: var(--error); }
|
|
57
|
+
.note .kind, .note .msg { color: var(--note); }
|
|
58
|
+
.banner .kind, .banner .msg { color: var(--banner); font-weight: 700; }
|
|
59
|
+
</style>
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<header id="bar">
|
|
63
|
+
<div>session <b id="sid">—</b></div>
|
|
64
|
+
<div>started <b id="started">—</b></div>
|
|
65
|
+
<div>events <b id="count">0</b></div>
|
|
66
|
+
<div>updated <b id="updated">—</b></div>
|
|
67
|
+
<div id="status"></div>
|
|
68
|
+
</header>
|
|
69
|
+
<div id="log"></div>
|
|
70
|
+
<script>
|
|
71
|
+
(function () {
|
|
72
|
+
const LOG_URL = "./current.log";
|
|
73
|
+
const POLL_MS = 2000;
|
|
74
|
+
const logEl = document.getElementById("log");
|
|
75
|
+
const bar = document.getElementById("bar");
|
|
76
|
+
const sidEl = document.getElementById("sid");
|
|
77
|
+
const startedEl = document.getElementById("started");
|
|
78
|
+
const countEl = document.getElementById("count");
|
|
79
|
+
const updatedEl = document.getElementById("updated");
|
|
80
|
+
const statusEl = document.getElementById("status");
|
|
81
|
+
|
|
82
|
+
let lastLen = 0;
|
|
83
|
+
let count = 0;
|
|
84
|
+
let sessionSet = false;
|
|
85
|
+
|
|
86
|
+
const LINE_RE = /^\[([^\]]+)\]\s*\[([^\]]+)\]\s*(.*)$/;
|
|
87
|
+
const KINDS = new Set(["dispatch", "commit", "test", "error", "note", "banner"]);
|
|
88
|
+
|
|
89
|
+
function isAtBottom() {
|
|
90
|
+
return logEl.scrollHeight - logEl.scrollTop - logEl.clientHeight < 40;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function renderLine(raw) {
|
|
94
|
+
const m = raw.match(LINE_RE);
|
|
95
|
+
let ts = "", kind = "note", msg = raw;
|
|
96
|
+
if (m) {
|
|
97
|
+
ts = m[1];
|
|
98
|
+
kind = KINDS.has(m[2].toLowerCase()) ? m[2].toLowerCase() : "note";
|
|
99
|
+
msg = m[3];
|
|
100
|
+
}
|
|
101
|
+
const div = document.createElement("div");
|
|
102
|
+
div.className = "line " + kind;
|
|
103
|
+
const tsSpan = document.createElement("span");
|
|
104
|
+
tsSpan.className = "ts";
|
|
105
|
+
tsSpan.textContent = ts;
|
|
106
|
+
const kSpan = document.createElement("span");
|
|
107
|
+
kSpan.className = "kind";
|
|
108
|
+
kSpan.textContent = kind;
|
|
109
|
+
const mSpan = document.createElement("span");
|
|
110
|
+
mSpan.className = "msg";
|
|
111
|
+
mSpan.textContent = msg;
|
|
112
|
+
div.appendChild(tsSpan);
|
|
113
|
+
div.appendChild(kSpan);
|
|
114
|
+
div.appendChild(mSpan);
|
|
115
|
+
logEl.appendChild(div);
|
|
116
|
+
|
|
117
|
+
if (kind === "banner" && !sessionSet) {
|
|
118
|
+
const idMatch = msg.match(/Session started:\s*(\S+)/);
|
|
119
|
+
if (idMatch) sidEl.textContent = idMatch[1];
|
|
120
|
+
if (ts) startedEl.textContent = ts;
|
|
121
|
+
sessionSet = true;
|
|
122
|
+
}
|
|
123
|
+
count += 1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function poll() {
|
|
127
|
+
try {
|
|
128
|
+
const res = await fetch(LOG_URL + "?t=" + Date.now(), { cache: "no-store" });
|
|
129
|
+
if (!res.ok) throw new Error("http " + res.status);
|
|
130
|
+
const text = await res.text();
|
|
131
|
+
if (text.length < lastLen) {
|
|
132
|
+
// File shrank — reset (new session).
|
|
133
|
+
logEl.innerHTML = "";
|
|
134
|
+
lastLen = 0;
|
|
135
|
+
count = 0;
|
|
136
|
+
sessionSet = false;
|
|
137
|
+
}
|
|
138
|
+
if (text.length > lastLen) {
|
|
139
|
+
const stick = isAtBottom();
|
|
140
|
+
const chunk = text.slice(lastLen);
|
|
141
|
+
lastLen = text.length;
|
|
142
|
+
const lines = chunk.split(/\r?\n/);
|
|
143
|
+
for (const line of lines) {
|
|
144
|
+
if (line.trim().length === 0) continue;
|
|
145
|
+
renderLine(line);
|
|
146
|
+
}
|
|
147
|
+
countEl.textContent = String(count);
|
|
148
|
+
updatedEl.textContent = new Date().toLocaleTimeString();
|
|
149
|
+
if (stick) logEl.scrollTop = logEl.scrollHeight;
|
|
150
|
+
}
|
|
151
|
+
bar.classList.remove("stalled");
|
|
152
|
+
statusEl.textContent = "";
|
|
153
|
+
} catch (e) {
|
|
154
|
+
bar.classList.add("stalled");
|
|
155
|
+
statusEl.textContent = "stalled — retrying";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
poll();
|
|
160
|
+
setInterval(poll, POLL_MS);
|
|
161
|
+
})();
|
|
162
|
+
</script>
|
|
163
|
+
</body>
|
|
164
|
+
</html>
|