@orboto/mcp 0.228.1 → 0.229.0

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.
@@ -92,4 +92,15 @@ describe('ORB-2225 orboto_wiki_runs', () => {
92
92
  const handler = makeWikiRunsHandler({ get, post: vi.fn() });
93
93
  expect(textOf(await handler({ spaceId: 'ACME-S1' }))).toContain('r2 applied ACME-D10 "Deploy notes" 2026-09-27T09:00:00Z (ops dropped: 1)');
94
94
  });
95
+ it('ORB-2611 - a queued run says how long it waits or runs and whether it stalled', async () => {
96
+ const get = vi.fn().mockResolvedValue({ runs: [
97
+ { id: 'r3', sourceKey: 'ACME-D11', sourceTitle: 'AGENTS.md study', status: 'queued', error: null, createdAt: '2026-10-20T15:53:33Z', startedAt: null, ageSeconds: 1260, stalled: true },
98
+ { id: 'r4', sourceKey: 'ACME-D12', sourceTitle: 'Context rules', status: 'queued', error: null, createdAt: '2026-10-20T15:53:33Z', queuedAt: '2026-10-20T15:53:33Z', startedAt: '2026-10-20T16:03:33Z', ageSeconds: 780, stalled: false },
99
+ ] });
100
+ const handler = makeWikiRunsHandler({ get, post: vi.fn() });
101
+ const text = textOf(await handler({ spaceId: 'ACME-S1', status: 'queued' }));
102
+ expect(get).toHaveBeenCalledWith('/spaces/ACME-S1/llm-wiki/ingest-runs?status=queued');
103
+ expect(text).toContain('r3 queued (waiting 21 min, stalled) ACME-D11');
104
+ expect(text).toContain('r4 queued (running 3 min) ACME-D12');
105
+ });
95
106
  });
@@ -189,14 +189,22 @@ export function makeWikiFlagStaleHandler(client) {
189
189
  return text(res.staleFlagged ? 'Page flagged as possibly outdated.' : 'Stale flag cleared.', { staleFlagged: res.staleFlagged });
190
190
  };
191
191
  }
192
+ /** ORB-2611 - the wait or run time of a queued run, and its stall. */
193
+ function queuedNote(r) {
194
+ if (r.status !== 'queued')
195
+ return '';
196
+ const waited = r.startedAt ? (Date.parse(r.startedAt) - Date.parse(r.queuedAt ?? r.createdAt)) / 1000 : 0;
197
+ const minutes = Math.max(1, Math.round(Math.max(0, (r.ageSeconds ?? 0) - waited) / 60));
198
+ return ` (${r.startedAt ? 'running' : 'waiting'} ${minutes} min${r.stalled ? ', stalled' : ''})`;
199
+ }
192
200
  export const wikiRunsToolConfig = {
193
201
  title: 'Wiki ingest runs',
194
- description: 'List the ingest runs of a wiki space (status failed shows each error) or retry a failed run.',
202
+ description: 'List the ingest runs of a wiki space (queued shows the wait and a stall, failed each error) or retry a failed or stalled run.',
195
203
  inputSchema: z.object({
196
204
  spaceId: z.string().min(1),
197
205
  action: z.enum(['list', 'retry']).optional(),
198
206
  runId: z.string().uuid().optional(),
199
- status: z.enum(['pending_review', 'applied', 'failed', 'skipped']).optional(),
207
+ status: z.enum(['pending_review', 'applied', 'failed', 'skipped', 'queued']).optional(),
200
208
  }).shape,
201
209
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
202
210
  };
@@ -204,13 +212,13 @@ export function makeWikiRunsHandler(client) {
204
212
  return async (input) => {
205
213
  if (input.action === 'retry') {
206
214
  if (!input.runId)
207
- return { isError: true, content: [{ type: 'text', text: 'action retry needs the runId of a failed run (action list, status failed).' }] };
215
+ return { isError: true, content: [{ type: 'text', text: 'action retry needs the runId of a failed or stalled run (action list, status failed or queued).' }] };
208
216
  const res = await client.post(`/spaces/${encodeURIComponent(input.spaceId)}/llm-wiki/ingest-runs/${input.runId}/retry`, {});
209
217
  return text(res.queued ? `Run ${res.runId} is queued for the ingest worker again.` : `Run ${res.runId} ran again: ${res.status}${res.error ? ` - ${res.error}` : ''}.`, res);
210
218
  }
211
219
  const qs = input.status ? `?status=${input.status}` : '';
212
220
  const res = await client.get(`/spaces/${encodeURIComponent(input.spaceId)}/llm-wiki/ingest-runs${qs}`);
213
- const lines = res.runs.map((r) => `- ${r.id} ${r.status} ${r.sourceKey ?? ''} "${r.sourceTitle}" ${r.createdAt}${r.droppedOps?.length ? ` (ops dropped: ${r.droppedOps.length})` : ''}${r.error ? ` - ${r.error}` : ''}`);
221
+ const lines = res.runs.map((r) => `- ${r.id} ${r.status}${queuedNote(r)} ${r.sourceKey ?? ''} "${r.sourceTitle}" ${r.createdAt}${r.droppedOps?.length ? ` (ops dropped: ${r.droppedOps.length})` : ''}${r.error ? ` - ${r.error}` : ''}`);
214
222
  return text(lines.length ? lines.join('\n') : 'No ingest runs.', res);
215
223
  };
216
224
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orboto/mcp",
3
- "version": "0.228.1",
3
+ "version": "0.229.0",
4
4
  "description": "Model Context Protocol server for orboto - exposes tickets, projects, milestones, time, docs, primer-facts, alerts and absences as MCP tools for Claude Desktop / Cursor / Copilot Chat / any MCP-aware AI client.",
5
5
  "license": "MIT",
6
6
  "type": "module",