@atolis-hq/wake 0.1.18 → 0.1.20

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.
@@ -1,7 +1,32 @@
1
1
  import { Octokit } from '@octokit/rest';
2
2
  import { createEtagCache, fetchPaginatedWithEtag, fetchSingleWithEtag, } from './github-etag-cache.js';
3
+ // Octokit's built-in request-log plugin routes every non-2xx response
4
+ // through `log.error` (console.error by default) before the error reaches
5
+ // our code, including the 304s that ETag-based conditional requests are
6
+ // *expected* to produce (see github-etag-cache.ts). Without this override,
7
+ // normal cache-hit traffic prints as spurious stderr errors. The plugin only
8
+ // hands `log.error` a pre-formatted string (`METHOD path - STATUS with id
9
+ // ID in Nms`), not the response object, so we extract the actual status
10
+ // code from that fixed format rather than substring-matching "304"
11
+ // anywhere in the message.
12
+ function requestLogStatus(message) {
13
+ const match = / - (\d{3}) with id /.exec(message);
14
+ return match === null ? undefined : Number(match[1]);
15
+ }
3
16
  export function createGitHubClient(token) {
4
- const octokit = new Octokit({ auth: token });
17
+ const octokit = new Octokit({
18
+ auth: token,
19
+ log: {
20
+ debug: () => { },
21
+ info: () => { },
22
+ warn: console.warn.bind(console),
23
+ error: (message) => {
24
+ if (requestLogStatus(message) !== 304) {
25
+ console.error(message);
26
+ }
27
+ },
28
+ },
29
+ });
5
30
  const etagCache = createEtagCache();
6
31
  return {
7
32
  async getAuthenticatedLogin() {
@@ -37,7 +37,8 @@ export const indexHtml = `<!DOCTYPE html>
37
37
  .statusbar .meta { color: rgba(255, 255, 255, 0.72); }
38
38
  .pill { padding: 0.15rem 0.5rem; border-radius: 999px; font-size: 0.75rem; font-weight: 600; }
39
39
  .pill-idle { background: #1f3d2c; color: #7fe3a3; }
40
- .pill-ticking { background: #1f3350; color: #7fb3ff; }
40
+ .pill-polling { background: #1f3350; color: #7fb3ff; }
41
+ .pill-working { background: #2d1f50; color: #c79bff; }
41
42
  .pill-paused { background: #4a3510; color: #ffcf7f; }
42
43
  nav { display: flex; gap: 0.25rem; padding: 0.4rem 1rem 0 0.3rem; background: var(--brand-darker); border-bottom: 1px solid #2c313a; }
43
44
  nav button { background: none; border: none; border-bottom: 2px solid transparent; color: rgba(255, 255, 255, 0.65); padding: 0.4rem 0.7rem 0.45rem; margin-bottom: -1px; cursor: pointer; font-size: 0.85rem; transition: color 0.12s ease; }
@@ -112,16 +112,26 @@ export async function buildStatus(input) {
112
112
  input.stateStore.listRecentRunRecords(1),
113
113
  buildBoard(input),
114
114
  ]);
115
- const lock = await readLockInfo(input.stateStore.paths.tickLockFile, input.now);
116
- const lockLive = lock.present && lock.pidAlive === true;
115
+ const [tickLock, runnerLock] = await Promise.all([
116
+ readLockInfo(input.stateStore.paths.tickLockFile, input.now),
117
+ readLockInfo(input.stateStore.paths.runnerLockFile, input.now),
118
+ ]);
119
+ const tickLockLive = tickLock.present && tickLock.pidAlive === true;
120
+ const runnerLockLive = runnerLock.present && runnerLock.pidAlive === true;
117
121
  // A quota-paused runner (#67) no longer stops the loop - routing falls
118
122
  // sideways to another candidate in the tier, so only the manual pause file
119
123
  // is a hard stop here. Per-runner health is surfaced separately below.
124
+ //
125
+ // Intake (tick.lock) and agent execution (runner.lock) are separate locks -
126
+ // an in-flight agent run holds only runner.lock, so both must be checked or
127
+ // the pill reads "idle" for the entire duration of a run.
120
128
  const loopState = paused
121
129
  ? 'paused'
122
- : lockLive
123
- ? 'ticking'
124
- : 'idle';
130
+ : runnerLockLive
131
+ ? 'working'
132
+ : tickLockLive
133
+ ? 'polling'
134
+ : 'idle';
125
135
  const runnerHealth = ledger?.runners ?? {};
126
136
  const lastEvent = recentEvents[0];
127
137
  const lastRun = recentRuns[0];
@@ -155,7 +165,8 @@ export async function buildStatus(input) {
155
165
  loopState,
156
166
  paused,
157
167
  runnerHealth,
158
- lock,
168
+ lock: tickLock,
169
+ runnerLock,
159
170
  lastEvent: lastEvent === undefined
160
171
  ? undefined
161
172
  : {
@@ -1 +1 @@
1
- export const wakeVersion = "0.1.18+g6b6248c";
1
+ export const wakeVersion = "0.1.20+g944b4a0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atolis-hq/wake",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Local autonomous agent control plane for software development",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {