@exaudeus/workrail 3.7.2 → 3.7.4
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/engine/engine-factory.js +4 -1
- package/dist/manifest.json +26 -26
- package/dist/mcp/handlers/v2-execution/start.js +16 -7
- package/dist/mcp/handlers/v2-resume.js +6 -0
- package/dist/mcp/output-schemas.d.ts +25 -5
- package/dist/mcp/output-schemas.js +10 -4
- package/dist/mcp/v2/tools.d.ts +9 -6
- package/dist/mcp/v2/tools.js +23 -10
- package/dist/mcp/v2-response-formatter.js +24 -4
- package/dist/mcp/workflow-protocol-contracts.js +13 -10
- package/dist/v2/infra/local/session-summary-provider/index.js +77 -0
- package/dist/v2/infra/local/workspace-anchor/index.js +23 -0
- package/dist/v2/projections/resume-ranking.d.ts +16 -8
- package/dist/v2/projections/resume-ranking.js +210 -39
- package/package.json +1 -1
- package/workflows/workflow-for-workflows.v2.json +40 -16
|
@@ -240,7 +240,8 @@ async function createWorkRailEngine(config = {}) {
|
|
|
240
240
|
engineActive = true;
|
|
241
241
|
const engine = {
|
|
242
242
|
async startWorkflow(workflowId) {
|
|
243
|
-
const
|
|
243
|
+
const workspacePath = process.cwd();
|
|
244
|
+
const result = await (0, start_js_1.executeStartWorkflow)({ workflowId, workspacePath }, v2Ctx);
|
|
244
245
|
if (result.isErr()) {
|
|
245
246
|
return (0, types_js_1.engineErr)(mapStartError(result.error));
|
|
246
247
|
}
|
|
@@ -248,9 +249,11 @@ async function createWorkRailEngine(config = {}) {
|
|
|
248
249
|
},
|
|
249
250
|
async continueWorkflow(stateToken, ackToken, output, context) {
|
|
250
251
|
const intent = ackToken ? 'advance' : 'rehydrate';
|
|
252
|
+
const workspacePath = process.cwd();
|
|
251
253
|
const input = {
|
|
252
254
|
continueToken: (0, types_js_1.unwrapToken)(stateToken),
|
|
253
255
|
intent: intent,
|
|
256
|
+
...(intent === 'rehydrate' ? { workspacePath } : {}),
|
|
254
257
|
...(output ? {
|
|
255
258
|
output: {
|
|
256
259
|
notesMarkdown: output.notesMarkdown,
|
package/dist/manifest.json
CHANGED
|
@@ -438,8 +438,8 @@
|
|
|
438
438
|
"bytes": 213
|
|
439
439
|
},
|
|
440
440
|
"engine/engine-factory.js": {
|
|
441
|
-
"sha256": "
|
|
442
|
-
"bytes":
|
|
441
|
+
"sha256": "5461827b470642059198115f5248e97463db9bfb012f63971a4c7f69acda5b7c",
|
|
442
|
+
"bytes": 13841
|
|
443
443
|
},
|
|
444
444
|
"engine/index.d.ts": {
|
|
445
445
|
"sha256": "91e12882c565e96a9809fdf43a0dc0a77fdffdfd562aaf43d2e86e6590ed0b16",
|
|
@@ -838,8 +838,8 @@
|
|
|
838
838
|
"bytes": 3422
|
|
839
839
|
},
|
|
840
840
|
"mcp/handlers/v2-execution/start.js": {
|
|
841
|
-
"sha256": "
|
|
842
|
-
"bytes":
|
|
841
|
+
"sha256": "e572eb50c6a0a30aa138620f32b04702727f07ce2570c29022d1027981c4bcef",
|
|
842
|
+
"bytes": 18496
|
|
843
843
|
},
|
|
844
844
|
"mcp/handlers/v2-reference-resolver.d.ts": {
|
|
845
845
|
"sha256": "0b1d2640306b6a0c1067ca66bb20e6ec35d291b33dc328a78d5bfa8006394234",
|
|
@@ -862,8 +862,8 @@
|
|
|
862
862
|
"bytes": 471
|
|
863
863
|
},
|
|
864
864
|
"mcp/handlers/v2-resume.js": {
|
|
865
|
-
"sha256": "
|
|
866
|
-
"bytes":
|
|
865
|
+
"sha256": "536ba5db0c8fedf8a55c63a59eae4da5ad1cc793e4abf137a5ac9536e6514f68",
|
|
866
|
+
"bytes": 4140
|
|
867
867
|
},
|
|
868
868
|
"mcp/handlers/v2-state-conversion.d.ts": {
|
|
869
869
|
"sha256": "94bd06904ef58dd210ff17ffb75c2492beea8937eb06d99749e5d860c0e0d96b",
|
|
@@ -914,12 +914,12 @@
|
|
|
914
914
|
"bytes": 7991
|
|
915
915
|
},
|
|
916
916
|
"mcp/output-schemas.d.ts": {
|
|
917
|
-
"sha256": "
|
|
918
|
-
"bytes":
|
|
917
|
+
"sha256": "191d696fd1c8d7dc8f1908c903f84117ceaed6c0aa323fb7606dd3566d739689",
|
|
918
|
+
"bytes": 53246
|
|
919
919
|
},
|
|
920
920
|
"mcp/output-schemas.js": {
|
|
921
|
-
"sha256": "
|
|
922
|
-
"bytes":
|
|
921
|
+
"sha256": "28aa9b75ef6c21522b458bd4d05c55e28673510356f8f7e56eb1304544d35132",
|
|
922
|
+
"bytes": 14384
|
|
923
923
|
},
|
|
924
924
|
"mcp/render-envelope.d.ts": {
|
|
925
925
|
"sha256": "22e83e1aba52968a7136cf289125a217b5f462a5a66a1eebe4669006e3326fdb",
|
|
@@ -1062,8 +1062,8 @@
|
|
|
1062
1062
|
"bytes": 527
|
|
1063
1063
|
},
|
|
1064
1064
|
"mcp/v2-response-formatter.js": {
|
|
1065
|
-
"sha256": "
|
|
1066
|
-
"bytes":
|
|
1065
|
+
"sha256": "308cc7c1fedd491f5d38607869d4b4e1196bfcf450835a53d52154827b323e23",
|
|
1066
|
+
"bytes": 22402
|
|
1067
1067
|
},
|
|
1068
1068
|
"mcp/v2/tool-registry.d.ts": {
|
|
1069
1069
|
"sha256": "d4d4927728c3cab1c014661d499dd0119538371bc6c5e821a4cd31df7abebedf",
|
|
@@ -1074,12 +1074,12 @@
|
|
|
1074
1074
|
"bytes": 3276
|
|
1075
1075
|
},
|
|
1076
1076
|
"mcp/v2/tools.d.ts": {
|
|
1077
|
-
"sha256": "
|
|
1078
|
-
"bytes":
|
|
1077
|
+
"sha256": "93f1eac69e9d2be8ca354d714fbc64e3cea0e235e6669847677071d83a66450f",
|
|
1078
|
+
"bytes": 7288
|
|
1079
1079
|
},
|
|
1080
1080
|
"mcp/v2/tools.js": {
|
|
1081
|
-
"sha256": "
|
|
1082
|
-
"bytes":
|
|
1081
|
+
"sha256": "2b5d12d4de385ca8c530532d12467f113d58a09a808fe075896d2b1c0caa52ae",
|
|
1082
|
+
"bytes": 10071
|
|
1083
1083
|
},
|
|
1084
1084
|
"mcp/validation/bounded-json.d.ts": {
|
|
1085
1085
|
"sha256": "82203ac6123d5c6989606c3b5405aaea99ab829c8958835f9ae3ba45b8bc8fd5",
|
|
@@ -1150,8 +1150,8 @@
|
|
|
1150
1150
|
"bytes": 1863
|
|
1151
1151
|
},
|
|
1152
1152
|
"mcp/workflow-protocol-contracts.js": {
|
|
1153
|
-
"sha256": "
|
|
1154
|
-
"bytes":
|
|
1153
|
+
"sha256": "250fb814372bbf75a4cff9adc2d257da4cf0f4f480dac263860e74ebdd405246",
|
|
1154
|
+
"bytes": 13981
|
|
1155
1155
|
},
|
|
1156
1156
|
"mcp/workflow-tool-edition-selector.d.ts": {
|
|
1157
1157
|
"sha256": "75194908a89aaf7dc48fb661aea099827e7032ec76daf8f2de91bd59d46764ef",
|
|
@@ -2118,8 +2118,8 @@
|
|
|
2118
2118
|
"bytes": 1136
|
|
2119
2119
|
},
|
|
2120
2120
|
"v2/infra/local/session-summary-provider/index.js": {
|
|
2121
|
-
"sha256": "
|
|
2122
|
-
"bytes":
|
|
2121
|
+
"sha256": "504d432a35b3ceb75697c00b5db1576570b38c1415304f903ba77d0dfed04ce7",
|
|
2122
|
+
"bytes": 10452
|
|
2123
2123
|
},
|
|
2124
2124
|
"v2/infra/local/sha256/index.d.ts": {
|
|
2125
2125
|
"sha256": "8a727b7e54a38275ca6f9f1b8730f97cfc0a212df035df1bdc58e716e6824230",
|
|
@@ -2166,8 +2166,8 @@
|
|
|
2166
2166
|
"bytes": 537
|
|
2167
2167
|
},
|
|
2168
2168
|
"v2/infra/local/workspace-anchor/index.js": {
|
|
2169
|
-
"sha256": "
|
|
2170
|
-
"bytes":
|
|
2169
|
+
"sha256": "d76172ecbe3457760abc0b6f0032eb4089758fb3c9ed473ba0f134ac57d37c1a",
|
|
2170
|
+
"bytes": 2993
|
|
2171
2171
|
},
|
|
2172
2172
|
"v2/ports/base32.port.d.ts": {
|
|
2173
2173
|
"sha256": "64aa2f2003a552917cbf71474472fc5e4afffaa29577204bbcbe5ffa989ceb82",
|
|
@@ -2386,12 +2386,12 @@
|
|
|
2386
2386
|
"bytes": 732
|
|
2387
2387
|
},
|
|
2388
2388
|
"v2/projections/resume-ranking.d.ts": {
|
|
2389
|
-
"sha256": "
|
|
2390
|
-
"bytes":
|
|
2389
|
+
"sha256": "b1d9e7d6fb3e59ced42f7c2e5fd9d8f9a18308aa6f4411a8aabf5dc174aa8dad",
|
|
2390
|
+
"bytes": 3960
|
|
2391
2391
|
},
|
|
2392
2392
|
"v2/projections/resume-ranking.js": {
|
|
2393
|
-
"sha256": "
|
|
2394
|
-
"bytes":
|
|
2393
|
+
"sha256": "1b256c992ded9ec52150b229799716d118ca2a3659a0cc523e727cde2ebf7b0c",
|
|
2394
|
+
"bytes": 13660
|
|
2395
2395
|
},
|
|
2396
2396
|
"v2/projections/run-context.d.ts": {
|
|
2397
2397
|
"sha256": "a4d57470a435ac9860f60b3244d1b828853995027cd510d8da42762d21b2a687",
|
|
@@ -212,15 +212,24 @@ function mintStartTokens(args) {
|
|
|
212
212
|
}
|
|
213
213
|
function executeStartWorkflow(input, ctx) {
|
|
214
214
|
const { gate, sessionStore, snapshotStore, pinnedStore, crypto, tokenCodecPorts, idFactory, validationPipelineDeps, tokenAliasStore, entropy } = ctx.v2;
|
|
215
|
-
const
|
|
215
|
+
const shouldUseRequestReader = ctx.featureFlags != null && (0, request_workflow_reader_js_1.hasRequestWorkspaceSignal)({
|
|
216
216
|
workspacePath: input.workspacePath,
|
|
217
217
|
resolvedRootUris: ctx.v2.resolvedRootUris,
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
218
|
+
});
|
|
219
|
+
const workflowReader = shouldUseRequestReader
|
|
220
|
+
? {
|
|
221
|
+
getWorkflowById: async (workflowId) => {
|
|
222
|
+
const requestReader = (0, request_workflow_reader_js_1.createWorkflowReaderForRequest)({
|
|
223
|
+
featureFlags: ctx.featureFlags,
|
|
224
|
+
workspacePath: input.workspacePath,
|
|
225
|
+
resolvedRootUris: ctx.v2.resolvedRootUris,
|
|
226
|
+
});
|
|
227
|
+
const requestResult = await requestReader.getWorkflowById(workflowId);
|
|
228
|
+
if (requestResult != null)
|
|
229
|
+
return requestResult;
|
|
230
|
+
return ctx.workflowService.getWorkflowById(workflowId);
|
|
231
|
+
},
|
|
232
|
+
}
|
|
224
233
|
: ctx.workflowService;
|
|
225
234
|
return loadAndPinWorkflow({
|
|
226
235
|
workflowId: input.workflowId,
|
|
@@ -24,6 +24,8 @@ async function handleV2ResumeSession(input, ctx) {
|
|
|
24
24
|
const query = {
|
|
25
25
|
gitHeadSha: input.gitHeadSha ?? anchorValue(anchors, 'git_head_sha'),
|
|
26
26
|
gitBranch: input.gitBranch ?? anchorValue(anchors, 'git_branch'),
|
|
27
|
+
repoRootHash: anchorValue(anchors, 'repo_root_hash'),
|
|
28
|
+
sameWorkspaceOnly: input.sameWorkspaceOnly,
|
|
27
29
|
freeTextQuery: input.query,
|
|
28
30
|
runId: input.runId,
|
|
29
31
|
sessionId: input.sessionId,
|
|
@@ -74,9 +76,13 @@ function mintCandidateTokens(candidates, ports) {
|
|
|
74
76
|
sessionId: candidate.sessionId,
|
|
75
77
|
runId: candidate.runId,
|
|
76
78
|
workflowId: candidate.workflowId,
|
|
79
|
+
sessionTitle: candidate.sessionTitle,
|
|
80
|
+
gitBranch: candidate.gitBranch,
|
|
77
81
|
resumeToken: resumeTokenRes.value,
|
|
78
82
|
snippet: candidate.snippet,
|
|
79
83
|
whyMatched: [...candidate.whyMatched],
|
|
84
|
+
confidence: candidate.confidence,
|
|
85
|
+
matchExplanation: candidate.matchExplanation,
|
|
80
86
|
pendingStepId: candidate.pendingStepId,
|
|
81
87
|
isComplete: candidate.isComplete,
|
|
82
88
|
lastModifiedMs: candidate.lastModifiedMs,
|
|
@@ -1160,12 +1160,16 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1160
1160
|
sessionId: z.ZodString;
|
|
1161
1161
|
runId: z.ZodString;
|
|
1162
1162
|
workflowId: z.ZodString;
|
|
1163
|
+
sessionTitle: z.ZodNullable<z.ZodString>;
|
|
1164
|
+
gitBranch: z.ZodNullable<z.ZodString>;
|
|
1163
1165
|
resumeToken: z.ZodString;
|
|
1164
1166
|
snippet: z.ZodString;
|
|
1167
|
+
confidence: z.ZodEnum<["strong", "medium", "weak"]>;
|
|
1168
|
+
matchExplanation: z.ZodString;
|
|
1165
1169
|
pendingStepId: z.ZodNullable<z.ZodString>;
|
|
1166
1170
|
isComplete: z.ZodBoolean;
|
|
1167
1171
|
lastModifiedMs: z.ZodNullable<z.ZodNumber>;
|
|
1168
|
-
whyMatched: z.ZodArray<z.ZodEnum<["matched_exact_id", "
|
|
1172
|
+
whyMatched: z.ZodArray<z.ZodEnum<["matched_exact_id", "matched_notes", "matched_notes_partial", "matched_workflow_id", "matched_head_sha", "matched_branch", "matched_repo_root", "recency_fallback"]>, "many">;
|
|
1169
1173
|
nextCall: z.ZodObject<{
|
|
1170
1174
|
tool: z.ZodLiteral<"continue_workflow">;
|
|
1171
1175
|
params: z.ZodObject<{
|
|
@@ -1192,9 +1196,11 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1192
1196
|
tool: "continue_workflow";
|
|
1193
1197
|
}>;
|
|
1194
1198
|
}, "strip", z.ZodTypeAny, {
|
|
1199
|
+
confidence: "strong" | "weak" | "medium";
|
|
1195
1200
|
workflowId: string;
|
|
1196
1201
|
runId: string;
|
|
1197
1202
|
sessionId: string;
|
|
1203
|
+
gitBranch: string | null;
|
|
1198
1204
|
isComplete: boolean;
|
|
1199
1205
|
nextCall: {
|
|
1200
1206
|
params: {
|
|
@@ -1203,15 +1209,19 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1203
1209
|
};
|
|
1204
1210
|
tool: "continue_workflow";
|
|
1205
1211
|
};
|
|
1212
|
+
sessionTitle: string | null;
|
|
1206
1213
|
resumeToken: string;
|
|
1207
1214
|
snippet: string;
|
|
1215
|
+
matchExplanation: string;
|
|
1208
1216
|
pendingStepId: string | null;
|
|
1209
1217
|
lastModifiedMs: number | null;
|
|
1210
|
-
whyMatched: ("matched_exact_id" | "
|
|
1218
|
+
whyMatched: ("matched_exact_id" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "matched_head_sha" | "matched_branch" | "matched_repo_root" | "recency_fallback")[];
|
|
1211
1219
|
}, {
|
|
1220
|
+
confidence: "strong" | "weak" | "medium";
|
|
1212
1221
|
workflowId: string;
|
|
1213
1222
|
runId: string;
|
|
1214
1223
|
sessionId: string;
|
|
1224
|
+
gitBranch: string | null;
|
|
1215
1225
|
isComplete: boolean;
|
|
1216
1226
|
nextCall: {
|
|
1217
1227
|
params: {
|
|
@@ -1220,18 +1230,22 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1220
1230
|
};
|
|
1221
1231
|
tool: "continue_workflow";
|
|
1222
1232
|
};
|
|
1233
|
+
sessionTitle: string | null;
|
|
1223
1234
|
resumeToken: string;
|
|
1224
1235
|
snippet: string;
|
|
1236
|
+
matchExplanation: string;
|
|
1225
1237
|
pendingStepId: string | null;
|
|
1226
1238
|
lastModifiedMs: number | null;
|
|
1227
|
-
whyMatched: ("matched_exact_id" | "
|
|
1239
|
+
whyMatched: ("matched_exact_id" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "matched_head_sha" | "matched_branch" | "matched_repo_root" | "recency_fallback")[];
|
|
1228
1240
|
}>, "many">;
|
|
1229
1241
|
totalEligible: z.ZodNumber;
|
|
1230
1242
|
}, "strip", z.ZodTypeAny, {
|
|
1231
1243
|
candidates: {
|
|
1244
|
+
confidence: "strong" | "weak" | "medium";
|
|
1232
1245
|
workflowId: string;
|
|
1233
1246
|
runId: string;
|
|
1234
1247
|
sessionId: string;
|
|
1248
|
+
gitBranch: string | null;
|
|
1235
1249
|
isComplete: boolean;
|
|
1236
1250
|
nextCall: {
|
|
1237
1251
|
params: {
|
|
@@ -1240,18 +1254,22 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1240
1254
|
};
|
|
1241
1255
|
tool: "continue_workflow";
|
|
1242
1256
|
};
|
|
1257
|
+
sessionTitle: string | null;
|
|
1243
1258
|
resumeToken: string;
|
|
1244
1259
|
snippet: string;
|
|
1260
|
+
matchExplanation: string;
|
|
1245
1261
|
pendingStepId: string | null;
|
|
1246
1262
|
lastModifiedMs: number | null;
|
|
1247
|
-
whyMatched: ("matched_exact_id" | "
|
|
1263
|
+
whyMatched: ("matched_exact_id" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "matched_head_sha" | "matched_branch" | "matched_repo_root" | "recency_fallback")[];
|
|
1248
1264
|
}[];
|
|
1249
1265
|
totalEligible: number;
|
|
1250
1266
|
}, {
|
|
1251
1267
|
candidates: {
|
|
1268
|
+
confidence: "strong" | "weak" | "medium";
|
|
1252
1269
|
workflowId: string;
|
|
1253
1270
|
runId: string;
|
|
1254
1271
|
sessionId: string;
|
|
1272
|
+
gitBranch: string | null;
|
|
1255
1273
|
isComplete: boolean;
|
|
1256
1274
|
nextCall: {
|
|
1257
1275
|
params: {
|
|
@@ -1260,11 +1278,13 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1260
1278
|
};
|
|
1261
1279
|
tool: "continue_workflow";
|
|
1262
1280
|
};
|
|
1281
|
+
sessionTitle: string | null;
|
|
1263
1282
|
resumeToken: string;
|
|
1264
1283
|
snippet: string;
|
|
1284
|
+
matchExplanation: string;
|
|
1265
1285
|
pendingStepId: string | null;
|
|
1266
1286
|
lastModifiedMs: number | null;
|
|
1267
|
-
whyMatched: ("matched_exact_id" | "
|
|
1287
|
+
whyMatched: ("matched_exact_id" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "matched_head_sha" | "matched_branch" | "matched_repo_root" | "recency_fallback")[];
|
|
1268
1288
|
}[];
|
|
1269
1289
|
totalEligible: number;
|
|
1270
1290
|
}>;
|
|
@@ -242,23 +242,29 @@ exports.V2ResumeSessionOutputSchema = zod_1.z.object({
|
|
|
242
242
|
sessionId: zod_1.z.string().min(1),
|
|
243
243
|
runId: zod_1.z.string().min(1),
|
|
244
244
|
workflowId: zod_1.z.string().min(1),
|
|
245
|
+
sessionTitle: zod_1.z.string().nullable().describe('Human-readable task/session title derived from persisted workflow context or early recap text.'),
|
|
246
|
+
gitBranch: zod_1.z.string().nullable().describe('Git branch associated with the session, if available.'),
|
|
245
247
|
resumeToken: zod_1.z.string().regex(token_patterns_js_1.STATE_TOKEN_PATTERN, 'Invalid resumeToken format'),
|
|
246
248
|
snippet: zod_1.z.string().max(1024),
|
|
249
|
+
confidence: zod_1.z.enum(['strong', 'medium', 'weak']).describe('Coarse confidence band for how likely this candidate is the intended session.'),
|
|
250
|
+
matchExplanation: zod_1.z.string().min(1).describe('Short natural-language explanation of why this candidate ranked here.'),
|
|
247
251
|
pendingStepId: zod_1.z.string().nullable().describe('The current pending step ID (e.g. "phase-3-implement") if the workflow is in progress. ' +
|
|
248
252
|
'Null if the workflow is complete or the step could not be determined.'),
|
|
249
253
|
isComplete: zod_1.z.boolean().describe('Whether the workflow run has completed. Completed sessions are deprioritized in ranking.'),
|
|
250
254
|
lastModifiedMs: zod_1.z.number().nullable().describe('Filesystem modification time (epoch ms) of the session. Null if unavailable.'),
|
|
251
255
|
whyMatched: zod_1.z.array(zod_1.z.enum([
|
|
252
256
|
'matched_exact_id',
|
|
253
|
-
'matched_head_sha',
|
|
254
|
-
'matched_branch',
|
|
255
257
|
'matched_notes',
|
|
256
258
|
'matched_notes_partial',
|
|
257
259
|
'matched_workflow_id',
|
|
260
|
+
'matched_head_sha',
|
|
261
|
+
'matched_branch',
|
|
262
|
+
'matched_repo_root',
|
|
258
263
|
'recency_fallback',
|
|
259
264
|
])).describe('Match signals explaining why this candidate was ranked. ' +
|
|
260
|
-
'matched_exact_id
|
|
261
|
-
'matched_notes_partial
|
|
265
|
+
'matched_exact_id and matched_notes are strongest. ' +
|
|
266
|
+
'matched_notes_partial/matched_workflow_id are moderate text signals. ' +
|
|
267
|
+
'matched_repo_root/head_sha/branch are workspace-context signals. ' +
|
|
262
268
|
'recency_fallback = no strong signal; inspect the snippet before resuming.'),
|
|
263
269
|
nextCall: exports.V2ResumeNextCallSchema,
|
|
264
270
|
})).max(5),
|
package/dist/mcp/v2/tools.d.ts
CHANGED
|
@@ -24,13 +24,13 @@ export declare const V2InspectWorkflowInput: z.ZodObject<{
|
|
|
24
24
|
export type V2InspectWorkflowInput = z.infer<typeof V2InspectWorkflowInput>;
|
|
25
25
|
export declare const V2StartWorkflowInput: z.ZodObject<{
|
|
26
26
|
workflowId: z.ZodString;
|
|
27
|
-
workspacePath: z.
|
|
27
|
+
workspacePath: z.ZodEffects<z.ZodString, string, string>;
|
|
28
28
|
}, "strip", z.ZodTypeAny, {
|
|
29
29
|
workflowId: string;
|
|
30
|
-
workspacePath
|
|
30
|
+
workspacePath: string;
|
|
31
31
|
}, {
|
|
32
32
|
workflowId: string;
|
|
33
|
-
workspacePath
|
|
33
|
+
workspacePath: string;
|
|
34
34
|
}>;
|
|
35
35
|
export type V2StartWorkflowInput = z.infer<typeof V2StartWorkflowInput>;
|
|
36
36
|
export declare const V2ContinueWorkflowInputShape: z.ZodObject<{
|
|
@@ -151,21 +151,24 @@ export declare const V2ResumeSessionInput: z.ZodObject<{
|
|
|
151
151
|
sessionId: z.ZodOptional<z.ZodString>;
|
|
152
152
|
gitBranch: z.ZodOptional<z.ZodString>;
|
|
153
153
|
gitHeadSha: z.ZodOptional<z.ZodString>;
|
|
154
|
-
workspacePath: z.
|
|
154
|
+
workspacePath: z.ZodEffects<z.ZodString, string, string>;
|
|
155
|
+
sameWorkspaceOnly: z.ZodOptional<z.ZodBoolean>;
|
|
155
156
|
}, "strict", z.ZodTypeAny, {
|
|
156
|
-
workspacePath
|
|
157
|
+
workspacePath: string;
|
|
157
158
|
query?: string | undefined;
|
|
158
159
|
runId?: string | undefined;
|
|
159
160
|
sessionId?: string | undefined;
|
|
160
161
|
gitBranch?: string | undefined;
|
|
161
162
|
gitHeadSha?: string | undefined;
|
|
163
|
+
sameWorkspaceOnly?: boolean | undefined;
|
|
162
164
|
}, {
|
|
163
|
-
workspacePath
|
|
165
|
+
workspacePath: string;
|
|
164
166
|
query?: string | undefined;
|
|
165
167
|
runId?: string | undefined;
|
|
166
168
|
sessionId?: string | undefined;
|
|
167
169
|
gitBranch?: string | undefined;
|
|
168
170
|
gitHeadSha?: string | undefined;
|
|
171
|
+
sameWorkspaceOnly?: boolean | undefined;
|
|
169
172
|
}>;
|
|
170
173
|
export type V2ResumeSessionInput = z.infer<typeof V2ResumeSessionInput>;
|
|
171
174
|
export declare const V2CheckpointWorkflowInput: z.ZodObject<{
|
package/dist/mcp/v2/tools.js
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.V2_TOOL_ANNOTATIONS = exports.V2_TOOL_TITLES = exports.V2CheckpointWorkflowInput = exports.V2ResumeSessionInput = exports.V2ContinueWorkflowInput = exports.V2ContinueWorkflowInputShape = exports.V2StartWorkflowInput = exports.V2InspectWorkflowInput = exports.V2ListWorkflowsInput = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
4
8
|
const zod_1 = require("zod");
|
|
5
9
|
const workflow_protocol_contracts_js_1 = require("../workflow-protocol-contracts.js");
|
|
10
|
+
function isAbsoluteWorkspacePath(p) {
|
|
11
|
+
return path_1.default.isAbsolute(p);
|
|
12
|
+
}
|
|
6
13
|
const workspacePathField = zod_1.z.string()
|
|
7
|
-
.refine((p) => p
|
|
8
|
-
.optional()
|
|
14
|
+
.refine((p) => isAbsoluteWorkspacePath(p), 'workspacePath must be an absolute path')
|
|
9
15
|
.describe('Absolute path to your current workspace directory (e.g. the "Workspace:" value from your system parameters). Used to resolve project-scoped workflow variants against the correct workspace. If omitted, WorkRail uses MCP roots when available, then falls back to the server process directory.');
|
|
16
|
+
const optionalWorkspacePathField = workspacePathField.optional();
|
|
10
17
|
exports.V2ListWorkflowsInput = zod_1.z.object({
|
|
11
|
-
workspacePath:
|
|
18
|
+
workspacePath: optionalWorkspacePathField,
|
|
12
19
|
});
|
|
13
20
|
exports.V2InspectWorkflowInput = zod_1.z.object({
|
|
14
21
|
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 inspect'),
|
|
15
22
|
mode: zod_1.z.enum(['metadata', 'preview']).default('preview').describe('Detail level: metadata (name and description only) or preview (full step-by-step breakdown, default)'),
|
|
16
|
-
workspacePath:
|
|
23
|
+
workspacePath: optionalWorkspacePathField,
|
|
17
24
|
});
|
|
18
25
|
exports.V2StartWorkflowInput = zod_1.z.object({
|
|
19
26
|
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'),
|
|
20
|
-
workspacePath: workspacePathField.describe('Absolute path to your current workspace directory (e.g. the "Workspace:" value from your system parameters).
|
|
27
|
+
workspacePath: workspacePathField.describe('Required. Absolute path to your current workspace directory (e.g. the "Workspace:" value from your system parameters). WorkRail uses this to resolve the correct project-scoped workflow variant and to anchor the session to the correct repo for future resume_session discovery. Shared MCP servers cannot infer this safely.'),
|
|
21
28
|
});
|
|
22
29
|
exports.V2ContinueWorkflowInputShape = zod_1.z.object({
|
|
23
|
-
workspacePath:
|
|
30
|
+
workspacePath: optionalWorkspacePathField,
|
|
24
31
|
continueToken: zod_1.z.string().min(1).describe('The token for your next continue_workflow call. Two valid token kinds: ' +
|
|
25
32
|
'(1) A continueToken (ct_...) from start_workflow or a previous continue_workflow — carries session identity AND advance authority. ' +
|
|
26
33
|
'(2) A resumeToken (st_...) from resume_session or checkpoint_workflow — carries session identity only; valid for intent: "rehydrate", not "advance". ' +
|
|
@@ -69,6 +76,13 @@ exports.V2ContinueWorkflowInput = exports.V2ContinueWorkflowInputShape
|
|
|
69
76
|
'Rehydration is read-only state recovery — it does not accept output.',
|
|
70
77
|
});
|
|
71
78
|
}
|
|
79
|
+
if (data.intent === 'rehydrate' && data.workspacePath === undefined) {
|
|
80
|
+
ctx.addIssue({
|
|
81
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
82
|
+
path: ['workspacePath'],
|
|
83
|
+
message: 'workspacePath is required for rehydration. Shared WorkRail servers cannot safely infer your current workspace, so pass the absolute "Workspace:" path from your system parameters.',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
72
86
|
})
|
|
73
87
|
.transform((data) => {
|
|
74
88
|
const normalized = workflow_protocol_contracts_js_1.CONTINUE_WORKFLOW_PROTOCOL.aliasMap
|
|
@@ -93,10 +107,9 @@ exports.V2ResumeSessionInput = zod_1.z.object({
|
|
|
93
107
|
'When provided, the matching session is returned as the sole top-priority candidate.'),
|
|
94
108
|
gitBranch: zod_1.z.string().max(256).optional().describe('Git branch name to match against session observations. Overrides auto-detected branch.'),
|
|
95
109
|
gitHeadSha: zod_1.z.string().regex(/^[0-9a-f]{40}$/).optional().describe('Git HEAD SHA to match against session observations. Overrides auto-detected HEAD.'),
|
|
96
|
-
workspacePath:
|
|
97
|
-
|
|
98
|
-
.
|
|
99
|
-
.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.'),
|
|
110
|
+
workspacePath: workspacePathField.describe('Required. Absolute path to your current workspace directory (e.g. the "Workspace:" value from your system parameters). WorkRail uses this to identify the current repo and resume the correct session on shared MCP servers.'),
|
|
111
|
+
sameWorkspaceOnly: zod_1.z.boolean().optional().describe('If true, only sessions from the same repo/workspace are considered when repo_root_hash is available. ' +
|
|
112
|
+
'Use this when the user clearly means "resume work from this repo only".'),
|
|
100
113
|
}).strict();
|
|
101
114
|
exports.V2CheckpointWorkflowInput = zod_1.z.object({
|
|
102
115
|
checkpointToken: zod_1.z.string().min(1).describe('The checkpoint token from the most recent start_workflow or continue_workflow response. ' +
|
|
@@ -400,11 +400,12 @@ function isResumeSessionResponse(data) {
|
|
|
400
400
|
}
|
|
401
401
|
const WHY_MATCHED_LABELS = {
|
|
402
402
|
matched_exact_id: 'Exact ID match',
|
|
403
|
-
matched_head_sha: 'Same git commit (HEAD SHA)',
|
|
404
|
-
matched_branch: 'Same git branch',
|
|
405
403
|
matched_notes: 'Query matched session notes',
|
|
406
404
|
matched_notes_partial: 'Query partially matched session notes',
|
|
407
405
|
matched_workflow_id: 'Query matched workflow type',
|
|
406
|
+
matched_head_sha: 'Same git commit (HEAD SHA)',
|
|
407
|
+
matched_branch: 'Same git branch',
|
|
408
|
+
matched_repo_root: 'Same workspace/repository',
|
|
408
409
|
recency_fallback: 'No strong match signal (recent session)',
|
|
409
410
|
};
|
|
410
411
|
function formatRelativeTime(epochMs) {
|
|
@@ -433,10 +434,21 @@ function formatResumeCandidate(c, index) {
|
|
|
433
434
|
const matchLabel = c.whyMatched.map(w => WHY_MATCHED_LABELS[w] ?? w).join(', ');
|
|
434
435
|
const isWeak = c.whyMatched.every(w => w === 'recency_fallback');
|
|
435
436
|
const statusTag = c.isComplete ? ' (completed)' : '';
|
|
436
|
-
|
|
437
|
+
const heading = c.sessionTitle?.trim() || c.workflowId;
|
|
438
|
+
lines.push(`### Candidate ${index + 1}: \`${heading}\`${statusTag}${isWeak ? ' (weak match)' : ''}`);
|
|
437
439
|
lines.push(`- **Session**: \`${c.sessionId}\``);
|
|
438
440
|
lines.push(`- **Run**: \`${c.runId}\``);
|
|
441
|
+
lines.push(`- **Workflow**: \`${c.workflowId}\``);
|
|
439
442
|
lines.push(`- **Match reason**: ${matchLabel}`);
|
|
443
|
+
if (c.confidence) {
|
|
444
|
+
lines.push(`- **Confidence**: ${c.confidence}`);
|
|
445
|
+
}
|
|
446
|
+
if (c.matchExplanation) {
|
|
447
|
+
lines.push(`- **Why this ranked here**: ${c.matchExplanation}`);
|
|
448
|
+
}
|
|
449
|
+
if (c.gitBranch) {
|
|
450
|
+
lines.push(`- **Branch**: \`${c.gitBranch}\``);
|
|
451
|
+
}
|
|
440
452
|
if (c.pendingStepId) {
|
|
441
453
|
lines.push(`- **Current step**: \`${c.pendingStepId}\``);
|
|
442
454
|
}
|
|
@@ -458,10 +470,11 @@ function formatResumeCandidate(c, index) {
|
|
|
458
470
|
lines.push('> This workflow has already completed. Resuming it will show the final state.');
|
|
459
471
|
}
|
|
460
472
|
lines.push('');
|
|
461
|
-
lines.push('To resume, call `continue_workflow` with:');
|
|
473
|
+
lines.push('To inspect or resume this candidate, call `continue_workflow` with:');
|
|
462
474
|
lines.push('```json');
|
|
463
475
|
lines.push(JSON.stringify(c.nextCall.params, null, 2));
|
|
464
476
|
lines.push('```');
|
|
477
|
+
lines.push('This `rehydrate` call restores the exact workflow state and shows the current step/context.');
|
|
465
478
|
return lines.join('\n');
|
|
466
479
|
}
|
|
467
480
|
const SEARCH_PARAMS_HELP = [
|
|
@@ -470,6 +483,7 @@ const SEARCH_PARAMS_HELP = [
|
|
|
470
483
|
'- `runId`: Exact run ID if the user has one (e.g. "run_abc123def456")',
|
|
471
484
|
'- `sessionId`: Exact session ID if the user has one (e.g. "sess_abc123")',
|
|
472
485
|
'- `workspacePath`: Absolute path to the workspace (helps match by git branch/commit)',
|
|
486
|
+
'- `sameWorkspaceOnly`: Restrict results to the current repo/workspace when that is clearly what the user means',
|
|
473
487
|
].join('\n');
|
|
474
488
|
function formatV2ResumeResponse(data) {
|
|
475
489
|
if (!isResumeSessionResponse(data))
|
|
@@ -514,6 +528,12 @@ function formatV2ResumeResponse(data) {
|
|
|
514
528
|
lines.push('');
|
|
515
529
|
lines.push(`Found **${totalEligible}** session(s) total. Showing the top ${candidates.length} ranked by match strength.`);
|
|
516
530
|
lines.push('');
|
|
531
|
+
const allWorkspaceDriven = candidates.every((c) => c.whyMatched.every((w) => w === 'matched_head_sha' || w === 'matched_branch'));
|
|
532
|
+
if (allWorkspaceDriven) {
|
|
533
|
+
lines.push('**Note**: These candidates are ranked primarily from current workspace git context (branch/commit), not from a strong text match on your query.');
|
|
534
|
+
lines.push('If the previews do not clearly match the user\'s request, inspect a candidate with `continue_workflow(..., intent: "rehydrate")` or ask for a more specific phrase / session ID.');
|
|
535
|
+
lines.push('');
|
|
536
|
+
}
|
|
517
537
|
const best = candidates[0];
|
|
518
538
|
const bestIsExact = best.whyMatched.includes('matched_exact_id');
|
|
519
539
|
if (bestIsExact) {
|
|
@@ -46,8 +46,8 @@ function findAliasFieldConflicts(value, aliasMap) {
|
|
|
46
46
|
}
|
|
47
47
|
exports.START_WORKFLOW_PROTOCOL = {
|
|
48
48
|
canonicalParams: {
|
|
49
|
-
required: ['workflowId'],
|
|
50
|
-
optional: [
|
|
49
|
+
required: ['workflowId', 'workspacePath'],
|
|
50
|
+
optional: [],
|
|
51
51
|
},
|
|
52
52
|
descriptions: {
|
|
53
53
|
standard: {
|
|
@@ -56,6 +56,7 @@ exports.START_WORKFLOW_PROTOCOL = {
|
|
|
56
56
|
rules: [
|
|
57
57
|
'Follow the returned step exactly; treat it as the user\'s current instruction.',
|
|
58
58
|
'When the step is done, call continue_workflow with the returned continueToken.',
|
|
59
|
+
'Always pass workspacePath. Shared MCP servers cannot safely infer which repo/workspace you mean.',
|
|
59
60
|
'Only pass context on later continue_workflow calls if facts changed.',
|
|
60
61
|
],
|
|
61
62
|
examplePayload: {
|
|
@@ -70,7 +71,7 @@ exports.START_WORKFLOW_PROTOCOL = {
|
|
|
70
71
|
rules: [
|
|
71
72
|
'Execute the returned step exactly as written.',
|
|
72
73
|
'When the step is complete, call continue_workflow with the returned continueToken.',
|
|
73
|
-
'Pass workspacePath
|
|
74
|
+
'Pass workspacePath on every call. Shared MCP servers cannot safely infer the correct workspace.',
|
|
74
75
|
],
|
|
75
76
|
examplePayload: {
|
|
76
77
|
workflowId: 'coding-task-workflow-agentic',
|
|
@@ -83,7 +84,7 @@ exports.START_WORKFLOW_PROTOCOL = {
|
|
|
83
84
|
exports.CONTINUE_WORKFLOW_PROTOCOL = {
|
|
84
85
|
canonicalParams: {
|
|
85
86
|
required: ['continueToken'],
|
|
86
|
-
optional: ['intent', 'context', 'output'],
|
|
87
|
+
optional: ['intent', 'context', 'output', 'workspacePath'],
|
|
87
88
|
},
|
|
88
89
|
aliasMap: {
|
|
89
90
|
contextVariables: 'context',
|
|
@@ -95,6 +96,7 @@ exports.CONTINUE_WORKFLOW_PROTOCOL = {
|
|
|
95
96
|
rules: [
|
|
96
97
|
'Advance by sending output (and intent: "advance" if you want to be explicit).',
|
|
97
98
|
'Rehydrate by omitting output (and intent: "rehydrate" if you want to be explicit).',
|
|
99
|
+
'When rehydrating, always pass workspacePath so WorkRail can restore the correct repo/workspace context on shared servers.',
|
|
98
100
|
'Put changed facts under context only.',
|
|
99
101
|
'Round-trip continueToken exactly as returned by WorkRail; use the single-token API only.',
|
|
100
102
|
'Notes (output.notesMarkdown): write for a human reader. Include what you did and key decisions, what you produced (files, tests, numbers), and anything notable (risks, open questions, deliberate omissions). Use markdown headings, bullets, bold, code refs. Be specific. Scope: THIS step only (WorkRail concatenates automatically). 10-30 lines ideal. Omitting notes blocks the step.',
|
|
@@ -114,6 +116,7 @@ exports.CONTINUE_WORKFLOW_PROTOCOL = {
|
|
|
114
116
|
'Use continueToken exactly as returned by WorkRail.',
|
|
115
117
|
'Use the single-token API only.',
|
|
116
118
|
'Advance by sending output; rehydrate by omitting output.',
|
|
119
|
+
'For rehydrate calls, pass workspacePath so WorkRail can restore the correct workspace context.',
|
|
117
120
|
'Put updated facts in context only.',
|
|
118
121
|
'Notes (output.notesMarkdown): write for a human reader. Include what you did and key decisions, what you produced (files, tests, numbers), and anything notable (risks, open questions, deliberate omissions). Use markdown headings, bullets, bold, code refs. Be specific. Scope: THIS step only (WorkRail concatenates automatically). 10-30 lines ideal. Omitting notes blocks the step.',
|
|
119
122
|
],
|
|
@@ -164,8 +167,8 @@ exports.CHECKPOINT_WORKFLOW_PROTOCOL = {
|
|
|
164
167
|
};
|
|
165
168
|
exports.RESUME_SESSION_PROTOCOL = {
|
|
166
169
|
canonicalParams: {
|
|
167
|
-
required: [],
|
|
168
|
-
optional: ['query', 'runId', 'sessionId', 'gitBranch', 'gitHeadSha'
|
|
170
|
+
required: ['workspacePath'],
|
|
171
|
+
optional: ['query', 'runId', 'sessionId', 'gitBranch', 'gitHeadSha'],
|
|
169
172
|
},
|
|
170
173
|
descriptions: {
|
|
171
174
|
standard: {
|
|
@@ -174,9 +177,9 @@ exports.RESUME_SESSION_PROTOCOL = {
|
|
|
174
177
|
rules: [
|
|
175
178
|
'If the user provides a run ID (run_...) or session ID (sess_...), pass it as runId or sessionId for an exact match. This is the most reliable way to find a specific session.',
|
|
176
179
|
'If the user describes what they were working on (e.g. "the mr ownership task"), pass their words as query. This searches session recap notes and workflow IDs for matching keywords.',
|
|
177
|
-
'Always pass workspacePath (from your system parameters)
|
|
180
|
+
'Always pass workspacePath (from your system parameters). Shared MCP servers cannot safely infer the current workspace, and resume quality depends on the current repo identity.',
|
|
178
181
|
'The response includes ranked candidates with match explanations and ready-to-use continuation templates. Present the top candidates to the user if there is ambiguity.',
|
|
179
|
-
'To resume a candidate: call continue_workflow with the candidate\'s nextCall.params (continueToken and intent: "rehydrate").
|
|
182
|
+
'To inspect or resume a candidate: call continue_workflow with the candidate\'s nextCall.params (continueToken and intent: "rehydrate"). This is the correct inspection path for v2 sessions and restores the full session context.',
|
|
180
183
|
'If no candidates match, ask the user for more details or suggest starting a fresh workflow with start_workflow.',
|
|
181
184
|
],
|
|
182
185
|
examplePayload: {
|
|
@@ -191,9 +194,9 @@ exports.RESUME_SESSION_PROTOCOL = {
|
|
|
191
194
|
rules: [
|
|
192
195
|
'If the user provides a run ID (run_...) or session ID (sess_...), pass it as runId or sessionId for exact lookup.',
|
|
193
196
|
'If the user describes their task, pass their words as query to search session notes.',
|
|
194
|
-
'Always pass workspacePath from your system parameters
|
|
197
|
+
'Always pass workspacePath from your system parameters. Shared MCP servers cannot safely infer the current workspace.',
|
|
195
198
|
'Present candidates to the user when there is ambiguity. The response explains match strength.',
|
|
196
|
-
'To resume: call continue_workflow with the chosen candidate\'s nextCall.params (continueToken + intent: "rehydrate").',
|
|
199
|
+
'To inspect or resume: call continue_workflow with the chosen candidate\'s nextCall.params (continueToken + intent: "rehydrate"). Do NOT use legacy session tools to inspect a v2 workflow resume candidate.',
|
|
197
200
|
'If no candidates match, ask for more details or start a fresh workflow.',
|
|
198
201
|
],
|
|
199
202
|
examplePayload: {
|