@telora/daemon 0.17.59 → 0.17.70
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/build-info.json +19 -3
- package/dist/cascade-restatement.d.ts +10 -0
- package/dist/cascade-restatement.d.ts.map +1 -1
- package/dist/cascade-restatement.js +107 -37
- package/dist/cascade-restatement.js.map +1 -1
- package/dist/ci-escalation.d.ts.map +1 -1
- package/dist/ci-escalation.js +5 -3
- package/dist/ci-escalation.js.map +1 -1
- package/dist/cli/backfill-frt-prose.d.ts +101 -0
- package/dist/cli/backfill-frt-prose.d.ts.map +1 -0
- package/dist/cli/backfill-frt-prose.js +195 -0
- package/dist/cli/backfill-frt-prose.js.map +1 -0
- package/dist/completion/event-escalations.d.ts +4 -11
- package/dist/completion/event-escalations.d.ts.map +1 -1
- package/dist/completion/event-escalations.js +21 -5
- package/dist/completion/event-escalations.js.map +1 -1
- package/dist/completion/event.d.ts +4 -11
- package/dist/completion/event.d.ts.map +1 -1
- package/dist/completion/event.js.map +1 -1
- package/dist/completion/review-exit-phase.d.ts.map +1 -1
- package/dist/completion/review-exit-phase.js +37 -7
- package/dist/completion/review-exit-phase.js.map +1 -1
- package/dist/completion/status-advance-phase.d.ts.map +1 -1
- package/dist/completion/status-advance-phase.js +46 -13
- package/dist/completion/status-advance-phase.js.map +1 -1
- package/dist/crash-recovery-cleanup.d.ts.map +1 -1
- package/dist/crash-recovery-cleanup.js +7 -1
- package/dist/crash-recovery-cleanup.js.map +1 -1
- package/dist/crash-recovery-types.d.ts +4 -9
- package/dist/crash-recovery-types.d.ts.map +1 -1
- package/dist/crash-recovery-types.js.map +1 -1
- package/dist/crash-recovery.d.ts +4 -9
- package/dist/crash-recovery.d.ts.map +1 -1
- package/dist/crash-recovery.js +5 -1
- package/dist/crash-recovery.js.map +1 -1
- package/dist/delivery-advance-block.d.ts +8 -6
- package/dist/delivery-advance-block.d.ts.map +1 -1
- package/dist/delivery-advance-block.js +14 -12
- package/dist/delivery-advance-block.js.map +1 -1
- package/dist/delivery-guards.d.ts.map +1 -1
- package/dist/delivery-guards.js +4 -1
- package/dist/delivery-guards.js.map +1 -1
- package/dist/delivery-lifecycle.d.ts.map +1 -1
- package/dist/delivery-lifecycle.js +47 -1
- package/dist/delivery-lifecycle.js.map +1 -1
- package/dist/delivery-merge.d.ts.map +1 -1
- package/dist/delivery-merge.js +5 -1
- package/dist/delivery-merge.js.map +1 -1
- package/dist/delivery-reconciler-apply.d.ts +85 -0
- package/dist/delivery-reconciler-apply.d.ts.map +1 -0
- package/dist/delivery-reconciler-apply.js +80 -0
- package/dist/delivery-reconciler-apply.js.map +1 -0
- package/dist/delivery-reconciler-shadow.d.ts +65 -0
- package/dist/delivery-reconciler-shadow.d.ts.map +1 -0
- package/dist/delivery-reconciler-shadow.js +127 -0
- package/dist/delivery-reconciler-shadow.js.map +1 -0
- package/dist/delivery-reconciler.d.ts +133 -0
- package/dist/delivery-reconciler.d.ts.map +1 -0
- package/dist/delivery-reconciler.js +160 -0
- package/dist/delivery-reconciler.js.map +1 -0
- package/dist/directive/directive-dispatch.d.ts.map +1 -1
- package/dist/directive/directive-dispatch.js +4 -1
- package/dist/directive/directive-dispatch.js.map +1 -1
- package/dist/escalation-provenance.d.ts +60 -0
- package/dist/escalation-provenance.d.ts.map +1 -0
- package/dist/escalation-provenance.js +153 -0
- package/dist/escalation-provenance.js.map +1 -0
- package/dist/escalations.d.ts +33 -3
- package/dist/escalations.d.ts.map +1 -1
- package/dist/escalations.js +58 -12
- package/dist/escalations.js.map +1 -1
- package/dist/focus-executor.js +1 -1
- package/dist/focus-executor.js.map +1 -1
- package/dist/focus-merge.d.ts.map +1 -1
- package/dist/focus-merge.js +3 -1
- package/dist/focus-merge.js.map +1 -1
- package/dist/focus-stage-lifecycle.d.ts.map +1 -1
- package/dist/focus-stage-lifecycle.js +5 -2
- package/dist/focus-stage-lifecycle.js.map +1 -1
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/dist/listener-auto-advance.d.ts.map +1 -1
- package/dist/listener-auto-advance.js +73 -34
- package/dist/listener-auto-advance.js.map +1 -1
- package/dist/listener.d.ts.map +1 -1
- package/dist/listener.js +12 -0
- package/dist/listener.js.map +1 -1
- package/dist/merge-back-loop.d.ts.map +1 -1
- package/dist/merge-back-loop.js +7 -2
- package/dist/merge-back-loop.js.map +1 -1
- package/dist/nexus-escalation-bridge.d.ts +92 -0
- package/dist/nexus-escalation-bridge.d.ts.map +1 -0
- package/dist/nexus-escalation-bridge.js +109 -0
- package/dist/nexus-escalation-bridge.js.map +1 -0
- package/dist/nexus-incoming.d.ts +47 -0
- package/dist/nexus-incoming.d.ts.map +1 -0
- package/dist/nexus-incoming.js +93 -0
- package/dist/nexus-incoming.js.map +1 -0
- package/dist/nexus-return.d.ts +131 -0
- package/dist/nexus-return.d.ts.map +1 -0
- package/dist/nexus-return.js +326 -0
- package/dist/nexus-return.js.map +1 -0
- package/dist/queries/deliveries.d.ts +12 -0
- package/dist/queries/deliveries.d.ts.map +1 -1
- package/dist/queries/deliveries.js +17 -0
- package/dist/queries/deliveries.js.map +1 -1
- package/dist/queries/issues.d.ts +62 -12
- package/dist/queries/issues.d.ts.map +1 -1
- package/dist/queries/issues.js +46 -13
- package/dist/queries/issues.js.map +1 -1
- package/dist/resolvers/escalation-answers.d.ts +22 -0
- package/dist/resolvers/escalation-answers.d.ts.map +1 -0
- package/dist/resolvers/escalation-answers.js +98 -0
- package/dist/resolvers/escalation-answers.js.map +1 -0
- package/dist/resolvers/index.d.ts.map +1 -1
- package/dist/resolvers/index.js +2 -0
- package/dist/resolvers/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus incoming-request poll: the receiving side of the cross-product request
|
|
3
|
+
* channel.
|
|
4
|
+
*
|
|
5
|
+
* Each poll cycle, for every configured product, the daemon looks for OPEN
|
|
6
|
+
* incoming requests (product_requests where target_product_id = this product)
|
|
7
|
+
* and applies the product's accept gate:
|
|
8
|
+
*
|
|
9
|
+
* - auto_with_decline (default): auto-accept + materialize the request as a
|
|
10
|
+
* scoped delivery in a per-product "Nexus Inbox" focus, where the target's
|
|
11
|
+
* AI team picks it up via the normal focus spawn path. (The target can still
|
|
12
|
+
* decline/clarify after the fact via MCP -- "accept with decline".)
|
|
13
|
+
* - human_required: leave the request OPEN; a human accepts it via MCP.
|
|
14
|
+
*
|
|
15
|
+
* The decision is a pure function (decideIncoming) so the gate is unit-tested
|
|
16
|
+
* without any I/O; the side effects (list/accept/materialize/policy read) are
|
|
17
|
+
* injected as deps so the poll wiring is testable with mocks.
|
|
18
|
+
*/
|
|
19
|
+
import { callApi } from './queries/shared.js';
|
|
20
|
+
/**
|
|
21
|
+
* Pure accept gate. human_required holds the request for a human; everything
|
|
22
|
+
* else (the default auto_with_decline) auto-accepts.
|
|
23
|
+
*/
|
|
24
|
+
export function decideIncoming(policy) {
|
|
25
|
+
return policy === 'human_required' ? 'await_human' : 'auto_accept';
|
|
26
|
+
}
|
|
27
|
+
/** Production deps backed by the product-api over callApi. */
|
|
28
|
+
export function defaultNexusIncomingDeps() {
|
|
29
|
+
return {
|
|
30
|
+
listIncomingOpen: async (productId) => {
|
|
31
|
+
const res = await callApi('product_request_list', {
|
|
32
|
+
productId,
|
|
33
|
+
direction: 'incoming',
|
|
34
|
+
status: 'open',
|
|
35
|
+
});
|
|
36
|
+
return res.requests ?? [];
|
|
37
|
+
},
|
|
38
|
+
getAcceptPolicy: async (productId) => {
|
|
39
|
+
const res = await callApi('get', { productId });
|
|
40
|
+
return res.product?.nexusAcceptPolicy === 'human_required' ? 'human_required' : 'auto_with_decline';
|
|
41
|
+
},
|
|
42
|
+
acceptRequest: async (requestId) => {
|
|
43
|
+
await callApi('product_request_accept', { requestId });
|
|
44
|
+
},
|
|
45
|
+
materializeRequest: async (requestId) => {
|
|
46
|
+
await callApi('product_request_materialize', { requestId });
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Poll one product for incoming open requests and apply its accept gate.
|
|
52
|
+
* Safe to call every poll cycle: it is a no-op when there is no incoming work,
|
|
53
|
+
* and individual request failures are logged without aborting the batch.
|
|
54
|
+
*/
|
|
55
|
+
export async function checkIncomingRequests(config, deps = defaultNexusIncomingDeps()) {
|
|
56
|
+
const productId = config.productId;
|
|
57
|
+
if (!productId)
|
|
58
|
+
return;
|
|
59
|
+
const log = deps.log ?? ((msg) => console.log(msg));
|
|
60
|
+
let requests;
|
|
61
|
+
try {
|
|
62
|
+
requests = await deps.listIncomingOpen(productId);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
log(`[nexus] failed to list incoming requests for ${productId}: ${err.message}`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (requests.length === 0)
|
|
69
|
+
return;
|
|
70
|
+
let policy;
|
|
71
|
+
try {
|
|
72
|
+
policy = await deps.getAcceptPolicy(productId);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
log(`[nexus] failed to read accept policy for ${productId}: ${err.message}`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (decideIncoming(policy) === 'await_human') {
|
|
79
|
+
log(`[nexus] ${requests.length} incoming request(s) for ${productId} await human approval (policy=human_required)`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
for (const req of requests) {
|
|
83
|
+
try {
|
|
84
|
+
await deps.acceptRequest(req.id);
|
|
85
|
+
await deps.materializeRequest(req.id);
|
|
86
|
+
log(`[nexus] auto-accepted + materialized request ${req.id} for product ${productId}`);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
log(`[nexus] failed to accept/materialize request ${req.id}: ${err.message}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=nexus-incoming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nexus-incoming.js","sourceRoot":"","sources":["../src/nexus-incoming.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus return-path poll: loop closure to the source.
|
|
3
|
+
*
|
|
4
|
+
* This closes the cross-product request differential. Two sides run each poll
|
|
5
|
+
* cycle, both safe to call every tick (no-op when there is no work):
|
|
6
|
+
*
|
|
7
|
+
* TARGET side -- for every incoming request still in_progress with a
|
|
8
|
+
* materialized delivery, ask the server to resolve it. The server gate
|
|
9
|
+
* (product_request_resolve) advances the request to 'closed' ONLY when the
|
|
10
|
+
* materialized delivery's execution_status is 'done' (it passed the verify
|
|
11
|
+
* gate); any other delivery state is a no-op. So merely calling resolve
|
|
12
|
+
* every tick converges the request the moment B's work lands.
|
|
13
|
+
*
|
|
14
|
+
* SOURCE side -- for every outgoing request in a terminal state
|
|
15
|
+
* ('closed' = completed, 'declined' = rejected) that has not yet notified
|
|
16
|
+
* its source (source_notified_at is null), file an escalation on the
|
|
17
|
+
* source's blocked focus so the human/agent there learns the cross-product
|
|
18
|
+
* dependency resolved, then stamp source_notified_at so it is not
|
|
19
|
+
* re-notified. This is the half that unblocks A without a human chasing it.
|
|
20
|
+
*
|
|
21
|
+
* shouldResolve is a pure predicate so the gate is unit-testable with no I/O;
|
|
22
|
+
* the side effects (list/resolve/notify/stamp) are injected as deps so the poll
|
|
23
|
+
* wiring is testable with mocks. Mirrors nexus-incoming.ts.
|
|
24
|
+
*/
|
|
25
|
+
import type { DaemonConfig } from './types.js';
|
|
26
|
+
import { type DeliveryGateState } from './queries/deliveries.js';
|
|
27
|
+
/**
|
|
28
|
+
* Minimal shape of a product_request list row (camelCase from the edge fn).
|
|
29
|
+
* All fields optional + defensive: the daemon must not assume any are present.
|
|
30
|
+
*/
|
|
31
|
+
export interface Req {
|
|
32
|
+
id: string;
|
|
33
|
+
status?: string;
|
|
34
|
+
materializedDeliveryId?: string | null;
|
|
35
|
+
sourceFocusId?: string | null;
|
|
36
|
+
sourceProductId?: string | null;
|
|
37
|
+
sourceDeliveryId?: string | null;
|
|
38
|
+
targetProductId?: string | null;
|
|
39
|
+
title?: string | null;
|
|
40
|
+
declineReason?: string | null;
|
|
41
|
+
clarificationMessage?: string | null;
|
|
42
|
+
clarificationNotifiedAt?: string | null;
|
|
43
|
+
sourceNotifiedAt?: string | null;
|
|
44
|
+
/** Contract-fulfillment results carried back by the target's deliver step. */
|
|
45
|
+
findings?: string | null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* gate_state written onto a source delivery the Nexus gate pauses. It carries
|
|
49
|
+
* the dashboard "Waiting on" blocker (rendered from `blocking[].guardName`) plus
|
|
50
|
+
* a `nexusBlock` provenance marker so the release half can prove THIS gate paused
|
|
51
|
+
* the delivery and never clobber a delivery a human paused for another reason.
|
|
52
|
+
*/
|
|
53
|
+
export interface NexusGateState extends DeliveryGateState {
|
|
54
|
+
nexusBlock: {
|
|
55
|
+
requestIds: string[];
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Current execution state of one source-product delivery (status + gate_state). */
|
|
59
|
+
export interface SourceDeliveryState {
|
|
60
|
+
id: string;
|
|
61
|
+
executionStatus?: string;
|
|
62
|
+
gateState?: unknown;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Pure resolution gate. The loop closes only once the materialized delivery has
|
|
66
|
+
* passed the verify gate to 'done'. (The authoritative check is server-side in
|
|
67
|
+
* product_request_resolve; this mirror keeps the gate explicit + unit-tested.)
|
|
68
|
+
*/
|
|
69
|
+
export declare function shouldResolve(deliveryStatus: string | undefined): boolean;
|
|
70
|
+
export interface NexusReturnDeps {
|
|
71
|
+
/** Incoming requests still in_progress, filtered to those with a materialized delivery. */
|
|
72
|
+
listIncomingInProgress: (productId: string) => Promise<Req[]>;
|
|
73
|
+
/** Read a delivery's execution_status (org_nodes). Kept for completeness/testing. */
|
|
74
|
+
getDeliveryStatus: (deliveryId: string) => Promise<string | undefined>;
|
|
75
|
+
/** Ask the server to resolve a request; returns true when it closed the loop. */
|
|
76
|
+
resolveRequest: (requestId: string) => Promise<boolean>;
|
|
77
|
+
/** Outgoing requests for the source product (any status). */
|
|
78
|
+
listOutgoing: (productId: string) => Promise<Req[]>;
|
|
79
|
+
/** Notify the source side (escalation on the blocked focus) about a terminal state. */
|
|
80
|
+
notifySource: (req: Req) => Promise<void>;
|
|
81
|
+
/** Stamp source_notified_at so the request is not re-notified. */
|
|
82
|
+
markSourceNotified: (requestId: string) => Promise<void>;
|
|
83
|
+
/** Notify the source side that the target requested clarification. */
|
|
84
|
+
notifyClarification: (req: Req) => Promise<void>;
|
|
85
|
+
/** Stamp clarification_notified_at so the same clarification is not re-notified. */
|
|
86
|
+
markClarificationNotified: (requestId: string) => Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Current execution_status + gate_state for every delivery in the source
|
|
89
|
+
* product (one read per poll). The source-gate reconciler keys off these.
|
|
90
|
+
*/
|
|
91
|
+
listSourceDeliveryStates: (productId: string) => Promise<SourceDeliveryState[]>;
|
|
92
|
+
/** Daemon-owned transition: pause a source delivery and write the Nexus gate_state. */
|
|
93
|
+
pauseSourceDelivery: (deliveryId: string, gateState: NexusGateState, fromStatus?: string) => Promise<void>;
|
|
94
|
+
/** Daemon-owned transition: re-queue a paused source delivery and clear gate_state. */
|
|
95
|
+
requeueSourceDelivery: (deliveryId: string, fromStatus?: string) => Promise<void>;
|
|
96
|
+
/** Resolve a product's display name for the "Waiting on" label (best-effort). */
|
|
97
|
+
getProductName: (productId: string) => Promise<string | undefined>;
|
|
98
|
+
log?: (msg: string) => void;
|
|
99
|
+
}
|
|
100
|
+
/** Production deps backed by the product-api over callApi + createEscalation. */
|
|
101
|
+
export declare function defaultNexusReturnDeps(config: DaemonConfig): NexusReturnDeps;
|
|
102
|
+
/**
|
|
103
|
+
* Poll one product for return-path loop closure. Runs both sides:
|
|
104
|
+
* TARGET -- resolve materialized in_progress incoming requests (server gates
|
|
105
|
+
* on delivery 'done').
|
|
106
|
+
* SOURCE -- notify + stamp terminal outgoing requests not yet notified.
|
|
107
|
+
* Each request's work is wrapped in try/catch so one failure does not abort the
|
|
108
|
+
* batch (mirrors nexus-incoming).
|
|
109
|
+
*/
|
|
110
|
+
export declare function checkResolvedRequests(config: DaemonConfig, deps?: NexusReturnDeps): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Block + auto-resume the source deliveries gated by outgoing Nexus requests.
|
|
113
|
+
*
|
|
114
|
+
* Per source delivery (grouped from `outgoing` by sourceDeliveryId):
|
|
115
|
+
* BLOCK -- a currently-`queued` (actionable) delivery with >=1 non-terminal
|
|
116
|
+
* outgoing request is paused, with gate_state carrying the
|
|
117
|
+
* "Waiting on <target product>" blocker + a nexusBlock provenance
|
|
118
|
+
* marker. `paused` is non-actionable + blocking in the spawn walk,
|
|
119
|
+
* so an armed focus stops spawning a team that cannot do the work.
|
|
120
|
+
* RELEASE -- a `paused` delivery THIS gate paused (nexusBlock provenance) is
|
|
121
|
+
* re-queued (and gate_state cleared) once ALL its outgoing requests
|
|
122
|
+
* are terminal AND none ended `declined` (every one `closed`). A
|
|
123
|
+
* declined request leaves it paused for a human to decide (the
|
|
124
|
+
* decline -> NEEDS_INTENT notify already fired above).
|
|
125
|
+
*
|
|
126
|
+
* Idempotent: only a `queued` delivery is paused, only a nexus-paused delivery
|
|
127
|
+
* is resumed; re-running with the same inputs is a no-op. Never clobbers a
|
|
128
|
+
* delivery a human paused (no nexusBlock marker) or one with no open request.
|
|
129
|
+
*/
|
|
130
|
+
export declare function reconcileSourceDeliveryGates(outgoing: Req[], deps: NexusReturnDeps, log: (msg: string) => void): Promise<void>;
|
|
131
|
+
//# sourceMappingURL=nexus-return.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nexus-return.d.ts","sourceRoot":"","sources":["../src/nexus-return.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus return-path poll: loop closure to the source.
|
|
3
|
+
*
|
|
4
|
+
* This closes the cross-product request differential. Two sides run each poll
|
|
5
|
+
* cycle, both safe to call every tick (no-op when there is no work):
|
|
6
|
+
*
|
|
7
|
+
* TARGET side -- for every incoming request still in_progress with a
|
|
8
|
+
* materialized delivery, ask the server to resolve it. The server gate
|
|
9
|
+
* (product_request_resolve) advances the request to 'closed' ONLY when the
|
|
10
|
+
* materialized delivery's execution_status is 'done' (it passed the verify
|
|
11
|
+
* gate); any other delivery state is a no-op. So merely calling resolve
|
|
12
|
+
* every tick converges the request the moment B's work lands.
|
|
13
|
+
*
|
|
14
|
+
* SOURCE side -- for every outgoing request in a terminal state
|
|
15
|
+
* ('closed' = completed, 'declined' = rejected) that has not yet notified
|
|
16
|
+
* its source (source_notified_at is null), file an escalation on the
|
|
17
|
+
* source's blocked focus so the human/agent there learns the cross-product
|
|
18
|
+
* dependency resolved, then stamp source_notified_at so it is not
|
|
19
|
+
* re-notified. This is the half that unblocks A without a human chasing it.
|
|
20
|
+
*
|
|
21
|
+
* shouldResolve is a pure predicate so the gate is unit-testable with no I/O;
|
|
22
|
+
* the side effects (list/resolve/notify/stamp) are injected as deps so the poll
|
|
23
|
+
* wiring is testable with mocks. Mirrors nexus-incoming.ts.
|
|
24
|
+
*/
|
|
25
|
+
import { callApi } from './queries/shared.js';
|
|
26
|
+
import { createEscalation } from './queries/issues.js';
|
|
27
|
+
import { updateDeliveryStatus } from './queries/deliveries.js';
|
|
28
|
+
import { ESCALATION_REASONS, ESCALATION_DISPOSITIONS, ESCALATION_KINDS, DELIVERY_STATUS } from '@telora/daemon-core';
|
|
29
|
+
/**
|
|
30
|
+
* Statuses in which an outgoing request still gates its source delivery -- the
|
|
31
|
+
* cross-product dependency is not yet settled, so the source must wait.
|
|
32
|
+
*/
|
|
33
|
+
const NON_TERMINAL_REQUEST_STATUSES = new Set(['open', 'accepted', 'in_progress', 'delivered']);
|
|
34
|
+
/** Type guard: was this delivery's pause written by the Nexus gate (has provenance)? */
|
|
35
|
+
function isNexusGateState(gateState) {
|
|
36
|
+
return (!!gateState &&
|
|
37
|
+
typeof gateState === 'object' &&
|
|
38
|
+
Array.isArray(gateState.nexusBlock?.requestIds));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Pure resolution gate. The loop closes only once the materialized delivery has
|
|
42
|
+
* passed the verify gate to 'done'. (The authoritative check is server-side in
|
|
43
|
+
* product_request_resolve; this mirror keeps the gate explicit + unit-tested.)
|
|
44
|
+
*/
|
|
45
|
+
export function shouldResolve(deliveryStatus) {
|
|
46
|
+
return deliveryStatus === 'done';
|
|
47
|
+
}
|
|
48
|
+
/** Terminal statuses on the source side that warrant a notification. */
|
|
49
|
+
const TERMINAL_SOURCE_STATUSES = new Set(['closed', 'declined']);
|
|
50
|
+
/** Production deps backed by the product-api over callApi + createEscalation. */
|
|
51
|
+
export function defaultNexusReturnDeps(config) {
|
|
52
|
+
return {
|
|
53
|
+
listIncomingInProgress: async (productId) => {
|
|
54
|
+
const res = await callApi('product_request_list', {
|
|
55
|
+
productId,
|
|
56
|
+
direction: 'incoming',
|
|
57
|
+
status: 'in_progress',
|
|
58
|
+
});
|
|
59
|
+
return (res.requests ?? []).filter((r) => !!r.materializedDeliveryId);
|
|
60
|
+
},
|
|
61
|
+
getDeliveryStatus: async (deliveryId) => {
|
|
62
|
+
// The server-side gate already reads delivery status during resolve, so
|
|
63
|
+
// this default is a thin convenience: delivery_list returns org_nodes.
|
|
64
|
+
const res = await callApi('delivery_list', { deliveryId });
|
|
65
|
+
const match = (res.deliveries ?? []).find((d) => d.id === deliveryId);
|
|
66
|
+
return match?.executionStatus;
|
|
67
|
+
},
|
|
68
|
+
resolveRequest: async (requestId) => {
|
|
69
|
+
const res = await callApi('product_request_resolve', { requestId });
|
|
70
|
+
return res.resolved === true;
|
|
71
|
+
},
|
|
72
|
+
listOutgoing: async (productId) => {
|
|
73
|
+
const res = await callApi('product_request_list', {
|
|
74
|
+
productId,
|
|
75
|
+
direction: 'outgoing',
|
|
76
|
+
});
|
|
77
|
+
return res.requests ?? [];
|
|
78
|
+
},
|
|
79
|
+
notifySource: async (req) => {
|
|
80
|
+
const declined = req.status === 'declined';
|
|
81
|
+
const reasonPhrase = declined
|
|
82
|
+
? `declined by the target product${req.declineReason ? `: ${req.declineReason}` : ''}`
|
|
83
|
+
: 'completed by the target product';
|
|
84
|
+
// Use BLOCKED_BY_EXTERNAL for declines (the source is still blocked and needs
|
|
85
|
+
// to decide next steps). Use DECISION_NEEDED for resolved (closed) requests:
|
|
86
|
+
// the dependency cleared and the source team can now unblock their work.
|
|
87
|
+
const reasonType = declined
|
|
88
|
+
? ESCALATION_REASONS.BLOCKED_BY_EXTERNAL
|
|
89
|
+
: ESCALATION_REASONS.DECISION_NEEDED;
|
|
90
|
+
const descriptionPrefix = declined
|
|
91
|
+
? '[Nexus dependency declined]'
|
|
92
|
+
: '[Nexus dependency resolved]';
|
|
93
|
+
await createEscalation({
|
|
94
|
+
organizationId: config.organizationId,
|
|
95
|
+
issueId: null,
|
|
96
|
+
reasonType,
|
|
97
|
+
// Disposition routes resolution: a resolved (closed) dependency clears the
|
|
98
|
+
// blocker so an agent on the source focus can act on it automatically; a
|
|
99
|
+
// decline leaves the source still blocked and needing a human to decide
|
|
100
|
+
// next steps.
|
|
101
|
+
disposition: declined
|
|
102
|
+
? ESCALATION_DISPOSITIONS.NEEDS_INTENT
|
|
103
|
+
: ESCALATION_DISPOSITIONS.AGENT_RESOLVABLE,
|
|
104
|
+
escalationKind: ESCALATION_KINDS.NEXUS_REQUEST_RESOLVED,
|
|
105
|
+
// Provenance: the source focus is the anchor; resolver derives productId.
|
|
106
|
+
anchor: { focusId: req.sourceFocusId ?? undefined },
|
|
107
|
+
...(req.sourceProductId ? { productId: req.sourceProductId } : {}),
|
|
108
|
+
description: `${descriptionPrefix} Nexus request "${req.title ?? '(untitled)'}" was ${reasonPhrase}. ` +
|
|
109
|
+
`${declined ? 'Review the decline reason and decide on next steps.' : 'The cross-product dependency is now clear -- you can unblock your work.'}` +
|
|
110
|
+
// Carry the target's delivered findings back so the source acts on the
|
|
111
|
+
// actual results, not just the fact of closure (honest-closure path).
|
|
112
|
+
(!declined && req.findings ? `\n\nDelivered findings: ${req.findings}` : ''),
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
markSourceNotified: async (requestId) => {
|
|
116
|
+
await callApi('product_request_mark_source_notified', { requestId });
|
|
117
|
+
},
|
|
118
|
+
notifyClarification: async (req) => {
|
|
119
|
+
await createEscalation({
|
|
120
|
+
organizationId: config.organizationId,
|
|
121
|
+
issueId: null,
|
|
122
|
+
reasonType: ESCALATION_REASONS.NEEDS_CLARIFICATION,
|
|
123
|
+
// A human on the source side must provide the clarification response.
|
|
124
|
+
disposition: ESCALATION_DISPOSITIONS.NEEDS_INTENT,
|
|
125
|
+
escalationKind: ESCALATION_KINDS.NEXUS_CLARIFICATION_REQUESTED,
|
|
126
|
+
// Provenance: the source focus is the anchor; resolver derives productId.
|
|
127
|
+
anchor: { focusId: req.sourceFocusId ?? undefined },
|
|
128
|
+
...(req.sourceProductId ? { productId: req.sourceProductId } : {}),
|
|
129
|
+
description: `[Nexus clarification requested] Nexus request "${req.title ?? '(untitled)'}" has a question from the target product: ` +
|
|
130
|
+
`${req.clarificationMessage ?? '(no message)'} -- reply or update the request to unblock the cross-product work.`,
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
markClarificationNotified: async (requestId) => {
|
|
134
|
+
await callApi('product_request_mark_clarification_notified', { requestId });
|
|
135
|
+
},
|
|
136
|
+
listSourceDeliveryStates: async (productId) => {
|
|
137
|
+
// detail:'full' so gate_state comes back (summary omits it). Outgoing
|
|
138
|
+
// requests originate in THIS product, so a single product-scoped list
|
|
139
|
+
// covers every source delivery the gate might touch.
|
|
140
|
+
const res = await callApi('delivery_list', { productId, detail: 'full', limit: 500 });
|
|
141
|
+
return (res.deliveries ?? []).map((d) => ({
|
|
142
|
+
id: d.id,
|
|
143
|
+
executionStatus: d.executionStatus,
|
|
144
|
+
gateState: d.gateState,
|
|
145
|
+
}));
|
|
146
|
+
},
|
|
147
|
+
pauseSourceDelivery: async (deliveryId, gateState, fromStatus) => {
|
|
148
|
+
await updateDeliveryStatus(deliveryId, DELIVERY_STATUS.PAUSED, undefined, gateState, undefined, { organizationId: config.organizationId, fromStatus });
|
|
149
|
+
},
|
|
150
|
+
requeueSourceDelivery: async (deliveryId, fromStatus) => {
|
|
151
|
+
// null clears the stale Nexus gate_state as the delivery resumes.
|
|
152
|
+
await updateDeliveryStatus(deliveryId, DELIVERY_STATUS.QUEUED, undefined, null, undefined, { organizationId: config.organizationId, fromStatus });
|
|
153
|
+
},
|
|
154
|
+
getProductName: async (productId) => {
|
|
155
|
+
try {
|
|
156
|
+
const res = await callApi('get', { productId });
|
|
157
|
+
return res.product?.name ?? undefined;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Poll one product for return-path loop closure. Runs both sides:
|
|
167
|
+
* TARGET -- resolve materialized in_progress incoming requests (server gates
|
|
168
|
+
* on delivery 'done').
|
|
169
|
+
* SOURCE -- notify + stamp terminal outgoing requests not yet notified.
|
|
170
|
+
* Each request's work is wrapped in try/catch so one failure does not abort the
|
|
171
|
+
* batch (mirrors nexus-incoming).
|
|
172
|
+
*/
|
|
173
|
+
export async function checkResolvedRequests(config, deps = defaultNexusReturnDeps(config)) {
|
|
174
|
+
const productId = config.productId;
|
|
175
|
+
if (!productId)
|
|
176
|
+
return;
|
|
177
|
+
const log = deps.log ?? ((msg) => console.log(msg));
|
|
178
|
+
// --- TARGET side: resolve materialized in_progress incoming requests. ---
|
|
179
|
+
let incoming = [];
|
|
180
|
+
try {
|
|
181
|
+
incoming = await deps.listIncomingInProgress(productId);
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
log(`[nexus] failed to list in_progress incoming requests for ${productId}: ${err.message}`);
|
|
185
|
+
}
|
|
186
|
+
for (const req of incoming) {
|
|
187
|
+
try {
|
|
188
|
+
const resolved = await deps.resolveRequest(req.id);
|
|
189
|
+
if (resolved) {
|
|
190
|
+
log(`[nexus] resolved incoming request ${req.id} (materialized delivery done) for ${productId}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
log(`[nexus] failed to resolve incoming request ${req.id}: ${err.message}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// --- SOURCE side: notify + stamp terminal outgoing requests. ---
|
|
198
|
+
let outgoing = [];
|
|
199
|
+
try {
|
|
200
|
+
outgoing = await deps.listOutgoing(productId);
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
log(`[nexus] failed to list outgoing requests for ${productId}: ${err.message}`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const pending = outgoing.filter((r) => r.status !== undefined && TERMINAL_SOURCE_STATUSES.has(r.status) && !r.sourceNotifiedAt);
|
|
207
|
+
for (const req of pending) {
|
|
208
|
+
try {
|
|
209
|
+
await deps.notifySource(req);
|
|
210
|
+
await deps.markSourceNotified(req.id);
|
|
211
|
+
log(`[nexus] notified source of resolved request ${req.id} (status=${req.status}) for ${productId}`);
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
log(`[nexus] failed to notify source for request ${req.id}: ${err.message}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// --- SOURCE side: notify about pending clarifications. ---
|
|
218
|
+
// Exclude terminal requests (closed/declined): the edge handler rejects clarify on
|
|
219
|
+
// terminal requests, but guard here too so any pre-existing stale rows don't fire.
|
|
220
|
+
const pendingClarification = outgoing.filter((r) => !!r.clarificationMessage &&
|
|
221
|
+
!r.clarificationNotifiedAt &&
|
|
222
|
+
r.status !== 'closed' &&
|
|
223
|
+
r.status !== 'declined');
|
|
224
|
+
for (const req of pendingClarification) {
|
|
225
|
+
try {
|
|
226
|
+
await deps.notifyClarification(req);
|
|
227
|
+
await deps.markClarificationNotified(req.id);
|
|
228
|
+
log(`[nexus] notified source of clarification request ${req.id} for ${productId}`);
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
log(`[nexus] failed to notify source about clarification for request ${req.id}: ${err.message}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// --- SOURCE side: dependency-aware delivery gate (block + auto-resume). ---
|
|
235
|
+
// Turn the cross-product dependency into an actuator on the source delivery's
|
|
236
|
+
// execution_status so an armed focus blocks instead of churning, and resumes
|
|
237
|
+
// itself the moment the dependency clears. Daemon-owned transitions only.
|
|
238
|
+
await reconcileSourceDeliveryGates(outgoing, deps, log);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Block + auto-resume the source deliveries gated by outgoing Nexus requests.
|
|
242
|
+
*
|
|
243
|
+
* Per source delivery (grouped from `outgoing` by sourceDeliveryId):
|
|
244
|
+
* BLOCK -- a currently-`queued` (actionable) delivery with >=1 non-terminal
|
|
245
|
+
* outgoing request is paused, with gate_state carrying the
|
|
246
|
+
* "Waiting on <target product>" blocker + a nexusBlock provenance
|
|
247
|
+
* marker. `paused` is non-actionable + blocking in the spawn walk,
|
|
248
|
+
* so an armed focus stops spawning a team that cannot do the work.
|
|
249
|
+
* RELEASE -- a `paused` delivery THIS gate paused (nexusBlock provenance) is
|
|
250
|
+
* re-queued (and gate_state cleared) once ALL its outgoing requests
|
|
251
|
+
* are terminal AND none ended `declined` (every one `closed`). A
|
|
252
|
+
* declined request leaves it paused for a human to decide (the
|
|
253
|
+
* decline -> NEEDS_INTENT notify already fired above).
|
|
254
|
+
*
|
|
255
|
+
* Idempotent: only a `queued` delivery is paused, only a nexus-paused delivery
|
|
256
|
+
* is resumed; re-running with the same inputs is a no-op. Never clobbers a
|
|
257
|
+
* delivery a human paused (no nexusBlock marker) or one with no open request.
|
|
258
|
+
*/
|
|
259
|
+
export async function reconcileSourceDeliveryGates(outgoing, deps, log) {
|
|
260
|
+
// Group outgoing requests by the source delivery they gate.
|
|
261
|
+
const byDelivery = new Map();
|
|
262
|
+
for (const req of outgoing) {
|
|
263
|
+
const deliveryId = req.sourceDeliveryId;
|
|
264
|
+
if (!deliveryId)
|
|
265
|
+
continue;
|
|
266
|
+
const list = byDelivery.get(deliveryId);
|
|
267
|
+
if (list)
|
|
268
|
+
list.push(req);
|
|
269
|
+
else
|
|
270
|
+
byDelivery.set(deliveryId, [req]);
|
|
271
|
+
}
|
|
272
|
+
if (byDelivery.size === 0)
|
|
273
|
+
return;
|
|
274
|
+
// One read of the source product's delivery states (status + gate_state).
|
|
275
|
+
let stateById = new Map();
|
|
276
|
+
try {
|
|
277
|
+
const states = await deps.listSourceDeliveryStates(
|
|
278
|
+
// sourceProductId is uniform across this product's outgoing requests, but
|
|
279
|
+
// fall back to scanning for any present value defensively.
|
|
280
|
+
outgoing.find((r) => r.sourceProductId)?.sourceProductId ?? '');
|
|
281
|
+
stateById = new Map(states.map((s) => [s.id, s]));
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
log(`[nexus] gate: failed to read source delivery states: ${err.message}`);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
for (const [deliveryId, reqs] of byDelivery) {
|
|
288
|
+
const state = stateById.get(deliveryId);
|
|
289
|
+
if (!state)
|
|
290
|
+
continue;
|
|
291
|
+
const status = state.executionStatus;
|
|
292
|
+
const openReqs = reqs.filter((r) => r.status && NON_TERMINAL_REQUEST_STATUSES.has(r.status));
|
|
293
|
+
const declined = reqs.some((r) => r.status === 'declined');
|
|
294
|
+
try {
|
|
295
|
+
// BLOCK: pause a queued delivery that is waiting on an open request.
|
|
296
|
+
if (status === DELIVERY_STATUS.QUEUED && openReqs.length > 0) {
|
|
297
|
+
const target = openReqs[0];
|
|
298
|
+
const targetName = (target.targetProductId ? await deps.getProductName(target.targetProductId) : undefined) ??
|
|
299
|
+
(target.title ? `request "${target.title}"` : undefined) ??
|
|
300
|
+
target.targetProductId ??
|
|
301
|
+
'another product';
|
|
302
|
+
const gateState = {
|
|
303
|
+
blocking: [{ guardName: `Waiting on ${targetName}`, passed: false }],
|
|
304
|
+
warnings: [],
|
|
305
|
+
evaluatedAt: new Date().toISOString(),
|
|
306
|
+
nexusBlock: { requestIds: openReqs.map((r) => r.id) },
|
|
307
|
+
};
|
|
308
|
+
await deps.pauseSourceDelivery(deliveryId, gateState, status);
|
|
309
|
+
log(`[nexus] gate: paused source delivery ${deliveryId.slice(0, 8)} -- waiting on ${targetName}`);
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
// RELEASE: re-queue a delivery THIS gate paused once its requests clear.
|
|
313
|
+
if (status === DELIVERY_STATUS.PAUSED &&
|
|
314
|
+
isNexusGateState(state.gateState) &&
|
|
315
|
+
openReqs.length === 0 &&
|
|
316
|
+
!declined) {
|
|
317
|
+
await deps.requeueSourceDelivery(deliveryId, status);
|
|
318
|
+
log(`[nexus] gate: resumed source delivery ${deliveryId.slice(0, 8)} -- all Nexus requests resolved`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
log(`[nexus] gate: failed to reconcile source delivery ${deliveryId.slice(0, 8)}: ${err.message}`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=nexus-return.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nexus-return.js","sourceRoot":"","sources":["../src/nexus-return.ts"],"names":[],"mappings":"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"}
|
|
@@ -214,4 +214,16 @@ export declare function getMergeConflictDeliveries(_organizationId: string, prod
|
|
|
214
214
|
focus_id: string | null;
|
|
215
215
|
pipeline_config: PipelineConfig | null;
|
|
216
216
|
}>>;
|
|
217
|
+
/**
|
|
218
|
+
* Return the delivery_id (and derived focus_id + product_id) for a single
|
|
219
|
+
* issue, for use by resolveProvenance when only an issueId anchor is available.
|
|
220
|
+
*
|
|
221
|
+
* Returns null when the issue is not found or has no delivery.
|
|
222
|
+
* Best-effort: callers must handle null gracefully.
|
|
223
|
+
*/
|
|
224
|
+
export declare function getIssueDelivery(issueId: string): Promise<{
|
|
225
|
+
deliveryId: string;
|
|
226
|
+
productId: string | null;
|
|
227
|
+
focusId: string | null;
|
|
228
|
+
} | null>;
|
|
217
229
|
//# sourceMappingURL=deliveries.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deliveries.d.ts","sourceRoot":"","sources":["../../src/queries/deliveries.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"deliveries.d.ts","sourceRoot":"","sources":["../../src/queries/deliveries.ts"],"names":[],"mappings":"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"}
|
|
@@ -285,4 +285,21 @@ export async function getMergeConflictDeliveries(_organizationId, productId) {
|
|
|
285
285
|
pipeline_config: d.pipelineConfig ?? null,
|
|
286
286
|
}));
|
|
287
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* Return the delivery_id (and derived focus_id + product_id) for a single
|
|
290
|
+
* issue, for use by resolveProvenance when only an issueId anchor is available.
|
|
291
|
+
*
|
|
292
|
+
* Returns null when the issue is not found or has no delivery.
|
|
293
|
+
* Best-effort: callers must handle null gracefully.
|
|
294
|
+
*/
|
|
295
|
+
export async function getIssueDelivery(issueId) {
|
|
296
|
+
const result = await callApi('daemon_get_issue_delivery', { issueId });
|
|
297
|
+
if (!result.deliveryId)
|
|
298
|
+
return null;
|
|
299
|
+
return {
|
|
300
|
+
deliveryId: result.deliveryId,
|
|
301
|
+
productId: result.productId ?? null,
|
|
302
|
+
focusId: result.focusId ?? null,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
288
305
|
//# sourceMappingURL=deliveries.js.map
|