@shardworks/astrolabe-apparatus 0.1.140 → 0.1.141
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 +14 -0
- package/dist/astrolabe.d.ts.map +1 -1
- package/dist/astrolabe.js +3 -0
- package/dist/astrolabe.js.map +1 -1
- package/package.json +10 -9
- package/pages/astrolabe/astrolabe.css +90 -0
- package/pages/astrolabe/astrolabe.js +623 -0
- package/pages/astrolabe/astrolabe.test.js +424 -0
- package/pages/astrolabe/index.html +65 -0
package/README.md
CHANGED
|
@@ -148,3 +148,17 @@ The `resolutionEngine` is `spec-writer` — the rig's completion summary comes f
|
|
|
148
148
|
| `spec-write` | `astrolabe:write` | Write or replace the generated specification |
|
|
149
149
|
|
|
150
150
|
Write tools only update their artifact field plus `updatedAt`. Status transitions are the exclusive responsibility of the clockwork engines.
|
|
151
|
+
|
|
152
|
+
### Pages (contributed to Oculus)
|
|
153
|
+
|
|
154
|
+
| Page ID | Title | Directory |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `astrolabe` | Astrolabe | `pages/astrolabe` |
|
|
157
|
+
|
|
158
|
+
The Astrolabe page provides a list/detail dashboard for PlanDoc records:
|
|
159
|
+
|
|
160
|
+
- **List view** — filterable by status, paginated (20 per page), showing status badge, codex, brief writ title, plan ID, and creation date.
|
|
161
|
+
- **Detail view** — metadata card with plan ID, status, codex, cross-links to brief and mandate writs (linking to the Clerk writs page via `?writ=ID`), per-step AI cost breakdowns (input/output tokens and USD cost for each anima-session engine), and tabbed content sections for Inventory, Scope, Decisions, Observations, and Spec.
|
|
162
|
+
- **Deep linking** — supports `?plan=ID` query parameter to open directly to a plan's detail view.
|
|
163
|
+
|
|
164
|
+
Markdown fields (inventory, observations, spec) are rendered client-side with a minimal renderer supporting headings, bold, italic, inline code, fenced code blocks, and lists. All content is HTML-escaped before rendering to prevent XSS.
|
package/dist/astrolabe.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"astrolabe.d.ts","sourceRoot":"","sources":["../src/astrolabe.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,wBAAwB,CAAC;AAQrE,OAAO,KAAK,EAEV,eAAe,EAGhB,MAAM,YAAY,CAAC;AAmBpB,iBAAS,sBAAsB,IAAI,eAAe,CAEjD;AAmGD,wBAAgB,eAAe,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"astrolabe.d.ts","sourceRoot":"","sources":["../src/astrolabe.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,wBAAwB,CAAC;AAQrE,OAAO,KAAK,EAEV,eAAe,EAGhB,MAAM,YAAY,CAAC;AAmBpB,iBAAS,sBAAsB,IAAI,eAAe,CAEjD;AAmGD,wBAAgB,eAAe,IAAI,MAAM,CA+PxC;AAGD,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
|
package/dist/astrolabe.js
CHANGED
package/dist/astrolabe.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"astrolabe.js","sourceRoot":"","sources":["../src/astrolabe.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"astrolabe.js","sourceRoot":"","sources":["../src/astrolabe.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shardworks/astrolabe-apparatus",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.141",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,20 +17,21 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"zod": "4.3.6",
|
|
20
|
-
"@shardworks/nexus-core": "0.1.
|
|
21
|
-
"@shardworks/
|
|
22
|
-
"@shardworks/
|
|
23
|
-
"@shardworks/clerk-apparatus": "0.1.
|
|
24
|
-
"@shardworks/
|
|
25
|
-
"@shardworks/
|
|
26
|
-
"@shardworks/loom-apparatus": "0.1.
|
|
20
|
+
"@shardworks/nexus-core": "0.1.141",
|
|
21
|
+
"@shardworks/stacks-apparatus": "0.1.141",
|
|
22
|
+
"@shardworks/tools-apparatus": "0.1.141",
|
|
23
|
+
"@shardworks/clerk-apparatus": "0.1.141",
|
|
24
|
+
"@shardworks/spider-apparatus": "0.1.141",
|
|
25
|
+
"@shardworks/fabricator-apparatus": "0.1.141",
|
|
26
|
+
"@shardworks/loom-apparatus": "0.1.141"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "25.5.0"
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"dist",
|
|
33
|
-
"sage.md"
|
|
33
|
+
"sage.md",
|
|
34
|
+
"pages"
|
|
34
35
|
],
|
|
35
36
|
"scripts": {
|
|
36
37
|
"build": "tsc",
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* Tab bar (duplicated from spider pattern — not yet in shared stylesheet) */
|
|
2
|
+
.tab-bar {
|
|
3
|
+
display: flex;
|
|
4
|
+
gap: 4px;
|
|
5
|
+
margin-bottom: 16px;
|
|
6
|
+
border-bottom: 1px solid var(--border, #333);
|
|
7
|
+
padding-bottom: 0;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.tab {
|
|
11
|
+
background: none;
|
|
12
|
+
border: none;
|
|
13
|
+
border-bottom: 2px solid transparent;
|
|
14
|
+
color: var(--text-dim, #888);
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
font-size: 14px;
|
|
17
|
+
font-weight: 500;
|
|
18
|
+
margin-bottom: -1px;
|
|
19
|
+
padding: 8px 16px;
|
|
20
|
+
transition: color 0.15s, border-color 0.15s;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.tab:hover { color: var(--text, #eee); }
|
|
24
|
+
.tab.active {
|
|
25
|
+
border-bottom-color: var(--cyan, #0ff);
|
|
26
|
+
color: var(--cyan, #0ff);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Plan list table */
|
|
30
|
+
#plan-tbody tr { cursor: pointer; }
|
|
31
|
+
#plan-tbody tr:hover { opacity: 0.85; }
|
|
32
|
+
|
|
33
|
+
/* Filter buttons */
|
|
34
|
+
.filter-btn { margin-right: 4px; }
|
|
35
|
+
.filter-btn.active-filter {
|
|
36
|
+
background: var(--blue, #7aa2f7);
|
|
37
|
+
color: var(--bg, #1a1b26);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Decision expandable rows */
|
|
41
|
+
.decision-row { cursor: pointer; }
|
|
42
|
+
.decision-row:hover { opacity: 0.85; }
|
|
43
|
+
.decision-detail td {
|
|
44
|
+
background: var(--bg2, #1a1b26);
|
|
45
|
+
padding: 1rem;
|
|
46
|
+
}
|
|
47
|
+
.decision-detail dl {
|
|
48
|
+
display: grid;
|
|
49
|
+
grid-template-columns: 140px 1fr;
|
|
50
|
+
gap: 4px 12px;
|
|
51
|
+
margin: 0;
|
|
52
|
+
}
|
|
53
|
+
.decision-detail dt {
|
|
54
|
+
color: var(--text-dim, #888);
|
|
55
|
+
font-size: 12px;
|
|
56
|
+
font-weight: 600;
|
|
57
|
+
text-transform: uppercase;
|
|
58
|
+
}
|
|
59
|
+
.decision-detail dd {
|
|
60
|
+
margin: 0;
|
|
61
|
+
overflow-wrap: anywhere;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Cost table */
|
|
65
|
+
.cost-table { margin-top: 12px; }
|
|
66
|
+
.cost-table th { font-size: 11px; text-transform: uppercase; color: var(--text-dim, #888); }
|
|
67
|
+
.cost-total { font-weight: 600; border-top: 2px solid var(--border, #333); }
|
|
68
|
+
|
|
69
|
+
/* Metadata grid */
|
|
70
|
+
.meta-grid {
|
|
71
|
+
display: grid;
|
|
72
|
+
grid-template-columns: max-content 1fr;
|
|
73
|
+
gap: 0.25rem 1rem;
|
|
74
|
+
font-size: 0.875rem;
|
|
75
|
+
}
|
|
76
|
+
.meta-grid dt { color: var(--text-dim, #888); font-weight: 600; text-transform: uppercase; font-size: 12px; }
|
|
77
|
+
.meta-grid dd { margin: 0; }
|
|
78
|
+
|
|
79
|
+
/* Rendered markdown */
|
|
80
|
+
.md-content h1, .md-content h2, .md-content h3,
|
|
81
|
+
.md-content h4, .md-content h5, .md-content h6 {
|
|
82
|
+
margin: 1em 0 0.5em;
|
|
83
|
+
}
|
|
84
|
+
.md-content h1 { font-size: 1.4em; }
|
|
85
|
+
.md-content h2 { font-size: 1.2em; }
|
|
86
|
+
.md-content h3 { font-size: 1.1em; }
|
|
87
|
+
.md-content p { margin: 0.5em 0; }
|
|
88
|
+
.md-content ul, .md-content ol { padding-left: 1.5em; margin: 0.5em 0; }
|
|
89
|
+
.md-content pre { max-height: 400px; overflow: auto; }
|
|
90
|
+
.md-content code { font-size: 12px; }
|
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Astrolabe dashboard — vanilla JS IIFE.
|
|
3
|
+
* No framework, no modules, no imports.
|
|
4
|
+
*/
|
|
5
|
+
(function () {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
// ── State ──────────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
var plans = [];
|
|
11
|
+
var currentPlan = null;
|
|
12
|
+
var activeTab = 'inventory';
|
|
13
|
+
var currentStatusFilter = '';
|
|
14
|
+
var offset = 0;
|
|
15
|
+
var LIMIT = 20;
|
|
16
|
+
var writTitleLookup = {};
|
|
17
|
+
|
|
18
|
+
// ── Utility ────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
function esc(s) {
|
|
21
|
+
if (s == null) return '';
|
|
22
|
+
return String(s)
|
|
23
|
+
.replace(/&/g, '&')
|
|
24
|
+
.replace(/</g, '<')
|
|
25
|
+
.replace(/>/g, '>')
|
|
26
|
+
.replace(/"/g, '"');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function formatDate(iso) {
|
|
30
|
+
if (!iso) return '';
|
|
31
|
+
try {
|
|
32
|
+
return new Date(iso).toLocaleString();
|
|
33
|
+
} catch (e) {
|
|
34
|
+
return iso;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── Status Badge ───────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
function statusBadge(status) {
|
|
41
|
+
var map = {
|
|
42
|
+
reading: 'badge badge--active',
|
|
43
|
+
analyzing: 'badge badge--active',
|
|
44
|
+
writing: 'badge badge--active',
|
|
45
|
+
reviewing: 'badge badge--warning',
|
|
46
|
+
completed: 'badge badge--success',
|
|
47
|
+
failed: 'badge badge--error'
|
|
48
|
+
};
|
|
49
|
+
var cls = map[status] || 'badge';
|
|
50
|
+
return '<span class="' + cls + '">' + esc(status) + '</span>';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── Markdown Rendering ─────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
function renderMarkdown(md) {
|
|
56
|
+
if (md == null || md === '') return '';
|
|
57
|
+
|
|
58
|
+
// HTML-escape input first to prevent XSS
|
|
59
|
+
var text = esc(md);
|
|
60
|
+
|
|
61
|
+
// Fenced code blocks (``` ... ```)
|
|
62
|
+
// After escaping, backticks are preserved
|
|
63
|
+
var codeBlocks = [];
|
|
64
|
+
text = text.replace(/```[\s\S]*?```/g, function (match) {
|
|
65
|
+
// Remove opening ``` (with optional language tag) and closing ```
|
|
66
|
+
var inner = match.replace(/^```[^\n]*\n?/, '').replace(/\n?```$/, '');
|
|
67
|
+
var idx = codeBlocks.length;
|
|
68
|
+
codeBlocks.push('<pre><code>' + inner + '</code></pre>');
|
|
69
|
+
return '\x00CODEBLOCK' + idx + '\x00';
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
var lines = text.split('\n');
|
|
73
|
+
var result = [];
|
|
74
|
+
var i = 0;
|
|
75
|
+
|
|
76
|
+
while (i < lines.length) {
|
|
77
|
+
var line = lines[i];
|
|
78
|
+
|
|
79
|
+
// Check for code block placeholder
|
|
80
|
+
var cbMatch = line.match(/^\x00CODEBLOCK(\d+)\x00$/);
|
|
81
|
+
if (cbMatch) {
|
|
82
|
+
result.push(codeBlocks[parseInt(cbMatch[1], 10)]);
|
|
83
|
+
i++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Headings
|
|
88
|
+
var headingMatch = line.match(/^(#{1,6}) (.+)$/);
|
|
89
|
+
if (headingMatch) {
|
|
90
|
+
var level = headingMatch[1].length;
|
|
91
|
+
var content = applyInline(headingMatch[2]);
|
|
92
|
+
result.push('<h' + level + '>' + content + '</h' + level + '>');
|
|
93
|
+
i++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Unordered lists
|
|
98
|
+
if (/^[\-\*] /.test(line)) {
|
|
99
|
+
var items = [];
|
|
100
|
+
while (i < lines.length && /^[\-\*] /.test(lines[i])) {
|
|
101
|
+
items.push('<li>' + applyInline(lines[i].replace(/^[\-\*] /, '')) + '</li>');
|
|
102
|
+
i++;
|
|
103
|
+
}
|
|
104
|
+
result.push('<ul>' + items.join('') + '</ul>');
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Ordered lists
|
|
109
|
+
if (/^\d+\. /.test(line)) {
|
|
110
|
+
var olItems = [];
|
|
111
|
+
while (i < lines.length && /^\d+\. /.test(lines[i])) {
|
|
112
|
+
olItems.push('<li>' + applyInline(lines[i].replace(/^\d+\. /, '')) + '</li>');
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
result.push('<ol>' + olItems.join('') + '</ol>');
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Empty lines
|
|
120
|
+
if (line.trim() === '') {
|
|
121
|
+
i++;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Paragraphs: collect consecutive non-empty, non-special lines
|
|
126
|
+
var para = [];
|
|
127
|
+
while (i < lines.length && lines[i].trim() !== '' &&
|
|
128
|
+
!/^#{1,6} /.test(lines[i]) &&
|
|
129
|
+
!/^[\-\*] /.test(lines[i]) &&
|
|
130
|
+
!/^\d+\. /.test(lines[i]) &&
|
|
131
|
+
!/^\x00CODEBLOCK/.test(lines[i])) {
|
|
132
|
+
para.push(applyInline(lines[i]));
|
|
133
|
+
i++;
|
|
134
|
+
}
|
|
135
|
+
if (para.length > 0) {
|
|
136
|
+
result.push('<p>' + para.join(' ') + '</p>');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return '<div class="md-content">' + result.join('') + '</div>';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function applyInline(text) {
|
|
144
|
+
// Bold: **text**
|
|
145
|
+
text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
|
146
|
+
// Italic: *text* or _text_
|
|
147
|
+
text = text.replace(/\*(.+?)\*/g, '<em>$1</em>');
|
|
148
|
+
text = text.replace(/\b_(.+?)_\b/g, '<em>$1</em>');
|
|
149
|
+
// Inline code: `code`
|
|
150
|
+
text = text.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
151
|
+
return text;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ── DOM References ─────────────────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
var listView = document.getElementById('plan-list-view');
|
|
157
|
+
var detailView = document.getElementById('plan-detail-view');
|
|
158
|
+
var tbody = document.getElementById('plan-tbody');
|
|
159
|
+
var emptyState = document.getElementById('empty-state');
|
|
160
|
+
var loadMoreBtn = document.getElementById('load-more-btn');
|
|
161
|
+
var backBtn = document.getElementById('back-btn');
|
|
162
|
+
var detailTitle = document.getElementById('detail-title');
|
|
163
|
+
var metaCard = document.getElementById('meta-card');
|
|
164
|
+
var tabContent = document.getElementById('tab-content');
|
|
165
|
+
|
|
166
|
+
// ── Filter Buttons ─────────────────────────────────────────────────────
|
|
167
|
+
|
|
168
|
+
var filterBtns = document.querySelectorAll('#status-filters .filter-btn');
|
|
169
|
+
for (var fi = 0; fi < filterBtns.length; fi++) {
|
|
170
|
+
(function (btn) {
|
|
171
|
+
btn.addEventListener('click', function () {
|
|
172
|
+
currentStatusFilter = btn.getAttribute('data-status');
|
|
173
|
+
for (var j = 0; j < filterBtns.length; j++) {
|
|
174
|
+
filterBtns[j].classList.remove('active-filter');
|
|
175
|
+
}
|
|
176
|
+
btn.classList.add('active-filter');
|
|
177
|
+
fetchPlans(true);
|
|
178
|
+
});
|
|
179
|
+
})(filterBtns[fi]);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ── Load More Button ───────────────────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
loadMoreBtn.addEventListener('click', function () {
|
|
185
|
+
fetchPlans(false);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// ── Back Button ────────────────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
backBtn.addEventListener('click', function () {
|
|
191
|
+
backToList();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// ── Tab Clicks ─────────────────────────────────────────────────────────
|
|
195
|
+
|
|
196
|
+
var tabBtns = document.querySelectorAll('#plan-tabs .tab');
|
|
197
|
+
for (var ti = 0; ti < tabBtns.length; ti++) {
|
|
198
|
+
(function (btn) {
|
|
199
|
+
btn.addEventListener('click', function () {
|
|
200
|
+
if (btn.getAttribute('data-disabled') === 'true') return;
|
|
201
|
+
var tabName = btn.getAttribute('data-tab');
|
|
202
|
+
activeTab = tabName;
|
|
203
|
+
for (var j = 0; j < tabBtns.length; j++) {
|
|
204
|
+
tabBtns[j].classList.remove('active');
|
|
205
|
+
}
|
|
206
|
+
btn.classList.add('active');
|
|
207
|
+
renderTab(tabName);
|
|
208
|
+
});
|
|
209
|
+
})(tabBtns[ti]);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ── Data Fetching ──────────────────────────────────────────────────────
|
|
213
|
+
|
|
214
|
+
function fetchPlans(replace) {
|
|
215
|
+
if (replace) {
|
|
216
|
+
offset = 0;
|
|
217
|
+
plans = [];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
var url = '/api/plan/list?limit=' + LIMIT + '&offset=' + offset;
|
|
221
|
+
if (currentStatusFilter) {
|
|
222
|
+
url += '&status=' + encodeURIComponent(currentStatusFilter);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
fetch(url)
|
|
226
|
+
.then(function (r) { return r.json(); })
|
|
227
|
+
.then(function (data) {
|
|
228
|
+
if (replace) {
|
|
229
|
+
plans = data;
|
|
230
|
+
} else {
|
|
231
|
+
plans = plans.concat(data);
|
|
232
|
+
}
|
|
233
|
+
offset += data.length;
|
|
234
|
+
loadMoreBtn.style.display = data.length >= LIMIT ? '' : 'none';
|
|
235
|
+
renderPlanList();
|
|
236
|
+
})
|
|
237
|
+
.catch(function (err) {
|
|
238
|
+
console.error('Failed to fetch plans:', err);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ── List Rendering ─────────────────────────────────────────────────────
|
|
243
|
+
|
|
244
|
+
function renderPlanList() {
|
|
245
|
+
if (plans.length === 0) {
|
|
246
|
+
tbody.innerHTML = '';
|
|
247
|
+
emptyState.style.display = '';
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
emptyState.style.display = 'none';
|
|
251
|
+
|
|
252
|
+
var html = '';
|
|
253
|
+
for (var i = 0; i < plans.length; i++) {
|
|
254
|
+
var p = plans[i];
|
|
255
|
+
var titleCell = writTitleLookup[p.id] !== undefined
|
|
256
|
+
? esc(writTitleLookup[p.id])
|
|
257
|
+
: '<span class="text-dim">loading...</span>';
|
|
258
|
+
|
|
259
|
+
html += '<tr data-idx="' + i + '">' +
|
|
260
|
+
'<td>' + statusBadge(p.status) + '</td>' +
|
|
261
|
+
'<td>' + esc(p.codex) + '</td>' +
|
|
262
|
+
'<td class="writ-title-cell" data-plan-id="' + esc(p.id) + '">' + titleCell + '</td>' +
|
|
263
|
+
'<td><code>' + esc(p.id) + '</code></td>' +
|
|
264
|
+
'<td>' + formatDate(p.createdAt) + '</td>' +
|
|
265
|
+
'</tr>';
|
|
266
|
+
}
|
|
267
|
+
tbody.innerHTML = html;
|
|
268
|
+
|
|
269
|
+
// Wire row click handlers
|
|
270
|
+
var rows = tbody.querySelectorAll('tr');
|
|
271
|
+
for (var ri = 0; ri < rows.length; ri++) {
|
|
272
|
+
(function (row) {
|
|
273
|
+
row.addEventListener('click', function () {
|
|
274
|
+
var idx = parseInt(row.getAttribute('data-idx'), 10);
|
|
275
|
+
showPlanDetail(plans[idx]);
|
|
276
|
+
});
|
|
277
|
+
})(rows[ri]);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Fetch writ titles for plans that don't have one cached
|
|
281
|
+
for (var wi = 0; wi < plans.length; wi++) {
|
|
282
|
+
(function (plan) {
|
|
283
|
+
if (writTitleLookup[plan.id] !== undefined) return;
|
|
284
|
+
fetch('/api/writ/show?id=' + encodeURIComponent(plan.id))
|
|
285
|
+
.then(function (r) { return r.json(); })
|
|
286
|
+
.then(function (writ) {
|
|
287
|
+
writTitleLookup[plan.id] = (writ && writ.title) ? writ.title : '\u2014';
|
|
288
|
+
var cell = document.querySelector('.writ-title-cell[data-plan-id="' + plan.id + '"]');
|
|
289
|
+
if (cell) cell.textContent = writTitleLookup[plan.id];
|
|
290
|
+
})
|
|
291
|
+
.catch(function () {
|
|
292
|
+
writTitleLookup[plan.id] = '\u2014';
|
|
293
|
+
var cell = document.querySelector('.writ-title-cell[data-plan-id="' + plan.id + '"]');
|
|
294
|
+
if (cell) cell.textContent = '\u2014';
|
|
295
|
+
});
|
|
296
|
+
})(plans[wi]);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// ── Detail View ────────────────────────────────────────────────────────
|
|
301
|
+
|
|
302
|
+
function showPlanDetail(plan) {
|
|
303
|
+
currentPlan = plan;
|
|
304
|
+
listView.style.display = 'none';
|
|
305
|
+
detailView.style.display = '';
|
|
306
|
+
|
|
307
|
+
detailTitle.textContent = 'Plan: ' + plan.id;
|
|
308
|
+
|
|
309
|
+
// Metadata card
|
|
310
|
+
var briefLink = '<a href="/pages/clerk/?writ=' + encodeURIComponent(plan.id) + '">' + esc(plan.id) + '</a>';
|
|
311
|
+
var mandateHtml = '';
|
|
312
|
+
if (plan.generatedWritId) {
|
|
313
|
+
mandateHtml = '<dt>Mandate Writ</dt><dd><a href="/pages/clerk/?writ=' +
|
|
314
|
+
encodeURIComponent(plan.generatedWritId) + '">' + esc(plan.generatedWritId) + '</a></dd>';
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
metaCard.innerHTML =
|
|
318
|
+
'<dl class="meta-grid">' +
|
|
319
|
+
'<dt>Plan ID</dt><dd><code>' + esc(plan.id) + '</code></dd>' +
|
|
320
|
+
'<dt>Status</dt><dd>' + statusBadge(plan.status) + '</dd>' +
|
|
321
|
+
'<dt>Codex</dt><dd>' + esc(plan.codex) + '</dd>' +
|
|
322
|
+
'<dt>Brief Writ</dt><dd>' + briefLink + '</dd>' +
|
|
323
|
+
mandateHtml +
|
|
324
|
+
'<dt>Created</dt><dd>' + formatDate(plan.createdAt) + '</dd>' +
|
|
325
|
+
'<dt>Updated</dt><dd>' + formatDate(plan.updatedAt) + '</dd>' +
|
|
326
|
+
'</dl>' +
|
|
327
|
+
'<div id="cost-summary" style="margin-top:12px;"><span class="text-dim">Loading cost data...</span></div>';
|
|
328
|
+
|
|
329
|
+
// Fetch cost data
|
|
330
|
+
fetchCostData(plan.id);
|
|
331
|
+
|
|
332
|
+
// Configure tabs — disable empty ones
|
|
333
|
+
var tabFields = {
|
|
334
|
+
inventory: plan.inventory,
|
|
335
|
+
scope: plan.scope,
|
|
336
|
+
decisions: plan.decisions,
|
|
337
|
+
observations: plan.observations,
|
|
338
|
+
spec: plan.spec
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
var firstAvailable = null;
|
|
342
|
+
for (var ti = 0; ti < tabBtns.length; ti++) {
|
|
343
|
+
var btn = tabBtns[ti];
|
|
344
|
+
var tabName = btn.getAttribute('data-tab');
|
|
345
|
+
var val = tabFields[tabName];
|
|
346
|
+
var isEmpty = val == null || val === '' || (Array.isArray(val) && val.length === 0);
|
|
347
|
+
|
|
348
|
+
if (isEmpty) {
|
|
349
|
+
btn.style.opacity = '0.3';
|
|
350
|
+
btn.style.cursor = 'default';
|
|
351
|
+
btn.setAttribute('data-disabled', 'true');
|
|
352
|
+
btn.classList.remove('active');
|
|
353
|
+
} else {
|
|
354
|
+
btn.style.opacity = '';
|
|
355
|
+
btn.style.cursor = '';
|
|
356
|
+
btn.setAttribute('data-disabled', 'false');
|
|
357
|
+
if (!firstAvailable) firstAvailable = tabName;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Activate first available tab
|
|
362
|
+
if (firstAvailable) {
|
|
363
|
+
activeTab = firstAvailable;
|
|
364
|
+
for (var ai = 0; ai < tabBtns.length; ai++) {
|
|
365
|
+
tabBtns[ai].classList.remove('active');
|
|
366
|
+
if (tabBtns[ai].getAttribute('data-tab') === firstAvailable) {
|
|
367
|
+
tabBtns[ai].classList.add('active');
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
renderTab(firstAvailable);
|
|
371
|
+
} else {
|
|
372
|
+
tabContent.innerHTML = '<p class="empty-state">No content available.</p>';
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ── Cost Data ──────────────────────────────────────────────────────────
|
|
377
|
+
|
|
378
|
+
function fetchCostData(planId) {
|
|
379
|
+
var costEl = document.getElementById('cost-summary');
|
|
380
|
+
|
|
381
|
+
fetch('/api/rig/list?limit=100')
|
|
382
|
+
.then(function (r) { return r.json(); })
|
|
383
|
+
.then(function (rigs) {
|
|
384
|
+
var rig = rigs.find(function (r) { return r.writId === planId; });
|
|
385
|
+
if (!rig) {
|
|
386
|
+
renderCostUnavailable(costEl);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
var sessionEngines = (rig.engines || []).filter(function (e) {
|
|
391
|
+
return e.designId === 'anima-session' && e.sessionId;
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
if (sessionEngines.length === 0) {
|
|
395
|
+
renderCostUnavailable(costEl);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
var fetches = sessionEngines.map(function (e) {
|
|
400
|
+
return fetch('/api/session/show?id=' + encodeURIComponent(e.sessionId))
|
|
401
|
+
.then(function (r) { return r.json(); })
|
|
402
|
+
.then(function (session) {
|
|
403
|
+
return { engineId: e.id, session: session };
|
|
404
|
+
})
|
|
405
|
+
.catch(function () { return null; });
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
return Promise.all(fetches);
|
|
409
|
+
})
|
|
410
|
+
.then(function (results) {
|
|
411
|
+
if (!results) return;
|
|
412
|
+
var valid = results.filter(Boolean);
|
|
413
|
+
if (valid.length === 0) {
|
|
414
|
+
renderCostUnavailable(costEl);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
renderCostTable(costEl, valid);
|
|
418
|
+
})
|
|
419
|
+
.catch(function () {
|
|
420
|
+
renderCostUnavailable(costEl);
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function renderCostUnavailable(el) {
|
|
425
|
+
if (el) el.innerHTML = '<span class="text-dim">Cost data not available</span>';
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function renderCostTable(el, results) {
|
|
429
|
+
var totalInput = 0;
|
|
430
|
+
var totalOutput = 0;
|
|
431
|
+
var totalCost = 0;
|
|
432
|
+
|
|
433
|
+
var rows = '';
|
|
434
|
+
for (var i = 0; i < results.length; i++) {
|
|
435
|
+
var r = results[i];
|
|
436
|
+
var s = r.session;
|
|
437
|
+
var inputTokens = (s.tokenUsage && s.tokenUsage.inputTokens) || 0;
|
|
438
|
+
var outputTokens = (s.tokenUsage && s.tokenUsage.outputTokens) || 0;
|
|
439
|
+
var cost = s.costUsd || 0;
|
|
440
|
+
|
|
441
|
+
totalInput += inputTokens;
|
|
442
|
+
totalOutput += outputTokens;
|
|
443
|
+
totalCost += cost;
|
|
444
|
+
|
|
445
|
+
rows += '<tr>' +
|
|
446
|
+
'<td>' + esc(r.engineId) + '</td>' +
|
|
447
|
+
'<td>' + inputTokens.toLocaleString() + '</td>' +
|
|
448
|
+
'<td>' + outputTokens.toLocaleString() + '</td>' +
|
|
449
|
+
'<td>$' + cost.toFixed(4) + '</td>' +
|
|
450
|
+
'</tr>';
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
rows += '<tr class="cost-total">' +
|
|
454
|
+
'<td><strong>Total</strong></td>' +
|
|
455
|
+
'<td><strong>' + totalInput.toLocaleString() + '</strong></td>' +
|
|
456
|
+
'<td><strong>' + totalOutput.toLocaleString() + '</strong></td>' +
|
|
457
|
+
'<td><strong>$' + totalCost.toFixed(4) + '</strong></td>' +
|
|
458
|
+
'</tr>';
|
|
459
|
+
|
|
460
|
+
el.innerHTML =
|
|
461
|
+
'<table class="data-table cost-table">' +
|
|
462
|
+
'<thead><tr>' +
|
|
463
|
+
'<th>Step</th><th>Input Tokens</th><th>Output Tokens</th><th>Cost (USD)</th>' +
|
|
464
|
+
'</tr></thead>' +
|
|
465
|
+
'<tbody>' + rows + '</tbody>' +
|
|
466
|
+
'</table>';
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// ── Tab Rendering ──────────────────────────────────────────────────────
|
|
470
|
+
|
|
471
|
+
function renderTab(tabName) {
|
|
472
|
+
if (!currentPlan) return;
|
|
473
|
+
|
|
474
|
+
switch (tabName) {
|
|
475
|
+
case 'inventory':
|
|
476
|
+
tabContent.innerHTML = renderMarkdown(currentPlan.inventory);
|
|
477
|
+
break;
|
|
478
|
+
case 'observations':
|
|
479
|
+
tabContent.innerHTML = renderMarkdown(currentPlan.observations);
|
|
480
|
+
break;
|
|
481
|
+
case 'spec':
|
|
482
|
+
tabContent.innerHTML = renderMarkdown(currentPlan.spec);
|
|
483
|
+
break;
|
|
484
|
+
case 'scope':
|
|
485
|
+
tabContent.innerHTML = renderScopeTable(currentPlan.scope);
|
|
486
|
+
break;
|
|
487
|
+
case 'decisions':
|
|
488
|
+
tabContent.innerHTML = renderDecisionsTable(currentPlan.decisions);
|
|
489
|
+
wireDecisionRows();
|
|
490
|
+
break;
|
|
491
|
+
default:
|
|
492
|
+
tabContent.innerHTML = '';
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// ── Scope Table ────────────────────────────────────────────────────────
|
|
497
|
+
|
|
498
|
+
function renderScopeTable(scope) {
|
|
499
|
+
if (!scope || scope.length === 0) return '<p class="empty-state">No scope items.</p>';
|
|
500
|
+
var html = '<table class="data-table"><thead><tr>' +
|
|
501
|
+
'<th>ID</th><th>Description</th><th>Status</th><th>Rationale</th>' +
|
|
502
|
+
'</tr></thead><tbody>';
|
|
503
|
+
for (var i = 0; i < scope.length; i++) {
|
|
504
|
+
var s = scope[i];
|
|
505
|
+
var badge = s.included
|
|
506
|
+
? '<span class="badge badge--success">included</span>'
|
|
507
|
+
: '<span class="badge badge--error">excluded</span>';
|
|
508
|
+
html += '<tr><td>' + esc(s.id) + '</td><td>' + esc(s.description) +
|
|
509
|
+
'</td><td>' + badge + '</td><td>' + esc(s.rationale) + '</td></tr>';
|
|
510
|
+
}
|
|
511
|
+
html += '</tbody></table>';
|
|
512
|
+
return html;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// ── Decisions Table ────────────────────────────────────────────────────
|
|
516
|
+
|
|
517
|
+
function renderDecisionsTable(decisions) {
|
|
518
|
+
if (!decisions || decisions.length === 0) return '<p class="empty-state">No decisions.</p>';
|
|
519
|
+
var html = '<table class="data-table" id="decisions-table"><thead><tr>' +
|
|
520
|
+
'<th>ID</th><th>Question</th><th>Selected</th>' +
|
|
521
|
+
'</tr></thead><tbody>';
|
|
522
|
+
for (var i = 0; i < decisions.length; i++) {
|
|
523
|
+
var d = decisions[i];
|
|
524
|
+
html += '<tr class="decision-row" data-idx="' + i + '">' +
|
|
525
|
+
'<td>' + esc(d.id) + '</td>' +
|
|
526
|
+
'<td>' + esc(d.question) + '</td>' +
|
|
527
|
+
'<td>' + esc(d.selected || '\u2014') + '</td></tr>';
|
|
528
|
+
}
|
|
529
|
+
html += '</tbody></table>';
|
|
530
|
+
return html;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function wireDecisionRows() {
|
|
534
|
+
var rows = document.querySelectorAll('.decision-row');
|
|
535
|
+
for (var i = 0; i < rows.length; i++) {
|
|
536
|
+
(function (row) {
|
|
537
|
+
row.addEventListener('click', function () {
|
|
538
|
+
var idx = parseInt(row.getAttribute('data-idx'), 10);
|
|
539
|
+
var existing = row.nextElementSibling;
|
|
540
|
+
|
|
541
|
+
// Toggle: remove if already expanded
|
|
542
|
+
if (existing && existing.classList.contains('decision-detail')) {
|
|
543
|
+
existing.remove();
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
var d = currentPlan.decisions[idx];
|
|
548
|
+
var detailHtml = '<td colspan="3">';
|
|
549
|
+
|
|
550
|
+
if (d.context) {
|
|
551
|
+
detailHtml += '<p><strong>Context:</strong> ' + esc(d.context) + '</p>';
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Options
|
|
555
|
+
if (d.options && Object.keys(d.options).length > 0) {
|
|
556
|
+
detailHtml += '<p><strong>Options:</strong></p><dl>';
|
|
557
|
+
var keys = Object.keys(d.options);
|
|
558
|
+
for (var k = 0; k < keys.length; k++) {
|
|
559
|
+
detailHtml += '<dt>' + esc(keys[k]) + '</dt><dd>' + esc(d.options[keys[k]]) + '</dd>';
|
|
560
|
+
}
|
|
561
|
+
detailHtml += '</dl>';
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (d.recommendation) {
|
|
565
|
+
detailHtml += '<p><strong>Recommendation:</strong> ' + esc(d.recommendation);
|
|
566
|
+
if (d.rationale) detailHtml += ' — ' + esc(d.rationale);
|
|
567
|
+
detailHtml += '</p>';
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (d.patronOverride) {
|
|
571
|
+
detailHtml += '<p style="color:var(--yellow)"><strong>Patron Override:</strong> ' +
|
|
572
|
+
esc(d.patronOverride) + '</p>';
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
detailHtml += '</td>';
|
|
576
|
+
|
|
577
|
+
var detailTr = document.createElement('tr');
|
|
578
|
+
detailTr.className = 'decision-detail';
|
|
579
|
+
detailTr.innerHTML = detailHtml;
|
|
580
|
+
row.insertAdjacentElement('afterend', detailTr);
|
|
581
|
+
});
|
|
582
|
+
})(rows[i]);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// ── Navigation ─────────────────────────────────────────────────────────
|
|
587
|
+
|
|
588
|
+
function backToList() {
|
|
589
|
+
detailView.style.display = 'none';
|
|
590
|
+
listView.style.display = '';
|
|
591
|
+
currentPlan = null;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// ── Deep Link ──────────────────────────────────────────────────────────
|
|
595
|
+
|
|
596
|
+
function handleDeepLink() {
|
|
597
|
+
var params = new URLSearchParams(window.location.search);
|
|
598
|
+
var planId = params.get('plan');
|
|
599
|
+
|
|
600
|
+
if (planId) {
|
|
601
|
+
// Deep link: fetch and show the specific plan
|
|
602
|
+
fetch('/api/plan/show?planId=' + encodeURIComponent(planId))
|
|
603
|
+
.then(function (r) {
|
|
604
|
+
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
605
|
+
return r.json();
|
|
606
|
+
})
|
|
607
|
+
.then(function (plan) {
|
|
608
|
+
showPlanDetail(plan);
|
|
609
|
+
})
|
|
610
|
+
.catch(function (err) {
|
|
611
|
+
console.error('Deep-link plan not found:', planId, err);
|
|
612
|
+
// Fallback: show list view
|
|
613
|
+
fetchPlans(true);
|
|
614
|
+
});
|
|
615
|
+
} else {
|
|
616
|
+
fetchPlans(true);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// ── Init ───────────────────────────────────────────────────────────────
|
|
621
|
+
|
|
622
|
+
handleDeepLink();
|
|
623
|
+
})();
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for astrolabe.js pure functions.
|
|
3
|
+
*
|
|
4
|
+
* Since astrolabe.js is a browser IIFE, we extract and test the pure
|
|
5
|
+
* functions (esc, formatDate, statusBadge, renderMarkdown, renderScopeTable,
|
|
6
|
+
* renderDecisionsTable) by re-defining them here in an identical manner.
|
|
7
|
+
*
|
|
8
|
+
* This validates the rendering logic without requiring a browser environment.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, it } from 'node:test';
|
|
12
|
+
import assert from 'node:assert/strict';
|
|
13
|
+
|
|
14
|
+
// ── Extracted pure functions (identical to astrolabe.js) ─────────────
|
|
15
|
+
|
|
16
|
+
function esc(s) {
|
|
17
|
+
if (s == null) return '';
|
|
18
|
+
return String(s)
|
|
19
|
+
.replace(/&/g, '&')
|
|
20
|
+
.replace(/</g, '<')
|
|
21
|
+
.replace(/>/g, '>')
|
|
22
|
+
.replace(/"/g, '"');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function formatDate(iso) {
|
|
26
|
+
if (!iso) return '';
|
|
27
|
+
try {
|
|
28
|
+
return new Date(iso).toLocaleString();
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return iso;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function statusBadge(status) {
|
|
35
|
+
var map = {
|
|
36
|
+
reading: 'badge badge--active',
|
|
37
|
+
analyzing: 'badge badge--active',
|
|
38
|
+
writing: 'badge badge--active',
|
|
39
|
+
reviewing: 'badge badge--warning',
|
|
40
|
+
completed: 'badge badge--success',
|
|
41
|
+
failed: 'badge badge--error'
|
|
42
|
+
};
|
|
43
|
+
var cls = map[status] || 'badge';
|
|
44
|
+
return '<span class="' + cls + '">' + esc(status) + '</span>';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function applyInline(text) {
|
|
48
|
+
text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
|
49
|
+
text = text.replace(/\*(.+?)\*/g, '<em>$1</em>');
|
|
50
|
+
text = text.replace(/\b_(.+?)_\b/g, '<em>$1</em>');
|
|
51
|
+
text = text.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
52
|
+
return text;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function renderMarkdown(md) {
|
|
56
|
+
if (md == null || md === '') return '';
|
|
57
|
+
|
|
58
|
+
var text = esc(md);
|
|
59
|
+
|
|
60
|
+
var codeBlocks = [];
|
|
61
|
+
text = text.replace(/```[\s\S]*?```/g, function (match) {
|
|
62
|
+
var inner = match.replace(/^```[^\n]*\n?/, '').replace(/\n?```$/, '');
|
|
63
|
+
var idx = codeBlocks.length;
|
|
64
|
+
codeBlocks.push('<pre><code>' + inner + '</code></pre>');
|
|
65
|
+
return '\x00CODEBLOCK' + idx + '\x00';
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
var lines = text.split('\n');
|
|
69
|
+
var result = [];
|
|
70
|
+
var i = 0;
|
|
71
|
+
|
|
72
|
+
while (i < lines.length) {
|
|
73
|
+
var line = lines[i];
|
|
74
|
+
|
|
75
|
+
var cbMatch = line.match(/^\x00CODEBLOCK(\d+)\x00$/);
|
|
76
|
+
if (cbMatch) {
|
|
77
|
+
result.push(codeBlocks[parseInt(cbMatch[1], 10)]);
|
|
78
|
+
i++;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var headingMatch = line.match(/^(#{1,6}) (.+)$/);
|
|
83
|
+
if (headingMatch) {
|
|
84
|
+
var level = headingMatch[1].length;
|
|
85
|
+
var content = applyInline(headingMatch[2]);
|
|
86
|
+
result.push('<h' + level + '>' + content + '</h' + level + '>');
|
|
87
|
+
i++;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (/^[\-\*] /.test(line)) {
|
|
92
|
+
var items = [];
|
|
93
|
+
while (i < lines.length && /^[\-\*] /.test(lines[i])) {
|
|
94
|
+
items.push('<li>' + applyInline(lines[i].replace(/^[\-\*] /, '')) + '</li>');
|
|
95
|
+
i++;
|
|
96
|
+
}
|
|
97
|
+
result.push('<ul>' + items.join('') + '</ul>');
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (/^\d+\. /.test(line)) {
|
|
102
|
+
var olItems = [];
|
|
103
|
+
while (i < lines.length && /^\d+\. /.test(lines[i])) {
|
|
104
|
+
olItems.push('<li>' + applyInline(lines[i].replace(/^\d+\. /, '')) + '</li>');
|
|
105
|
+
i++;
|
|
106
|
+
}
|
|
107
|
+
result.push('<ol>' + olItems.join('') + '</ol>');
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (line.trim() === '') {
|
|
112
|
+
i++;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
var para = [];
|
|
117
|
+
while (i < lines.length && lines[i].trim() !== '' &&
|
|
118
|
+
!/^#{1,6} /.test(lines[i]) &&
|
|
119
|
+
!/^[\-\*] /.test(lines[i]) &&
|
|
120
|
+
!/^\d+\. /.test(lines[i]) &&
|
|
121
|
+
!/^\x00CODEBLOCK/.test(lines[i])) {
|
|
122
|
+
para.push(applyInline(lines[i]));
|
|
123
|
+
i++;
|
|
124
|
+
}
|
|
125
|
+
if (para.length > 0) {
|
|
126
|
+
result.push('<p>' + para.join(' ') + '</p>');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return '<div class="md-content">' + result.join('') + '</div>';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function renderScopeTable(scope) {
|
|
134
|
+
if (!scope || scope.length === 0) return '<p class="empty-state">No scope items.</p>';
|
|
135
|
+
var html = '<table class="data-table"><thead><tr>' +
|
|
136
|
+
'<th>ID</th><th>Description</th><th>Status</th><th>Rationale</th>' +
|
|
137
|
+
'</tr></thead><tbody>';
|
|
138
|
+
for (var i = 0; i < scope.length; i++) {
|
|
139
|
+
var s = scope[i];
|
|
140
|
+
var badge = s.included
|
|
141
|
+
? '<span class="badge badge--success">included</span>'
|
|
142
|
+
: '<span class="badge badge--error">excluded</span>';
|
|
143
|
+
html += '<tr><td>' + esc(s.id) + '</td><td>' + esc(s.description) +
|
|
144
|
+
'</td><td>' + badge + '</td><td>' + esc(s.rationale) + '</td></tr>';
|
|
145
|
+
}
|
|
146
|
+
html += '</tbody></table>';
|
|
147
|
+
return html;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function renderDecisionsTable(decisions) {
|
|
151
|
+
if (!decisions || decisions.length === 0) return '<p class="empty-state">No decisions.</p>';
|
|
152
|
+
var html = '<table class="data-table" id="decisions-table"><thead><tr>' +
|
|
153
|
+
'<th>ID</th><th>Question</th><th>Selected</th>' +
|
|
154
|
+
'</tr></thead><tbody>';
|
|
155
|
+
for (var i = 0; i < decisions.length; i++) {
|
|
156
|
+
var d = decisions[i];
|
|
157
|
+
html += '<tr class="decision-row" data-idx="' + i + '">' +
|
|
158
|
+
'<td>' + esc(d.id) + '</td>' +
|
|
159
|
+
'<td>' + esc(d.question) + '</td>' +
|
|
160
|
+
'<td>' + esc(d.selected || '\u2014') + '</td></tr>';
|
|
161
|
+
}
|
|
162
|
+
html += '</tbody></table>';
|
|
163
|
+
return html;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ── Tests ────────────────────────────────────────────────────────────
|
|
167
|
+
|
|
168
|
+
describe('esc()', () => {
|
|
169
|
+
it('returns empty string for null', () => {
|
|
170
|
+
assert.equal(esc(null), '');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('returns empty string for undefined', () => {
|
|
174
|
+
assert.equal(esc(undefined), '');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('escapes HTML special characters', () => {
|
|
178
|
+
assert.equal(esc('<script>"&'), '<script>"&');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('converts numbers to string', () => {
|
|
182
|
+
assert.equal(esc(42), '42');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('formatDate()', () => {
|
|
187
|
+
it('returns empty string for falsy input', () => {
|
|
188
|
+
assert.equal(formatDate(''), '');
|
|
189
|
+
assert.equal(formatDate(null), '');
|
|
190
|
+
assert.equal(formatDate(undefined), '');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('formats an ISO date string', () => {
|
|
194
|
+
var result = formatDate('2024-01-15T10:30:00Z');
|
|
195
|
+
assert.ok(result.length > 0, 'should produce a non-empty string');
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('statusBadge()', () => {
|
|
200
|
+
it('reading maps to badge--active', () => {
|
|
201
|
+
var html = statusBadge('reading');
|
|
202
|
+
assert.ok(html.includes('badge badge--active'));
|
|
203
|
+
assert.ok(html.includes('reading'));
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('analyzing maps to badge--active', () => {
|
|
207
|
+
assert.ok(statusBadge('analyzing').includes('badge--active'));
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('writing maps to badge--active', () => {
|
|
211
|
+
assert.ok(statusBadge('writing').includes('badge--active'));
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('reviewing maps to badge--warning', () => {
|
|
215
|
+
assert.ok(statusBadge('reviewing').includes('badge--warning'));
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('completed maps to badge--success', () => {
|
|
219
|
+
assert.ok(statusBadge('completed').includes('badge--success'));
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('failed maps to badge--error', () => {
|
|
223
|
+
assert.ok(statusBadge('failed').includes('badge--error'));
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('unknown status falls back to bare badge class', () => {
|
|
227
|
+
var html = statusBadge('unknown');
|
|
228
|
+
assert.equal(html, '<span class="badge">unknown</span>');
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
describe('renderMarkdown()', () => {
|
|
233
|
+
it('returns empty string for null', () => {
|
|
234
|
+
assert.equal(renderMarkdown(null), '');
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('returns empty string for undefined', () => {
|
|
238
|
+
assert.equal(renderMarkdown(undefined), '');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('returns empty string for empty string', () => {
|
|
242
|
+
assert.equal(renderMarkdown(''), '');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('renders headings', () => {
|
|
246
|
+
var result = renderMarkdown('# H1\n## H2\n### H3');
|
|
247
|
+
assert.ok(result.includes('<h1>H1</h1>'));
|
|
248
|
+
assert.ok(result.includes('<h2>H2</h2>'));
|
|
249
|
+
assert.ok(result.includes('<h3>H3</h3>'));
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('renders h4, h5, h6', () => {
|
|
253
|
+
var result = renderMarkdown('#### H4\n##### H5\n###### H6');
|
|
254
|
+
assert.ok(result.includes('<h4>H4</h4>'));
|
|
255
|
+
assert.ok(result.includes('<h5>H5</h5>'));
|
|
256
|
+
assert.ok(result.includes('<h6>H6</h6>'));
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('renders bold text', () => {
|
|
260
|
+
var result = renderMarkdown('some **bold** text');
|
|
261
|
+
assert.ok(result.includes('<strong>bold</strong>'));
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('renders italic text with asterisks', () => {
|
|
265
|
+
var result = renderMarkdown('some *italic* text');
|
|
266
|
+
assert.ok(result.includes('<em>italic</em>'));
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('renders inline code', () => {
|
|
270
|
+
var result = renderMarkdown('use `code` here');
|
|
271
|
+
assert.ok(result.includes('<code>code</code>'));
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('renders fenced code blocks', () => {
|
|
275
|
+
var result = renderMarkdown('```js\nconst x = 1;\n```');
|
|
276
|
+
assert.ok(result.includes('<pre><code>'));
|
|
277
|
+
assert.ok(result.includes('const x = 1;'));
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('renders unordered lists', () => {
|
|
281
|
+
var result = renderMarkdown('- item1\n- item2');
|
|
282
|
+
assert.ok(result.includes('<ul>'));
|
|
283
|
+
assert.ok(result.includes('<li>item1</li>'));
|
|
284
|
+
assert.ok(result.includes('<li>item2</li>'));
|
|
285
|
+
assert.ok(result.includes('</ul>'));
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('renders ordered lists', () => {
|
|
289
|
+
var result = renderMarkdown('1. first\n2. second');
|
|
290
|
+
assert.ok(result.includes('<ol>'));
|
|
291
|
+
assert.ok(result.includes('<li>first</li>'));
|
|
292
|
+
assert.ok(result.includes('<li>second</li>'));
|
|
293
|
+
assert.ok(result.includes('</ol>'));
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('renders paragraphs', () => {
|
|
297
|
+
var result = renderMarkdown('hello world');
|
|
298
|
+
assert.ok(result.includes('<p>hello world</p>'));
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('wraps output in md-content div', () => {
|
|
302
|
+
var result = renderMarkdown('test');
|
|
303
|
+
assert.ok(result.startsWith('<div class="md-content">'));
|
|
304
|
+
assert.ok(result.endsWith('</div>'));
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('prevents XSS — escapes script tags', () => {
|
|
308
|
+
var result = renderMarkdown('<script>alert(1)</script>');
|
|
309
|
+
assert.ok(!result.includes('<script>'));
|
|
310
|
+
assert.ok(result.includes('<script>'));
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('prevents XSS — escapes HTML in headings', () => {
|
|
314
|
+
var result = renderMarkdown('# <img onerror=alert(1)>');
|
|
315
|
+
assert.ok(!result.includes('<img'));
|
|
316
|
+
assert.ok(result.includes('<img'));
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('renders unordered lists with * prefix', () => {
|
|
320
|
+
var result = renderMarkdown('* alpha\n* beta');
|
|
321
|
+
assert.ok(result.includes('<ul>'));
|
|
322
|
+
assert.ok(result.includes('<li>alpha</li>'));
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
describe('renderScopeTable()', () => {
|
|
327
|
+
it('returns empty state for null scope', () => {
|
|
328
|
+
assert.ok(renderScopeTable(null).includes('No scope items'));
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('returns empty state for empty array', () => {
|
|
332
|
+
assert.ok(renderScopeTable([]).includes('No scope items'));
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('renders included item with success badge', () => {
|
|
336
|
+
var scope = [
|
|
337
|
+
{ id: 's1', description: 'Feature A', rationale: 'Important', included: true }
|
|
338
|
+
];
|
|
339
|
+
var html = renderScopeTable(scope);
|
|
340
|
+
assert.ok(html.includes('badge--success'));
|
|
341
|
+
assert.ok(html.includes('included'));
|
|
342
|
+
assert.ok(html.includes('Feature A'));
|
|
343
|
+
assert.ok(html.includes('Important'));
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('renders excluded item with error badge', () => {
|
|
347
|
+
var scope = [
|
|
348
|
+
{ id: 's2', description: 'Feature B', rationale: 'Out of scope', included: false }
|
|
349
|
+
];
|
|
350
|
+
var html = renderScopeTable(scope);
|
|
351
|
+
assert.ok(html.includes('badge--error'));
|
|
352
|
+
assert.ok(html.includes('excluded'));
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('renders two items correctly', () => {
|
|
356
|
+
var scope = [
|
|
357
|
+
{ id: 's1', description: 'A', rationale: 'R1', included: true },
|
|
358
|
+
{ id: 's2', description: 'B', rationale: 'R2', included: false }
|
|
359
|
+
];
|
|
360
|
+
var html = renderScopeTable(scope);
|
|
361
|
+
assert.ok(html.includes('s1'));
|
|
362
|
+
assert.ok(html.includes('s2'));
|
|
363
|
+
assert.ok(html.includes('badge--success'));
|
|
364
|
+
assert.ok(html.includes('badge--error'));
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('escapes HTML in scope fields', () => {
|
|
368
|
+
var scope = [
|
|
369
|
+
{ id: '<xss>', description: '<b>evil</b>', rationale: '&test', included: true }
|
|
370
|
+
];
|
|
371
|
+
var html = renderScopeTable(scope);
|
|
372
|
+
assert.ok(html.includes('<xss>'));
|
|
373
|
+
assert.ok(!html.includes('<xss>'));
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
describe('renderDecisionsTable()', () => {
|
|
378
|
+
it('returns empty state for null decisions', () => {
|
|
379
|
+
assert.ok(renderDecisionsTable(null).includes('No decisions'));
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('returns empty state for empty array', () => {
|
|
383
|
+
assert.ok(renderDecisionsTable([]).includes('No decisions'));
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('renders a decision row', () => {
|
|
387
|
+
var decisions = [
|
|
388
|
+
{ id: 'd1', question: 'Which DB?', selected: 'postgres', options: {} }
|
|
389
|
+
];
|
|
390
|
+
var html = renderDecisionsTable(decisions);
|
|
391
|
+
assert.ok(html.includes('d1'));
|
|
392
|
+
assert.ok(html.includes('Which DB?'));
|
|
393
|
+
assert.ok(html.includes('postgres'));
|
|
394
|
+
assert.ok(html.includes('decision-row'));
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('shows em-dash when no selection', () => {
|
|
398
|
+
var decisions = [
|
|
399
|
+
{ id: 'd2', question: 'Color?', options: {} }
|
|
400
|
+
];
|
|
401
|
+
var html = renderDecisionsTable(decisions);
|
|
402
|
+
assert.ok(html.includes('\u2014'));
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it('renders multiple decisions with correct data-idx', () => {
|
|
406
|
+
var decisions = [
|
|
407
|
+
{ id: 'd1', question: 'Q1', selected: 'A', options: {} },
|
|
408
|
+
{ id: 'd2', question: 'Q2', selected: 'B', options: {} }
|
|
409
|
+
];
|
|
410
|
+
var html = renderDecisionsTable(decisions);
|
|
411
|
+
assert.ok(html.includes('data-idx="0"'));
|
|
412
|
+
assert.ok(html.includes('data-idx="1"'));
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it('escapes HTML in decision fields', () => {
|
|
416
|
+
var decisions = [
|
|
417
|
+
{ id: '<xss>', question: '<script>', selected: '&test', options: {} }
|
|
418
|
+
];
|
|
419
|
+
var html = renderDecisionsTable(decisions);
|
|
420
|
+
assert.ok(html.includes('<xss>'));
|
|
421
|
+
assert.ok(html.includes('<script>'));
|
|
422
|
+
assert.ok(!html.includes('<script>'));
|
|
423
|
+
});
|
|
424
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Astrolabe</title>
|
|
6
|
+
<link rel="stylesheet" href="astrolabe.css">
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<main style="padding: 24px;">
|
|
10
|
+
|
|
11
|
+
<!-- ── List View ──────────────────────────────────────────────────── -->
|
|
12
|
+
<div id="plan-list-view">
|
|
13
|
+
<h2>Plans</h2>
|
|
14
|
+
|
|
15
|
+
<div id="status-filters" style="margin-bottom: 12px;">
|
|
16
|
+
<button class="btn filter-btn active-filter" data-status="">All</button>
|
|
17
|
+
<button class="btn filter-btn" data-status="reading">Reading</button>
|
|
18
|
+
<button class="btn filter-btn" data-status="analyzing">Analyzing</button>
|
|
19
|
+
<button class="btn filter-btn" data-status="reviewing">Reviewing</button>
|
|
20
|
+
<button class="btn filter-btn" data-status="writing">Writing</button>
|
|
21
|
+
<button class="btn filter-btn" data-status="completed">Completed</button>
|
|
22
|
+
<button class="btn filter-btn" data-status="failed">Failed</button>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<table class="data-table">
|
|
26
|
+
<thead>
|
|
27
|
+
<tr>
|
|
28
|
+
<th>Status</th>
|
|
29
|
+
<th>Codex</th>
|
|
30
|
+
<th>Title</th>
|
|
31
|
+
<th>Plan ID</th>
|
|
32
|
+
<th>Created</th>
|
|
33
|
+
</tr>
|
|
34
|
+
</thead>
|
|
35
|
+
<tbody id="plan-tbody"></tbody>
|
|
36
|
+
</table>
|
|
37
|
+
|
|
38
|
+
<div id="empty-state" class="empty-state" style="display:none;">No plans found.</div>
|
|
39
|
+
|
|
40
|
+
<div style="text-align:center; margin-top:12px;">
|
|
41
|
+
<button id="load-more-btn" class="btn" style="display:none;">Load More</button>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<!-- ── Detail View ────────────────────────────────────────────────── -->
|
|
46
|
+
<div id="plan-detail-view" style="display:none;">
|
|
47
|
+
<button id="back-btn" class="btn" style="margin-bottom:12px;">← Back to list</button>
|
|
48
|
+
<h2 id="detail-title"></h2>
|
|
49
|
+
|
|
50
|
+
<div id="meta-card" class="card" style="margin-bottom:16px;"></div>
|
|
51
|
+
|
|
52
|
+
<div class="tab-bar" id="plan-tabs">
|
|
53
|
+
<button class="tab active" data-tab="inventory">Inventory</button>
|
|
54
|
+
<button class="tab" data-tab="scope">Scope</button>
|
|
55
|
+
<button class="tab" data-tab="decisions">Decisions</button>
|
|
56
|
+
<button class="tab" data-tab="observations">Observations</button>
|
|
57
|
+
<button class="tab" data-tab="spec">Spec</button>
|
|
58
|
+
</div>
|
|
59
|
+
<div id="tab-content"></div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
</main>
|
|
63
|
+
<script src="astrolabe.js"></script>
|
|
64
|
+
</body>
|
|
65
|
+
</html>
|