@atolis-hq/wake 0.2.48 → 0.2.50

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.
@@ -38,6 +38,10 @@ export const indexHtml = `<!DOCTYPE html>
38
38
  .statusbar button { background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.18); color: #fff; border-radius: 6px; padding: 0.22rem 0.55rem; cursor: pointer; font-size: 0.78rem; }
39
39
  .statusbar button:hover:not(:disabled) { border-color: var(--accent-light); background: rgba(45, 212, 191, 0.16); }
40
40
  .statusbar button:disabled { cursor: wait; opacity: 0.62; }
41
+ .statusbar .pause-control { background: #5c1f1a; border-color: #ff8f7f; font-weight: 700; }
42
+ .statusbar .pause-control:hover:not(:disabled) { background: #733027; border-color: #ffd0c8; }
43
+ .statusbar .pause-control.is-paused { background: #1f4b34; border-color: #7fe3a3; }
44
+ .statusbar .pause-control.is-paused:hover:not(:disabled) { background: #276340; border-color: #c3f3d2; }
41
45
  .pill { padding: 0.15rem 0.5rem; border-radius: 999px; font-size: 0.75rem; font-weight: 600; }
42
46
  .pill-idle { background: #1f3d2c; color: #7fe3a3; }
43
47
  .pill-polling { background: #1f3350; color: #7fb3ff; }
@@ -121,6 +125,7 @@ export const indexHtml = `<!DOCTYPE html>
121
125
  </header>
122
126
  <div class="statusbar">
123
127
  <span id="loop-pill" class="pill">…</span>
128
+ <button id="pause-toggle" type="button" class="pause-control">Pause</button>
124
129
  <button id="force-tick" type="button">Tick now</button>
125
130
  <span id="status-summary" class="meta"></span>
126
131
  </div>
@@ -184,6 +189,12 @@ async function postJson(path) {
184
189
  return res.json();
185
190
  }
186
191
 
192
+ async function deleteJson(path) {
193
+ const res = await fetch(API + path, { method: 'DELETE' });
194
+ if (!res.ok) throw new Error(path + ' -> ' + res.status);
195
+ return res.json();
196
+ }
197
+
187
198
  function fmtMs(ms) {
188
199
  if (ms === undefined || ms === null) return '—';
189
200
  const s = Math.floor(ms / 1000);
@@ -220,6 +231,10 @@ async function renderStatusBar() {
220
231
  const pill = document.getElementById('loop-pill');
221
232
  pill.textContent = status.loopState;
222
233
  pill.className = 'pill pill-' + status.loopState;
234
+ const pauseButton = document.getElementById('pause-toggle');
235
+ pauseButton.dataset.paused = String(status.paused);
236
+ pauseButton.textContent = status.paused ? 'Resume' : 'Pause';
237
+ pauseButton.classList.toggle('is-paused', status.paused);
223
238
  const freshness = status.sourceFreshness.level;
224
239
  const summary = document.getElementById('status-summary');
225
240
  summary.textContent =
@@ -232,6 +247,23 @@ async function renderStatusBar() {
232
247
  }
233
248
  }
234
249
 
250
+ async function togglePause() {
251
+ const button = document.getElementById('pause-toggle');
252
+ const paused = button.dataset.paused === 'true';
253
+ button.disabled = true;
254
+ button.textContent = paused ? 'Resuming...' : 'Pausing...';
255
+ try {
256
+ if (paused) await deleteJson('/pause');
257
+ else await postJson('/pause');
258
+ await renderStatusBar();
259
+ switchView(currentView, { showLoading: false });
260
+ } catch (err) {
261
+ document.getElementById('status-summary').textContent = 'pause toggle failed: ' + err.message;
262
+ } finally {
263
+ button.disabled = false;
264
+ }
265
+ }
266
+
235
267
  async function forceTickNow() {
236
268
  const button = document.getElementById('force-tick');
237
269
  button.disabled = true;
@@ -842,6 +874,7 @@ document.getElementById('modal-overlay').addEventListener('click', (event) => {
842
874
  }
843
875
  });
844
876
  document.getElementById('force-tick').addEventListener('click', forceTickNow);
877
+ document.getElementById('pause-toggle').addEventListener('click', togglePause);
845
878
 
846
879
  renderStatusBar();
847
880
  switchView('board');
@@ -1,5 +1,7 @@
1
1
  import { createServer } from 'node:http';
2
2
  import { randomUUID } from 'node:crypto';
3
+ import { mkdir, rm, writeFile } from 'node:fs/promises';
4
+ import { dirname } from 'node:path';
3
5
  import { createProjectionUpdater } from '../../core/projection-updater.js';
4
6
  import { configuredTicketSource } from '../../domain/sources.js';
5
7
  import { createEventEnvelope } from '../../lib/event-log.js';
@@ -155,6 +157,17 @@ async function handleRequest(req, res, options, now, projectionUpdater) {
155
157
  sendJson(res, 202, request);
156
158
  return;
157
159
  }
160
+ if (req.method === 'POST' && resource === 'pause' && segments.length === 1) {
161
+ await mkdir(dirname(stateStore.paths.pauseFile), { recursive: true });
162
+ await writeFile(stateStore.paths.pauseFile, `${now().toISOString()}\n`, 'utf8');
163
+ sendJson(res, 200, { paused: true });
164
+ return;
165
+ }
166
+ if (req.method === 'DELETE' && resource === 'pause' && segments.length === 1) {
167
+ await rm(stateStore.paths.pauseFile, { force: true });
168
+ sendJson(res, 200, { paused: false });
169
+ return;
170
+ }
158
171
  if (req.method === 'POST' &&
159
172
  resource === 'runners' &&
160
173
  segments.length === 3 &&
package/dist/src/main.js CHANGED
@@ -608,15 +608,8 @@ async function runTick(args) {
608
608
  console.error(details);
609
609
  }
610
610
  }
611
- async function runStart(args) {
612
- const runtime = await buildRuntime(args);
613
- await runtime.stateStore.assertStateHealthy();
614
- const runnerOverride = readFlagBeforeCommandTerminator('--runner', args);
615
- await runStartupPreflight(runtime.config, {
616
- ...(runnerOverride === undefined ? {} : { runnerOverride }),
617
- workspaceManager: runtime.workspaceManager,
618
- });
619
- const controlPlane = createControlPlane({
611
+ export function createResidentControlPlane(runtime) {
612
+ return createControlPlane({
620
613
  tickRunner: runtime.tickRunner,
621
614
  intervalMs: runtime.config.scheduler.intervalMs,
622
615
  maxIntervalMs: runtime.config.scheduler.maxIntervalMs,
@@ -638,6 +631,16 @@ async function runStart(args) {
638
631
  return readTickRequestId(runtime.stateStore.paths.tickRequestFile);
639
632
  },
640
633
  });
634
+ }
635
+ async function runStart(args) {
636
+ const runtime = await buildRuntime(args);
637
+ await runtime.stateStore.assertStateHealthy();
638
+ const runnerOverride = readFlagBeforeCommandTerminator('--runner', args);
639
+ await runStartupPreflight(runtime.config, {
640
+ ...(runnerOverride === undefined ? {} : { runnerOverride }),
641
+ workspaceManager: runtime.workspaceManager,
642
+ });
643
+ const controlPlane = createResidentControlPlane(runtime);
641
644
  const stop = () => controlPlane.stop();
642
645
  process.on('SIGINT', stop);
643
646
  process.on('SIGTERM', stop);
@@ -124,4 +124,4 @@ export function resolveWakeVersion(options = {}) {
124
124
  }
125
125
  return '0.1.0-dev';
126
126
  }
127
- export const wakeVersion = "g40a6bf0";
127
+ export const wakeVersion = "gb436c70";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atolis-hq/wake",
3
- "version": "0.2.48",
3
+ "version": "0.2.50",
4
4
  "description": "Local autonomous agent control plane for software development",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {