ccakashic 0.2.8 → 0.3.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/README.md +33 -4
- package/dist/bin/ccakashic.js +227 -5
- package/dist/cmux.js +264 -0
- package/dist/dashboard.js +330 -0
- package/dist/discover.js +78 -28
- package/dist/html-generator.js +49 -47
- package/dist/pages.js +33 -22
- package/dist/parser.js +27 -0
- package/dist/resume-ui.js +148 -0
- package/dist/template-assets.js +32 -20
- package/dist/util.js +80 -0
- package/package.json +2 -2
package/dist/template-assets.js
CHANGED
|
@@ -573,19 +573,23 @@ body {
|
|
|
573
573
|
function getAppJS() {
|
|
574
574
|
return `
|
|
575
575
|
(function() {
|
|
576
|
-
|
|
576
|
+
function esc(s) {
|
|
577
|
+
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Simple markdown renderer (no external dependency).
|
|
581
|
+
// SECURITY: callers pass el.textContent, which DECODES the server's HTML
|
|
582
|
+
// entities back to raw characters, so session content (semi-untrusted: it can
|
|
583
|
+
// contain text from fetched pages/files/tool output) arrives unescaped. We
|
|
584
|
+
// re-escape it up front before applying markdown — markdown syntax chars
|
|
585
|
+
// ([ ] ( ) * \` # -) are untouched by escaping so markdown still renders,
|
|
586
|
+
// while <, >, " stay inert as < > " and cannot inject HTML.
|
|
577
587
|
function renderMarkdown(text) {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
.replace(/&/g, '&')
|
|
582
|
-
.replace(/</g, '<')
|
|
583
|
-
.replace(/>/g, '>')
|
|
584
|
-
.replace(/"/g, '"');
|
|
585
|
-
|
|
586
|
-
// Code blocks (fenced)
|
|
588
|
+
text = esc(text);
|
|
589
|
+
|
|
590
|
+
// Code blocks (fenced) — content is already escaped, do not re-escape
|
|
587
591
|
text = text.replace(/\`\`\`(\\w*)?\\n([\\s\\S]*?)\`\`\`/g, function(m, lang, code) {
|
|
588
|
-
return '<pre><code class="language-' + (lang || '') + '">' +
|
|
592
|
+
return '<pre><code class="language-' + (lang || '') + '">' + code.trim() + '</code></pre>';
|
|
589
593
|
});
|
|
590
594
|
|
|
591
595
|
// Inline code
|
|
@@ -606,8 +610,15 @@ function getAppJS() {
|
|
|
606
610
|
text = text.replace(/^[\\-*] (.+)$/gm, '<li>$1</li>');
|
|
607
611
|
text = text.replace(/(<li>.*<\\/li>\\n?)+/g, '<ul>$&</ul>');
|
|
608
612
|
|
|
609
|
-
// Links
|
|
610
|
-
|
|
613
|
+
// Links — href is already escaped (so " is " and can't break out of
|
|
614
|
+
// the attribute), but still allowlist safe schemes to block javascript:.
|
|
615
|
+
// The leading-slash branch uses (?!\\/) so protocol-relative //evil.com
|
|
616
|
+
// (which navigates off-site) is rejected — only same-origin /path passes.
|
|
617
|
+
text = text.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, function(m, label, href) {
|
|
618
|
+
return /^(https?:\\/\\/|\\/(?!\\/)|#)/i.test(href)
|
|
619
|
+
? '<a href="' + href + '" target="_blank" rel="noopener">' + label + '</a>'
|
|
620
|
+
: label;
|
|
621
|
+
});
|
|
611
622
|
|
|
612
623
|
// Paragraphs (simple: double newlines)
|
|
613
624
|
text = text.replace(/\\n\\n/g, '</p><p>');
|
|
@@ -625,14 +636,15 @@ function getAppJS() {
|
|
|
625
636
|
return text;
|
|
626
637
|
}
|
|
627
638
|
|
|
628
|
-
|
|
629
|
-
|
|
639
|
+
// Render markdown in all [data-markdown] elements. Exposed globally so the
|
|
640
|
+
// dashboard can re-apply it to pane content replaced after a poll.
|
|
641
|
+
function applyMarkdown(root) {
|
|
642
|
+
root.querySelectorAll('[data-markdown]').forEach(function(el) {
|
|
643
|
+
el.innerHTML = renderMarkdown(el.textContent);
|
|
644
|
+
});
|
|
630
645
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
document.querySelectorAll('[data-markdown]').forEach(function(el) {
|
|
634
|
-
el.innerHTML = renderMarkdown(el.textContent);
|
|
635
|
-
});
|
|
646
|
+
window.ccakashicApplyMarkdown = applyMarkdown;
|
|
647
|
+
applyMarkdown(document);
|
|
636
648
|
|
|
637
649
|
// Scroll to bottom when hash is #session-bottom. We re-scroll here (after
|
|
638
650
|
// markdown rendering) because the DOM height grows when markdown expands,
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Shared helpers used across the HTML generators and the server.
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.ACTIVE_THRESHOLD_MS = void 0;
|
|
38
|
+
exports.getOrCreateToken = getOrCreateToken;
|
|
39
|
+
exports.escapeHtml = escapeHtml;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const os = __importStar(require("os"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const crypto = __importStar(require("crypto"));
|
|
44
|
+
const CONFIG_DIR = path.join(os.homedir(), '.config', 'ccakashic');
|
|
45
|
+
const TOKEN_FILE = path.join(CONFIG_DIR, 'token');
|
|
46
|
+
// The /api/resume CSRF token, persisted so it survives a server restart and the
|
|
47
|
+
// buttons on already-open tabs keep working without a reload. Falls back to an
|
|
48
|
+
// in-memory token if the file can't be read/written. DNS rebinding is already
|
|
49
|
+
// blocked by the Host-header check, so this token is defense-in-depth.
|
|
50
|
+
function getOrCreateToken() {
|
|
51
|
+
try {
|
|
52
|
+
const existing = fs.readFileSync(TOKEN_FILE, 'utf-8').trim();
|
|
53
|
+
if (/^[a-f0-9]{32,}$/.test(existing))
|
|
54
|
+
return existing;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// not created yet
|
|
58
|
+
}
|
|
59
|
+
const token = crypto.randomBytes(16).toString('hex');
|
|
60
|
+
try {
|
|
61
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
62
|
+
fs.writeFileSync(TOKEN_FILE, token, { mode: 0o600 });
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// fall back to an ephemeral token (rotates on restart)
|
|
66
|
+
}
|
|
67
|
+
return token;
|
|
68
|
+
}
|
|
69
|
+
function escapeHtml(str) {
|
|
70
|
+
return String(str)
|
|
71
|
+
.replace(/&/g, '&')
|
|
72
|
+
.replace(/</g, '<')
|
|
73
|
+
.replace(/>/g, '>')
|
|
74
|
+
.replace(/"/g, '"')
|
|
75
|
+
.replace(/'/g, ''');
|
|
76
|
+
}
|
|
77
|
+
// A session whose file was touched within this window is treated as still
|
|
78
|
+
// attached to a live `claude` process. Shared so the dashboard status dot and
|
|
79
|
+
// the resume fork-confirmation use the exact same definition of "active".
|
|
80
|
+
exports.ACTIVE_THRESHOLD_MS = 2 * 60_000;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccakashic",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "A cross-project dashboard for your Claude Code sessions (~/.claude/projects/) — browse logs as beautiful HTML, see which sessions are waiting for you, and resume any of them in one click via cmux",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ccakashic": "dist/bin/ccakashic.js"
|
|
7
7
|
},
|