@exaudeus/workrail 1.6.0 → 1.7.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/manifest.json +42 -34
- package/dist/mcp/handlers/v2-advance-core/event-builders.js +2 -2
- package/dist/mcp/handlers/v2-context-budget.js +1 -1
- package/dist/mcp/handlers/v2-execution/start.js +3 -9
- package/dist/mcp/handlers/v2-resume.js +3 -10
- package/dist/mcp/handlers/v2-workspace-resolution.d.ts +5 -0
- package/dist/mcp/handlers/v2-workspace-resolution.js +22 -0
- package/dist/mcp/tool-descriptions.js +13 -0
- package/dist/mcp/v2/tools.d.ts +6 -0
- package/dist/mcp/v2/tools.js +8 -0
- package/dist/v2/durable-core/constants.d.ts +5 -0
- package/dist/v2/durable-core/constants.js +5 -1
- package/dist/v2/durable-core/domain/recap-recovery.js +5 -4
- package/dist/v2/durable-core/schemas/session/outputs.js +3 -3
- package/dist/v2/infra/local/session-summary-provider/index.d.ts +0 -2
- package/dist/v2/infra/local/session-summary-provider/index.js +101 -107
- package/dist/v2/infra/local/workspace-anchor/index.d.ts +5 -7
- package/dist/v2/infra/local/workspace-anchor/index.js +16 -14
- package/dist/v2/ports/workspace-anchor.port.d.ts +10 -5
- package/dist/v2/projections/artifacts.js +1 -1
- package/package.json +1 -1
package/dist/manifest.json
CHANGED
|
@@ -558,8 +558,8 @@
|
|
|
558
558
|
"bytes": 2464
|
|
559
559
|
},
|
|
560
560
|
"mcp/handlers/v2-advance-core/event-builders.js": {
|
|
561
|
-
"sha256": "
|
|
562
|
-
"bytes":
|
|
561
|
+
"sha256": "cb510635b173965f6cb2af312289f0903600a7483376b8b7156351f5bcf1fbd2",
|
|
562
|
+
"bytes": 5774
|
|
563
563
|
},
|
|
564
564
|
"mcp/handlers/v2-advance-core/index.d.ts": {
|
|
565
565
|
"sha256": "a927c7e13912cfcad6340922a24f5b9331d513ce25191049aabdce96a7a86a68",
|
|
@@ -614,8 +614,8 @@
|
|
|
614
614
|
"bytes": 674
|
|
615
615
|
},
|
|
616
616
|
"mcp/handlers/v2-context-budget.js": {
|
|
617
|
-
"sha256": "
|
|
618
|
-
"bytes":
|
|
617
|
+
"sha256": "5450c08d25900fd639090ba0090fc4c866e02295ee11aa52c187447424fdc4c2",
|
|
618
|
+
"bytes": 7199
|
|
619
619
|
},
|
|
620
620
|
"mcp/handlers/v2-error-mapping.d.ts": {
|
|
621
621
|
"sha256": "bbaf580dfc22ca6b5ef1d57036fb549c640d6f37bd7d525f1a805b4d14c4d75c",
|
|
@@ -686,16 +686,16 @@
|
|
|
686
686
|
"bytes": 2789
|
|
687
687
|
},
|
|
688
688
|
"mcp/handlers/v2-execution/start.js": {
|
|
689
|
-
"sha256": "
|
|
690
|
-
"bytes":
|
|
689
|
+
"sha256": "aeee2ba6b1cc0d461d2421eed0f99ca22f4006baa7f5663cc28855d00c950d87",
|
|
690
|
+
"bytes": 15015
|
|
691
691
|
},
|
|
692
692
|
"mcp/handlers/v2-resume.d.ts": {
|
|
693
693
|
"sha256": "d88f6c35bcaf946666c837b72fda3702a2ebab5e478eb90f7b4b672a0e5fa24f",
|
|
694
694
|
"bytes": 471
|
|
695
695
|
},
|
|
696
696
|
"mcp/handlers/v2-resume.js": {
|
|
697
|
-
"sha256": "
|
|
698
|
-
"bytes":
|
|
697
|
+
"sha256": "74d66519764615780c556828c23ada5fa7df887c8263793de4323322aef14408",
|
|
698
|
+
"bytes": 2826
|
|
699
699
|
},
|
|
700
700
|
"mcp/handlers/v2-state-conversion.d.ts": {
|
|
701
701
|
"sha256": "94bd06904ef58dd210ff17ffb75c2492beea8937eb06d99749e5d860c0e0d96b",
|
|
@@ -721,6 +721,14 @@
|
|
|
721
721
|
"sha256": "bed0ffc401958c14343158e142e4be344bad49cabc95f99a811d872bc76989a7",
|
|
722
722
|
"bytes": 6027
|
|
723
723
|
},
|
|
724
|
+
"mcp/handlers/v2-workspace-resolution.d.ts": {
|
|
725
|
+
"sha256": "45cdf30b7989d16201b4569c6c109e9ccea04c76fd044af1471fe57faa49da3a",
|
|
726
|
+
"bytes": 483
|
|
727
|
+
},
|
|
728
|
+
"mcp/handlers/v2-workspace-resolution.js": {
|
|
729
|
+
"sha256": "4c6765112c49ade9c04b5f0606026e5058071ce278a6fb9c3b8207b7ca79c697",
|
|
730
|
+
"bytes": 909
|
|
731
|
+
},
|
|
724
732
|
"mcp/handlers/workflow.d.ts": {
|
|
725
733
|
"sha256": "050565039a20af3f7fc8311337ff4547438ecc59433e5744aacce8f203326774",
|
|
726
734
|
"bytes": 1748
|
|
@@ -766,8 +774,8 @@
|
|
|
766
774
|
"bytes": 132
|
|
767
775
|
},
|
|
768
776
|
"mcp/tool-descriptions.js": {
|
|
769
|
-
"sha256": "
|
|
770
|
-
"bytes":
|
|
777
|
+
"sha256": "1444469a7f3ac328573cc8af0cca347754e17fb184a832f78405fd4f21ed6350",
|
|
778
|
+
"bytes": 17534
|
|
771
779
|
},
|
|
772
780
|
"mcp/tool-factory.d.ts": {
|
|
773
781
|
"sha256": "0fe3c6b863b2d7aef0c3d659ff54f3a9ee8a0a3c2005b6565d2f8ad517bc7211",
|
|
@@ -826,12 +834,12 @@
|
|
|
826
834
|
"bytes": 3078
|
|
827
835
|
},
|
|
828
836
|
"mcp/v2/tools.d.ts": {
|
|
829
|
-
"sha256": "
|
|
830
|
-
"bytes":
|
|
837
|
+
"sha256": "8d37b32d7a00d534b2ecbdc71018e3849714531ec3021862427494be85909eab",
|
|
838
|
+
"bytes": 5486
|
|
831
839
|
},
|
|
832
840
|
"mcp/v2/tools.js": {
|
|
833
|
-
"sha256": "
|
|
834
|
-
"bytes":
|
|
841
|
+
"sha256": "0d26b75a7e038f494570f5fdc1d624f5bb28bfa7e368ea4d3259ae27dc889301",
|
|
842
|
+
"bytes": 7748
|
|
835
843
|
},
|
|
836
844
|
"mcp/validation/bounded-json.d.ts": {
|
|
837
845
|
"sha256": "82203ac6123d5c6989606c3b5405aaea99ab829c8958835f9ae3ba45b8bc8fd5",
|
|
@@ -1162,12 +1170,12 @@
|
|
|
1162
1170
|
"bytes": 447
|
|
1163
1171
|
},
|
|
1164
1172
|
"v2/durable-core/constants.d.ts": {
|
|
1165
|
-
"sha256": "
|
|
1166
|
-
"bytes":
|
|
1173
|
+
"sha256": "2cdc1fe66cb2024e17977e024c73b9bb50845b70c9ac3925c2635e843a94f7f8",
|
|
1174
|
+
"bytes": 3699
|
|
1167
1175
|
},
|
|
1168
1176
|
"v2/durable-core/constants.js": {
|
|
1169
|
-
"sha256": "
|
|
1170
|
-
"bytes":
|
|
1177
|
+
"sha256": "29372d3e7f868b5c40d6270a1f39477a680524688e73b03613305fafef4a9553",
|
|
1178
|
+
"bytes": 3558
|
|
1171
1179
|
},
|
|
1172
1180
|
"v2/durable-core/domain/ack-advance-append-plan.d.ts": {
|
|
1173
1181
|
"sha256": "2e802606656a0c1938192e5533aa46c74bc42789b5c315c79f6de4850017b30e",
|
|
@@ -1310,8 +1318,8 @@
|
|
|
1310
1318
|
"bytes": 983
|
|
1311
1319
|
},
|
|
1312
1320
|
"v2/durable-core/domain/recap-recovery.js": {
|
|
1313
|
-
"sha256": "
|
|
1314
|
-
"bytes":
|
|
1321
|
+
"sha256": "4829d21e589ce5ed35beb9118eb07ffe05f6c1f18f6a20d7830b29ccc2da4e89",
|
|
1322
|
+
"bytes": 3034
|
|
1315
1323
|
},
|
|
1316
1324
|
"v2/durable-core/domain/recommendation-warnings.d.ts": {
|
|
1317
1325
|
"sha256": "a9f9e4c09f2ab72e858d8f4045201448a62cbf7b4b1070d0448498f858331222",
|
|
@@ -1614,8 +1622,8 @@
|
|
|
1614
1622
|
"bytes": 4285
|
|
1615
1623
|
},
|
|
1616
1624
|
"v2/durable-core/schemas/session/outputs.js": {
|
|
1617
|
-
"sha256": "
|
|
1618
|
-
"bytes":
|
|
1625
|
+
"sha256": "8ec5056762f2a0000ab2b1caf01b468f39695b778039c68ea85a9f42fccf3986",
|
|
1626
|
+
"bytes": 2156
|
|
1619
1627
|
},
|
|
1620
1628
|
"v2/durable-core/schemas/session/preferences.d.ts": {
|
|
1621
1629
|
"sha256": "763697078bda9fa8fb7a499978a94d85d1852f0fd8fc07af295ac895d25dba66",
|
|
@@ -1810,12 +1818,12 @@
|
|
|
1810
1818
|
"bytes": 28456
|
|
1811
1819
|
},
|
|
1812
1820
|
"v2/infra/local/session-summary-provider/index.d.ts": {
|
|
1813
|
-
"sha256": "
|
|
1814
|
-
"bytes":
|
|
1821
|
+
"sha256": "59db8bf5e38f983eedd21ff902a24324f7bedbb5f3eade1e4b0d5742b28447c2",
|
|
1822
|
+
"bytes": 1004
|
|
1815
1823
|
},
|
|
1816
1824
|
"v2/infra/local/session-summary-provider/index.js": {
|
|
1817
|
-
"sha256": "
|
|
1818
|
-
"bytes":
|
|
1825
|
+
"sha256": "f6c0df4a3355241ee3eb83c0013f9a252479f27f4c9172e0607464339fba6920",
|
|
1826
|
+
"bytes": 5655
|
|
1819
1827
|
},
|
|
1820
1828
|
"v2/infra/local/sha256/index.d.ts": {
|
|
1821
1829
|
"sha256": "8a727b7e54a38275ca6f9f1b8730f97cfc0a212df035df1bdc58e716e6824230",
|
|
@@ -1850,12 +1858,12 @@
|
|
|
1850
1858
|
"bytes": 304
|
|
1851
1859
|
},
|
|
1852
1860
|
"v2/infra/local/workspace-anchor/index.d.ts": {
|
|
1853
|
-
"sha256": "
|
|
1854
|
-
"bytes":
|
|
1861
|
+
"sha256": "ac5cfe8d36fab1bcff8ee1e4c13cd4b8f20b7cf109647b76bfb74e720b9eda41",
|
|
1862
|
+
"bytes": 537
|
|
1855
1863
|
},
|
|
1856
1864
|
"v2/infra/local/workspace-anchor/index.js": {
|
|
1857
|
-
"sha256": "
|
|
1858
|
-
"bytes":
|
|
1865
|
+
"sha256": "a0fe032a9205606c6d592221f1300a3113c7d0cb3e126e458fef3dc8fa6e823c",
|
|
1866
|
+
"bytes": 2272
|
|
1859
1867
|
},
|
|
1860
1868
|
"v2/ports/base32.port.d.ts": {
|
|
1861
1869
|
"sha256": "64aa2f2003a552917cbf71474472fc5e4afffaa29577204bbcbe5ffa989ceb82",
|
|
@@ -1994,8 +2002,8 @@
|
|
|
1994
2002
|
"bytes": 77
|
|
1995
2003
|
},
|
|
1996
2004
|
"v2/ports/workspace-anchor.port.d.ts": {
|
|
1997
|
-
"sha256": "
|
|
1998
|
-
"bytes":
|
|
2005
|
+
"sha256": "8614bc27a958291d53d6a24ffc30fdf5352d98f02b79470993d6c134e72d83eb",
|
|
2006
|
+
"bytes": 751
|
|
1999
2007
|
},
|
|
2000
2008
|
"v2/ports/workspace-anchor.port.js": {
|
|
2001
2009
|
"sha256": "d43aa81f5bc89faa359e0f97c814ba25155591ff078fbb9bfd40f8c7c9683230",
|
|
@@ -2014,8 +2022,8 @@
|
|
|
2014
2022
|
"bytes": 955
|
|
2015
2023
|
},
|
|
2016
2024
|
"v2/projections/artifacts.js": {
|
|
2017
|
-
"sha256": "
|
|
2018
|
-
"bytes":
|
|
2025
|
+
"sha256": "eb06aff128112850fdc8b3bfafae759500ca65aed279f096a077e000a9a1bf99",
|
|
2026
|
+
"bytes": 2033
|
|
2019
2027
|
},
|
|
2020
2028
|
"v2/projections/capabilities.d.ts": {
|
|
2021
2029
|
"sha256": "ee4c4bb728b5fc7343a43c9bb13a981a9bf0bd1b39e68ff8c866b4119012eac1",
|
|
@@ -84,7 +84,7 @@ function buildNotesOutputs(allowNotesAppend, attemptId, inputOutput) {
|
|
|
84
84
|
outputId: String((0, index_js_1.asOutputId)(`out_recap_${String(attemptId)}`)),
|
|
85
85
|
outputChannel: constants_js_1.OUTPUT_CHANNEL.RECAP,
|
|
86
86
|
payload: {
|
|
87
|
-
payloadKind:
|
|
87
|
+
payloadKind: constants_js_1.PAYLOAD_KIND.NOTES,
|
|
88
88
|
notesMarkdown: (0, notes_markdown_js_1.toNotesMarkdownV1)(inputOutput.notesMarkdown),
|
|
89
89
|
},
|
|
90
90
|
}];
|
|
@@ -102,7 +102,7 @@ function buildArtifactOutputs(inputArtifacts, attemptId, sha256) {
|
|
|
102
102
|
outputId: (0, index_js_1.asOutputId)(`out_artifact_${String(attemptId)}_${idx}`),
|
|
103
103
|
outputChannel: constants_js_1.OUTPUT_CHANNEL.ARTIFACT,
|
|
104
104
|
payload: {
|
|
105
|
-
payloadKind:
|
|
105
|
+
payloadKind: constants_js_1.PAYLOAD_KIND.ARTIFACT_REF,
|
|
106
106
|
sha256: sha256.sha256(canonicalBytes),
|
|
107
107
|
contentType: 'application/json',
|
|
108
108
|
byteLength: canonicalBytes.length,
|
|
@@ -158,7 +158,7 @@ function collectArtifactsForEvaluation(args) {
|
|
|
158
158
|
continue;
|
|
159
159
|
if (e.data.outputChannel !== constants_js_1.OUTPUT_CHANNEL.ARTIFACT)
|
|
160
160
|
continue;
|
|
161
|
-
if (e.data.payload.payloadKind !==
|
|
161
|
+
if (e.data.payload.payloadKind !== constants_js_1.PAYLOAD_KIND.ARTIFACT_REF)
|
|
162
162
|
continue;
|
|
163
163
|
const payload = e.data.payload;
|
|
164
164
|
if (payload.content === undefined)
|
|
@@ -16,6 +16,7 @@ const observation_builder_js_1 = require("../../../v2/durable-core/domain/observ
|
|
|
16
16
|
const workflow_source_js_1 = require("../../../types/workflow-source.js");
|
|
17
17
|
const workflow_definition_js_1 = require("../../../types/workflow-definition.js");
|
|
18
18
|
const v2_execution_helpers_js_1 = require("../v2-execution-helpers.js");
|
|
19
|
+
const v2_workspace_resolution_js_1 = require("../v2-workspace-resolution.js");
|
|
19
20
|
const v2_token_ops_js_1 = require("../v2-token-ops.js");
|
|
20
21
|
const v2_state_conversion_js_1 = require("../v2-state-conversion.js");
|
|
21
22
|
const v2_execution_helpers_js_2 = require("../v2-execution-helpers.js");
|
|
@@ -229,15 +230,8 @@ function executeStartWorkflow(input, ctx) {
|
|
|
229
230
|
pinnedStore,
|
|
230
231
|
})
|
|
231
232
|
.andThen(({ workflow, firstStep, workflowHash, pinnedWorkflow }) => {
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
const anchorsRA = workspaceResolver
|
|
235
|
-
? (primaryRootUri
|
|
236
|
-
? workspaceResolver.resolveFromUri(primaryRootUri)
|
|
237
|
-
: workspaceResolver.resolveFromCwd())
|
|
238
|
-
.map((anchors) => (0, observation_builder_js_1.anchorsToObservations)(anchors))
|
|
239
|
-
.orElse(() => (0, neverthrow_1.okAsync)([]))
|
|
240
|
-
: (0, neverthrow_1.okAsync)([]);
|
|
233
|
+
const anchorsRA = (0, v2_workspace_resolution_js_1.resolveWorkspaceAnchors)(ctx.v2, input.workspacePath)
|
|
234
|
+
.map((anchors) => (0, observation_builder_js_1.anchorsToObservations)(anchors));
|
|
241
235
|
return anchorsRA.andThen((observations) => {
|
|
242
236
|
const sessionId = idFactory.mintSessionId();
|
|
243
237
|
const runId = idFactory.mintRunId();
|
|
@@ -6,6 +6,7 @@ const output_schemas_js_1 = require("../output-schemas.js");
|
|
|
6
6
|
const v2_token_ops_js_1 = require("./v2-token-ops.js");
|
|
7
7
|
const index_js_1 = require("../../v2/durable-core/ids/index.js");
|
|
8
8
|
const resume_session_js_1 = require("../../v2/usecases/resume-session.js");
|
|
9
|
+
const v2_workspace_resolution_js_1 = require("./v2-workspace-resolution.js");
|
|
9
10
|
function anchorValue(anchors, key) {
|
|
10
11
|
const anchor = anchors.find((a) => a.key === key);
|
|
11
12
|
return anchor?.value;
|
|
@@ -18,16 +19,8 @@ async function handleV2ResumeSession(input, ctx) {
|
|
|
18
19
|
if (!v2.sessionSummaryProvider) {
|
|
19
20
|
return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', 'resume_session requires sessionSummaryProvider port');
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const primaryRootUri = v2.resolvedRootUris?.[0];
|
|
24
|
-
const anchorRes = await (primaryRootUri
|
|
25
|
-
? v2.workspaceResolver.resolveFromUri(primaryRootUri)
|
|
26
|
-
: v2.workspaceResolver.resolveFromCwd());
|
|
27
|
-
if (anchorRes.isOk()) {
|
|
28
|
-
anchors = anchorRes.value;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
22
|
+
const anchorsResult = await (0, v2_workspace_resolution_js_1.resolveWorkspaceAnchors)(v2, input.workspacePath);
|
|
23
|
+
const anchors = anchorsResult.isOk() ? anchorsResult.value : [];
|
|
31
24
|
const query = {
|
|
32
25
|
gitHeadSha: input.gitHeadSha ?? anchorValue(anchors, 'git_head_sha'),
|
|
33
26
|
gitBranch: input.gitBranch ?? anchorValue(anchors, 'git_branch'),
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ResultAsync } from 'neverthrow';
|
|
2
|
+
import type { WorkspaceAnchor, WorkspaceSource } from '../../v2/ports/workspace-anchor.port.js';
|
|
3
|
+
import type { V2Dependencies } from '../types.js';
|
|
4
|
+
export declare function selectWorkspaceSource(workspacePath: string | undefined, resolvedRootUris: readonly string[]): WorkspaceSource;
|
|
5
|
+
export declare function resolveWorkspaceAnchors(v2: V2Dependencies, workspacePath: string | undefined): ResultAsync<readonly WorkspaceAnchor[], never>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.selectWorkspaceSource = selectWorkspaceSource;
|
|
4
|
+
exports.resolveWorkspaceAnchors = resolveWorkspaceAnchors;
|
|
5
|
+
const neverthrow_1 = require("neverthrow");
|
|
6
|
+
function selectWorkspaceSource(workspacePath, resolvedRootUris) {
|
|
7
|
+
if (workspacePath !== undefined) {
|
|
8
|
+
return { kind: 'explicit_path', path: workspacePath };
|
|
9
|
+
}
|
|
10
|
+
const primaryUri = resolvedRootUris[0];
|
|
11
|
+
if (primaryUri !== undefined) {
|
|
12
|
+
return { kind: 'mcp_root_uri', uri: primaryUri };
|
|
13
|
+
}
|
|
14
|
+
return { kind: 'server_cwd' };
|
|
15
|
+
}
|
|
16
|
+
function resolveWorkspaceAnchors(v2, workspacePath) {
|
|
17
|
+
if (!v2.workspaceResolver)
|
|
18
|
+
return (0, neverthrow_1.okAsync)([]);
|
|
19
|
+
const source = selectWorkspaceSource(workspacePath, v2.resolvedRootUris ?? []);
|
|
20
|
+
return v2.workspaceResolver.resolve(source)
|
|
21
|
+
.orElse(() => (0, neverthrow_1.okAsync)([]));
|
|
22
|
+
}
|
|
@@ -75,6 +75,8 @@ What to do:
|
|
|
75
75
|
3. Optionally add output.notesMarkdown summarizing your work
|
|
76
76
|
4. Don't predict what comes next - the workflow will tell you
|
|
77
77
|
|
|
78
|
+
Workspace anchoring: Pass workspacePath (the "Workspace:" path from your system parameters) so this session can be found by resume_session in future chats. Without it, session discovery may not work.
|
|
79
|
+
|
|
78
80
|
Context auto-loads: If you provide context at start, WorkRail remembers it. On future continue_workflow calls, only pass context if you have NEW information to add.`,
|
|
79
81
|
continue_workflow: `Get the next step in the workflow (WorkRail v2, feature-flagged).
|
|
80
82
|
|
|
@@ -130,6 +132,8 @@ Returns: checkpointNodeId + a fresh stateToken.`,
|
|
|
130
132
|
|
|
131
133
|
Use this when you need to resume a previously started workflow but don't have the stateToken (e.g., new chat, lost context).
|
|
132
134
|
|
|
135
|
+
Pass workspacePath (the "Workspace:" path from your system parameters) to match sessions anchored to your current workspace. Without it, git-based tier matching won't work.
|
|
136
|
+
|
|
133
137
|
WorkRail ranks sessions using a 5-tier matching algorithm:
|
|
134
138
|
1. Exact git HEAD SHA match
|
|
135
139
|
2. Git branch match (exact or prefix)
|
|
@@ -225,6 +229,11 @@ REQUIRED BEHAVIOR:
|
|
|
225
229
|
4. Round-trip tokens UNCHANGED (don't decode, inspect, or modify them)
|
|
226
230
|
5. Follow the workflow to completion - don't improvise alternative approaches
|
|
227
231
|
|
|
232
|
+
Workspace anchoring (IMPORTANT):
|
|
233
|
+
- Pass workspacePath set to the "Workspace:" value from your system parameters
|
|
234
|
+
- This anchors the session to your workspace so resume_session can find it in future chats
|
|
235
|
+
- Example: workspacePath: "/Users/you/git/my-project"
|
|
236
|
+
|
|
228
237
|
Context handling:
|
|
229
238
|
- Pass context at start to establish baseline facts
|
|
230
239
|
- WorkRail auto-loads context on subsequent calls
|
|
@@ -295,6 +304,10 @@ Call this when resuming a workflow without a stateToken. WorkRail ranks sessions
|
|
|
295
304
|
4. Workflow ID match (tier 4)
|
|
296
305
|
5. Recency (tier 5)
|
|
297
306
|
|
|
307
|
+
IMPORTANT: Pass workspacePath set to the "Workspace:" value from your system parameters.
|
|
308
|
+
Without it, tier 1 and tier 2 matching won't work (git context defaults to server directory, not yours).
|
|
309
|
+
Example: workspacePath: "/Users/you/git/my-project"
|
|
310
|
+
|
|
298
311
|
Returns: Up to 5 candidates with stateTokens. Use the best match's stateToken with continue_workflow.`,
|
|
299
312
|
},
|
|
300
313
|
};
|
package/dist/mcp/v2/tools.d.ts
CHANGED
|
@@ -16,12 +16,15 @@ export type V2InspectWorkflowInput = z.infer<typeof V2InspectWorkflowInput>;
|
|
|
16
16
|
export declare const V2StartWorkflowInput: z.ZodObject<{
|
|
17
17
|
workflowId: z.ZodString;
|
|
18
18
|
context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
19
|
+
workspacePath: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
19
20
|
}, "strip", z.ZodTypeAny, {
|
|
20
21
|
workflowId: string;
|
|
21
22
|
context?: Record<string, unknown> | undefined;
|
|
23
|
+
workspacePath?: string | undefined;
|
|
22
24
|
}, {
|
|
23
25
|
workflowId: string;
|
|
24
26
|
context?: Record<string, unknown> | undefined;
|
|
27
|
+
workspacePath?: string | undefined;
|
|
25
28
|
}>;
|
|
26
29
|
export type V2StartWorkflowInput = z.infer<typeof V2StartWorkflowInput>;
|
|
27
30
|
export declare const V2ContinueWorkflowInput: z.ZodPipeline<z.ZodEffects<z.ZodObject<{
|
|
@@ -119,12 +122,15 @@ export declare const V2ResumeSessionInput: z.ZodObject<{
|
|
|
119
122
|
query: z.ZodOptional<z.ZodString>;
|
|
120
123
|
gitBranch: z.ZodOptional<z.ZodString>;
|
|
121
124
|
gitHeadSha: z.ZodOptional<z.ZodString>;
|
|
125
|
+
workspacePath: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
122
126
|
}, "strict", z.ZodTypeAny, {
|
|
123
127
|
query?: string | undefined;
|
|
128
|
+
workspacePath?: string | undefined;
|
|
124
129
|
gitBranch?: string | undefined;
|
|
125
130
|
gitHeadSha?: string | undefined;
|
|
126
131
|
}, {
|
|
127
132
|
query?: string | undefined;
|
|
133
|
+
workspacePath?: string | undefined;
|
|
128
134
|
gitBranch?: string | undefined;
|
|
129
135
|
gitHeadSha?: string | undefined;
|
|
130
136
|
}>;
|
package/dist/mcp/v2/tools.js
CHANGED
|
@@ -10,6 +10,10 @@ exports.V2InspectWorkflowInput = zod_1.z.object({
|
|
|
10
10
|
exports.V2StartWorkflowInput = zod_1.z.object({
|
|
11
11
|
workflowId: zod_1.z.string().min(1).regex(/^[A-Za-z0-9_-]+$/, 'Workflow ID must contain only letters, numbers, hyphens, and underscores').describe('The workflow ID to start'),
|
|
12
12
|
context: zod_1.z.record(zod_1.z.unknown()).optional().describe('External facts influencing execution (ticketId, branch, constraints). Pass once at start to establish baseline. WorkRail auto-loads context on subsequent continue_workflow calls. Only pass context again if facts have CHANGED (e.g., user provided new information). Do NOT re-pass unchanged values.'),
|
|
13
|
+
workspacePath: zod_1.z.string()
|
|
14
|
+
.refine((p) => p.startsWith('/'), 'workspacePath must be an absolute path (starting with /)')
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('Absolute path to your current workspace directory (e.g. the "Workspace:" value from your system parameters). Used to anchor this session to your workspace for future resume_session discovery. Pass this on every start_workflow call. If omitted, WorkRail uses the server process directory which may not match your workspace.'),
|
|
13
17
|
});
|
|
14
18
|
exports.V2ContinueWorkflowInput = zod_1.z.object({
|
|
15
19
|
intent: zod_1.z.enum(['advance', 'rehydrate']).optional().describe('What you want to do. Auto-inferred from ackToken if omitted: ' +
|
|
@@ -62,6 +66,10 @@ exports.V2ResumeSessionInput = zod_1.z.object({
|
|
|
62
66
|
query: zod_1.z.string().max(256).optional().describe('Free text search to find a relevant session. Matches against recap notes and workflow IDs.'),
|
|
63
67
|
gitBranch: zod_1.z.string().max(256).optional().describe('Git branch name to match against session observations. Overrides auto-detected branch.'),
|
|
64
68
|
gitHeadSha: zod_1.z.string().regex(/^[0-9a-f]{40}$/).optional().describe('Git HEAD SHA to match against session observations. Overrides auto-detected HEAD.'),
|
|
69
|
+
workspacePath: zod_1.z.string()
|
|
70
|
+
.refine((p) => p.startsWith('/'), 'workspacePath must be an absolute path (starting with /)')
|
|
71
|
+
.optional()
|
|
72
|
+
.describe('Absolute path to your current workspace directory (e.g. the "Workspace:" value from your system parameters). Used to resolve your git branch and HEAD SHA for workspace-aware session matching. Pass the same path used in the original start_workflow call. If omitted, WorkRail uses the server process directory which may not match your workspace.'),
|
|
65
73
|
}).strict();
|
|
66
74
|
exports.V2CheckpointWorkflowInput = zod_1.z.object({
|
|
67
75
|
checkpointToken: zod_1.z.string().min(1).describe('The checkpoint token from the most recent start_workflow or continue_workflow response. ' +
|
|
@@ -40,6 +40,11 @@ export declare const OUTPUT_CHANNEL: {
|
|
|
40
40
|
readonly ARTIFACT: "artifact";
|
|
41
41
|
};
|
|
42
42
|
export type OutputChannelV1 = typeof OUTPUT_CHANNEL[keyof typeof OUTPUT_CHANNEL];
|
|
43
|
+
export declare const PAYLOAD_KIND: {
|
|
44
|
+
readonly NOTES: "notes";
|
|
45
|
+
readonly ARTIFACT_REF: "artifact_ref";
|
|
46
|
+
};
|
|
47
|
+
export type PayloadKindV1 = typeof PAYLOAD_KIND[keyof typeof PAYLOAD_KIND];
|
|
43
48
|
export declare const EDGE_KIND: {
|
|
44
49
|
readonly ACKED_STEP: "acked_step";
|
|
45
50
|
readonly CHECKPOINT: "checkpoint";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AUTONOMY_MODE = exports.ADVANCE_INTENT = exports.MANIFEST_KIND = exports.EDGE_CAUSE = exports.ADVANCE_OUTCOME = exports.ENGINE_STATE = exports.EDGE_KIND = exports.OUTPUT_CHANNEL = exports.EVENT_KIND = exports.DELIMITER_SAFE_ID_PATTERN = exports.SHA256_DIGEST_PATTERN = exports.RECOVERY_BUDGET_BYTES = exports.TRUNCATION_MARKER = exports.DEFAULT_RETRY_AFTER_MS = exports.SESSION_LOCK_RETRY_AFTER_MS = exports.MAX_OBSERVATION_SHORT_STRING_LENGTH = exports.MAX_CONTEXT_DEPTH = exports.MAX_CONTEXT_BYTES = exports.MAX_VALIDATION_SUGGESTIONS_BYTES = exports.MAX_VALIDATION_ISSUES_BYTES = exports.MAX_VALIDATION_SUGGESTION_ITEM_BYTES = exports.MAX_VALIDATION_ISSUE_ITEM_BYTES = exports.MAX_OUTPUT_NOTES_MARKDOWN_BYTES = exports.MAX_DECISION_TRACE_TOTAL_BYTES = exports.MAX_DECISION_TRACE_ENTRY_SUMMARY_BYTES = exports.MAX_DECISION_TRACE_ENTRIES = exports.MAX_BLOCKER_SUGGESTED_FIX_BYTES = exports.MAX_BLOCKER_MESSAGE_BYTES = exports.MAX_BLOCKERS = void 0;
|
|
3
|
+
exports.AUTONOMY_MODE = exports.ADVANCE_INTENT = exports.MANIFEST_KIND = exports.EDGE_CAUSE = exports.ADVANCE_OUTCOME = exports.ENGINE_STATE = exports.EDGE_KIND = exports.PAYLOAD_KIND = exports.OUTPUT_CHANNEL = exports.EVENT_KIND = exports.DELIMITER_SAFE_ID_PATTERN = exports.SHA256_DIGEST_PATTERN = exports.RECOVERY_BUDGET_BYTES = exports.TRUNCATION_MARKER = exports.DEFAULT_RETRY_AFTER_MS = exports.SESSION_LOCK_RETRY_AFTER_MS = exports.MAX_OBSERVATION_SHORT_STRING_LENGTH = exports.MAX_CONTEXT_DEPTH = exports.MAX_CONTEXT_BYTES = exports.MAX_VALIDATION_SUGGESTIONS_BYTES = exports.MAX_VALIDATION_ISSUES_BYTES = exports.MAX_VALIDATION_SUGGESTION_ITEM_BYTES = exports.MAX_VALIDATION_ISSUE_ITEM_BYTES = exports.MAX_OUTPUT_NOTES_MARKDOWN_BYTES = exports.MAX_DECISION_TRACE_TOTAL_BYTES = exports.MAX_DECISION_TRACE_ENTRY_SUMMARY_BYTES = exports.MAX_DECISION_TRACE_ENTRIES = exports.MAX_BLOCKER_SUGGESTED_FIX_BYTES = exports.MAX_BLOCKER_MESSAGE_BYTES = exports.MAX_BLOCKERS = void 0;
|
|
4
4
|
exports.MAX_BLOCKERS = 10;
|
|
5
5
|
exports.MAX_BLOCKER_MESSAGE_BYTES = 512;
|
|
6
6
|
exports.MAX_BLOCKER_SUGGESTED_FIX_BYTES = 1024;
|
|
@@ -41,6 +41,10 @@ exports.OUTPUT_CHANNEL = {
|
|
|
41
41
|
RECAP: 'recap',
|
|
42
42
|
ARTIFACT: 'artifact',
|
|
43
43
|
};
|
|
44
|
+
exports.PAYLOAD_KIND = {
|
|
45
|
+
NOTES: 'notes',
|
|
46
|
+
ARTIFACT_REF: 'artifact_ref',
|
|
47
|
+
};
|
|
44
48
|
exports.EDGE_KIND = {
|
|
45
49
|
ACKED_STEP: 'acked_step',
|
|
46
50
|
CHECKPOINT: 'checkpoint',
|
|
@@ -4,6 +4,7 @@ exports.collectAncestryRecap = collectAncestryRecap;
|
|
|
4
4
|
exports.collectDownstreamRecap = collectDownstreamRecap;
|
|
5
5
|
exports.buildChildSummary = buildChildSummary;
|
|
6
6
|
const neverthrow_1 = require("neverthrow");
|
|
7
|
+
const constants_js_1 = require("../constants.js");
|
|
7
8
|
function collectAncestryRecap(args) {
|
|
8
9
|
const buildChain = (cur, visited) => {
|
|
9
10
|
if (!cur || visited.has(cur))
|
|
@@ -22,9 +23,9 @@ function collectAncestryRecap(args) {
|
|
|
22
23
|
if (!nodeOutputs)
|
|
23
24
|
return [];
|
|
24
25
|
return nodeOutputs.currentByChannel.recap
|
|
25
|
-
.filter(r => r.payload.payloadKind ===
|
|
26
|
+
.filter(r => r.payload.payloadKind === constants_js_1.PAYLOAD_KIND.NOTES)
|
|
26
27
|
.map(r => {
|
|
27
|
-
if (r.payload.payloadKind ===
|
|
28
|
+
if (r.payload.payloadKind === constants_js_1.PAYLOAD_KIND.NOTES) {
|
|
28
29
|
return r.payload.notesMarkdown;
|
|
29
30
|
}
|
|
30
31
|
return '';
|
|
@@ -48,9 +49,9 @@ function collectDownstreamRecap(args) {
|
|
|
48
49
|
if (!nodeOutputs)
|
|
49
50
|
return [];
|
|
50
51
|
return nodeOutputs.currentByChannel.recap
|
|
51
|
-
.filter(r => r.payload.payloadKind ===
|
|
52
|
+
.filter(r => r.payload.payloadKind === constants_js_1.PAYLOAD_KIND.NOTES)
|
|
52
53
|
.map(r => {
|
|
53
|
-
if (r.payload.payloadKind ===
|
|
54
|
+
if (r.payload.payloadKind === constants_js_1.PAYLOAD_KIND.NOTES) {
|
|
54
55
|
return r.payload.notesMarkdown;
|
|
55
56
|
}
|
|
56
57
|
return '';
|
|
@@ -10,7 +10,7 @@ const sha256DigestSchema = zod_1.z
|
|
|
10
10
|
.describe('sha256 digest in WorkRail v2 format');
|
|
11
11
|
exports.OutputChannelSchema = zod_1.z.enum(['recap', 'artifact']);
|
|
12
12
|
exports.NotesPayloadV1Schema = zod_1.z.object({
|
|
13
|
-
payloadKind: zod_1.z.literal(
|
|
13
|
+
payloadKind: zod_1.z.literal(constants_js_1.PAYLOAD_KIND.NOTES),
|
|
14
14
|
notesMarkdown: zod_1.z
|
|
15
15
|
.string()
|
|
16
16
|
.min(1)
|
|
@@ -19,7 +19,7 @@ exports.NotesPayloadV1Schema = zod_1.z.object({
|
|
|
19
19
|
}),
|
|
20
20
|
});
|
|
21
21
|
exports.ArtifactRefPayloadV1Schema = zod_1.z.object({
|
|
22
|
-
payloadKind: zod_1.z.literal(
|
|
22
|
+
payloadKind: zod_1.z.literal(constants_js_1.PAYLOAD_KIND.ARTIFACT_REF),
|
|
23
23
|
sha256: sha256DigestSchema,
|
|
24
24
|
contentType: zod_1.z.string().min(1),
|
|
25
25
|
byteLength: zod_1.z.number().int().nonnegative(),
|
|
@@ -34,7 +34,7 @@ exports.NodeOutputAppendedDataV1Schema = zod_1.z
|
|
|
34
34
|
payload: exports.OutputPayloadV1Schema,
|
|
35
35
|
})
|
|
36
36
|
.superRefine((v, ctx) => {
|
|
37
|
-
if (v.outputChannel ===
|
|
37
|
+
if (v.outputChannel === constants_js_1.OUTPUT_CHANNEL.RECAP && v.payload.payloadKind !== constants_js_1.PAYLOAD_KIND.NOTES) {
|
|
38
38
|
ctx.addIssue({
|
|
39
39
|
code: zod_1.z.ZodIssueCode.custom,
|
|
40
40
|
message: 'outputChannel=recap requires payloadKind=notes',
|
|
@@ -13,6 +13,4 @@ export declare class LocalSessionSummaryProviderV2 implements SessionSummaryProv
|
|
|
13
13
|
private readonly ports;
|
|
14
14
|
constructor(ports: LocalSessionSummaryProviderPorts);
|
|
15
15
|
loadHealthySummaries(): ResultAsync<readonly HealthySessionSummary[], SessionSummaryError>;
|
|
16
|
-
private collectHealthySummaries;
|
|
17
|
-
private tryLoadSummary;
|
|
18
16
|
}
|
|
@@ -9,6 +9,16 @@ const run_dag_js_1 = require("../../../projections/run-dag.js");
|
|
|
9
9
|
const node_outputs_js_1 = require("../../../projections/node-outputs.js");
|
|
10
10
|
const constants_js_1 = require("../../../durable-core/constants.js");
|
|
11
11
|
const MAX_SESSIONS_TO_SCAN = 50;
|
|
12
|
+
const MAX_RECAP_ANCESTOR_DEPTH = 100;
|
|
13
|
+
const EMPTY_OBSERVATIONS = {
|
|
14
|
+
gitHeadSha: null,
|
|
15
|
+
gitBranch: null,
|
|
16
|
+
repoRootHash: null,
|
|
17
|
+
};
|
|
18
|
+
const UNKNOWN_WORKFLOW = {
|
|
19
|
+
workflowId: null,
|
|
20
|
+
workflowName: null,
|
|
21
|
+
};
|
|
12
22
|
class LocalSessionSummaryProviderV2 {
|
|
13
23
|
constructor(ports) {
|
|
14
24
|
this.ports = ports;
|
|
@@ -22,123 +32,107 @@ class LocalSessionSummaryProviderV2 {
|
|
|
22
32
|
code: 'SESSION_SUMMARY_ENUMERATION_FAILED',
|
|
23
33
|
message: `Failed to enumerate sessions: ${fsErr.message}`,
|
|
24
34
|
}))
|
|
25
|
-
.andThen((sessionIds) =>
|
|
26
|
-
const capped = sessionIds.slice(0, MAX_SESSIONS_TO_SCAN);
|
|
27
|
-
return this.collectHealthySummaries(capped);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
collectHealthySummaries(sessionIds) {
|
|
31
|
-
const summaries = [];
|
|
32
|
-
let chain = (0, neverthrow_1.okAsync)(undefined);
|
|
33
|
-
for (const sessionId of sessionIds) {
|
|
34
|
-
chain = chain.andThen(() => this.tryLoadSummary(sessionId).map((summary) => {
|
|
35
|
-
if (summary !== null) {
|
|
36
|
-
summaries.push(summary);
|
|
37
|
-
}
|
|
38
|
-
}));
|
|
39
|
-
}
|
|
40
|
-
return chain.map(() => summaries);
|
|
41
|
-
}
|
|
42
|
-
tryLoadSummary(sessionId) {
|
|
43
|
-
return this.ports.sessionStore
|
|
44
|
-
.load(sessionId)
|
|
45
|
-
.map((truth) => {
|
|
46
|
-
const healthRes = (0, session_health_js_1.projectSessionHealthV2)(truth);
|
|
47
|
-
if (healthRes.isErr())
|
|
48
|
-
return null;
|
|
49
|
-
if (healthRes.value.kind !== 'healthy')
|
|
50
|
-
return null;
|
|
51
|
-
const dagRes = (0, run_dag_js_1.projectRunDagV2)(truth.events);
|
|
52
|
-
if (dagRes.isErr())
|
|
53
|
-
return null;
|
|
54
|
-
const runs = Object.values(dagRes.value.runsById);
|
|
55
|
-
if (runs.length === 0)
|
|
56
|
-
return null;
|
|
57
|
-
const runsWithActivity = runs
|
|
58
|
-
.filter((r) => r.preferredTipNodeId !== null)
|
|
59
|
-
.map((r) => {
|
|
60
|
-
const tipNode = r.nodesById[r.preferredTipNodeId];
|
|
61
|
-
const maxEventIndex = tipNode ? tipNode.createdAtEventIndex : 0;
|
|
62
|
-
return { run: r, lastActivityEventIndex: maxEventIndex };
|
|
63
|
-
})
|
|
64
|
-
.sort((a, b) => b.lastActivityEventIndex - a.lastActivityEventIndex);
|
|
65
|
-
if (runsWithActivity.length === 0)
|
|
66
|
-
return null;
|
|
67
|
-
const bestRun = runsWithActivity[0];
|
|
68
|
-
const run = bestRun.run;
|
|
69
|
-
const outputsRes = (0, node_outputs_js_1.projectNodeOutputsV2)(truth.events);
|
|
70
|
-
const recapSnippet = outputsRes.isOk() && run.preferredTipNodeId
|
|
71
|
-
? extractRecapFromOutputs(outputsRes.value, run.preferredTipNodeId)
|
|
72
|
-
: null;
|
|
73
|
-
const observations = extractObservations(truth.events);
|
|
74
|
-
const workflow = extractWorkflowIdentity(truth.events, run.runId);
|
|
75
|
-
return {
|
|
76
|
-
sessionId,
|
|
77
|
-
runId: run.runId,
|
|
78
|
-
preferredTip: {
|
|
79
|
-
nodeId: run.preferredTipNodeId,
|
|
80
|
-
lastActivityEventIndex: bestRun.lastActivityEventIndex,
|
|
81
|
-
},
|
|
82
|
-
recapSnippet,
|
|
83
|
-
observations,
|
|
84
|
-
workflow,
|
|
85
|
-
};
|
|
86
|
-
})
|
|
87
|
-
.orElse(() => (0, neverthrow_1.okAsync)(null));
|
|
35
|
+
.andThen((sessionIds) => collectHealthySummaries(sessionIds.slice(0, MAX_SESSIONS_TO_SCAN), this.ports.sessionStore));
|
|
88
36
|
}
|
|
89
37
|
}
|
|
90
38
|
exports.LocalSessionSummaryProviderV2 = LocalSessionSummaryProviderV2;
|
|
91
|
-
function
|
|
92
|
-
|
|
93
|
-
|
|
39
|
+
function collectHealthySummaries(sessionIds, sessionStore) {
|
|
40
|
+
return sessionIds.reduce((acc, sessionId) => acc.andThen((summaries) => loadSessionSummary(sessionId, sessionStore).map((summary) => summary !== null ? [...summaries, summary] : summaries)), (0, neverthrow_1.okAsync)([]));
|
|
41
|
+
}
|
|
42
|
+
function loadSessionSummary(sessionId, sessionStore) {
|
|
43
|
+
return sessionStore
|
|
44
|
+
.load(sessionId)
|
|
45
|
+
.map((truth) => projectSessionSummary(sessionId, truth))
|
|
46
|
+
.orElse(() => (0, neverthrow_1.okAsync)(null));
|
|
47
|
+
}
|
|
48
|
+
function projectSessionSummary(sessionId, truth) {
|
|
49
|
+
const health = (0, session_health_js_1.projectSessionHealthV2)(truth);
|
|
50
|
+
if (health.isErr() || health.value.kind !== 'healthy')
|
|
94
51
|
return null;
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
52
|
+
const dag = (0, run_dag_js_1.projectRunDagV2)(truth.events);
|
|
53
|
+
if (dag.isErr())
|
|
97
54
|
return null;
|
|
98
|
-
const
|
|
99
|
-
if (
|
|
55
|
+
const bestRun = selectBestRun(Object.values(dag.value.runsById));
|
|
56
|
+
if (!bestRun)
|
|
100
57
|
return null;
|
|
101
|
-
const
|
|
102
|
-
|
|
58
|
+
const outputsRes = (0, node_outputs_js_1.projectNodeOutputsV2)(truth.events);
|
|
59
|
+
const recapSnippet = outputsRes.isOk()
|
|
60
|
+
? extractAggregateRecap(outputsRes.value, bestRun.run, bestRun.tipNodeId)
|
|
61
|
+
: null;
|
|
62
|
+
return {
|
|
63
|
+
sessionId,
|
|
64
|
+
runId: bestRun.run.runId,
|
|
65
|
+
preferredTip: {
|
|
66
|
+
nodeId: bestRun.tipNodeId,
|
|
67
|
+
lastActivityEventIndex: bestRun.lastActivityEventIndex,
|
|
68
|
+
},
|
|
69
|
+
recapSnippet,
|
|
70
|
+
observations: extractObservations(truth.events),
|
|
71
|
+
workflow: extractWorkflowIdentity(truth.events, bestRun.run.runId),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function selectBestRun(runs) {
|
|
75
|
+
const runsWithTip = runs.flatMap((r) => {
|
|
76
|
+
const tipNodeId = r.preferredTipNodeId;
|
|
77
|
+
if (!tipNodeId)
|
|
78
|
+
return [];
|
|
79
|
+
const tipNode = r.nodesById[tipNodeId];
|
|
80
|
+
return [{ run: r, tipNodeId, lastActivityEventIndex: tipNode?.createdAtEventIndex ?? 0 }];
|
|
81
|
+
});
|
|
82
|
+
if (runsWithTip.length === 0)
|
|
103
83
|
return null;
|
|
104
|
-
return (
|
|
84
|
+
return runsWithTip.reduce((best, r) => r.lastActivityEventIndex > best.lastActivityEventIndex ? r : best);
|
|
105
85
|
}
|
|
106
86
|
function extractObservations(events) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
switch (data.key) {
|
|
115
|
-
case 'git_head_sha':
|
|
116
|
-
gitHeadSha = data.value.value;
|
|
117
|
-
break;
|
|
118
|
-
case 'git_branch':
|
|
119
|
-
gitBranch = data.value.value;
|
|
120
|
-
break;
|
|
121
|
-
case 'repo_root_hash':
|
|
122
|
-
repoRootHash = data.value.value;
|
|
123
|
-
break;
|
|
124
|
-
default:
|
|
125
|
-
break;
|
|
87
|
+
return events
|
|
88
|
+
.filter((e) => e.kind === constants_js_1.EVENT_KIND.OBSERVATION_RECORDED)
|
|
89
|
+
.reduce((acc, e) => {
|
|
90
|
+
switch (e.data.key) {
|
|
91
|
+
case 'git_head_sha': return { ...acc, gitHeadSha: e.data.value.value };
|
|
92
|
+
case 'git_branch': return { ...acc, gitBranch: e.data.value.value };
|
|
93
|
+
case 'repo_root_hash': return { ...acc, repoRootHash: e.data.value.value };
|
|
126
94
|
}
|
|
127
|
-
}
|
|
128
|
-
return { gitHeadSha, gitBranch, repoRootHash };
|
|
95
|
+
}, EMPTY_OBSERVATIONS);
|
|
129
96
|
}
|
|
130
97
|
function extractWorkflowIdentity(events, runId) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
98
|
+
const event = events
|
|
99
|
+
.filter((e) => e.kind === constants_js_1.EVENT_KIND.RUN_STARTED)
|
|
100
|
+
.find((e) => e.scope.runId === runId);
|
|
101
|
+
if (!event)
|
|
102
|
+
return UNKNOWN_WORKFLOW;
|
|
103
|
+
return {
|
|
104
|
+
workflowId: event.data.workflowId,
|
|
105
|
+
workflowName: null,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function collectAncestorNodeIds(nodesById, nodeId, remainingDepth) {
|
|
109
|
+
if (remainingDepth === 0)
|
|
110
|
+
return [nodeId];
|
|
111
|
+
const node = nodesById[nodeId];
|
|
112
|
+
if (!node)
|
|
113
|
+
return [nodeId];
|
|
114
|
+
const parentIds = node.parentNodeId
|
|
115
|
+
? collectAncestorNodeIds(nodesById, node.parentNodeId, remainingDepth - 1)
|
|
116
|
+
: [];
|
|
117
|
+
return [nodeId, ...parentIds];
|
|
118
|
+
}
|
|
119
|
+
function extractNodeRecapMarkdown(outputs, nodeId) {
|
|
120
|
+
const nodeView = outputs.nodesById[nodeId];
|
|
121
|
+
if (!nodeView)
|
|
122
|
+
return null;
|
|
123
|
+
const recapOutputs = nodeView.currentByChannel[constants_js_1.OUTPUT_CHANNEL.RECAP];
|
|
124
|
+
if (!recapOutputs || recapOutputs.length === 0)
|
|
125
|
+
return null;
|
|
126
|
+
const latest = recapOutputs.at(-1);
|
|
127
|
+
if (!latest || latest.payload.payloadKind !== constants_js_1.PAYLOAD_KIND.NOTES)
|
|
128
|
+
return null;
|
|
129
|
+
return latest.payload.notesMarkdown;
|
|
130
|
+
}
|
|
131
|
+
function extractAggregateRecap(outputs, run, tipNodeId) {
|
|
132
|
+
const parts = collectAncestorNodeIds(run.nodesById, tipNodeId, MAX_RECAP_ANCESTOR_DEPTH)
|
|
133
|
+
.map((nodeId) => extractNodeRecapMarkdown(outputs, nodeId))
|
|
134
|
+
.filter((md) => md !== null);
|
|
135
|
+
if (parts.length === 0)
|
|
136
|
+
return null;
|
|
137
|
+
return (0, resume_ranking_js_1.asRecapSnippet)(parts.join('\n\n'));
|
|
144
138
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { ResultAsync as RA } from 'neverthrow';
|
|
2
|
-
import type {
|
|
3
|
-
export declare class LocalWorkspaceAnchorV2 implements
|
|
2
|
+
import type { WorkspaceContextResolverPortV2, WorkspaceSource, WorkspaceAnchor, WorkspaceAnchorError } from '../../../ports/workspace-anchor.port.js';
|
|
3
|
+
export declare class LocalWorkspaceAnchorV2 implements WorkspaceContextResolverPortV2 {
|
|
4
4
|
private readonly defaultCwd;
|
|
5
5
|
constructor(defaultCwd: string);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
private resolveFromPath;
|
|
10
|
-
private resolve;
|
|
6
|
+
resolve(source: WorkspaceSource): RA<readonly WorkspaceAnchor[], WorkspaceAnchorError>;
|
|
7
|
+
private resolveGitIdentityAt;
|
|
8
|
+
private runGitCommands;
|
|
11
9
|
private gitCommand;
|
|
12
10
|
}
|
|
@@ -10,25 +10,27 @@ class LocalWorkspaceAnchorV2 {
|
|
|
10
10
|
constructor(defaultCwd) {
|
|
11
11
|
this.defaultCwd = defaultCwd;
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
resolve(source) {
|
|
14
|
+
switch (source.kind) {
|
|
15
|
+
case 'explicit_path':
|
|
16
|
+
return this.resolveGitIdentityAt(source.path);
|
|
17
|
+
case 'mcp_root_uri': {
|
|
18
|
+
const fsPath = uriToFsPath(source.uri);
|
|
19
|
+
if (fsPath === null)
|
|
20
|
+
return (0, neverthrow_1.okAsync)([]);
|
|
21
|
+
return this.resolveGitIdentityAt(fsPath);
|
|
22
|
+
}
|
|
23
|
+
case 'server_cwd':
|
|
24
|
+
return this.resolveGitIdentityAt(this.defaultCwd);
|
|
25
|
+
}
|
|
24
26
|
}
|
|
25
|
-
|
|
26
|
-
return neverthrow_1.ResultAsync.fromPromise(this.
|
|
27
|
+
resolveGitIdentityAt(cwd) {
|
|
28
|
+
return neverthrow_1.ResultAsync.fromPromise(this.runGitCommands(cwd), (cause) => ({
|
|
27
29
|
code: 'ANCHOR_RESOLVE_FAILED',
|
|
28
30
|
message: `Failed to resolve workspace anchors: ${String(cause)}`,
|
|
29
31
|
}));
|
|
30
32
|
}
|
|
31
|
-
async
|
|
33
|
+
async runGitCommands(cwd) {
|
|
32
34
|
const anchors = [];
|
|
33
35
|
const branch = await this.gitCommand('git rev-parse --abbrev-ref HEAD', cwd);
|
|
34
36
|
if (branch && branch !== 'HEAD') {
|
|
@@ -13,10 +13,15 @@ export type WorkspaceAnchorError = {
|
|
|
13
13
|
readonly code: 'ANCHOR_RESOLVE_FAILED';
|
|
14
14
|
readonly message: string;
|
|
15
15
|
};
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
export type WorkspaceSource = {
|
|
17
|
+
readonly kind: 'explicit_path';
|
|
18
|
+
readonly path: string;
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'mcp_root_uri';
|
|
21
|
+
readonly uri: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: 'server_cwd';
|
|
24
|
+
};
|
|
19
25
|
export interface WorkspaceContextResolverPortV2 {
|
|
20
|
-
|
|
21
|
-
resolveFromCwd(): ResultAsync<readonly WorkspaceAnchor[], WorkspaceAnchorError>;
|
|
26
|
+
resolve(source: WorkspaceSource): ResultAsync<readonly WorkspaceAnchor[], WorkspaceAnchorError>;
|
|
22
27
|
}
|
|
@@ -20,7 +20,7 @@ function projectArtifactsV2(events) {
|
|
|
20
20
|
if (e.data.outputChannel !== constants_js_1.OUTPUT_CHANNEL.ARTIFACT)
|
|
21
21
|
continue;
|
|
22
22
|
const payload = e.data.payload;
|
|
23
|
-
if (payload.payloadKind !==
|
|
23
|
+
if (payload.payloadKind !== constants_js_1.PAYLOAD_KIND.ARTIFACT_REF)
|
|
24
24
|
continue;
|
|
25
25
|
const contentPayload = payload;
|
|
26
26
|
if (contentPayload.content === undefined)
|