@cadraos/sdk 0.3.8 → 0.3.10
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.
- package/dist/board-host/index.d.cts +74 -6
- package/dist/board-host/index.d.ts +74 -6
- package/dist/board-host/server/index.d.cts +81 -6
- package/dist/board-host/server/index.d.ts +81 -6
- package/dist/chat/index.cjs +2 -47
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +8 -9
- package/dist/chat/index.d.ts +8 -9
- package/dist/chat/index.js +2 -47
- package/dist/chat/index.js.map +1 -1
- package/dist/index.cjs +0 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +0 -43
- package/dist/index.js.map +1 -1
- package/dist/kanban/engine/index.cjs +113 -31
- package/dist/kanban/engine/index.cjs.map +1 -1
- package/dist/kanban/engine/index.d.cts +112 -6
- package/dist/kanban/engine/index.d.ts +112 -6
- package/dist/kanban/engine/index.js +113 -31
- package/dist/kanban/engine/index.js.map +1 -1
- package/dist/kanban/index.cjs +807 -158
- package/dist/kanban/index.cjs.map +1 -1
- package/dist/kanban/index.d.cts +382 -11
- package/dist/kanban/index.d.ts +382 -11
- package/dist/kanban/index.js +802 -159
- package/dist/kanban/index.js.map +1 -1
- package/dist/teams/index.cjs +0 -43
- package/dist/teams/index.cjs.map +1 -1
- package/dist/teams/index.d.cts +7 -0
- package/dist/teams/index.d.ts +7 -0
- package/dist/teams/index.js +0 -43
- package/dist/teams/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -12,6 +12,10 @@ function mapHandler(h) {
|
|
|
12
12
|
type: h.type,
|
|
13
13
|
agentUuid: h.agent_uuid,
|
|
14
14
|
teamUuid: h.team_uuid,
|
|
15
|
+
// FINDING-6: carry the remote_agent binding through the wire parse. The
|
|
16
|
+
// engine's remote_agent dispatch reads `remoteAgentUuid`; dropping it here
|
|
17
|
+
// made every published remote_agent lane dispatch-dead.
|
|
18
|
+
remoteAgentUuid: h.remote_agent_uuid,
|
|
15
19
|
agentRef: h.agent_ref,
|
|
16
20
|
webhook: h.webhook ? {
|
|
17
21
|
url: h.webhook.url,
|
|
@@ -321,6 +325,8 @@ async function dispatchStageHandler(ctx, cadra, webhookOpts) {
|
|
|
321
325
|
orgId: ctx.orgId,
|
|
322
326
|
input: ctx.input,
|
|
323
327
|
idemKey: runIdemKey,
|
|
328
|
+
// Board/headless dispatch always disables ask_user (spec §6.5 / FINDING-5).
|
|
329
|
+
allowAskUser: false,
|
|
324
330
|
callbackRef: ctx.callbackUrl
|
|
325
331
|
});
|
|
326
332
|
return { dispatched: true, executionUuid };
|
|
@@ -334,6 +340,8 @@ async function dispatchStageHandler(ctx, cadra, webhookOpts) {
|
|
|
334
340
|
orgId: ctx.orgId,
|
|
335
341
|
input: ctx.input,
|
|
336
342
|
idemKey: runIdemKey,
|
|
343
|
+
// Board/headless dispatch always disables ask_user (spec §6.5 / FINDING-5).
|
|
344
|
+
allowAskUser: false,
|
|
337
345
|
callbackRef: ctx.callbackUrl
|
|
338
346
|
});
|
|
339
347
|
return { dispatched: true, executionUuid };
|
|
@@ -384,10 +392,25 @@ function nextId(prefix) {
|
|
|
384
392
|
idSeq += 1;
|
|
385
393
|
return `${prefix}-${idSeq}`;
|
|
386
394
|
}
|
|
395
|
+
var DEFAULT_STALE_QUEUED_MS = 15 * 6e4;
|
|
387
396
|
var InMemoryStorageAdapter = class {
|
|
388
397
|
cards = /* @__PURE__ */ new Map();
|
|
389
398
|
logs = /* @__PURE__ */ new Map();
|
|
390
399
|
runs = /* @__PURE__ */ new Map();
|
|
400
|
+
/**
|
|
401
|
+
* A `queued` stage-run older than this (ms) is STALE and re-claimable by
|
|
402
|
+
* `beginStageRun` (design §10) — it models a run whose process died between
|
|
403
|
+
* `beginStageRun` and dispatch, so `failStageRun` never ran. A `failed` run is
|
|
404
|
+
* re-claimable regardless of age. Must comfortably exceed the dispatch time so
|
|
405
|
+
* a genuinely in-flight `queued` run is never re-claimed out from under it.
|
|
406
|
+
*/
|
|
407
|
+
staleQueuedMs;
|
|
408
|
+
/** Injectable clock (ms) — real hosts use `Date.now`; tests pin it. */
|
|
409
|
+
now;
|
|
410
|
+
constructor(opts) {
|
|
411
|
+
this.staleQueuedMs = opts?.staleQueuedMs ?? DEFAULT_STALE_QUEUED_MS;
|
|
412
|
+
this.now = opts?.now ?? (() => Date.now());
|
|
413
|
+
}
|
|
391
414
|
// ----- Cards -----
|
|
392
415
|
async listCards(boardConfigUuid) {
|
|
393
416
|
return [...this.cards.values()].filter((c) => c.boardConfigUuid === boardConfigUuid).map((c) => this.publicCard(c));
|
|
@@ -487,18 +510,48 @@ var InMemoryStorageAdapter = class {
|
|
|
487
510
|
// ----- Stage runs -----
|
|
488
511
|
async beginStageRun(cardId, r) {
|
|
489
512
|
const existing = this.runs.get(r.idemKey);
|
|
490
|
-
if (existing)
|
|
513
|
+
if (existing) {
|
|
514
|
+
if (this.isReclaimable(existing)) {
|
|
515
|
+
const run2 = {
|
|
516
|
+
idemKey: r.idemKey,
|
|
517
|
+
cardId,
|
|
518
|
+
stageId: r.stageId,
|
|
519
|
+
handlerType: r.handlerType,
|
|
520
|
+
status: "queued",
|
|
521
|
+
attempts: (existing.attempts ?? 1) + 1,
|
|
522
|
+
createdAt: new Date(this.now()).toISOString()
|
|
523
|
+
};
|
|
524
|
+
this.runs.set(r.idemKey, run2);
|
|
525
|
+
return { created: true, run: { ...run2 } };
|
|
526
|
+
}
|
|
527
|
+
return { created: false, run: { ...existing } };
|
|
528
|
+
}
|
|
491
529
|
const run = {
|
|
492
530
|
idemKey: r.idemKey,
|
|
493
531
|
cardId,
|
|
494
532
|
stageId: r.stageId,
|
|
495
533
|
handlerType: r.handlerType,
|
|
496
534
|
status: "queued",
|
|
497
|
-
|
|
535
|
+
attempts: 1,
|
|
536
|
+
createdAt: new Date(this.now()).toISOString()
|
|
498
537
|
};
|
|
499
538
|
this.runs.set(r.idemKey, run);
|
|
500
539
|
return { created: true, run: { ...run } };
|
|
501
540
|
}
|
|
541
|
+
/**
|
|
542
|
+
* A stranded stage-run the next `beginStageRun` may re-claim (design §10): a
|
|
543
|
+
* `failed` run (dispatch threw), or a `queued` run older than `staleQueuedMs`
|
|
544
|
+
* (a process died before dispatch flipped it). `running`/`completed` runs are
|
|
545
|
+
* never re-claimed.
|
|
546
|
+
*/
|
|
547
|
+
isReclaimable(run) {
|
|
548
|
+
if (run.status === "failed") return true;
|
|
549
|
+
if (run.status === "queued") {
|
|
550
|
+
const age = this.now() - Date.parse(run.createdAt);
|
|
551
|
+
return Number.isFinite(age) && age >= this.staleQueuedMs;
|
|
552
|
+
}
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
502
555
|
async completeStageRun(idemKey, c) {
|
|
503
556
|
const run = this.runs.get(idemKey);
|
|
504
557
|
if (!run) throw new Error(`No stage run for idemKey ${idemKey}`);
|
|
@@ -1193,6 +1246,14 @@ function runAdapterConformance(makeAdapter, runner) {
|
|
|
1193
1246
|
expect(still.lane).toBe("generate");
|
|
1194
1247
|
});
|
|
1195
1248
|
const asConductor = (adapter) => adapter.listDueCards && adapter.countsByLane && adapter.capabilities ? adapter : null;
|
|
1249
|
+
const supportsField = (adapter, field) => {
|
|
1250
|
+
const fields = adapter.capabilities().dueRuleFields;
|
|
1251
|
+
return fields.includes("*") || fields.includes(field);
|
|
1252
|
+
};
|
|
1253
|
+
const supportsPredicate = (adapter, ref) => {
|
|
1254
|
+
const preds = adapter.capabilities().dueRulePredicates;
|
|
1255
|
+
return preds.includes("*") || preds.includes(ref);
|
|
1256
|
+
};
|
|
1196
1257
|
it("listDueCards {kind:'always'} returns every card in the lane", async () => {
|
|
1197
1258
|
const base = await makeAdapter();
|
|
1198
1259
|
const adapter = asConductor(base);
|
|
@@ -1224,6 +1285,7 @@ function runAdapterConformance(makeAdapter, runner) {
|
|
|
1224
1285
|
const base = await makeAdapter();
|
|
1225
1286
|
const adapter = asConductor(base);
|
|
1226
1287
|
if (!adapter) return;
|
|
1288
|
+
if (!supportsField(adapter, "next_touch_at")) return;
|
|
1227
1289
|
const past = new Date(Date.now() - 6e4).toISOString();
|
|
1228
1290
|
const future = new Date(Date.now() + 6e4).toISOString();
|
|
1229
1291
|
await seedCard(adapter, "scheduled", "due", { next_touch_at: past });
|
|
@@ -1245,6 +1307,7 @@ function runAdapterConformance(makeAdapter, runner) {
|
|
|
1245
1307
|
const base = await makeAdapter();
|
|
1246
1308
|
const adapter = asConductor(base);
|
|
1247
1309
|
if (!adapter) return;
|
|
1310
|
+
if (!supportsPredicate(adapter, "status")) return;
|
|
1248
1311
|
await seedCard(adapter, "queued", "approved", { status: "approved" });
|
|
1249
1312
|
await seedCard(adapter, "queued", "draft", { status: "draft" });
|
|
1250
1313
|
const rule = {
|
|
@@ -1261,6 +1324,8 @@ function runAdapterConformance(makeAdapter, runner) {
|
|
|
1261
1324
|
const base = await makeAdapter();
|
|
1262
1325
|
const adapter = asConductor(base);
|
|
1263
1326
|
if (!adapter) return;
|
|
1327
|
+
if (!supportsField(adapter, "next_touch_at") || !supportsPredicate(adapter, "status"))
|
|
1328
|
+
return;
|
|
1264
1329
|
const past = new Date(Date.now() - 6e4).toISOString();
|
|
1265
1330
|
const future = new Date(Date.now() + 6e4).toISOString();
|
|
1266
1331
|
await seedCard(adapter, "queued", "send-me", {
|
|
@@ -1523,20 +1588,28 @@ function createEngine(options) {
|
|
|
1523
1588
|
if (!begin.created) {
|
|
1524
1589
|
return { dispatched: false, executionUuid: begin.run.executionUuid };
|
|
1525
1590
|
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1591
|
+
let result;
|
|
1592
|
+
try {
|
|
1593
|
+
result = await dispatchStageHandler(
|
|
1594
|
+
{
|
|
1595
|
+
cardId,
|
|
1596
|
+
boardConfigUuid: card.boardId,
|
|
1597
|
+
configVersion: cfg.version,
|
|
1598
|
+
stage,
|
|
1599
|
+
idemKey,
|
|
1600
|
+
input: cardContext(card, stage),
|
|
1601
|
+
orgId: options.orgId,
|
|
1602
|
+
callbackUrl
|
|
1603
|
+
},
|
|
1604
|
+
cadraClient,
|
|
1605
|
+
webhookOptions
|
|
1606
|
+
);
|
|
1607
|
+
} catch (err) {
|
|
1608
|
+
await adapter.failStageRun(idemKey, {
|
|
1609
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1610
|
+
});
|
|
1611
|
+
throw err;
|
|
1612
|
+
}
|
|
1540
1613
|
if (result.executionUuid && adapter.markStageRunDispatched) {
|
|
1541
1614
|
await adapter.markStageRunDispatched(idemKey, {
|
|
1542
1615
|
executionUuid: result.executionUuid
|
|
@@ -1605,21 +1678,30 @@ function createEngine(options) {
|
|
|
1605
1678
|
}));
|
|
1606
1679
|
batchMembers.set(batchKey, batchCards.map((c) => c.idemKey));
|
|
1607
1680
|
const lead = eligible[0].card;
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1681
|
+
let result;
|
|
1682
|
+
try {
|
|
1683
|
+
result = await dispatchStageHandler(
|
|
1684
|
+
{
|
|
1685
|
+
cardId: lead.id,
|
|
1686
|
+
boardConfigUuid: lead.boardId,
|
|
1687
|
+
configVersion: cfg.version,
|
|
1688
|
+
stage,
|
|
1689
|
+
idemKey: eligible[0].idemKey,
|
|
1690
|
+
input: batchContext(lead, stage, batchCards),
|
|
1691
|
+
orgId: options.orgId,
|
|
1692
|
+
callbackUrl,
|
|
1693
|
+
batch: { batchKey, cards: batchCards }
|
|
1694
|
+
},
|
|
1695
|
+
cadraClient,
|
|
1696
|
+
webhookOptions
|
|
1697
|
+
);
|
|
1698
|
+
} catch (err) {
|
|
1699
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1700
|
+
for (const { idemKey } of eligible) {
|
|
1701
|
+
await adapter.failStageRun(idemKey, { error: msg });
|
|
1702
|
+
}
|
|
1703
|
+
throw err;
|
|
1704
|
+
}
|
|
1623
1705
|
if (result.executionUuid && adapter.markStageRunDispatched) {
|
|
1624
1706
|
for (const { idemKey } of eligible) {
|
|
1625
1707
|
await adapter.markStageRunDispatched(idemKey, {
|