@atolis-hq/wake 0.2.26 → 0.2.27

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.
@@ -80,6 +80,10 @@ export const indexHtml = `<!DOCTYPE html>
80
80
  @media (max-width: 767px) {
81
81
  .modal-overlay { padding: 0; }
82
82
  .modal { width: 100%; height: 100%; max-height: none; border-radius: 0; border-left: 0; border-right: 0; }
83
+ .columns { display: flex; flex-direction: column; overflow-x: unset; }
84
+ .col { min-height: unset; }
85
+ .col-empty { padding: 0.25rem 0.5rem; }
86
+ .col-empty h2 { margin: 0.1rem 0.4rem; }
83
87
  }
84
88
  .tiles { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 1rem; }
85
89
  .tile { background: #1a1d23; border-radius: 10px; padding: 0.6rem 0.9rem; min-width: 120px; }
@@ -249,7 +253,6 @@ async function renderBoard(context) {
249
253
  const board = await getJson('/board', context.signal);
250
254
  if (!isActiveRequest(context.requestId)) return;
251
255
  const main = document.getElementById('main');
252
- main.innerHTML = '';
253
256
  const columns = el('div', { class: 'columns' }, CONDITIONS.map((cond) => {
254
257
  const items = board.filter((c) => c.condition === cond);
255
258
  const cards = items.map((item) => el('div', {
@@ -263,12 +266,12 @@ async function renderBoard(context) {
263
266
  ]),
264
267
  el('div', { class: 'meta', text: item.lastRunSentinel ? 'last: ' + item.lastRunAction + ' → ' + item.lastRunSentinel : item.conditionReason }),
265
268
  ]));
266
- return el('div', { class: 'col' }, [
269
+ return el('div', { class: 'col' + (items.length === 0 ? ' col-empty' : '') }, [
267
270
  el('h2', { text: cond + ' (' + items.length + ')' }),
268
271
  ...cards,
269
272
  ]);
270
273
  }));
271
- main.appendChild(columns);
274
+ main.replaceChildren(columns);
272
275
  }
273
276
 
274
277
  function resourceUriToUrl(resourceUri) {
@@ -435,15 +438,13 @@ async function renderActivity(context) {
435
438
  const events = await getJson('/events?limit=200', context.signal);
436
439
  if (!isActiveRequest(context.requestId)) return;
437
440
  const main = document.getElementById('main');
438
- main.innerHTML = '';
439
- const table = el('table', {}, [
441
+ main.replaceChildren(el('table', {}, [
440
442
  el('tr', {}, ['time', 'direction', 'type', 'work item'].map((h) => el('th', { text: h }))),
441
443
  ...events.map((ev) => el('tr', {}, [
442
444
  el('td', { text: ev.ingestedAt }), el('td', { text: ev.direction }),
443
445
  el('td', { text: ev.sourceEventType }), el('td', { text: ev.workItemKey }),
444
446
  ])),
445
- ]);
446
- main.appendChild(table);
447
+ ]));
447
448
  }
448
449
 
449
450
  function fmtCost(usd) {
@@ -673,43 +674,43 @@ async function renderAnalytics(context) {
673
674
  const metrics = await getJson('/metrics?window=' + encodeURIComponent(analyticsWindow) + '&metric=' + encodeURIComponent(analyticsMetric), context.signal);
674
675
  if (!isActiveRequest(context.requestId)) return;
675
676
  const main = document.getElementById('main');
676
- main.innerHTML = '';
677
- main.appendChild(el('div', { class: 'toolbar' }, [
678
- el('label', {}, [
679
- document.createTextNode('Window'),
680
- selectBox(analyticsWindow, [['1d', '1d'], ['3d', '3d'], ['5d', '5d'], ['7d', '7d']], (value) => {
681
- analyticsWindow = value;
682
- switchView('analytics');
683
- }),
677
+ main.replaceChildren(
678
+ el('div', { class: 'toolbar' }, [
679
+ el('label', {}, [
680
+ document.createTextNode('Window'),
681
+ selectBox(analyticsWindow, [['1d', '1d'], ['3d', '3d'], ['5d', '5d'], ['7d', '7d']], (value) => {
682
+ analyticsWindow = value;
683
+ switchView('analytics');
684
+ }),
685
+ ]),
686
+ el('label', {}, [
687
+ document.createTextNode('Metric'),
688
+ selectBox(analyticsMetric, METRIC_OPTIONS, (value) => {
689
+ analyticsMetric = value;
690
+ switchView('analytics');
691
+ }),
692
+ ]),
684
693
  ]),
685
- el('label', {}, [
686
- document.createTextNode('Metric'),
687
- selectBox(analyticsMetric, METRIC_OPTIONS, (value) => {
688
- analyticsMetric = value;
689
- switchView('analytics');
690
- }),
694
+ el('div', { class: 'tiles' }, [
695
+ tile('Runs', fmtNumber(metrics.summary.totalRuns)),
696
+ tile('Completed', fmtNumber(metrics.summary.completedRuns)),
697
+ tile('Blocked/approval', fmtNumber(metrics.summary.blockedRuns + metrics.summary.awaitingApprovalRuns)),
698
+ tile('Failed', fmtNumber(metrics.summary.failedRuns)),
699
+ tile('Tokens', fmtNumber(metrics.summary.totalTokens)),
700
+ tile('Cost', fmtCost(metrics.summary.totalCostUsd)),
701
+ tile('Median run', fmtDuration(metrics.summary.medianRunDurationMs) || '—'),
702
+ tile('Work done', fmtNumber(metrics.summary.completedWorkItems)),
703
+ tile('Median e2e', fmtDuration(metrics.summary.medianWorkItemDurationMs) || '—'),
691
704
  ]),
692
- ]));
693
- main.appendChild(el('div', { class: 'tiles' }, [
694
- tile('Runs', fmtNumber(metrics.summary.totalRuns)),
695
- tile('Completed', fmtNumber(metrics.summary.completedRuns)),
696
- tile('Blocked/approval', fmtNumber(metrics.summary.blockedRuns + metrics.summary.awaitingApprovalRuns)),
697
- tile('Failed', fmtNumber(metrics.summary.failedRuns)),
698
- tile('Tokens', fmtNumber(metrics.summary.totalTokens)),
699
- tile('Cost', fmtCost(metrics.summary.totalCostUsd)),
700
- tile('Median run', fmtDuration(metrics.summary.medianRunDurationMs) || '—'),
701
- tile('Work done', fmtNumber(metrics.summary.completedWorkItems)),
702
- tile('Median e2e', fmtDuration(metrics.summary.medianWorkItemDurationMs) || '—'),
703
- ]));
704
- main.appendChild(renderMetricDetail(metrics.detail));
705
+ renderMetricDetail(metrics.detail),
706
+ );
705
707
  }
706
708
 
707
709
  async function renderRuns(context) {
708
710
  const runs = await getJson('/runs', context.signal);
709
711
  if (!isActiveRequest(context.requestId)) return;
710
712
  const main = document.getElementById('main');
711
- main.innerHTML = '';
712
- const table = el('table', {}, [
713
+ main.replaceChildren(el('table', {}, [
713
714
  el('tr', {}, ['repo#issue', 'action', 'status', 'sentinel', 'runner', 'tokens', 'cost', 'started', 'finished'].map((h) => el('th', { text: h }))),
714
715
  ...runs.map((r) => el('tr', {}, [
715
716
  el('td', { text: r.repo + '#' + r.issueNumber }), el('td', { text: r.action }), el('td', { text: r.status }),
@@ -717,87 +718,87 @@ async function renderRuns(context) {
717
718
  el('td', { text: fmtTokens(r.tokenUsage) }), el('td', { text: fmtCost(r.tokenUsage && r.tokenUsage.costUsd) }),
718
719
  el('td', { text: r.startedAt }), el('td', { text: r.finishedAt || '' }),
719
720
  ])),
720
- ]);
721
- main.appendChild(table);
721
+ ]));
722
722
  }
723
723
 
724
724
  async function renderConfig(context) {
725
725
  const data = await getJson('/config', context.signal);
726
726
  if (!isActiveRequest(context.requestId)) return;
727
727
  const main = document.getElementById('main');
728
- main.innerHTML = '';
729
- main.appendChild(el('h3', { text: 'Routing table' }));
730
- main.appendChild(el('table', {}, [
731
- el('tr', {}, ['stage', 'action', 'tier', 'runner', 'model', 'fallback order'].map((h) => el('th', { text: h }))),
732
- ...data.routingTable.map((r) => el('tr', {}, [
733
- el('td', { text: r.stage }), el('td', { text: r.action || '' }), el('td', { text: r.tier || '' }),
734
- el('td', { text: r.runnerName || '' }), el('td', { text: r.model || '' }),
735
- el('td', {}, (r.candidates || []).map((c) => {
736
- if (!c.paused) return el('span', { class: 'chip', text: c.runnerName });
737
- const btn = el('button', { type: 'button', class: 'btn', text: 'Unpause', style: 'margin-top:0;font-size:0.7rem;padding:0.1rem 0.4rem;' });
738
- btn.addEventListener('click', async () => {
739
- btn.disabled = true;
740
- btn.textContent = 'Unpausing…';
741
- try {
742
- await postJson('/runners/' + encodeURIComponent(c.runnerName) + '/unpause');
743
- switchView('config');
744
- } catch (err) {
745
- btn.disabled = false;
746
- btn.textContent = 'Unpause';
747
- document.getElementById('status-summary').textContent = 'unpause failed: ' + err.message;
748
- }
749
- });
750
- return el('span', { style: 'display:inline-flex;align-items:center;gap:0.25rem;margin-right:0.25rem;' }, [
751
- el('span', { class: 'chip amber', text: c.runnerName + ' (paused)' }),
752
- btn,
753
- ]);
754
- })),
755
- ])),
756
- ]));
757
- main.appendChild(el('h3', { text: 'Effective config (redacted)' }));
758
- main.appendChild(el('pre', { text: JSON.stringify(data.config, null, 2) }));
728
+ main.replaceChildren(
729
+ el('h3', { text: 'Routing table' }),
730
+ el('table', {}, [
731
+ el('tr', {}, ['stage', 'action', 'tier', 'runner', 'model', 'fallback order'].map((h) => el('th', { text: h }))),
732
+ ...data.routingTable.map((r) => el('tr', {}, [
733
+ el('td', { text: r.stage }), el('td', { text: r.action || '' }), el('td', { text: r.tier || '' }),
734
+ el('td', { text: r.runnerName || '' }), el('td', { text: r.model || '' }),
735
+ el('td', {}, (r.candidates || []).map((c) => {
736
+ if (!c.paused) return el('span', { class: 'chip', text: c.runnerName });
737
+ const btn = el('button', { type: 'button', class: 'btn', text: 'Unpause', style: 'margin-top:0;font-size:0.7rem;padding:0.1rem 0.4rem;' });
738
+ btn.addEventListener('click', async () => {
739
+ btn.disabled = true;
740
+ btn.textContent = 'Unpausing…';
741
+ try {
742
+ await postJson('/runners/' + encodeURIComponent(c.runnerName) + '/unpause');
743
+ switchView('config');
744
+ } catch (err) {
745
+ btn.disabled = false;
746
+ btn.textContent = 'Unpause';
747
+ document.getElementById('status-summary').textContent = 'unpause failed: ' + err.message;
748
+ }
749
+ });
750
+ return el('span', { style: 'display:inline-flex;align-items:center;gap:0.25rem;margin-right:0.25rem;' }, [
751
+ el('span', { class: 'chip amber', text: c.runnerName + ' (paused)' }),
752
+ btn,
753
+ ]);
754
+ })),
755
+ ])),
756
+ ]),
757
+ el('h3', { text: 'Effective config (redacted)' }),
758
+ el('pre', { text: JSON.stringify(data.config, null, 2) }),
759
+ );
759
760
  }
760
761
 
761
762
  async function renderHealth(context) {
762
763
  const health = await getJson('/health', context.signal);
763
764
  if (!isActiveRequest(context.requestId)) return;
764
765
  const main = document.getElementById('main');
765
- main.innerHTML = '';
766
766
  const runnerNames = Object.keys(health.pause.runnerHealth || {});
767
- main.appendChild(el('div', { class: 'tiles' }, [
768
- tile('Tick lock', health.lock.present ? (health.lock.stale ? 'stale' : 'held') : 'free'),
769
- tile('Paused', String(health.pause.paused)),
770
- tile('Runners paused now', String(runnerNames.filter((name) => {
771
- const until = health.pause.runnerHealth[name].pausedUntil;
772
- return until && Date.parse(until) > Date.now();
773
- }).length)),
774
- tile('Integrity issues', String(health.integrityIssues.length)),
775
- ]));
776
- main.appendChild(el('h3', { text: 'Runner health (quota fallback, #67)' }));
777
- if (runnerNames.length === 0) {
778
- main.appendChild(el('p', { class: 'meta', text: 'No quota failures recorded.' }));
779
- } else {
780
- main.appendChild(el('table', {}, [
781
- el('tr', {}, ['runner', 'status', 'paused until', 'failure count', 'last failure'].map((h) => el('th', { text: h }))),
782
- ...runnerNames.map((name) => {
783
- const entry = health.pause.runnerHealth[name];
784
- const paused = entry.pausedUntil && Date.parse(entry.pausedUntil) > Date.now();
785
- return el('tr', {}, [
786
- el('td', { text: name }),
787
- el('td', {}, [el('span', { class: 'chip' + (paused ? ' amber' : ' ok') , text: paused ? 'paused' : 'available' })]),
788
- el('td', { text: entry.pausedUntil || '' }),
789
- el('td', { text: String(entry.failureCount || 0) }),
790
- el('td', { text: entry.lastFailureAt || '' }),
791
- ]);
792
- }),
793
- ]));
794
- }
795
- main.appendChild(el('h3', { text: 'Storage' }));
796
- main.appendChild(el('pre', { text: JSON.stringify(health.storage, null, 2) }));
797
- main.appendChild(el('h3', { text: 'Source polling' }));
798
- main.appendChild(el('pre', { text: JSON.stringify(health.sources, null, 2) }));
799
- main.appendChild(el('h3', { text: 'Integrity issues' }));
800
- main.appendChild(el('pre', { text: JSON.stringify(health.integrityIssues, null, 2) }));
767
+ const runnerSection = runnerNames.length === 0
768
+ ? el('p', { class: 'meta', text: 'No quota failures recorded.' })
769
+ : el('table', {}, [
770
+ el('tr', {}, ['runner', 'status', 'paused until', 'failure count', 'last failure'].map((h) => el('th', { text: h }))),
771
+ ...runnerNames.map((name) => {
772
+ const entry = health.pause.runnerHealth[name];
773
+ const paused = entry.pausedUntil && Date.parse(entry.pausedUntil) > Date.now();
774
+ return el('tr', {}, [
775
+ el('td', { text: name }),
776
+ el('td', {}, [el('span', { class: 'chip' + (paused ? ' amber' : ' ok') , text: paused ? 'paused' : 'available' })]),
777
+ el('td', { text: entry.pausedUntil || '' }),
778
+ el('td', { text: String(entry.failureCount || 0) }),
779
+ el('td', { text: entry.lastFailureAt || '' }),
780
+ ]);
781
+ }),
782
+ ]);
783
+ main.replaceChildren(
784
+ el('div', { class: 'tiles' }, [
785
+ tile('Tick lock', health.lock.present ? (health.lock.stale ? 'stale' : 'held') : 'free'),
786
+ tile('Paused', String(health.pause.paused)),
787
+ tile('Runners paused now', String(runnerNames.filter((name) => {
788
+ const until = health.pause.runnerHealth[name].pausedUntil;
789
+ return until && Date.parse(until) > Date.now();
790
+ }).length)),
791
+ tile('Integrity issues', String(health.integrityIssues.length)),
792
+ ]),
793
+ el('h3', { text: 'Runner health (quota fallback, #67)' }),
794
+ runnerSection,
795
+ el('h3', { text: 'Storage' }),
796
+ el('pre', { text: JSON.stringify(health.storage, null, 2) }),
797
+ el('h3', { text: 'Source polling' }),
798
+ el('pre', { text: JSON.stringify(health.sources, null, 2) }),
799
+ el('h3', { text: 'Integrity issues' }),
800
+ el('pre', { text: JSON.stringify(health.integrityIssues, null, 2) }),
801
+ );
801
802
  }
802
803
 
803
804
  function tile(label, value) {
@@ -124,4 +124,4 @@ export function resolveWakeVersion(options = {}) {
124
124
  }
125
125
  return '0.1.0-dev';
126
126
  }
127
- export const wakeVersion = "gf6fad76";
127
+ export const wakeVersion = "g76dc1bc";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atolis-hq/wake",
3
- "version": "0.2.26",
3
+ "version": "0.2.27",
4
4
  "description": "Local autonomous agent control plane for software development",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {