@cat-factory/server 0.323.0 → 0.325.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/dist/app.d.ts.map +1 -1
- package/dist/app.js +5 -0
- package/dist/app.js.map +1 -1
- package/dist/modules/publicApi/PublicApiController.d.ts.map +1 -1
- package/dist/modules/publicApi/PublicApiController.js +5 -292
- package/dist/modules/publicApi/PublicApiController.js.map +1 -1
- package/dist/modules/publicApi/PublicDecisionController.d.ts.map +1 -1
- package/dist/modules/publicApi/PublicDecisionController.js +2 -0
- package/dist/modules/publicApi/PublicDecisionController.js.map +1 -1
- package/dist/modules/publicApi/PublicFragmentController.d.ts +4 -0
- package/dist/modules/publicApi/PublicFragmentController.d.ts.map +1 -0
- package/dist/modules/publicApi/PublicFragmentController.js +61 -0
- package/dist/modules/publicApi/PublicFragmentController.js.map +1 -0
- package/dist/modules/publicApi/boardProjection.d.ts.map +1 -1
- package/dist/modules/publicApi/boardProjection.js +4 -0
- package/dist/modules/publicApi/boardProjection.js.map +1 -1
- package/dist/modules/publicApi/decisions/bugFishingProjection.d.ts +19 -0
- package/dist/modules/publicApi/decisions/bugFishingProjection.d.ts.map +1 -0
- package/dist/modules/publicApi/decisions/bugFishingProjection.js +130 -0
- package/dist/modules/publicApi/decisions/bugFishingProjection.js.map +1 -0
- package/dist/modules/publicApi/decisions/bugFishingRoutes.d.ts +4 -0
- package/dist/modules/publicApi/decisions/bugFishingRoutes.d.ts.map +1 -0
- package/dist/modules/publicApi/decisions/bugFishingRoutes.js +73 -0
- package/dist/modules/publicApi/decisions/bugFishingRoutes.js.map +1 -0
- package/dist/modules/publicApi/decisions/projection.d.ts +21 -0
- package/dist/modules/publicApi/decisions/projection.d.ts.map +1 -1
- package/dist/modules/publicApi/decisions/projection.js +65 -11
- package/dist/modules/publicApi/decisions/projection.js.map +1 -1
- package/dist/modules/publicApi/fragmentCatalog.d.ts +47 -0
- package/dist/modules/publicApi/fragmentCatalog.d.ts.map +1 -0
- package/dist/modules/publicApi/fragmentCatalog.js +106 -0
- package/dist/modules/publicApi/fragmentCatalog.js.map +1 -0
- package/dist/modules/publicApi/openapiDocument.generated.d.ts +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.d.ts.map +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.js +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.js.map +1 -1
- package/dist/modules/publicApi/publicApiAdmission.d.ts +1 -1
- package/dist/modules/publicApi/publicApiAdmission.d.ts.map +1 -1
- package/dist/modules/publicApi/publicApiAdmission.js +5 -1
- package/dist/modules/publicApi/publicApiAdmission.js.map +1 -1
- package/dist/modules/publicApi/publicApiStream.d.ts +50 -1
- package/dist/modules/publicApi/publicApiStream.d.ts.map +1 -1
- package/dist/modules/publicApi/publicApiStream.js +83 -5
- package/dist/modules/publicApi/publicApiStream.js.map +1 -1
- package/dist/modules/publicApi/publicApiStreamRoutes.d.ts +30 -0
- package/dist/modules/publicApi/publicApiStreamRoutes.d.ts.map +1 -0
- package/dist/modules/publicApi/publicApiStreamRoutes.js +275 -0
- package/dist/modules/publicApi/publicApiStreamRoutes.js.map +1 -0
- package/dist/modules/publicApi/runProjection.d.ts +30 -0
- package/dist/modules/publicApi/runProjection.d.ts.map +1 -0
- package/dist/modules/publicApi/runProjection.js +127 -0
- package/dist/modules/publicApi/runProjection.js.map +1 -0
- package/dist/modules/publicApi/taskCreation.d.ts +2 -0
- package/dist/modules/publicApi/taskCreation.d.ts.map +1 -1
- package/dist/modules/publicApi/taskCreation.js +20 -12
- package/dist/modules/publicApi/taskCreation.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapiDocument.generated.js","sourceRoot":"","sources":["../../../src/modules/publicApi/openapiDocument.generated.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,EAAE;AACF,0FAA0F;AAC1F,8FAA8F;AAC9F,8FAA8F;AAC9F,8EAA8E;AAE9E,MAAM,CAAC,MAAM,YAAY,GAAG,
|
|
1
|
+
{"version":3,"file":"openapiDocument.generated.js","sourceRoot":"","sources":["../../../src/modules/publicApi/openapiDocument.generated.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,EAAE;AACF,0FAA0F;AAC1F,8FAA8F;AAC9F,8FAA8F;AAC9F,8EAA8E;AAE9E,MAAM,CAAC,MAAM,YAAY,GAAG,yizxBAAyizxB,CAAA"}
|
|
@@ -98,7 +98,7 @@ export declare const PUBLIC_TASK_STOP_PATH = "POST /api/v1/tasks/:taskId/stop";
|
|
|
98
98
|
* decision surface admits it cannot answer are one decision. See
|
|
99
99
|
* `backend/docs/adr/0043-public-decision-surface.md`.
|
|
100
100
|
*/
|
|
101
|
-
export declare const PUBLICLY_ANSWERABLE_PARK_SURFACES: Map<string, "agent-decision" | "approval-gate" | "brainstorm" | "clarity-review" | "follow-ups" | "fork" | "human-test" | "input-gate" | "interview" | "judge" | "pr-review" | "requirements-review" | "visual-confirmation">;
|
|
101
|
+
export declare const PUBLICLY_ANSWERABLE_PARK_SURFACES: Map<string, "agent-decision" | "approval-gate" | "brainstorm" | "bug-fishing" | "clarity-review" | "follow-ups" | "fork" | "human-test" | "input-gate" | "interview" | "judge" | "pr-review" | "requirements-review" | "visual-confirmation">;
|
|
102
102
|
/** The pipeline shape admission reasons about: the step chain plus its parallel flag arrays. */
|
|
103
103
|
export interface AdmissiblePipelineShape {
|
|
104
104
|
agentKinds: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publicApiAdmission.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiAdmission.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,KAAK,iBAAiB,
|
|
1
|
+
{"version":3,"file":"publicApiAdmission.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiAdmission.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,KAAK,iBAAiB,EAWvB,MAAM,qBAAqB,CAAA;AAG5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEvD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,aAK/B,CAAA;AASF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,eAAe,CAAA;AAuBnD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,6BAA6B,sBAAsB,CAAA;AAkDhE;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,iCAAiC,CAAA;AACpE,eAAO,MAAM,qBAAqB,oCAAoC,CAAA;AAEtE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,iCAAiC,+OAe5C,CAAA;AAEF,gGAAgG;AAChG,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,OAAO,EAAE,CAAA;IACnB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,OAAO,EAAE,CAAA;IACjB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;QAAE,YAAY,CAAC,EAAE;YAAE,UAAU,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAA;CACjG;AASD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,uBAAuB,EACjC,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAIT;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,UAAU,EAAE,iBAAiB,CAAA;IAC7B,2GAA2G;IAC3G,KAAK,EAAE,YAAY,CAAA;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,YAAY,EAAE,YAAY,CAAA;CAC3B,GAAG,mBAAmB,CAEtB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,mBAAmB,GAC9B,OAAO,CAET;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,mBAAmB,GAC9B,MAAM,EAAE,CAwBV;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CA2BjG;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,mBAAmB,EAC/B,OAAO,EAAE;IAAE,eAAe,EAAE,OAAO,CAAA;CAAE,GACpC,MAAM,EAAE,CAKV;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,mBAAmB,GAC9B,OAAO,CAIT"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// cross-runtime conformance suite.
|
|
11
11
|
//
|
|
12
12
|
// See backend/docs/adr/0047-headless-clarification-loop.md (D1).
|
|
13
|
-
import { ARCHITECTURE_BRAINSTORM_AGENT_KIND, CLARITY_REVIEW_AGENT_KIND, CURATION_GATE_TRAIT, INTERVIEW_GATE_TRAIT, isInlineModelStep, PR_REVIEWER_KIND, REQUIREMENTS_BRAINSTORM_AGENT_KIND, REQUIREMENTS_REVIEW_AGENT_KIND, traitsFor, } from '@cat-factory/agents';
|
|
13
|
+
import { ARCHITECTURE_BRAINSTORM_AGENT_KIND, BUG_FISHER_KIND, CLARITY_REVIEW_AGENT_KIND, CURATION_GATE_TRAIT, INTERVIEW_GATE_TRAIT, isInlineModelStep, PR_REVIEWER_KIND, REQUIREMENTS_BRAINSTORM_AGENT_KIND, REQUIREMENTS_REVIEW_AGENT_KIND, traitsFor, } from '@cat-factory/agents';
|
|
14
14
|
/**
|
|
15
15
|
* Inline agent kinds that PARK a run on a human/gate decision. This MUST list every
|
|
16
16
|
* inline-and-parking kind: the two review gates AND the two brainstorm dialogues (all four set the
|
|
@@ -197,6 +197,10 @@ export const PUBLICLY_ANSWERABLE_PARK_SURFACES = new Map([
|
|
|
197
197
|
// The PR deep review's finding curation: `…/decisions/pr-review/resolve` (finish / fix / post),
|
|
198
198
|
// plus per-finding dismiss, challenge and resume.
|
|
199
199
|
[PR_REVIEWER_KIND, 'pr-review'],
|
|
200
|
+
// The bug-fishing expedition's triage: `…/decisions/bug-fishing/address` (one bug-fix task per
|
|
201
|
+
// marked finding), plus per-finding dismiss and `…/resolve` to finish. The second curating kind
|
|
202
|
+
// to gain verbs, which is why `curationWait` now names only a deployment's OWN curating kinds.
|
|
203
|
+
[BUG_FISHER_KIND, 'bug-fishing'],
|
|
200
204
|
]);
|
|
201
205
|
/** The enabled steps of a pipeline, paired with their ORIGINAL index (gates are index-aligned). */
|
|
202
206
|
function enabledSteps(pipeline) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publicApiAdmission.js","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiAdmission.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,0FAA0F;AAC1F,mCAAmC;AACnC,EAAE;AACF,iGAAiG;AACjG,mGAAmG;AACnG,mGAAmG;AACnG,mGAAmG;AACnG,sFAAsF;AACtF,mCAAmC;AACnC,EAAE;AACF,iEAAiE;AAEjE,OAAO,EAEL,kCAAkC,EAClC,yBAAyB,EACzB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,kCAAkC,EAClC,8BAA8B,EAC9B,SAAS,GACV,MAAM,qBAAqB,CAAA;AAK5B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAS;IAClD,8BAA8B;IAC9B,yBAAyB;IACzB,kCAAkC;IAClC,kCAAkC;CACnC,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,0BAA0B,GAAG,eAAe,CAAA;AAElD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,YAAY,CAAA;AAEnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,sBAAsB,GAAG,WAAW,CAAA;AAE1C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,mBAAmB,CAAA;AAEhE;;;;;;;;;;;;;;;GAeG;AACH,SAAS,cAAc,CAAC,MAA+B;IACrD,OAAO,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;AACxC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,eAAe,CAAC,IAAY,EAAE,KAAmB;IACxD,OAAO,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,OAAO,CAAA;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,8BAA8B,CAAA;AACpE,MAAM,CAAC,MAAM,qBAAqB,GAAG,iCAAiC,CAAA;AAEtE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,MAAM,iCAAiC,GAAG,IAAI,GAAG,CAA6B;IACnF,CAAC,8BAA8B,EAAE,qBAAqB,CAAC;IACvD,CAAC,yBAAyB,EAAE,gBAAgB,CAAC;IAC7C,CAAC,kCAAkC,EAAE,YAAY,CAAC;IAClD,CAAC,kCAAkC,EAAE,YAAY,CAAC;IAClD,CAAC,uBAAuB,EAAE,YAAY,CAAC;IACvC,CAAC,0BAA0B,EAAE,eAAe,CAAC;IAC7C,CAAC,sBAAsB,EAAE,WAAW,CAAC;IACrC,gGAAgG;IAChG,kDAAkD;IAClD,CAAC,gBAAgB,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"publicApiAdmission.js","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiAdmission.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExecutionStatus, PublicRun } from '@cat-factory/contracts';
|
|
1
|
+
import type { ExecutionStatus, PublicDecisionList, PublicRun } from '@cat-factory/contracts';
|
|
2
2
|
/**
|
|
3
3
|
* Whether a run is PARKED: waiting on a human decision and unable to move until one is answered.
|
|
4
4
|
*
|
|
@@ -21,6 +21,25 @@ export declare function createParkAnnouncer(): {
|
|
|
21
21
|
/** Feed each poll's status; true exactly on the tick a NEW park should be announced. */
|
|
22
22
|
shouldAnnounce: (status: ExecutionStatus) => boolean;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Tracks the last DECISION payload written, so a `decision-state` frame is emitted only when the
|
|
26
|
+
* run's decision list actually moved.
|
|
27
|
+
*
|
|
28
|
+
* The counterpart of {@link createParkAnnouncer}, and it fails the same two invisible ways. A
|
|
29
|
+
* detector that always fires turns a park into an unbounded stream of identical payloads, since a
|
|
30
|
+
* park lasts as long as a human takes and the projection is rebuilt every tick. One that latches
|
|
31
|
+
* and never re-arms delivers the first state and then goes quiet, which is the failure the channel
|
|
32
|
+
* exists to prevent: a review whose slices report one by one would report the first and nothing
|
|
33
|
+
* after it, and a caller cannot tell that from a reviewer that stopped.
|
|
34
|
+
*
|
|
35
|
+
* Compared on the SERIALIZED payload rather than a field of it, for the reason the progress frames
|
|
36
|
+
* beside it are: what counts as "moved" is decided by the whole projection, so a decision kind that
|
|
37
|
+
* grows a field is covered with no edit here.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createDecisionAnnouncer(): {
|
|
40
|
+
/** Feed each tick's serialized decision list; true exactly when it should be written. */
|
|
41
|
+
shouldAnnounce: (payload: string) => boolean;
|
|
42
|
+
};
|
|
24
43
|
/**
|
|
25
44
|
* Per-step character cap on the deliverable a STREAM frame carries, applied to `output` and to
|
|
26
45
|
* `data`'s serialized size alike.
|
|
@@ -49,4 +68,34 @@ export declare const STREAM_DELIVERABLE_PREVIEW_CHARS = 2000;
|
|
|
49
68
|
* then absent in a way that reads as never written.
|
|
50
69
|
*/
|
|
51
70
|
export declare function reduceRunForStream(run: PublicRun): PublicRun;
|
|
71
|
+
/**
|
|
72
|
+
* Per-string character cap on the model-authored text a DECISION frame carries.
|
|
73
|
+
*
|
|
74
|
+
* Smaller than {@link STREAM_DELIVERABLE_PREVIEW_CHARS}, which bounds the same class of content on
|
|
75
|
+
* the run streams, and the difference is what the cap is paid PER. The run stream pays it once per
|
|
76
|
+
* step, so a pipeline's length bounds the frame; a decision list pays it once per string in a list
|
|
77
|
+
* the RUN sizes (a deep review parks with one finding per issue it found, each carrying a detail,
|
|
78
|
+
* an evidence quote and a suggested fix), so the same number would still let one frame reach
|
|
79
|
+
* hundreds of kilobytes and be re-sent on every change.
|
|
80
|
+
*
|
|
81
|
+
* Sized as a preview a caller can act on: enough to recognise what a finding is about and decide
|
|
82
|
+
* whether to fetch it whole, which is what `GET /api/v1/runs/{runId}/decisions` is for.
|
|
83
|
+
*/
|
|
84
|
+
export declare const STREAM_DECISION_TEXT_PREVIEW_CHARS = 1000;
|
|
85
|
+
/**
|
|
86
|
+
* Reduce a decision list for an SSE frame: clip every over-long string to a preview and report the
|
|
87
|
+
* clip on the list's own `truncated` flag.
|
|
88
|
+
*
|
|
89
|
+
* Kind-AGNOSTIC by construction, for the same reason {@link createDecisionAnnouncer} compares the
|
|
90
|
+
* serialized payload rather than a field of it: what a decision kind carries is decided by that
|
|
91
|
+
* kind, so a rule written per kind is one a new kind (or a new field on an old one) silently
|
|
92
|
+
* escapes. Clipping by LENGTH wherever the text sits covers all fourteen with no edit, and the ids,
|
|
93
|
+
* statuses, counts and enums a caller routes on are short by construction, so nothing it acts on
|
|
94
|
+
* is what gets clipped.
|
|
95
|
+
*
|
|
96
|
+
* What is NEVER reduced is the list itself. Every decision the run is asking is in every frame,
|
|
97
|
+
* because an empty `decisions` that means "this payload was narrowed" and one that means "nothing
|
|
98
|
+
* is being asked" are opposite facts, and telling them apart is the whole job of this surface.
|
|
99
|
+
*/
|
|
100
|
+
export declare function reduceDecisionsForStream(list: PublicDecisionList): PublicDecisionList;
|
|
52
101
|
//# sourceMappingURL=publicApiStream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publicApiStream.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"publicApiStream.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,SAAS,EAEV,MAAM,wBAAwB,CAAA;AAa/B;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAEzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,IAAI;IACrC,wFAAwF;IACxF,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAA;CACrD,CAaA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,IAAI;IACzC,yFAAyF;IACzF,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAA;CAC7C,CASA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC,OAAQ,CAAA;AAErD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG,SAAS,CAE5D;AAkBD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kCAAkC,OAAQ,CAAA;AAEvD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,CAiBrF"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// other not is invisible in review and only shows up as a second park nobody was told about.
|
|
1
|
+
// The pure decisions the public SSE streams share: when a park is announced, when a decision list
|
|
2
|
+
// counts as moved, and how a frame is reduced for the wire. The loops themselves are in
|
|
3
|
+
// `publicApiStreamRoutes.ts`.
|
|
5
4
|
//
|
|
6
|
-
//
|
|
5
|
+
// Split out because BOTH streams need identical behaviour and this is exactly the kind of state
|
|
6
|
+
// that drifts when copy-pasted: one loop re-arming on resume and the other not is invisible in
|
|
7
|
+
// review and only shows up as a second park nobody was told about.
|
|
8
|
+
//
|
|
9
|
+
// It is also the only part of the stream loop that is unit-testable at all: everything around it
|
|
7
10
|
// is a live poll over the store behind a hijacked response.
|
|
8
11
|
/**
|
|
9
12
|
* Whether a run is PARKED: waiting on a human decision and unable to move until one is answered.
|
|
@@ -40,6 +43,32 @@ export function createParkAnnouncer() {
|
|
|
40
43
|
},
|
|
41
44
|
};
|
|
42
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Tracks the last DECISION payload written, so a `decision-state` frame is emitted only when the
|
|
48
|
+
* run's decision list actually moved.
|
|
49
|
+
*
|
|
50
|
+
* The counterpart of {@link createParkAnnouncer}, and it fails the same two invisible ways. A
|
|
51
|
+
* detector that always fires turns a park into an unbounded stream of identical payloads, since a
|
|
52
|
+
* park lasts as long as a human takes and the projection is rebuilt every tick. One that latches
|
|
53
|
+
* and never re-arms delivers the first state and then goes quiet, which is the failure the channel
|
|
54
|
+
* exists to prevent: a review whose slices report one by one would report the first and nothing
|
|
55
|
+
* after it, and a caller cannot tell that from a reviewer that stopped.
|
|
56
|
+
*
|
|
57
|
+
* Compared on the SERIALIZED payload rather than a field of it, for the reason the progress frames
|
|
58
|
+
* beside it are: what counts as "moved" is decided by the whole projection, so a decision kind that
|
|
59
|
+
* grows a field is covered with no edit here.
|
|
60
|
+
*/
|
|
61
|
+
export function createDecisionAnnouncer() {
|
|
62
|
+
let last = null;
|
|
63
|
+
return {
|
|
64
|
+
shouldAnnounce(payload) {
|
|
65
|
+
if (payload === last)
|
|
66
|
+
return false;
|
|
67
|
+
last = payload;
|
|
68
|
+
return true;
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
43
72
|
/**
|
|
44
73
|
* Per-step character cap on the deliverable a STREAM frame carries, applied to `output` and to
|
|
45
74
|
* `data`'s serialized size alike.
|
|
@@ -85,4 +114,53 @@ function reduceStepForStream(step) {
|
|
|
85
114
|
truncated: true,
|
|
86
115
|
};
|
|
87
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Per-string character cap on the model-authored text a DECISION frame carries.
|
|
119
|
+
*
|
|
120
|
+
* Smaller than {@link STREAM_DELIVERABLE_PREVIEW_CHARS}, which bounds the same class of content on
|
|
121
|
+
* the run streams, and the difference is what the cap is paid PER. The run stream pays it once per
|
|
122
|
+
* step, so a pipeline's length bounds the frame; a decision list pays it once per string in a list
|
|
123
|
+
* the RUN sizes (a deep review parks with one finding per issue it found, each carrying a detail,
|
|
124
|
+
* an evidence quote and a suggested fix), so the same number would still let one frame reach
|
|
125
|
+
* hundreds of kilobytes and be re-sent on every change.
|
|
126
|
+
*
|
|
127
|
+
* Sized as a preview a caller can act on: enough to recognise what a finding is about and decide
|
|
128
|
+
* whether to fetch it whole, which is what `GET /api/v1/runs/{runId}/decisions` is for.
|
|
129
|
+
*/
|
|
130
|
+
export const STREAM_DECISION_TEXT_PREVIEW_CHARS = 1_000;
|
|
131
|
+
/**
|
|
132
|
+
* Reduce a decision list for an SSE frame: clip every over-long string to a preview and report the
|
|
133
|
+
* clip on the list's own `truncated` flag.
|
|
134
|
+
*
|
|
135
|
+
* Kind-AGNOSTIC by construction, for the same reason {@link createDecisionAnnouncer} compares the
|
|
136
|
+
* serialized payload rather than a field of it: what a decision kind carries is decided by that
|
|
137
|
+
* kind, so a rule written per kind is one a new kind (or a new field on an old one) silently
|
|
138
|
+
* escapes. Clipping by LENGTH wherever the text sits covers all fourteen with no edit, and the ids,
|
|
139
|
+
* statuses, counts and enums a caller routes on are short by construction, so nothing it acts on
|
|
140
|
+
* is what gets clipped.
|
|
141
|
+
*
|
|
142
|
+
* What is NEVER reduced is the list itself. Every decision the run is asking is in every frame,
|
|
143
|
+
* because an empty `decisions` that means "this payload was narrowed" and one that means "nothing
|
|
144
|
+
* is being asked" are opposite facts, and telling them apart is the whole job of this surface.
|
|
145
|
+
*/
|
|
146
|
+
export function reduceDecisionsForStream(list) {
|
|
147
|
+
let clipped = false;
|
|
148
|
+
const clip = (value) => {
|
|
149
|
+
if (typeof value === 'string') {
|
|
150
|
+
if (value.length <= STREAM_DECISION_TEXT_PREVIEW_CHARS)
|
|
151
|
+
return value;
|
|
152
|
+
clipped = true;
|
|
153
|
+
return value.slice(0, STREAM_DECISION_TEXT_PREVIEW_CHARS);
|
|
154
|
+
}
|
|
155
|
+
if (Array.isArray(value))
|
|
156
|
+
return value.map(clip);
|
|
157
|
+
if (value && typeof value === 'object') {
|
|
158
|
+
return Object.fromEntries(Object.entries(value).map(([key, v]) => [key, clip(v)]));
|
|
159
|
+
}
|
|
160
|
+
return value;
|
|
161
|
+
};
|
|
162
|
+
const decisions = clip(list.decisions);
|
|
163
|
+
const unanswerable = clip(list.unanswerable);
|
|
164
|
+
return { ...list, decisions, unanswerable, truncated: clipped };
|
|
165
|
+
}
|
|
88
166
|
//# sourceMappingURL=publicApiStream.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publicApiStream.js","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStream.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"publicApiStream.js","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
import type { AppEnv } from '../../http/env.js';
|
|
3
|
+
/**
|
|
4
|
+
* `GET /api/v1/runs/:runId/decision-events`: the run's whole `PublicDecisionList`, pushed as a
|
|
5
|
+
* `decision-state` frame whenever it changes.
|
|
6
|
+
*
|
|
7
|
+
* This is what makes a chunked operation legible without polling. A run's progress lives on the
|
|
8
|
+
* execution, but what a PR deep review or a bug-fishing expedition is DOING lives on state the run
|
|
9
|
+
* projection does not carry (`step.prReview`, `step.bugFishing`): its own status, how many slices
|
|
10
|
+
* have reported, a challenge verdict landing. None of that moves `publicRun`, so on the two run
|
|
11
|
+
* streams beside this one a review emits no frame at all for its entire duration and then a single
|
|
12
|
+
* `decision` at the park. The documentation told a caller to poll `/runs/:runId/decisions` for
|
|
13
|
+
* exactly the progress those streams could not give it; this serves the same payload by push.
|
|
14
|
+
*
|
|
15
|
+
* ITS OWN ROUTE rather than a flag on the run streams, and the reason is the published SDKs rather
|
|
16
|
+
* than taste. A query parameter added to an existing operation is emitted as a positional argument
|
|
17
|
+
* ahead of the trailing options bag, so `stream(id, options)` becomes `stream(id, query, options)`
|
|
18
|
+
* in TypeScript and `Stream(ctx, id)` grows an argument in Go: an in-place retype of four released
|
|
19
|
+
* clients, which this surface does not do. A NEW operation is the additive shape, and it turns out
|
|
20
|
+
* to be the better one anyway. It is keyed by RUN like the decision list it streams, so one route
|
|
21
|
+
* serves a board task and a headless job where a flag needed adding to two; and the run streams
|
|
22
|
+
* stay what they are, which is progress channels.
|
|
23
|
+
*
|
|
24
|
+
* `read` scope, matching `GET /api/v1/runs/:runId/decisions`: knowing what a run is waiting on is a
|
|
25
|
+
* monitoring concern, and answering is what needs `decide`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function registerRunDecisionStreamRoute(app: Hono<AppEnv>): void;
|
|
28
|
+
export declare function registerJobStreamRoute(app: Hono<AppEnv>): void;
|
|
29
|
+
export declare function registerTaskRunStreamRoute(app: Hono<AppEnv>): void;
|
|
30
|
+
//# sourceMappingURL=publicApiStreamRoutes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publicApiStreamRoutes.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStreamRoutes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAoC/C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAgEtE;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAqF9D;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAgFlE"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { streamSSE } from 'hono/streaming';
|
|
2
|
+
import { projectDecisionList } from './decisions/projection.js';
|
|
3
|
+
import { loadScopedRun } from './decisions/scope.js';
|
|
4
|
+
import { authorize } from './publicApiAuth.js';
|
|
5
|
+
import { createDecisionAnnouncer, createParkAnnouncer, isParked, reduceDecisionsForStream, reduceRunForStream, } from './publicApiStream.js';
|
|
6
|
+
import { loadPublicJob, toPublicJob, toPublicRun } from './runProjection.js';
|
|
7
|
+
// The public SSE routes: the two RUN streams (`GET /api/v1/jobs/:id/events` and
|
|
8
|
+
// `GET /api/v1/tasks/:taskId/events`) and the DECISION stream beside them
|
|
9
|
+
// (`GET /api/v1/runs/:runId/decision-events`).
|
|
10
|
+
//
|
|
11
|
+
// Both are BOUNDED POLLS over the persisted run rather than a subscription to an event hub, which
|
|
12
|
+
// is what makes them runtime-symmetric by construction: there is nothing per-facade to wire, so
|
|
13
|
+
// the Worker and Node serve the identical stream. Frames are de-duplicated on the serialized
|
|
14
|
+
// payload, so a quiet run produces a quiet stream.
|
|
15
|
+
//
|
|
16
|
+
// Neither is a JSON route contract (the response is `text/event-stream`), so both are raw Hono
|
|
17
|
+
// routes documented by hand in `scripts/generate-openapi.mjs`. Their `read` scope literal lives
|
|
18
|
+
// here and is restated there; keep the two in step.
|
|
19
|
+
//
|
|
20
|
+
// They live in their own module because they are the bulk of what `PublicApiController` used to
|
|
21
|
+
// be and they share the decision channel below, which neither of that controller's other route
|
|
22
|
+
// groups has anything to do with.
|
|
23
|
+
/** How often a stream re-reads the run, and the hard cap on how long the connection stays open. */
|
|
24
|
+
const SSE_POLL_MS = 1000;
|
|
25
|
+
const SSE_MAX_MS = 5 * 60 * 1000;
|
|
26
|
+
/** Re-verify the caller's key at most this often on a live stream, so a mid-stream revoke cuts it. */
|
|
27
|
+
const SSE_REAUTH_MS = 5000;
|
|
28
|
+
/**
|
|
29
|
+
* `GET /api/v1/runs/:runId/decision-events`: the run's whole `PublicDecisionList`, pushed as a
|
|
30
|
+
* `decision-state` frame whenever it changes.
|
|
31
|
+
*
|
|
32
|
+
* This is what makes a chunked operation legible without polling. A run's progress lives on the
|
|
33
|
+
* execution, but what a PR deep review or a bug-fishing expedition is DOING lives on state the run
|
|
34
|
+
* projection does not carry (`step.prReview`, `step.bugFishing`): its own status, how many slices
|
|
35
|
+
* have reported, a challenge verdict landing. None of that moves `publicRun`, so on the two run
|
|
36
|
+
* streams beside this one a review emits no frame at all for its entire duration and then a single
|
|
37
|
+
* `decision` at the park. The documentation told a caller to poll `/runs/:runId/decisions` for
|
|
38
|
+
* exactly the progress those streams could not give it; this serves the same payload by push.
|
|
39
|
+
*
|
|
40
|
+
* ITS OWN ROUTE rather than a flag on the run streams, and the reason is the published SDKs rather
|
|
41
|
+
* than taste. A query parameter added to an existing operation is emitted as a positional argument
|
|
42
|
+
* ahead of the trailing options bag, so `stream(id, options)` becomes `stream(id, query, options)`
|
|
43
|
+
* in TypeScript and `Stream(ctx, id)` grows an argument in Go: an in-place retype of four released
|
|
44
|
+
* clients, which this surface does not do. A NEW operation is the additive shape, and it turns out
|
|
45
|
+
* to be the better one anyway. It is keyed by RUN like the decision list it streams, so one route
|
|
46
|
+
* serves a board task and a headless job where a flag needed adding to two; and the run streams
|
|
47
|
+
* stay what they are, which is progress channels.
|
|
48
|
+
*
|
|
49
|
+
* `read` scope, matching `GET /api/v1/runs/:runId/decisions`: knowing what a run is waiting on is a
|
|
50
|
+
* monitoring concern, and answering is what needs `decide`.
|
|
51
|
+
*/
|
|
52
|
+
export function registerRunDecisionStreamRoute(app) {
|
|
53
|
+
app.get('/api/v1/runs/:runId/decision-events', async (c) => {
|
|
54
|
+
const gate = await authorize(c, 'read');
|
|
55
|
+
if ('fail' in gate) {
|
|
56
|
+
return c.json({ error: { code: gate.fail.code, message: gate.fail.message } }, gate.fail.status);
|
|
57
|
+
}
|
|
58
|
+
const { auth } = gate;
|
|
59
|
+
const runId = c.req.param('runId');
|
|
60
|
+
const container = c.get('container');
|
|
61
|
+
// The same resolution the decision ROUTES use, so this streams exactly the population they
|
|
62
|
+
// answer: a board task run or a headless job anchor in the key's workspace, and anything else
|
|
63
|
+
// is a 404 indistinguishable from a run that never existed.
|
|
64
|
+
const scoped = await loadScopedRun(c, auth.workspaceId, runId);
|
|
65
|
+
if (!scoped) {
|
|
66
|
+
return c.json({ error: { code: 'not_found', message: 'Run not found' } }, 404);
|
|
67
|
+
}
|
|
68
|
+
const { blockId } = scoped;
|
|
69
|
+
const keys = container.publicApiKeys;
|
|
70
|
+
return streamSSE(c, async (stream) => {
|
|
71
|
+
const startedAt = Date.now();
|
|
72
|
+
let lastAuthCheck = Date.now();
|
|
73
|
+
// Change-detected on the serialized payload, like the progress frames on the run streams, so
|
|
74
|
+
// a park that lasts an hour costs one frame rather than 3,600 identical ones.
|
|
75
|
+
const changed = createDecisionAnnouncer();
|
|
76
|
+
for (;;) {
|
|
77
|
+
if (stream.aborted)
|
|
78
|
+
break;
|
|
79
|
+
if (keys && Date.now() - lastAuthCheck > SSE_REAUTH_MS) {
|
|
80
|
+
if (!(await keys.isActive(auth.keyId)))
|
|
81
|
+
break;
|
|
82
|
+
lastAuthCheck = Date.now();
|
|
83
|
+
}
|
|
84
|
+
const execution = await container.executionRepository.get(auth.workspaceId, runId);
|
|
85
|
+
if (!execution)
|
|
86
|
+
break;
|
|
87
|
+
const list = await projectDecisionList(c, auth.workspaceId, blockId, execution);
|
|
88
|
+
// Reduced for the same reason `reduceRunForStream` reduces beside it: the frame carries the
|
|
89
|
+
// WHOLE list and is re-sent whenever any part of it moves, so a park holding eighty
|
|
90
|
+
// model-authored findings would repeat all of them for the rest of the run. The list itself
|
|
91
|
+
// is never narrowed: only the prose inside it is clipped, and `truncated` says so.
|
|
92
|
+
const data = JSON.stringify(reduceDecisionsForStream(list));
|
|
93
|
+
if (changed.shouldAnnounce(data)) {
|
|
94
|
+
await stream.writeSSE({ event: 'decision-state', data });
|
|
95
|
+
}
|
|
96
|
+
// A finished run asks nothing, so the stream ends rather than holding a connection open
|
|
97
|
+
// over a list that can no longer move. The LAST frame is written above first, which is what
|
|
98
|
+
// makes the close readable: a caller sees the decisions empty out and then the terminal.
|
|
99
|
+
if (execution.status === 'done' || execution.status === 'failed') {
|
|
100
|
+
await stream.writeSSE({ event: 'done', data });
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
if (Date.now() - startedAt > SSE_MAX_MS) {
|
|
104
|
+
await stream.writeSSE({ event: 'timeout', data: '{}' });
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
await stream.sleep(SSE_POLL_MS);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
export function registerJobStreamRoute(app) {
|
|
113
|
+
// Stream a job's progress + terminal completion over SSE. Authenticated by the API key header
|
|
114
|
+
// (an external client can set headers, unlike a browser `EventSource`).
|
|
115
|
+
app.get('/api/v1/jobs/:id/events', async (c) => {
|
|
116
|
+
const gate = await authorize(c, 'read');
|
|
117
|
+
if ('fail' in gate) {
|
|
118
|
+
return c.json({ error: { code: gate.fail.code, message: gate.fail.message } }, gate.fail.status);
|
|
119
|
+
}
|
|
120
|
+
const { auth } = gate;
|
|
121
|
+
const id = c.req.param('id');
|
|
122
|
+
const container = c.get('container');
|
|
123
|
+
// Same headless-job scoping as the poll read: only a headless run this surface created.
|
|
124
|
+
const initial = await loadPublicJob(c, auth.workspaceId, id);
|
|
125
|
+
if (!initial) {
|
|
126
|
+
return c.json({ error: { code: 'not_found', message: 'Job not found' } }, 404);
|
|
127
|
+
}
|
|
128
|
+
const keys = container.publicApiKeys;
|
|
129
|
+
return streamSSE(c, async (stream) => {
|
|
130
|
+
const startedAt = Date.now();
|
|
131
|
+
let lastAuthCheck = Date.now();
|
|
132
|
+
let last = '';
|
|
133
|
+
// Emit the initial state immediately, then poll until terminal / client-gone / revoked /
|
|
134
|
+
// timeout. A `blocked` run is a PARK awaiting a human decision, no longer a dead end, since
|
|
135
|
+
// a `decide`-scope caller can answer it over `/api/v1/runs/:runId/decisions`, so the stream
|
|
136
|
+
// announces the park and keeps watching rather than closing on it.
|
|
137
|
+
const parks = createParkAnnouncer();
|
|
138
|
+
for (;;) {
|
|
139
|
+
if (stream.aborted)
|
|
140
|
+
break;
|
|
141
|
+
// Re-verify the key periodically so a mid-stream revoke cuts the connection (the key was
|
|
142
|
+
// only proven once, at open). Cheap non-hashing revocation check, throttled.
|
|
143
|
+
if (keys && Date.now() - lastAuthCheck > SSE_REAUTH_MS) {
|
|
144
|
+
if (!(await keys.isActive(auth.keyId)))
|
|
145
|
+
break;
|
|
146
|
+
lastAuthCheck = Date.now();
|
|
147
|
+
}
|
|
148
|
+
const execution = await container.executionRepository.get(auth.workspaceId, id);
|
|
149
|
+
if (!execution)
|
|
150
|
+
break;
|
|
151
|
+
const job = toPublicJob(execution, auth.externalIdentity);
|
|
152
|
+
const data = JSON.stringify(job);
|
|
153
|
+
if (data !== last) {
|
|
154
|
+
await stream.writeSSE({
|
|
155
|
+
event: job.status === 'succeeded' ? 'done' : job.status === 'failed' ? 'error' : 'progress',
|
|
156
|
+
data,
|
|
157
|
+
});
|
|
158
|
+
last = data;
|
|
159
|
+
}
|
|
160
|
+
// A `blocked` run has PARKED on a human decision. Announce it once (so a caller learns of
|
|
161
|
+
// the park by push rather than by polling the decisions endpoint on a timer) and keep the
|
|
162
|
+
// stream open: the park is answerable, and answering resumes the very run being watched,
|
|
163
|
+
// which the caller should see through the SAME connection. Announced once per park rather
|
|
164
|
+
// than every tick, so a long park doesn't spam identical frames; re-armed when the run
|
|
165
|
+
// resumes, so a second park later in the pipeline is announced too.
|
|
166
|
+
if (parks.shouldAnnounce(execution.status)) {
|
|
167
|
+
await stream.writeSSE({ event: 'decision', data });
|
|
168
|
+
}
|
|
169
|
+
// A `paused` run is NOT terminal: the spend gate pauses a run when the workspace budget
|
|
170
|
+
// is exhausted and RESUMES it once budget frees up (ExecutionService.evaluateStep), so keep
|
|
171
|
+
// polling (bounded by SSE_MAX_MS below) rather than signalling a false terminal stop.
|
|
172
|
+
// `blocked` is likewise non-terminal now (see above).
|
|
173
|
+
if (execution.status !== 'running' &&
|
|
174
|
+
execution.status !== 'paused' &&
|
|
175
|
+
!isParked(execution.status)) {
|
|
176
|
+
// The run has stopped. When it ended in a terminal public status (succeeded/failed) the
|
|
177
|
+
// event above already carried `done`/`error`. A raw status that maps to `running` but is
|
|
178
|
+
// neither terminal nor a park (a `cancelled` stop lands as `failed`, so this is the
|
|
179
|
+
// belt-and-braces arm) would otherwise close the stream after a `progress` frame, leaving
|
|
180
|
+
// the client unable to tell "terminal" from "connection dropped". Emit an explicit
|
|
181
|
+
// terminal `stopped` frame so every close is unambiguous.
|
|
182
|
+
if (job.status === 'running')
|
|
183
|
+
await stream.writeSSE({ event: 'stopped', data });
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
if (Date.now() - startedAt > SSE_MAX_MS) {
|
|
187
|
+
// Bound the connection; the client can reconnect to keep watching.
|
|
188
|
+
await stream.writeSSE({ event: 'timeout', data: '{}' });
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
await stream.sleep(SSE_POLL_MS);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
export function registerTaskRunStreamRoute(app) {
|
|
197
|
+
// Stream a task's run over SSE: the same bounded-poll pattern as the jobs stream, re-reading the
|
|
198
|
+
// persisted run + its block each tick so a mid-run PR-open surfaces. Terminal on `done`/`failed`;
|
|
199
|
+
// a parked `blocked`/`paused` keeps polling until the run resumes or the connection hits
|
|
200
|
+
// SSE_MAX_MS.
|
|
201
|
+
app.get('/api/v1/tasks/:taskId/events', async (c) => {
|
|
202
|
+
const gate = await authorize(c, 'read');
|
|
203
|
+
if ('fail' in gate) {
|
|
204
|
+
return c.json({ error: { code: gate.fail.code, message: gate.fail.message } }, gate.fail.status);
|
|
205
|
+
}
|
|
206
|
+
const { auth } = gate;
|
|
207
|
+
const taskId = c.req.param('taskId');
|
|
208
|
+
const container = c.get('container');
|
|
209
|
+
const found = await container.boardService.getServiceTask(auth.workspaceId, taskId);
|
|
210
|
+
if (!found) {
|
|
211
|
+
return c.json({ error: { code: 'not_found', message: 'Task not found' } }, 404);
|
|
212
|
+
}
|
|
213
|
+
const run = await container.executionRepository.getByBlock(auth.workspaceId, taskId);
|
|
214
|
+
if (!run) {
|
|
215
|
+
return c.json({ error: { code: 'no_run', message: 'Task has not been started' } }, 404);
|
|
216
|
+
}
|
|
217
|
+
const runId = run.id;
|
|
218
|
+
const keys = container.publicApiKeys;
|
|
219
|
+
return streamSSE(c, async (stream) => {
|
|
220
|
+
const startedAt = Date.now();
|
|
221
|
+
let lastAuthCheck = Date.now();
|
|
222
|
+
let last = '';
|
|
223
|
+
// Announce a park once per park (see the jobs stream for the rationale); re-armed on resume
|
|
224
|
+
// so a later step's park is announced too.
|
|
225
|
+
const parks = createParkAnnouncer();
|
|
226
|
+
for (;;) {
|
|
227
|
+
if (stream.aborted)
|
|
228
|
+
break;
|
|
229
|
+
if (keys && Date.now() - lastAuthCheck > SSE_REAUTH_MS) {
|
|
230
|
+
if (!(await keys.isActive(auth.keyId)))
|
|
231
|
+
break;
|
|
232
|
+
lastAuthCheck = Date.now();
|
|
233
|
+
}
|
|
234
|
+
const execution = await container.executionRepository.get(auth.workspaceId, runId);
|
|
235
|
+
// Re-read the block for the current PR/branch: the run opens the PR mid-flight, so
|
|
236
|
+
// the block (not the execution) carries it.
|
|
237
|
+
const block = await container.boardService.getServiceTask(auth.workspaceId, taskId);
|
|
238
|
+
if (!execution || !block)
|
|
239
|
+
break;
|
|
240
|
+
// Reduced for the wire: the frame carries the whole run, so an oversized step deliverable
|
|
241
|
+
// would be re-sent on every change for the rest of the run. See `reduceRunForStream`.
|
|
242
|
+
const runView = reduceRunForStream(toPublicRun(execution, block.block, auth.externalIdentity));
|
|
243
|
+
const data = JSON.stringify(runView);
|
|
244
|
+
if (data !== last) {
|
|
245
|
+
await stream.writeSSE({
|
|
246
|
+
event: runView.status === 'done'
|
|
247
|
+
? 'done'
|
|
248
|
+
: runView.status === 'failed'
|
|
249
|
+
? 'error'
|
|
250
|
+
: 'progress',
|
|
251
|
+
data,
|
|
252
|
+
});
|
|
253
|
+
last = data;
|
|
254
|
+
}
|
|
255
|
+
// A `blocked` run has PARKED on a human decision (a requirements/clarity review, a
|
|
256
|
+
// brainstorm, an approval gate, a fork choice). Push it as a distinct `decision` frame so
|
|
257
|
+
// the caller reacts to the park instead of inferring it from a `progress` payload whose
|
|
258
|
+
// status happens to read `blocked`; `GET /api/v1/runs/:runId/decisions` then carries what
|
|
259
|
+
// is actually being asked. The stream stays open across the park: answering resumes this
|
|
260
|
+
// very run, and the caller should see that on the same connection.
|
|
261
|
+
if (parks.shouldAnnounce(execution.status)) {
|
|
262
|
+
await stream.writeSSE({ event: 'decision', data });
|
|
263
|
+
}
|
|
264
|
+
if (execution.status === 'done' || execution.status === 'failed')
|
|
265
|
+
break;
|
|
266
|
+
if (Date.now() - startedAt > SSE_MAX_MS) {
|
|
267
|
+
await stream.writeSSE({ event: 'timeout', data: '{}' });
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
await stream.sleep(SSE_POLL_MS);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=publicApiStreamRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publicApiStreamRoutes.js","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStreamRoutes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Block, ExecutionInstance, PublicJob, PublicRun } from '@cat-factory/contracts';
|
|
2
|
+
import type { Context } from 'hono';
|
|
3
|
+
import type { AppEnv } from '../../http/env.js';
|
|
4
|
+
/**
|
|
5
|
+
* Project a persisted execution onto the external job resource (no block/board internals).
|
|
6
|
+
*
|
|
7
|
+
* Takes the READING key's own identity because the run's pinned one is not visible to every key
|
|
8
|
+
* (`runIdentityVisibility.ts` holds the rule and why there is one). Passed as a parameter rather
|
|
9
|
+
* than read off the context here, so the projection stays a pure function of the run plus the
|
|
10
|
+
* caller and the SSE loops can render frame after frame without re-reading anything.
|
|
11
|
+
*/
|
|
12
|
+
export declare function toPublicJob(execution: ExecutionInstance, readerIdentity: string | null): PublicJob;
|
|
13
|
+
/**
|
|
14
|
+
* Project a task's persisted run + its block onto the RICH external run resource: per-step
|
|
15
|
+
* state/progress/subtasks, the failure kind+message, and the PR (url + branch). The run's
|
|
16
|
+
* `status` is the raw execution status (`running`/`blocked`/`paused`/`done`/`failed`): the
|
|
17
|
+
* public run view deliberately surfaces the parked states (unlike the coarse `publicJob`), so
|
|
18
|
+
* a caller can tell an awaiting-a-human `blocked` from a still-`running` step. The PR branch
|
|
19
|
+
* lives on the BLOCK (`block.pullRequest`), not the run, so both are joined here.
|
|
20
|
+
*/
|
|
21
|
+
export declare function toPublicRun(execution: ExecutionInstance, block: Block, readerIdentity: string | null): PublicRun;
|
|
22
|
+
/**
|
|
23
|
+
* Load a public JOB by id for an authenticated key: the persisted execution, but ONLY when it is
|
|
24
|
+
* anchored on a HEADLESS internal block (a run this public surface created). Returns null when no
|
|
25
|
+
* such run exists in the key's workspace OR the id points at a normal board execution, so an
|
|
26
|
+
* external key can never read an arbitrary in-workspace run's output, only its own headless jobs.
|
|
27
|
+
* Runtime-symmetric: one `executionRepository.get` + one `boardService.getInternalTask` point-read.
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadPublicJob<E extends AppEnv>(c: Context<E>, workspaceId: string, id: string): Promise<ExecutionInstance | null>;
|
|
30
|
+
//# sourceMappingURL=runProjection.d.ts.map
|