[object Object]

← back to AbramsEgo

auto-save: 2026-07-01T12:12:34 (4 files) — build-queue/STOP build-queue/tasks/06a-cards-datetime.md public/index.html build-queue/failed/06a-cards-datetime.md

79460f7fdd7142eeb4f03eb2ee9d441dba91a396 · 2026-07-01 12:12:35 -0700 · Steve Abrams

Files touched

Diff

commit 79460f7fdd7142eeb4f03eb2ee9d441dba91a396
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 1 12:12:35 2026 -0700

    auto-save: 2026-07-01T12:12:34 (4 files) — build-queue/STOP build-queue/tasks/06a-cards-datetime.md public/index.html build-queue/failed/06a-cards-datetime.md
---
 build-queue/STOP                                   |  0
 .../{tasks => failed}/06a-cards-datetime.md        |  0
 public/index.html                                  | 75 +++++++++++++++-------
 3 files changed, 52 insertions(+), 23 deletions(-)

diff --git a/build-queue/STOP b/build-queue/STOP
deleted file mode 100644
index e69de29..0000000
diff --git a/build-queue/tasks/06a-cards-datetime.md b/build-queue/failed/06a-cards-datetime.md
similarity index 100%
rename from build-queue/tasks/06a-cards-datetime.md
rename to build-queue/failed/06a-cards-datetime.md
diff --git a/public/index.html b/public/index.html
index 59a8883..4e2098d 100644
--- a/public/index.html
+++ b/public/index.html
@@ -136,6 +136,7 @@
   <!-- CANARIES -->
   <section class="card span4">
     <h2>🐤 Canary board</h2>
+    <div id="canaries-ctl"></div>
     <div class="list" id="canaries"></div>
   </section>
 
@@ -184,7 +185,8 @@
   <!-- CRON / LAUNCHD (panel 4) — every scheduled com.steve.* job as an admin card -->
   <section class="card span12">
     <h2>⏱ Cron / launchd <span class="muted" id="crons-sub"></span></h2>
-    <div id="crongrid" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px"></div>
+    <div id="crongrid-ctl"></div>
+    <div id="crongrid" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px;max-height:560px;overflow:auto"></div>
   </section>
 
   <!-- AI CHAT -->
@@ -322,13 +324,9 @@ async function load(){
   $('loc-up').innerHTML=`<span class="good">${l.up??'—'}</span><span class="dim" style="font-size:16px">/${l.total??'—'} up</span>`;
   $('loc-list').innerHTML=(l.procs||[]).map(pr=>lrow(`${statusDot(pr.status)}${esc(pr.name)}`,`${pr.memMB!=null?pr.memMB+'M':''}`,whenChip(pr.startedAt))).join('')||'<span class="muted">no local pm2 procs</span>';
 
-  // ---- canaries ----
+  // ---- canaries ---- (sort + density + infinite scroll like every DW grid)
   const cans=(d.canaries&&d.canaries.canaries)||[];
-  $('canaries').innerHTML=cans.map(cn=>{
-    const v=(cn.verdict||'').toUpperCase();
-    const col=/FAIL|DOWN|CRIT/.test(v)?'bad':/WARN|DEGRAD/.test(v)?'warn':/PASS|UP|HEALTH|OK/.test(v)?'good':'dim';
-    return lrow(esc(cn.name),`<span class="${col}">${esc(cn.verdict||'—')}</span> <span class="dim">${cn.ageMin}m${cn.stale?' ⚠':''}</span>`,whenChip(cn.mtime,cn.scanned));
-  }).join('')||'<span class="muted">no canaries</span>';
+  renderCanaries(cans);
 
   // ---- crons / officers ----
   const cr=d.crons||{};
@@ -459,27 +457,58 @@ function renderActivity(d){
 // PID · idle=grey · nonzero-exit=red.
 function renderCrons(d){
   const cr=d.crons||{};
-  const jobs=(cr.jobs||[]).slice().sort((a,b)=>String(a.label).localeCompare(String(b.label)));
+  const jobs=cr.jobs||[];
   $('crons-sub').textContent=`· ${cr.loadedCount??0} loaded / ${cr.count??0} total · com.steve.*`;
-  const el=$('crongrid'); if(!el) return;
-  const pill=(j)=>{
+  const cronPill=(j)=>{
     if(j.state==='running') return `<span class="pill live">▶ running · ${esc(j.pid)}</span>`;
     if(j.state==='error') return `<span class="pill" style="color:var(--bad);border-color:#ff5d6c44;background:#ff5d6c0f">✕ exit ${esc(j.lastExit)}</span>`;
     return `<span class="pill">idle</span>`;
   };
-  el.innerHTML=jobs.map(j=>{
-    const iso=j.created||j.modified||'';
-    const dt=iso?new Date(iso):null;
-    const when=dt?dt.toLocaleString(undefined,{year:'numeric',month:'short',day:'numeric',hour:'numeric',minute:'2-digit'}):'—';
-    const name=String(j.label||'').replace(/^com\.steve\./,'');
-    const sched=j.schedule?`⏲ ${esc(j.schedule)}`:'<span class="dim">no schedule</span>';
-    const prog=j.program?` · <span class="dim">${esc(j.program)}</span>`:'';
-    return `<div class="subcard" title="created ${esc(iso)}">
-      <div class="subcard-top"><span class="subcard-proj">${esc(name)}</span>${pill(j)}</div>
-      <div class="subcard-when" style="margin-top:6px">${sched}${prog}</div>
-      <div class="subcard-when">🕓 ${esc(when)}</div>
-    </div>`;
-  }).join('')||'<span class="muted">no com.steve.* jobs</span>';
+  const cronRank=(j)=> j.state==='error'?0 : j.state==='running'?1 : 2;
+  initGrid('crons',{
+    controlsHost:$('crongrid-ctl'), host:$('crongrid'), batch:18, minCols:1, maxCols:6, defaultCols:4,
+    empty:'no com.steve.* jobs',
+    sortModes:[
+      {k:'new',  label:'Newest',    cmp:(a,b)=>tsOf(b.created,b.modified)-tsOf(a.created,a.modified)},
+      {k:'old',  label:'Oldest',    cmp:(a,b)=>tsOf(a.created,a.modified)-tsOf(b.created,b.modified)},
+      {k:'name', label:'Name A→Z',  cmp:(a,b)=>String(a.label||'').localeCompare(String(b.label||''))},
+      {k:'stat', label:'Status',    cmp:(a,b)=>cronRank(a)-cronRank(b)||String(a.label||'').localeCompare(String(b.label||''))},
+    ],
+    render:(j)=>{
+      const iso=j.created||j.modified||'';
+      const name=String(j.label||'').replace(/^com\.steve\./,'');
+      const sched=j.schedule?`⏲ ${esc(j.schedule)}`:'<span class="dim">no schedule</span>';
+      const prog=j.program?` · <span class="dim">${esc(j.program)}</span>`:'';
+      return `<div class="subcard" title="created ${esc(iso)}">
+        <div class="subcard-top"><span class="subcard-proj">${esc(name)}</span>${cronPill(j)}</div>
+        <div class="subcard-when" style="margin-top:6px">${sched}${prog}</div>
+        <div class="subcard-when">${whenChip(j.created,j.modified)||'🕓 —'}</div>
+      </div>`;
+    },
+  });
+  feedGrid('crons', jobs);
+}
+// canary board — each canary is a card with a created/scanned date+time; grid
+// gets sort + density + infinite scroll (verdict/staleness/name modes).
+function renderCanaries(cans){
+  const vrank=(cn)=>{ const v=(cn.verdict||'').toUpperCase();
+    return /FAIL|DOWN|CRIT/.test(v)?0:/WARN|DEGRAD/.test(v)?1:/PASS|UP|HEALTH|OK/.test(v)?2:3; };
+  initGrid('canaries',{
+    controlsHost:$('canaries-ctl'), host:$('canaries'), batch:20, minCols:1, maxCols:3, defaultCols:1,
+    empty:'no canaries',
+    sortModes:[
+      {k:'new',    label:'Newest',    cmp:(a,b)=>tsOf(b.mtime,b.scanned)-tsOf(a.mtime,a.scanned)},
+      {k:'verdict',label:'Verdict',   cmp:(a,b)=>vrank(a)-vrank(b)||(a.name||'').localeCompare(b.name||'')},
+      {k:'stale',  label:'Staleness', cmp:(a,b)=>(b.ageMin||0)-(a.ageMin||0)},
+      {k:'name',   label:'Name A→Z',  cmp:(a,b)=>(a.name||'').localeCompare(b.name||'')},
+    ],
+    render:(cn)=>{
+      const v=(cn.verdict||'').toUpperCase();
+      const col=/FAIL|DOWN|CRIT/.test(v)?'bad':/WARN|DEGRAD/.test(v)?'warn':/PASS|UP|HEALTH|OK/.test(v)?'good':'dim';
+      return lrow(esc(cn.name),`<span class="${col}">${esc(cn.verdict||'—')}</span> <span class="dim">${cn.ageMin}m${cn.stale?' ⚠':''}</span>`,whenChip(cn.mtime,cn.scanned));
+    },
+  });
+  feedGrid('canaries', cans);
 }
 function statusDot(st){const c=st==='online'?'var(--good)':st?'var(--bad)':'var(--dim)';return `<span class="dot" style="background:${c}"></span>`;}
 function fmtDur(s){if(s==null)return null;if(s<60)return s+'s';if(s<3600)return Math.floor(s/60)+'m';return Math.floor(s/3600)+'h';}

← 6268895 queue: re-split timed-out 06 into 06a (card date+time) + 06b  ·  back to AbramsEgo  ·  chore: replenish build queue (2 tasks + replenisher) 3031aa5 →