@parall/daemon 1.44.0 → 1.45.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.
- package/bundle/manifest.json +9 -9
- package/bundle/parall-claude-agent.js +336 -92
- package/bundle/parall-codex-agent.js +964 -1342
- package/bundle/parall-daemon.js +866 -311
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +229 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/runtime-bin-resolver.d.ts +7 -1
- package/dist/runtime-bin-resolver.d.ts.map +1 -1
- package/dist/runtime-bin-resolver.js +57 -22
- package/dist/runtimes.d.ts +15 -4
- package/dist/runtimes.d.ts.map +1 -1
- package/dist/runtimes.js +60 -5
- package/dist/supervisor.d.ts.map +1 -1
- package/dist/supervisor.js +4 -1
- package/dist/win-lifecycle.d.ts +96 -0
- package/dist/win-lifecycle.d.ts.map +1 -0
- package/dist/win-lifecycle.js +229 -0
- package/dist/win-service.d.ts +119 -0
- package/dist/win-service.d.ts.map +1 -0
- package/dist/win-service.js +226 -0
- package/package.json +6 -6
|
@@ -26487,9 +26487,6 @@ function laneContextFilePath(contextDir, targetUri, threadRootId) {
|
|
|
26487
26487
|
return path.join(contextDir, `${laneKeyForTarget(targetUri, threadRootId)}.json`);
|
|
26488
26488
|
}
|
|
26489
26489
|
|
|
26490
|
-
// ts/agent-core/dist/lane-ledger.js
|
|
26491
|
-
import * as fs from "node:fs";
|
|
26492
|
-
|
|
26493
26490
|
// ts/sdk/dist/types.js
|
|
26494
26491
|
var MENTION_ALL_USER_ID = "all";
|
|
26495
26492
|
|
|
@@ -29101,6 +29098,7 @@ var ParallWs = class {
|
|
|
29101
29098
|
};
|
|
29102
29099
|
|
|
29103
29100
|
// ts/agent-core/dist/lane-ledger.js
|
|
29101
|
+
import * as fs from "node:fs";
|
|
29104
29102
|
var LedgerUnsupportedError = class extends Error {
|
|
29105
29103
|
};
|
|
29106
29104
|
function isStaleLane(err) {
|
|
@@ -29384,6 +29382,20 @@ var LaneLedger = class {
|
|
|
29384
29382
|
this.lanes.set(lane.laneKey, lane);
|
|
29385
29383
|
return lane;
|
|
29386
29384
|
}
|
|
29385
|
+
/**
|
|
29386
|
+
* Drop a lane's local record without any server call — for a typed lane
|
|
29387
|
+
* whose member the by-id complete just resolved (the server dropped the
|
|
29388
|
+
* vacated lane row in the same transaction). Calling completeIfIdle
|
|
29389
|
+
* instead would fire a lane-form Complete at a lane that no longer exists
|
|
29390
|
+
* and burn an RPC on the guaranteed STALE_LANE answer.
|
|
29391
|
+
*/
|
|
29392
|
+
dropLocal(laneKey) {
|
|
29393
|
+
const lane = this.lanes.get(laneKey);
|
|
29394
|
+
if (!lane)
|
|
29395
|
+
return;
|
|
29396
|
+
this.lanes.delete(laneKey);
|
|
29397
|
+
this.removeLaneContext(lane);
|
|
29398
|
+
}
|
|
29387
29399
|
/**
|
|
29388
29400
|
* Remove the per-lane context file (and its CLI sidecar) when the lane
|
|
29389
29401
|
* ends. A leftover file would make a later cross-context send to the same
|
|
@@ -29463,10 +29475,104 @@ async function dispatchLaneGroup(host, opts) {
|
|
|
29463
29475
|
await ledger.completeIfIdle(lane.laneKey, pendingInjections || opts.hasMoreLocal());
|
|
29464
29476
|
return "dispatched";
|
|
29465
29477
|
}
|
|
29478
|
+
function typedLedgerEventIds(host, events) {
|
|
29479
|
+
if (!host.laneLedger || host.ledgerDisabled)
|
|
29480
|
+
return null;
|
|
29481
|
+
const ids = [];
|
|
29482
|
+
for (const ev of events) {
|
|
29483
|
+
if (!ev.dispatchEventId || host.usesLaneLedger(ev))
|
|
29484
|
+
return null;
|
|
29485
|
+
ids.push(ev.dispatchEventId);
|
|
29486
|
+
}
|
|
29487
|
+
return ids.length > 0 ? ids : null;
|
|
29488
|
+
}
|
|
29489
|
+
function isByIDCompleteUnsupported(err) {
|
|
29490
|
+
return err instanceof ApiError && err.status === 400;
|
|
29491
|
+
}
|
|
29492
|
+
async function resolveDispatchByID(host, dispatchEventId, lane) {
|
|
29493
|
+
try {
|
|
29494
|
+
await host.opts.client.completeDispatch(host.opts.config.org_id, {
|
|
29495
|
+
dispatch_event_id: dispatchEventId,
|
|
29496
|
+
...lane ? { lane } : {},
|
|
29497
|
+
turn_outcome: "ok"
|
|
29498
|
+
});
|
|
29499
|
+
return "ok";
|
|
29500
|
+
} catch (err) {
|
|
29501
|
+
if (err instanceof ApiError && err.status === 409)
|
|
29502
|
+
return "stale";
|
|
29503
|
+
if (isByIDCompleteUnsupported(err))
|
|
29504
|
+
return "unsupported";
|
|
29505
|
+
host.opts.log?.warn(`by-id complete failed for ${dispatchEventId} \u2014 leaving for re-drive: ${String(err)}`);
|
|
29506
|
+
return "failed";
|
|
29507
|
+
}
|
|
29508
|
+
}
|
|
29509
|
+
function clearTypedDedupeForEvent(host, event) {
|
|
29510
|
+
const sourceId = event.ackSourceId;
|
|
29511
|
+
if (!sourceId)
|
|
29512
|
+
return;
|
|
29513
|
+
switch (event.ackSourceType) {
|
|
29514
|
+
case "task_activity": {
|
|
29515
|
+
const prefix = `${event.targetId}:`;
|
|
29516
|
+
for (const key of host.dispatchedTasks) {
|
|
29517
|
+
if (key.startsWith(prefix))
|
|
29518
|
+
host.dispatchedTasks.delete(key);
|
|
29519
|
+
}
|
|
29520
|
+
break;
|
|
29521
|
+
}
|
|
29522
|
+
case "comment":
|
|
29523
|
+
host.dispatchedTasks.delete(`comment:${sourceId}`);
|
|
29524
|
+
break;
|
|
29525
|
+
case "schedule_run":
|
|
29526
|
+
host.dispatchedTasks.delete(`schedule_run:${sourceId}`);
|
|
29527
|
+
break;
|
|
29528
|
+
case "external_trigger_run":
|
|
29529
|
+
host.dispatchedTasks.delete(`external_trigger_run:${sourceId}`);
|
|
29530
|
+
break;
|
|
29531
|
+
case "channel_message":
|
|
29532
|
+
host.dispatchedMessages.delete(`channel_message:${sourceId}`);
|
|
29533
|
+
break;
|
|
29534
|
+
case "approval":
|
|
29535
|
+
host.dispatchedTasks.delete(`approval:${sourceId}`);
|
|
29536
|
+
break;
|
|
29537
|
+
}
|
|
29538
|
+
}
|
|
29539
|
+
async function settleDrainedTypedGroup(host, events, ids, turnErrored) {
|
|
29540
|
+
if (turnErrored) {
|
|
29541
|
+
host.opts.log?.info(`buffered typed turn for ${events[events.length - 1]?.messageId} surfaced a runtime error \u2014 leaving for re-drive`);
|
|
29542
|
+
for (const event of events)
|
|
29543
|
+
clearTypedDedupeForEvent(host, event);
|
|
29544
|
+
return;
|
|
29545
|
+
}
|
|
29546
|
+
const legacyAckFrom = async (start) => {
|
|
29547
|
+
for (const [j, id] of ids.slice(start).entries()) {
|
|
29548
|
+
try {
|
|
29549
|
+
await host.opts.client.ackDispatchByID(host.opts.config.org_id, id);
|
|
29550
|
+
} catch {
|
|
29551
|
+
clearTypedDedupeForEvent(host, events[start + j]);
|
|
29552
|
+
}
|
|
29553
|
+
}
|
|
29554
|
+
};
|
|
29555
|
+
if (host.typedByIdCompleteUnsupported) {
|
|
29556
|
+
await legacyAckFrom(0);
|
|
29557
|
+
return;
|
|
29558
|
+
}
|
|
29559
|
+
for (const [i, id] of ids.entries()) {
|
|
29560
|
+
const outcome = await resolveDispatchByID(host, id);
|
|
29561
|
+
if (outcome === "unsupported") {
|
|
29562
|
+
host.typedByIdCompleteUnsupported = true;
|
|
29563
|
+
host.opts.log?.warn("server predates the by-id dispatch complete \u2014 falling back to legacy typed acks");
|
|
29564
|
+
await legacyAckFrom(i);
|
|
29565
|
+
return;
|
|
29566
|
+
}
|
|
29567
|
+
if (outcome !== "ok") {
|
|
29568
|
+
clearTypedDedupeForEvent(host, events[i]);
|
|
29569
|
+
}
|
|
29570
|
+
}
|
|
29571
|
+
}
|
|
29466
29572
|
var TYPED_BACKOFF_BASE_MS = 2e3;
|
|
29467
29573
|
var TYPED_BACKOFF_CAP_MS = 5 * 6e4;
|
|
29468
29574
|
var TYPED_BACKOFF_MAP_CAP = 512;
|
|
29469
|
-
async function consumeTypedDispatch(host, ref, run,
|
|
29575
|
+
async function consumeTypedDispatch(host, ref, run, hooks) {
|
|
29470
29576
|
const backoffKey = ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`;
|
|
29471
29577
|
const armed = host.typedRedriveBackoff.get(backoffKey);
|
|
29472
29578
|
if (armed) {
|
|
@@ -29482,8 +29588,8 @@ async function consumeTypedDispatch(host, ref, run, ack) {
|
|
|
29482
29588
|
return;
|
|
29483
29589
|
}
|
|
29484
29590
|
const settleAck = (ackResult) => ackResult !== false;
|
|
29485
|
-
const settle = (
|
|
29486
|
-
if (
|
|
29591
|
+
const settle = (resolved2) => {
|
|
29592
|
+
if (resolved2) {
|
|
29487
29593
|
host.typedRedriveBackoff.delete(backoffKey);
|
|
29488
29594
|
return;
|
|
29489
29595
|
}
|
|
@@ -29497,13 +29603,13 @@ async function consumeTypedDispatch(host, ref, run, ack) {
|
|
|
29497
29603
|
host.typedRedriveBackoff.set(backoffKey, { failures, until: Date.now() + backoffMs });
|
|
29498
29604
|
};
|
|
29499
29605
|
const runLegacy = async () => {
|
|
29500
|
-
let
|
|
29606
|
+
let acked = false;
|
|
29501
29607
|
try {
|
|
29502
29608
|
if (await run(ref.dispatchEventId)) {
|
|
29503
|
-
|
|
29609
|
+
acked = settleAck(await hooks.legacyAck(ref.dispatchEventId));
|
|
29504
29610
|
}
|
|
29505
29611
|
} finally {
|
|
29506
|
-
settle(
|
|
29612
|
+
settle(acked);
|
|
29507
29613
|
}
|
|
29508
29614
|
};
|
|
29509
29615
|
if (!host.laneLedger || host.ledgerDisabled) {
|
|
@@ -29525,15 +29631,39 @@ async function consumeTypedDispatch(host, ref, run, ack) {
|
|
|
29525
29631
|
host.opts.log?.info(`typed dispatch ${ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`} not claimable (held elsewhere or already resolved) \u2014 skipping`);
|
|
29526
29632
|
return;
|
|
29527
29633
|
}
|
|
29528
|
-
let
|
|
29634
|
+
let resolved = false;
|
|
29635
|
+
let viaLegacyAck = false;
|
|
29529
29636
|
try {
|
|
29530
29637
|
if (await run(lane.typedDispatchEventId)) {
|
|
29531
|
-
|
|
29638
|
+
if (host.typedByIdCompleteUnsupported || !lane.typedDispatchEventId) {
|
|
29639
|
+
viaLegacyAck = true;
|
|
29640
|
+
resolved = settleAck(await hooks.legacyAck(lane.typedDispatchEventId));
|
|
29641
|
+
} else {
|
|
29642
|
+
const outcome = await resolveDispatchByID(host, lane.typedDispatchEventId, lane.lane);
|
|
29643
|
+
if (outcome === "unsupported") {
|
|
29644
|
+
host.typedByIdCompleteUnsupported = true;
|
|
29645
|
+
host.opts.log?.warn("server predates the by-id dispatch complete \u2014 falling back to the legacy typed ack");
|
|
29646
|
+
viaLegacyAck = true;
|
|
29647
|
+
resolved = settleAck(await hooks.legacyAck(lane.typedDispatchEventId));
|
|
29648
|
+
} else if (outcome === "stale") {
|
|
29649
|
+
hooks.clearDedupe?.();
|
|
29650
|
+
resolved = true;
|
|
29651
|
+
} else {
|
|
29652
|
+
resolved = outcome === "ok";
|
|
29653
|
+
if (!resolved) {
|
|
29654
|
+
hooks.clearDedupe?.();
|
|
29655
|
+
}
|
|
29656
|
+
}
|
|
29657
|
+
}
|
|
29532
29658
|
}
|
|
29533
29659
|
} finally {
|
|
29534
|
-
settle(
|
|
29535
|
-
|
|
29536
|
-
|
|
29660
|
+
settle(resolved);
|
|
29661
|
+
if (resolved && !viaLegacyAck) {
|
|
29662
|
+
host.laneLedger.dropLocal(lane.laneKey);
|
|
29663
|
+
} else {
|
|
29664
|
+
await host.laneLedger.completeIfIdle(lane.laneKey, false).catch(() => {
|
|
29665
|
+
});
|
|
29666
|
+
}
|
|
29537
29667
|
}
|
|
29538
29668
|
}
|
|
29539
29669
|
async function consumeMessageWorkItem(host, item) {
|
|
@@ -29542,6 +29672,16 @@ async function consumeMessageWorkItem(host, item) {
|
|
|
29542
29672
|
if (!host.tryClaimMessage(item.source_id))
|
|
29543
29673
|
return;
|
|
29544
29674
|
const ackItem = () => {
|
|
29675
|
+
if (host.laneLedger && !host.ledgerDisabled && !host.typedByIdCompleteUnsupported) {
|
|
29676
|
+
void resolveDispatchByID(host, item.id).then((outcome) => {
|
|
29677
|
+
if (outcome === "unsupported") {
|
|
29678
|
+
host.typedByIdCompleteUnsupported = true;
|
|
29679
|
+
host.opts.client.ackDispatchByID(host.opts.config.org_id, item.id).catch(() => {
|
|
29680
|
+
});
|
|
29681
|
+
}
|
|
29682
|
+
});
|
|
29683
|
+
return;
|
|
29684
|
+
}
|
|
29545
29685
|
host.opts.client.ackDispatchByID(host.opts.config.org_id, item.id).catch(() => {
|
|
29546
29686
|
});
|
|
29547
29687
|
};
|
|
@@ -30721,20 +30861,23 @@ var ParallAgentGateway = class {
|
|
|
30721
30861
|
if (data.status !== "todo" && data.status !== "in_progress")
|
|
30722
30862
|
return;
|
|
30723
30863
|
try {
|
|
30724
|
-
await this.consumeTypedDispatch(data.dispatch_event_id ? { dispatchEventId: data.dispatch_event_id } : { sourceType: "task_activity", sourceId: data.id }, (dispatchEventId) => this.handleTaskAssignment(data, data.id, dispatchEventId),
|
|
30725
|
-
|
|
30726
|
-
|
|
30864
|
+
await this.consumeTypedDispatch(data.dispatch_event_id ? { dispatchEventId: data.dispatch_event_id } : { sourceType: "task_activity", sourceId: data.id }, (dispatchEventId) => this.handleTaskAssignment(data, data.id, dispatchEventId), {
|
|
30865
|
+
legacyAck: (dispatchEventId) => {
|
|
30866
|
+
if (dispatchEventId) {
|
|
30867
|
+
return this.ackDispatchEvent(dispatchEventId, () => {
|
|
30868
|
+
this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`);
|
|
30869
|
+
});
|
|
30870
|
+
}
|
|
30871
|
+
return this.opts.client.ackDispatch(this.opts.config.org_id, {
|
|
30872
|
+
source_type: "task_activity",
|
|
30873
|
+
source_id: data.id
|
|
30874
|
+
}).then(() => true, (err) => {
|
|
30727
30875
|
this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`);
|
|
30876
|
+
this.opts.log?.warn(`dispatch ack failed for task ${data.id}, releasing for re-drive: ${String(err)}`);
|
|
30877
|
+
return false;
|
|
30728
30878
|
});
|
|
30729
|
-
}
|
|
30730
|
-
|
|
30731
|
-
source_type: "task_activity",
|
|
30732
|
-
source_id: data.id
|
|
30733
|
-
}).then(() => true, (err) => {
|
|
30734
|
-
this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`);
|
|
30735
|
-
this.opts.log?.warn(`dispatch ack failed for task ${data.id}, releasing for re-drive: ${String(err)}`);
|
|
30736
|
-
return false;
|
|
30737
|
-
});
|
|
30879
|
+
},
|
|
30880
|
+
clearDedupe: () => this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`)
|
|
30738
30881
|
});
|
|
30739
30882
|
} catch (err) {
|
|
30740
30883
|
this.opts.log?.error(`task dispatch failed for ${data.id}: ${String(err)}`);
|
|
@@ -30753,7 +30896,10 @@ var ParallAgentGateway = class {
|
|
|
30753
30896
|
if (!data.source_id || !data.task_id)
|
|
30754
30897
|
return;
|
|
30755
30898
|
try {
|
|
30756
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.handleTaskComment(data.source_id, data.task_id ?? "", data.actor_id, data.delivery_reason
|
|
30899
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.handleTaskComment(data.source_id, data.task_id ?? "", data.actor_id, data.delivery_reason, dispatchEventId), {
|
|
30900
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30901
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30902
|
+
});
|
|
30757
30903
|
} catch (err) {
|
|
30758
30904
|
this.opts.log?.error(`task comment dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30759
30905
|
}
|
|
@@ -30761,7 +30907,10 @@ var ParallAgentGateway = class {
|
|
|
30761
30907
|
if (!data.source_id)
|
|
30762
30908
|
return;
|
|
30763
30909
|
try {
|
|
30764
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.handleWikiComment(data.source_id, data.actor_id, data.delivery_reason
|
|
30910
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.handleWikiComment(data.source_id, data.actor_id, data.delivery_reason, dispatchEventId), {
|
|
30911
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30912
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30913
|
+
});
|
|
30765
30914
|
} catch (err) {
|
|
30766
30915
|
this.opts.log?.error(`wiki comment dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30767
30916
|
}
|
|
@@ -30772,7 +30921,10 @@ var ParallAgentGateway = class {
|
|
|
30772
30921
|
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.handleTaskDispatch(data.task_id ?? "", data.source_id ?? data.task_id ?? "", {
|
|
30773
30922
|
allowCreator: true,
|
|
30774
30923
|
dispatchEventId
|
|
30775
|
-
}),
|
|
30924
|
+
}), {
|
|
30925
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30926
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30927
|
+
});
|
|
30776
30928
|
} catch (err) {
|
|
30777
30929
|
this.opts.log?.error(`task update dispatch failed for ${data.task_id}: ${String(err)}`);
|
|
30778
30930
|
}
|
|
@@ -30780,7 +30932,10 @@ var ParallAgentGateway = class {
|
|
|
30780
30932
|
if (!data.source_id)
|
|
30781
30933
|
return;
|
|
30782
30934
|
try {
|
|
30783
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleScheduleFire(data.source_id, data.actor_id
|
|
30935
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleScheduleFire(data.source_id, data.actor_id, dispatchEventId), {
|
|
30936
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30937
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30938
|
+
});
|
|
30784
30939
|
} catch (err) {
|
|
30785
30940
|
this.opts.log?.error(`schedule fire dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30786
30941
|
}
|
|
@@ -30788,7 +30943,10 @@ var ParallAgentGateway = class {
|
|
|
30788
30943
|
if (!data.source_id)
|
|
30789
30944
|
return;
|
|
30790
30945
|
try {
|
|
30791
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleExternalTriggerRun(data.source_id
|
|
30946
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleExternalTriggerRun(data.source_id, dispatchEventId), {
|
|
30947
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30948
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30949
|
+
});
|
|
30792
30950
|
} catch (err) {
|
|
30793
30951
|
this.opts.log?.error(`external trigger dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30794
30952
|
}
|
|
@@ -30796,7 +30954,10 @@ var ParallAgentGateway = class {
|
|
|
30796
30954
|
if (!data.source_id)
|
|
30797
30955
|
return;
|
|
30798
30956
|
try {
|
|
30799
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleChannelMessage(data.source_id
|
|
30957
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleChannelMessage(data.source_id, dispatchEventId), {
|
|
30958
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30959
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30960
|
+
});
|
|
30800
30961
|
} catch (err) {
|
|
30801
30962
|
this.opts.log?.error(`channel message dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30802
30963
|
}
|
|
@@ -30804,7 +30965,10 @@ var ParallAgentGateway = class {
|
|
|
30804
30965
|
if (!data.source_id)
|
|
30805
30966
|
return;
|
|
30806
30967
|
try {
|
|
30807
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleApprovalDecided(data.source_id, data.actor_id, data.chat_id ?? null
|
|
30968
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleApprovalDecided(data.source_id, data.actor_id, data.chat_id ?? null, dispatchEventId), {
|
|
30969
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30970
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30971
|
+
});
|
|
30808
30972
|
} catch (err) {
|
|
30809
30973
|
this.opts.log?.error(`approval decided dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30810
30974
|
}
|
|
@@ -30887,6 +31051,20 @@ var ParallAgentGateway = class {
|
|
|
30887
31051
|
source_id: sourceId
|
|
30888
31052
|
});
|
|
30889
31053
|
}
|
|
31054
|
+
/**
|
|
31055
|
+
* Sticky: the server answered a by-id complete with 400 (predates the
|
|
31056
|
+
* form). Typed resolution falls back to the legacy ack for the rest of
|
|
31057
|
+
* the process lifetime.
|
|
31058
|
+
*/
|
|
31059
|
+
typedByIdCompleteUnsupported = false;
|
|
31060
|
+
// Typed-face ledger helpers live in gateway-lane-flow.ts; thin delegates
|
|
31061
|
+
// keep the site code and tests on the class surface.
|
|
31062
|
+
typedLedgerEventIds(events) {
|
|
31063
|
+
return typedLedgerEventIds(this.laneFlowHost(), events);
|
|
31064
|
+
}
|
|
31065
|
+
resolveDispatchByID(dispatchEventId, lane) {
|
|
31066
|
+
return resolveDispatchByID(this.laneFlowHost(), dispatchEventId, lane);
|
|
31067
|
+
}
|
|
30890
31068
|
/** True when this event's lifecycle is owned by the dispatch lane ledger. */
|
|
30891
31069
|
usesLaneLedger(event) {
|
|
30892
31070
|
return this.laneLedger != null && !this.ledgerDisabled && this.laneLedger.handles(event);
|
|
@@ -30917,15 +31095,16 @@ var ParallAgentGateway = class {
|
|
|
30917
31095
|
dispatchLaneGroup(opts) {
|
|
30918
31096
|
return dispatchLaneGroup(this.laneFlowHost(), opts);
|
|
30919
31097
|
}
|
|
30920
|
-
consumeTypedDispatch(ref, run,
|
|
30921
|
-
return consumeTypedDispatch(this.laneFlowHost(), ref, run,
|
|
31098
|
+
consumeTypedDispatch(ref, run, hooks) {
|
|
31099
|
+
return consumeTypedDispatch(this.laneFlowHost(), ref, run, hooks);
|
|
30922
31100
|
}
|
|
30923
|
-
//
|
|
30924
|
-
//
|
|
30925
|
-
//
|
|
30926
|
-
//
|
|
30927
|
-
//
|
|
30928
|
-
//
|
|
31101
|
+
// Legacy administrative ack (ledger-disabled fallback only). Typed
|
|
31102
|
+
// completion must wait until the ack has either committed or failed.
|
|
31103
|
+
// Errors stay best-effort: a failed ack leaves the row received, so
|
|
31104
|
+
// Complete releases and re-drives it safely. The boolean outcome feeds the
|
|
31105
|
+
// typed-consume backoff — an ack that failed must count as a failed
|
|
31106
|
+
// consume, or an ack outage would clear the backoff entry and let the
|
|
31107
|
+
// release re-drive spin at wire speed.
|
|
30929
31108
|
ackDispatchEvent(dispatchEventId, onFailure) {
|
|
30930
31109
|
return this.opts.client.ackDispatchByID(this.opts.config.org_id, dispatchEventId).then(() => true, (err) => {
|
|
30931
31110
|
onFailure?.();
|
|
@@ -30933,6 +31112,9 @@ var ParallAgentGateway = class {
|
|
|
30933
31112
|
return false;
|
|
30934
31113
|
});
|
|
30935
31114
|
}
|
|
31115
|
+
// PARITY: this switch and gateway-lane-flow's clearTypedDedupeForEvent must
|
|
31116
|
+
// handle the same typed source families — extend BOTH when adding a typed
|
|
31117
|
+
// event type (same dedupe entries, keyed from different event shapes).
|
|
30936
31118
|
clearTypedDispatchDedupe(item) {
|
|
30937
31119
|
switch (item.event_type) {
|
|
30938
31120
|
case "task_assign":
|
|
@@ -31506,6 +31688,12 @@ var ParallAgentGateway = class {
|
|
|
31506
31688
|
dispatched = outcome === "dispatched";
|
|
31507
31689
|
} else {
|
|
31508
31690
|
dispatched = await this.runDispatch(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
|
|
31691
|
+
if (dispatched && this.typedLedgerEventIds(events) && this.consumeTurnError(fork.fork.sessionKey)) {
|
|
31692
|
+
this.opts.log?.info(`typed fork turn for ${last.messageId} surfaced a runtime error \u2014 releasing for retry`);
|
|
31693
|
+
for (const item of items)
|
|
31694
|
+
item.resolve(false);
|
|
31695
|
+
continue;
|
|
31696
|
+
}
|
|
31509
31697
|
}
|
|
31510
31698
|
if (!dispatched) {
|
|
31511
31699
|
for (const item of items) {
|
|
@@ -31655,13 +31843,16 @@ var ParallAgentGateway = class {
|
|
|
31655
31843
|
}
|
|
31656
31844
|
continue;
|
|
31657
31845
|
}
|
|
31658
|
-
|
|
31659
|
-
|
|
31660
|
-
|
|
31661
|
-
|
|
31662
|
-
|
|
31663
|
-
|
|
31664
|
-
|
|
31846
|
+
const typedRefs = this.typedLedgerEventIds(events);
|
|
31847
|
+
if (!typedRefs) {
|
|
31848
|
+
try {
|
|
31849
|
+
await this.emitDispatchReceived(event);
|
|
31850
|
+
} catch (err) {
|
|
31851
|
+
this.opts.log?.warn?.(`mark-received failed for buffered dispatch, leaving unacked for retry: ${String(err)}`);
|
|
31852
|
+
this.dispatchState.mainBuffer.unshift(...events);
|
|
31853
|
+
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
31854
|
+
break;
|
|
31855
|
+
}
|
|
31665
31856
|
}
|
|
31666
31857
|
const dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier);
|
|
31667
31858
|
if (!dispatched) {
|
|
@@ -31669,6 +31860,10 @@ var ParallAgentGateway = class {
|
|
|
31669
31860
|
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
31670
31861
|
break;
|
|
31671
31862
|
}
|
|
31863
|
+
if (typedRefs) {
|
|
31864
|
+
await settleDrainedTypedGroup(this.laneFlowHost(), events, typedRefs, this.consumeTurnError(this.opts.runtimeKey));
|
|
31865
|
+
continue;
|
|
31866
|
+
}
|
|
31672
31867
|
for (const bufferedEvent of events) {
|
|
31673
31868
|
const sourceType = bufferedEvent.ackSourceType ?? (bufferedEvent.type === "task" ? "task_activity" : "message");
|
|
31674
31869
|
const sourceId = bufferedEvent.ackSourceId ?? bufferedEvent.messageId;
|
|
@@ -31728,20 +31923,27 @@ var ParallAgentGateway = class {
|
|
|
31728
31923
|
}
|
|
31729
31924
|
return outcome === "dispatched";
|
|
31730
31925
|
}
|
|
31731
|
-
|
|
31732
|
-
|
|
31733
|
-
|
|
31734
|
-
|
|
31735
|
-
|
|
31736
|
-
|
|
31737
|
-
|
|
31738
|
-
|
|
31739
|
-
|
|
31740
|
-
|
|
31926
|
+
const typedRefs = this.typedLedgerEventIds([event]);
|
|
31927
|
+
if (!typedRefs) {
|
|
31928
|
+
try {
|
|
31929
|
+
await this.emitDispatchReceived(event);
|
|
31930
|
+
} catch (err) {
|
|
31931
|
+
this.opts.log?.warn?.(`mark-received failed, leaving unacked for retry: ${String(err)}`);
|
|
31932
|
+
this.dispatchState.mainDispatching = false;
|
|
31933
|
+
this.dispatchState.mainCurrentTargetId = void 0;
|
|
31934
|
+
this.mainCurrentGroupKey = void 0;
|
|
31935
|
+
this.dispatchState.mainPreDispatchBranchPoint = void 0;
|
|
31936
|
+
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
31937
|
+
return false;
|
|
31938
|
+
}
|
|
31741
31939
|
}
|
|
31742
31940
|
let dispatched = false;
|
|
31743
31941
|
try {
|
|
31744
31942
|
dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
|
|
31943
|
+
if (dispatched && typedRefs && this.consumeTurnError(this.opts.runtimeKey)) {
|
|
31944
|
+
this.opts.log?.info(`typed dispatch turn for ${event.messageId} surfaced a runtime error \u2014 releasing for retry`);
|
|
31945
|
+
dispatched = false;
|
|
31946
|
+
}
|
|
31745
31947
|
if (!dispatched) {
|
|
31746
31948
|
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
31747
31949
|
}
|
|
@@ -31783,7 +31985,7 @@ var ParallAgentGateway = class {
|
|
|
31783
31985
|
this.dispatchState.mainBuffer.push(event);
|
|
31784
31986
|
return false;
|
|
31785
31987
|
}
|
|
31786
|
-
if (!this.usesLaneLedger(event)) {
|
|
31988
|
+
if (!this.usesLaneLedger(event) && !this.typedLedgerEventIds([event])) {
|
|
31787
31989
|
try {
|
|
31788
31990
|
await this.emitDispatchReceived(event);
|
|
31789
31991
|
} catch (err) {
|
|
@@ -31964,7 +32166,10 @@ var ParallAgentGateway = class {
|
|
|
31964
32166
|
return;
|
|
31965
32167
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? "", item.source_id ?? item.task_id ?? "", {
|
|
31966
32168
|
dispatchEventId
|
|
31967
|
-
}),
|
|
32169
|
+
}), {
|
|
32170
|
+
legacyAck: (dispatchEventId) => this.ackDispatchEvent(dispatchEventId ?? item.id, () => this.clearTypedDispatchDedupe(item)),
|
|
32171
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(item)
|
|
32172
|
+
});
|
|
31968
32173
|
}
|
|
31969
32174
|
consumeMessageWorkItem(item) {
|
|
31970
32175
|
return consumeMessageWorkItem(this.laneFlowHost(), item);
|
|
@@ -32025,7 +32230,7 @@ var ParallAgentGateway = class {
|
|
|
32025
32230
|
}
|
|
32026
32231
|
return this.handleTaskAssignment(task, ackSourceId, opts.dispatchEventId);
|
|
32027
32232
|
}
|
|
32028
|
-
async handleTaskComment(commentId, taskId, actorId, deliveryReason) {
|
|
32233
|
+
async handleTaskComment(commentId, taskId, actorId, deliveryReason, dispatchEventId) {
|
|
32029
32234
|
if (this.shuttingDown)
|
|
32030
32235
|
return false;
|
|
32031
32236
|
const dedupeKey = `comment:${commentId}`;
|
|
@@ -32081,7 +32286,8 @@ var ParallAgentGateway = class {
|
|
|
32081
32286
|
body: parts.join("\n"),
|
|
32082
32287
|
deliveryReason: deliveryReason ?? void 0,
|
|
32083
32288
|
ackSourceType: "comment",
|
|
32084
|
-
ackSourceId: commentId
|
|
32289
|
+
ackSourceId: commentId,
|
|
32290
|
+
dispatchEventId
|
|
32085
32291
|
};
|
|
32086
32292
|
let dispatched;
|
|
32087
32293
|
try {
|
|
@@ -32095,7 +32301,7 @@ var ParallAgentGateway = class {
|
|
|
32095
32301
|
}
|
|
32096
32302
|
return dispatched;
|
|
32097
32303
|
}
|
|
32098
|
-
async handleWikiComment(commentId, actorId, deliveryReason) {
|
|
32304
|
+
async handleWikiComment(commentId, actorId, deliveryReason, dispatchEventId) {
|
|
32099
32305
|
if (this.shuttingDown)
|
|
32100
32306
|
return false;
|
|
32101
32307
|
const dedupeKey = `comment:${commentId}`;
|
|
@@ -32141,7 +32347,8 @@ var ParallAgentGateway = class {
|
|
|
32141
32347
|
deliveryReason: deliveryReason ?? void 0,
|
|
32142
32348
|
replyTargetUri: comment.target_uri,
|
|
32143
32349
|
ackSourceType: "comment",
|
|
32144
|
-
ackSourceId: commentId
|
|
32350
|
+
ackSourceId: commentId,
|
|
32351
|
+
dispatchEventId
|
|
32145
32352
|
};
|
|
32146
32353
|
let dispatched;
|
|
32147
32354
|
try {
|
|
@@ -32163,7 +32370,7 @@ var ParallAgentGateway = class {
|
|
|
32163
32370
|
* access to already-delivered run snapshots, and the runtime must not crash
|
|
32164
32371
|
* or retry forever in that case.
|
|
32165
32372
|
*/
|
|
32166
|
-
async fetchAndHandleScheduleFire(runId, actorId) {
|
|
32373
|
+
async fetchAndHandleScheduleFire(runId, actorId, dispatchEventId) {
|
|
32167
32374
|
let run = null;
|
|
32168
32375
|
try {
|
|
32169
32376
|
run = await this.opts.client.getScheduleRun(this.opts.config.org_id, runId);
|
|
@@ -32178,9 +32385,9 @@ var ParallAgentGateway = class {
|
|
|
32178
32385
|
}
|
|
32179
32386
|
if (!run)
|
|
32180
32387
|
return true;
|
|
32181
|
-
return this.handleScheduleFire(run, actorId);
|
|
32388
|
+
return this.handleScheduleFire(run, actorId, dispatchEventId);
|
|
32182
32389
|
}
|
|
32183
|
-
async handleScheduleFire(run, actorId) {
|
|
32390
|
+
async handleScheduleFire(run, actorId, dispatchEventId) {
|
|
32184
32391
|
if (this.shuttingDown)
|
|
32185
32392
|
return false;
|
|
32186
32393
|
const dedupeKey = `schedule_run:${run.id}`;
|
|
@@ -32203,7 +32410,8 @@ var ParallAgentGateway = class {
|
|
|
32203
32410
|
scheduledFireAt: run.scheduled_fire_at,
|
|
32204
32411
|
attachedUri: run.fired_attached_uri ?? void 0,
|
|
32205
32412
|
ackSourceType: "schedule_run",
|
|
32206
|
-
ackSourceId: run.id
|
|
32413
|
+
ackSourceId: run.id,
|
|
32414
|
+
dispatchEventId
|
|
32207
32415
|
};
|
|
32208
32416
|
let dispatched;
|
|
32209
32417
|
try {
|
|
@@ -32217,7 +32425,7 @@ var ParallAgentGateway = class {
|
|
|
32217
32425
|
}
|
|
32218
32426
|
return dispatched;
|
|
32219
32427
|
}
|
|
32220
|
-
async fetchAndHandleExternalTriggerRun(runId) {
|
|
32428
|
+
async fetchAndHandleExternalTriggerRun(runId, dispatchEventId) {
|
|
32221
32429
|
let run = null;
|
|
32222
32430
|
try {
|
|
32223
32431
|
run = await this.opts.client.getExternalTriggerRun(this.opts.config.org_id, runId);
|
|
@@ -32232,14 +32440,14 @@ var ParallAgentGateway = class {
|
|
|
32232
32440
|
}
|
|
32233
32441
|
if (!run)
|
|
32234
32442
|
return true;
|
|
32235
|
-
return this.handleExternalTriggerRun(run);
|
|
32443
|
+
return this.handleExternalTriggerRun(run, dispatchEventId);
|
|
32236
32444
|
}
|
|
32237
32445
|
// fetchAndHandleChannelMessage resolves a channel_message dispatch to its
|
|
32238
32446
|
// durable ChannelMessage + conversation and hands it to the inbound
|
|
32239
32447
|
// pipeline. targetId = the ChannelConversation id, so per-conversation
|
|
32240
32448
|
// multi-turn continuity rides the same per-target session mechanics as
|
|
32241
32449
|
// chats. Design: docs/engineering-design/external-im-channel-design.md.
|
|
32242
|
-
async fetchAndHandleChannelMessage(messageId) {
|
|
32450
|
+
async fetchAndHandleChannelMessage(messageId, dispatchEventId) {
|
|
32243
32451
|
if (this.shuttingDown)
|
|
32244
32452
|
return false;
|
|
32245
32453
|
const claimKey = `channel_message:${messageId}`;
|
|
@@ -32292,7 +32500,8 @@ var ParallAgentGateway = class {
|
|
|
32292
32500
|
channelExternalMessageId: msg.external_message_id,
|
|
32293
32501
|
channelCliCapable: cliCapable,
|
|
32294
32502
|
ackSourceType: "channel_message",
|
|
32295
|
-
ackSourceId: msg.id
|
|
32503
|
+
ackSourceId: msg.id,
|
|
32504
|
+
dispatchEventId
|
|
32296
32505
|
};
|
|
32297
32506
|
let dispatched;
|
|
32298
32507
|
try {
|
|
@@ -32306,7 +32515,7 @@ var ParallAgentGateway = class {
|
|
|
32306
32515
|
}
|
|
32307
32516
|
return dispatched;
|
|
32308
32517
|
}
|
|
32309
|
-
async handleExternalTriggerRun(run) {
|
|
32518
|
+
async handleExternalTriggerRun(run, dispatchEventId) {
|
|
32310
32519
|
if (this.shuttingDown)
|
|
32311
32520
|
return false;
|
|
32312
32521
|
const dedupeKey = `external_trigger_run:${run.id}`;
|
|
@@ -32331,7 +32540,8 @@ var ParallAgentGateway = class {
|
|
|
32331
32540
|
externalIngressEventType: run.ingress_event_type || void 0,
|
|
32332
32541
|
attachedUri,
|
|
32333
32542
|
ackSourceType: "external_trigger_run",
|
|
32334
|
-
ackSourceId: run.id
|
|
32543
|
+
ackSourceId: run.id,
|
|
32544
|
+
dispatchEventId
|
|
32335
32545
|
};
|
|
32336
32546
|
let dispatched;
|
|
32337
32547
|
try {
|
|
@@ -32345,7 +32555,7 @@ var ParallAgentGateway = class {
|
|
|
32345
32555
|
}
|
|
32346
32556
|
return dispatched;
|
|
32347
32557
|
}
|
|
32348
|
-
async fetchAndHandleApprovalDecided(approvalId, actorId, chatId) {
|
|
32558
|
+
async fetchAndHandleApprovalDecided(approvalId, actorId, chatId, dispatchEventId) {
|
|
32349
32559
|
let approval = null;
|
|
32350
32560
|
try {
|
|
32351
32561
|
approval = await this.opts.client.getApproval(approvalId);
|
|
@@ -32376,7 +32586,12 @@ var ParallAgentGateway = class {
|
|
|
32376
32586
|
senderId: actorId ?? approval.decided_by ?? "system",
|
|
32377
32587
|
senderName: "approver",
|
|
32378
32588
|
messageId: approval.id,
|
|
32379
|
-
body
|
|
32589
|
+
body,
|
|
32590
|
+
// The WorkItem's real source pair. Without it the legacy fallback
|
|
32591
|
+
// guessed ('message', approval_id) — a pair no row matches.
|
|
32592
|
+
ackSourceType: "approval",
|
|
32593
|
+
ackSourceId: approval.id,
|
|
32594
|
+
dispatchEventId
|
|
32380
32595
|
};
|
|
32381
32596
|
let dispatched;
|
|
32382
32597
|
try {
|
|
@@ -32423,7 +32638,17 @@ var ParallAgentGateway = class {
|
|
|
32423
32638
|
break;
|
|
32424
32639
|
if (overflowMode && processed >= CATCHUP_MAX) {
|
|
32425
32640
|
try {
|
|
32426
|
-
|
|
32641
|
+
if (this.laneLedger && !this.ledgerDisabled && !this.typedByIdCompleteUnsupported) {
|
|
32642
|
+
const outcome = await this.resolveDispatchByID(item.id);
|
|
32643
|
+
if (outcome === "unsupported") {
|
|
32644
|
+
this.typedByIdCompleteUnsupported = true;
|
|
32645
|
+
await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
|
|
32646
|
+
} else if (outcome === "failed") {
|
|
32647
|
+
throw new Error("by-id complete failed");
|
|
32648
|
+
}
|
|
32649
|
+
} else {
|
|
32650
|
+
await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
|
|
32651
|
+
}
|
|
32427
32652
|
skipped++;
|
|
32428
32653
|
const key = item.event_type;
|
|
32429
32654
|
skippedByType.set(key, (skippedByType.get(key) ?? 0) + 1);
|
|
@@ -32434,12 +32659,15 @@ var ParallAgentGateway = class {
|
|
|
32434
32659
|
}
|
|
32435
32660
|
processed++;
|
|
32436
32661
|
try {
|
|
32437
|
-
const
|
|
32662
|
+
const typedHooks = {
|
|
32663
|
+
legacyAck: () => this.ackDispatchEvent(item.id, () => this.clearTypedDispatchDedupe(item)),
|
|
32664
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(item)
|
|
32665
|
+
};
|
|
32438
32666
|
if (item.event_type === "task_assign" && item.task_id) {
|
|
32439
32667
|
try {
|
|
32440
32668
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? "", item.source_id ?? item.task_id ?? "", {
|
|
32441
32669
|
dispatchEventId
|
|
32442
|
-
}),
|
|
32670
|
+
}), typedHooks);
|
|
32443
32671
|
} catch (err) {
|
|
32444
32672
|
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
32445
32673
|
continue;
|
|
@@ -32449,23 +32677,23 @@ var ParallAgentGateway = class {
|
|
|
32449
32677
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? "", item.source_id ?? item.task_id ?? "", {
|
|
32450
32678
|
allowCreator: true,
|
|
32451
32679
|
dispatchEventId
|
|
32452
|
-
}),
|
|
32680
|
+
}), typedHooks);
|
|
32453
32681
|
} catch (err) {
|
|
32454
32682
|
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
32455
32683
|
continue;
|
|
32456
32684
|
}
|
|
32457
32685
|
} else if (item.event_type === "task_comment" && item.source_id && item.task_id) {
|
|
32458
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.handleTaskComment(item.source_id, item.task_id ?? "", item.actor_id, item.delivery_reason),
|
|
32686
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskComment(item.source_id, item.task_id ?? "", item.actor_id, item.delivery_reason, dispatchEventId), typedHooks);
|
|
32459
32687
|
} else if (item.event_type === "wiki_comment" && item.source_id) {
|
|
32460
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.handleWikiComment(item.source_id, item.actor_id, item.delivery_reason),
|
|
32688
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleWikiComment(item.source_id, item.actor_id, item.delivery_reason, dispatchEventId), typedHooks);
|
|
32461
32689
|
} else if (item.event_type === "schedule.fire" && item.source_id) {
|
|
32462
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleScheduleFire(item.source_id, item.actor_id),
|
|
32690
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleScheduleFire(item.source_id, item.actor_id, dispatchEventId), typedHooks);
|
|
32463
32691
|
} else if (item.event_type === "external_trigger" && item.source_id) {
|
|
32464
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleExternalTriggerRun(item.source_id),
|
|
32692
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleExternalTriggerRun(item.source_id, dispatchEventId), typedHooks);
|
|
32465
32693
|
} else if (item.event_type === "channel_message" && item.source_id) {
|
|
32466
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleChannelMessage(item.source_id),
|
|
32694
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleChannelMessage(item.source_id, dispatchEventId), typedHooks);
|
|
32467
32695
|
} else if (item.event_type === "approval_decided" && item.source_id) {
|
|
32468
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleApprovalDecided(item.source_id, item.actor_id, item.chat_id ?? null),
|
|
32696
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleApprovalDecided(item.source_id, item.actor_id, item.chat_id ?? null, dispatchEventId), typedHooks);
|
|
32469
32697
|
} else if (item.event_type === "message" && item.source_id && item.chat_id) {
|
|
32470
32698
|
await this.consumeMessageWorkItem({
|
|
32471
32699
|
id: item.id,
|
|
@@ -33163,16 +33391,32 @@ parall tasks list --assignee-id prll://usr_xxx # first page only (default 20)
|
|
|
33163
33391
|
parall tasks subtasks prll://tsk_xxx # children of a single parent task
|
|
33164
33392
|
|
|
33165
33393
|
# Create a task (add --parent-id to make it a SUBTASK of another task)
|
|
33166
|
-
parall tasks create --title "Task title" [--assignee-id prll://usr_xxx] [--parent-id prll://tsk_xxx] [--project-id prll://prj_xxx]
|
|
33394
|
+
parall tasks create --title "Task title" [--assignee-id prll://usr_xxx] [--parent-id prll://tsk_xxx] [--project-id prll://prj_xxx] [--due-date 2026-08-01]
|
|
33167
33395
|
|
|
33168
|
-
# Update task status
|
|
33169
|
-
|
|
33170
|
-
parall tasks update prll://tsk_xxx --status
|
|
33396
|
+
# Update task status \u2014 add --placement end so the task lands at the end of
|
|
33397
|
+
# its NEW status column (a bare --status keeps the old column's sort_order)
|
|
33398
|
+
parall tasks update prll://tsk_xxx --status in_progress --placement end
|
|
33399
|
+
parall tasks update prll://tsk_xxx --status done --placement end
|
|
33400
|
+
|
|
33401
|
+
# Due date \u2014 a plain YYYY-MM-DD date (no timestamps); "none" clears it
|
|
33402
|
+
parall tasks update prll://tsk_xxx --due-date 2026-08-01
|
|
33403
|
+
parall tasks update prll://tsk_xxx --due-date none
|
|
33404
|
+
|
|
33405
|
+
# Move a task to the end of its status column
|
|
33406
|
+
parall tasks update prll://tsk_xxx --placement end
|
|
33171
33407
|
|
|
33172
33408
|
# Add a comment
|
|
33173
33409
|
parall tasks comments add prll://tsk_xxx --body "Progress update..."
|
|
33174
33410
|
\`\`\`
|
|
33175
33411
|
|
|
33412
|
+
Ordering: to append a task to the end of a status column, always use
|
|
33413
|
+
\`--placement end\` \u2014 the server resolves the position atomically. This
|
|
33414
|
+
includes status changes: a bare \`--status\` keeps the task's old
|
|
33415
|
+
\`sort_order\`, which may collide inside the new column. Do NOT compute a
|
|
33416
|
+
\`sort_order\` value yourself from listed tasks (your view may be stale or
|
|
33417
|
+
partial). \`--sort-order\` is only for pinpoint insertion between two cards
|
|
33418
|
+
you just listed, and it cannot be combined with \`--placement\`.
|
|
33419
|
+
|
|
33176
33420
|
Subtasks are just tasks with a parent: create one with \`tasks create --parent-id\`,
|
|
33177
33421
|
re-parent with \`tasks update --parent-id\`, list a parent's children with
|
|
33178
33422
|
\`tasks subtasks\`. \`tasks list\` without \`--parent-id\` already returns both
|
|
@@ -33207,7 +33451,7 @@ watcher.
|
|
|
33207
33451
|
When you receive \`[Event: task.assigned]\`:
|
|
33208
33452
|
|
|
33209
33453
|
1. Acknowledge with a comment: \`tasks comments add prll://tsk_xxx --body "On it"\`
|
|
33210
|
-
2. Update status: \`tasks update prll://tsk_xxx --status in_progress\`
|
|
33454
|
+
2. Update status: \`tasks update prll://tsk_xxx --status in_progress --placement end\`
|
|
33211
33455
|
3. Do the work
|
|
33212
33456
|
4. Report results in a comment. If a gate remains \u2014 review, merge, deploy,
|
|
33213
33457
|
requester acceptance \u2014 set \`in_review\` and name the gate; set \`done\`
|
|
@@ -33453,7 +33697,7 @@ parall schedules create \\
|
|
|
33453
33697
|
--run-at <FUTURE_RFC3339_TIME>
|
|
33454
33698
|
\`\`\`
|
|
33455
33699
|
|
|
33456
|
-
\`--target-ids\` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). \`--attached-to-uri\` optionally anchors the schedule to a task / chat / project / wiki page \u2014 when that resource is archived or deleted, the schedule auto-cancels (\`
|
|
33700
|
+
\`--target-ids\` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). \`--attached-to-uri\` optionally anchors the schedule to a task / chat / project / wiki page \u2014 when that resource is archived or deleted, the schedule auto-cancels (\`status_reason=attached_gone\`). A schedule whose agent targets all sit on a terminated machine is auto-paused by the platform (\`status_reason=attendee_unreachable\`) instead of firing into a void; resuming a recurring schedule while the machine is still terminated just pauses it again on the next slot (a one-shot resumed past its catch-up window instead follows the normal missed semantics and completes).
|
|
33457
33701
|
|
|
33458
33702
|
### Reminders for someone else
|
|
33459
33703
|
|