@tablation/crew 0.49.5 → 0.49.6

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.
Files changed (2) hide show
  1. package/dist/cli.js +39 -8
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -4931,6 +4931,8 @@ var Tracker = class {
4931
4931
  * writes pass its seat's agent key so the event log and rule context see an
4932
4932
  * agent, not the ship's human principal.
4933
4933
  */
4934
+ /** Told once per failed best-effort read (`events`); poll.ts points it at the pass's emitter. */
4935
+ onReadFailure;
4934
4936
  constructor(route, ship, opts = {}) {
4935
4937
  this.route = route;
4936
4938
  if (!route.resolved) {
@@ -5372,10 +5374,16 @@ var Tracker = class {
5372
5374
  */
5373
5375
  async events(type, limit = 500) {
5374
5376
  const filters = encodeURIComponent(JSON.stringify([{ columnName: "event_type", operator: "EQ", value: type }]));
5375
- const res = await this.eventsFetch("GET", `/events?limit=${limit}&filters=${filters}`);
5376
- if (res.status === 404) return [];
5377
- if (!res.ok) throw new Error(`reading ${type} events failed: HTTP ${res.status}`);
5378
- const rows = await res.json();
5377
+ let rows;
5378
+ try {
5379
+ const res = await this.eventsFetch("GET", `/events?limit=${limit}&filters=${filters}`);
5380
+ if (res.status === 404) return [];
5381
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
5382
+ rows = await res.json();
5383
+ } catch (err) {
5384
+ this.onReadFailure?.(`reading ${type} events failed: ${err instanceof Error ? err.message : String(err)}`);
5385
+ return [];
5386
+ }
5379
5387
  return rows.filter((e) => e.event_type === type).sort((a, b) => Date.parse(b.occurred_at ?? b.created_at ?? "") - Date.parse(a.occurred_at ?? a.created_at ?? ""));
5380
5388
  }
5381
5389
  /** The newest event of `type` on a ticket, or undefined — e.g. the `pushed` tip QA verifies against. */
@@ -6455,14 +6463,23 @@ async function runStalledSweep(o, stalled) {
6455
6463
  async function decideCycle(o) {
6456
6464
  const { route, ship, state, emit } = o;
6457
6465
  const tracker = new Tracker(route, ship);
6466
+ tracker.onReadFailure = (m) => emit.warn(m);
6458
6467
  emit.enter("poll");
6468
+ const optional = async (what, read, fallback) => {
6469
+ try {
6470
+ return await read;
6471
+ } catch (err) {
6472
+ emit.warn(`reading ${what} failed: ${err instanceof Error ? err.message : String(err)}`);
6473
+ return fallback;
6474
+ }
6475
+ };
6459
6476
  const [tickets, comments, crewRows, epicRows, ships, projectModes, stalledEvents] = await Promise.all([
6460
6477
  tracker.openTickets(),
6461
6478
  tracker.comments(200),
6462
6479
  tracker.crewRows(),
6463
- tracker.epicRows(),
6464
- tracker.shipRows(),
6465
- tracker.projectWorkModes(),
6480
+ optional("epics", tracker.epicRows(), []),
6481
+ optional("ships", tracker.shipRows(), []),
6482
+ optional("project work modes", tracker.projectWorkModes(), /* @__PURE__ */ new Map()),
6466
6483
  tracker.events("stalled")
6467
6484
  ]);
6468
6485
  const directionEvents = (await Promise.all([...DIRECTION_EVENT_TYPES, "pushed"].map((t) => tracker.events(t)))).flat();
@@ -12547,7 +12564,18 @@ async function runDaemonLoop(o) {
12547
12564
  let passes = 0;
12548
12565
  for (; ; ) {
12549
12566
  if (o.signal?.aborted) return "aborted";
12550
- const result = await o.runPass();
12567
+ let result;
12568
+ try {
12569
+ result = await o.runPass();
12570
+ } catch (err) {
12571
+ passes++;
12572
+ o.onPassError?.(err);
12573
+ if (o.maxPasses !== void 0 && passes >= o.maxPasses) return "maxPasses";
12574
+ if (o.signal?.aborted) return "aborted";
12575
+ await sleep(backoff);
12576
+ backoff = Math.min(backoff * 2, ceiling);
12577
+ continue;
12578
+ }
12551
12579
  passes++;
12552
12580
  if (result.started.length > 0) {
12553
12581
  backoff = floor;
@@ -14473,6 +14501,9 @@ ${changed2.map((c) => ` - ${c}
14473
14501
  `)
14474
14502
  })
14475
14503
  }),
14504
+ onPassError: (err) => emit.error(
14505
+ `daemon pass failed, continuing: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
14506
+ ),
14476
14507
  checkStale: makeStaleChecker(watchPaths, { reloadSentinel: reloadSentinelFor(cfg.ship.stateDir) }),
14477
14508
  onPass: (result) => {
14478
14509
  if (result.started.length) emit.emit(`daemon pass started: ${result.started.join(", ")}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.49.5",
3
+ "version": "0.49.6",
4
4
  "description": "A standing team of headless agents that picks work off a Tablation board, does it on a machine you control, and reports back.",
5
5
  "type": "module",
6
6
  "license": "MIT",