opencode-self-improvement 0.6.0 → 0.6.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-self-improvement",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Durable memory for opencode: remember facts, decisions, and commands across sessions, plus a one-command per-repo setup (/repo-init).",
5
5
  "main": "index.ts",
6
6
  "exports": {
@@ -143,6 +143,22 @@
143
143
  </div>
144
144
  </div>
145
145
 
146
+ <script id="viewer-helpers">
147
+ // Pure render helpers — DOM-free by contract so test/viewer.test.ts can eval
148
+ // THIS block standalone and assert the shipped escaping (issue #11). Keep it
149
+ // free of document/window references.
150
+ // Store values are untrusted by principle, not just by policy: ts and
151
+ // superseded_by are normally code-written ISO strings, but a hostile import
152
+ // file (pre-#9 route) or a forged store file could plant HTML here, and the
153
+ // row template renders via innerHTML in the viewer's own origin.
154
+ function esc(s) { return String(s).replace(/[&<>"]/g, (c) => ({ "&":"&amp;", "<":"&lt;", ">":"&gt;", '"':"&quot;" }[c])); }
155
+ function badge(cls, text) { return `<span class="badge ${esc(cls)}">${esc(text)}</span>`; }
156
+ function tsCell(ts) {
157
+ const parts = String(ts).split("T");
158
+ return `${esc(parts[0])}<br>${esc((parts[1] || "").slice(0, 8))}`;
159
+ }
160
+ </script>
161
+
146
162
  <script>
147
163
  const $ = (id) => document.getElementById(id);
148
164
  let DATA = null;
@@ -188,7 +204,7 @@ function render() {
188
204
  $("rows").innerHTML = rows.map((m) => {
189
205
  const status = kind === "blocked" ? "blocked" : kind === "deleted" ? "deleted"
190
206
  : m.superseded_by ? "superseded" : "active";
191
- const stBadge = status === "superseded" ? badge("status-superseded", `superseded \u2192 ${m.superseded_by.slice(0,8)}`)
207
+ const stBadge = status === "superseded" ? badge("status-superseded", "superseded \u2192 " + m.superseded_by.slice(0,8))
192
208
  : badge("status-" + status, status);
193
209
  const actions = kind === "blocked"
194
210
  ? `<button class="btn warn" data-action="unblock" data-ts="${esc(m.ts)}" title="Restore this memory to the read paths">unblock</button>`
@@ -198,9 +214,9 @@ function render() {
198
214
  <button class="btn danger" data-action="delete" data-ts="${esc(m.ts)}" title="Delete: snapshot the file, then remove this entry (audited)">delete</button>
199
215
  <button class="btn danger" data-action="block" data-ts="${esc(m.ts)}" title="Block (poison): keep on disk but hide from recall/inject">block</button>`;
200
216
  return `<tr>
201
- <td class="ts">${m.ts.split("T")[0]}<br>${(m.ts.split("T")[1] || "").slice(0,8)}</td>
202
- <td>${badge("type", esc(m.type))}</td>
203
- <td>${badge("scope", esc(m.scope))}</td>
217
+ <td class="ts">${tsCell(m.ts)}</td>
218
+ <td>${badge("type", m.type)}</td>
219
+ <td>${badge("scope", m.scope)}</td>
204
220
  <td class="content">${esc(m.content)}</td>
205
221
  <td>${stBadge}</td>
206
222
  <td class="actions">${actions}</td>
@@ -214,8 +230,6 @@ function render() {
214
230
  $("cDeleted").textContent = DATA.deleted.length;
215
231
  }
216
232
 
217
- function esc(s) { return String(s).replace(/[&<>"]/g, (c) => ({ "&":"&amp;", "<":"&lt;", ">":"&gt;", '"':"&quot;" }[c])); }
218
-
219
233
  async function refresh() {
220
234
  DATA = await api("/api/data");
221
235
  const scopes = [...new Set(DATA.memories.map((m) => m.scope))].sort();
@@ -226,8 +240,6 @@ async function refresh() {
226
240
  render();
227
241
  }
228
242
 
229
- function badge(cls, text) { return `<span class="badge ${cls}">${text}</span>`; }
230
-
231
243
  function openEdit(ts) {
232
244
  const m = DATA.memories.find((x) => x.ts === ts);
233
245
  editingTs = ts;