@exaudeus/workrail 3.7.1 → 3.7.2
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 +35 -35
- package/dist/mcp/handler-factory.js +1 -1
- package/dist/mcp/handlers/v2-resume.js +5 -0
- package/dist/mcp/output-schemas.d.ts +24 -9
- package/dist/mcp/output-schemas.js +8 -1
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/v2/tools.d.ts +6 -0
- package/dist/mcp/v2/tools.js +5 -0
- package/dist/mcp/v2-response-formatter.d.ts +1 -0
- package/dist/mcp/v2-response-formatter.js +148 -0
- package/dist/mcp/workflow-protocol-contracts.js +19 -19
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +10 -10
- package/dist/v2/durable-core/schemas/session/manifest.d.ts +2 -2
- package/dist/v2/durable-core/tokens/payloads.d.ts +24 -24
- package/dist/v2/infra/local/session-summary-provider/index.d.ts +2 -0
- package/dist/v2/infra/local/session-summary-provider/index.js +54 -17
- package/dist/v2/projections/resume-ranking.d.ts +21 -2
- package/dist/v2/projections/resume-ranking.js +66 -6
- package/dist/v2/usecases/enumerate-sessions.d.ts +5 -1
- package/dist/v2/usecases/enumerate-sessions.js +1 -1
- package/package.json +1 -1
package/dist/manifest.json
CHANGED
|
@@ -670,8 +670,8 @@
|
|
|
670
670
|
"bytes": 883
|
|
671
671
|
},
|
|
672
672
|
"mcp/handler-factory.js": {
|
|
673
|
-
"sha256": "
|
|
674
|
-
"bytes":
|
|
673
|
+
"sha256": "6eb67d1501582d1cfcf777d7d930a6cf3cb32ccbd450c7083133745ef27d2661",
|
|
674
|
+
"bytes": 5381
|
|
675
675
|
},
|
|
676
676
|
"mcp/handlers/session.d.ts": {
|
|
677
677
|
"sha256": "38926e69a0e4935d1dbcdc53848be9fff0e4d8f96827883da3216f217918fa82",
|
|
@@ -862,8 +862,8 @@
|
|
|
862
862
|
"bytes": 471
|
|
863
863
|
},
|
|
864
864
|
"mcp/handlers/v2-resume.js": {
|
|
865
|
-
"sha256": "
|
|
866
|
-
"bytes":
|
|
865
|
+
"sha256": "780e4611d4fb7d7f7fac8cddf576ada1e9ba752f167a678ebd03d94ee518e298",
|
|
866
|
+
"bytes": 3828
|
|
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": "b33bd6e889811ee4de7bd3b4b4fd6d52042cb7a6bdd23c8bd38baa42775e39c3",
|
|
918
|
+
"bytes": 52320
|
|
919
919
|
},
|
|
920
920
|
"mcp/output-schemas.js": {
|
|
921
|
-
"sha256": "
|
|
922
|
-
"bytes":
|
|
921
|
+
"sha256": "ba7dda4faec5a8bc1e497b41966b5033ab2930c9cae7b46e85ea1d25b39f79fa",
|
|
922
|
+
"bytes": 13715
|
|
923
923
|
},
|
|
924
924
|
"mcp/render-envelope.d.ts": {
|
|
925
925
|
"sha256": "22e83e1aba52968a7136cf289125a217b5f462a5a66a1eebe4669006e3326fdb",
|
|
@@ -942,8 +942,8 @@
|
|
|
942
942
|
"bytes": 960
|
|
943
943
|
},
|
|
944
944
|
"mcp/server.js": {
|
|
945
|
-
"sha256": "
|
|
946
|
-
"bytes":
|
|
945
|
+
"sha256": "9689ba068eaac9f36f328fa5429b5abe84bb8bd0062f0a59b60dc361dea09cd2",
|
|
946
|
+
"bytes": 11677
|
|
947
947
|
},
|
|
948
948
|
"mcp/step-content-envelope.d.ts": {
|
|
949
949
|
"sha256": "19bd63c4d4de1d5d93393d346625d28ffd1bebdc320d4ba4e694cb740ec97d3b",
|
|
@@ -1058,12 +1058,12 @@
|
|
|
1058
1058
|
"bytes": 2674
|
|
1059
1059
|
},
|
|
1060
1060
|
"mcp/v2-response-formatter.d.ts": {
|
|
1061
|
-
"sha256": "
|
|
1062
|
-
"bytes":
|
|
1061
|
+
"sha256": "3dd2bb5beef01afc8dca6b3df8bfd52283dc4393c5d85d2906a56bf4ae9806c9",
|
|
1062
|
+
"bytes": 527
|
|
1063
1063
|
},
|
|
1064
1064
|
"mcp/v2-response-formatter.js": {
|
|
1065
|
-
"sha256": "
|
|
1066
|
-
"bytes":
|
|
1065
|
+
"sha256": "f8a8cb5c1fe1b081eca9228a09732dde7247aaf396ff14556cc721c66eee5ab8",
|
|
1066
|
+
"bytes": 21118
|
|
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": "89fff4db9e2b8f734d7453801fbc404a1518fccafce2a942af6656a6cdc2dc1e",
|
|
1078
|
+
"bytes": 7228
|
|
1079
1079
|
},
|
|
1080
1080
|
"mcp/v2/tools.js": {
|
|
1081
|
-
"sha256": "
|
|
1082
|
-
"bytes":
|
|
1081
|
+
"sha256": "c8bfc63a04911d44f13e62c0d9357dacf62ec437dd21f5b6f09c289a973687cb",
|
|
1082
|
+
"bytes": 9406
|
|
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": "8da5f9dfb6f87ec12de5f6e925ae25b022a91432c430738bff1ba14fafeb03fb",
|
|
1154
|
+
"bytes": 13357
|
|
1155
1155
|
},
|
|
1156
1156
|
"mcp/workflow-tool-edition-selector.d.ts": {
|
|
1157
1157
|
"sha256": "75194908a89aaf7dc48fb661aea099827e7032ec76daf8f2de91bd59d46764ef",
|
|
@@ -1802,7 +1802,7 @@
|
|
|
1802
1802
|
"bytes": 3397
|
|
1803
1803
|
},
|
|
1804
1804
|
"v2/durable-core/schemas/export-bundle/index.d.ts": {
|
|
1805
|
-
"sha256": "
|
|
1805
|
+
"sha256": "6521642cefd019f75dba36890b71c20c5508e04baef584a09557a4b98f894321",
|
|
1806
1806
|
"bytes": 479848
|
|
1807
1807
|
},
|
|
1808
1808
|
"v2/durable-core/schemas/export-bundle/index.js": {
|
|
@@ -1882,7 +1882,7 @@
|
|
|
1882
1882
|
"bytes": 715
|
|
1883
1883
|
},
|
|
1884
1884
|
"v2/durable-core/schemas/session/manifest.d.ts": {
|
|
1885
|
-
"sha256": "
|
|
1885
|
+
"sha256": "82840f71d8cde0d10834fe411c9ea494e043af93637c4ffb9c14fdf27bbb1b8c",
|
|
1886
1886
|
"bytes": 1594
|
|
1887
1887
|
},
|
|
1888
1888
|
"v2/durable-core/schemas/session/manifest.js": {
|
|
@@ -1938,7 +1938,7 @@
|
|
|
1938
1938
|
"bytes": 4205
|
|
1939
1939
|
},
|
|
1940
1940
|
"v2/durable-core/tokens/payloads.d.ts": {
|
|
1941
|
-
"sha256": "
|
|
1941
|
+
"sha256": "4b84627aeee7c8f6d4c142e9ffb3511674d74d012601731d81193dfd6b95ba1c",
|
|
1942
1942
|
"bytes": 6921
|
|
1943
1943
|
},
|
|
1944
1944
|
"v2/durable-core/tokens/payloads.js": {
|
|
@@ -2114,12 +2114,12 @@
|
|
|
2114
2114
|
"bytes": 28456
|
|
2115
2115
|
},
|
|
2116
2116
|
"v2/infra/local/session-summary-provider/index.d.ts": {
|
|
2117
|
-
"sha256": "
|
|
2118
|
-
"bytes":
|
|
2117
|
+
"sha256": "291d1303ef9f1ee0889830c5b42964a2d9b8c7d27b36a9b55d710ca5950c32ca",
|
|
2118
|
+
"bytes": 1136
|
|
2119
2119
|
},
|
|
2120
2120
|
"v2/infra/local/session-summary-provider/index.js": {
|
|
2121
|
-
"sha256": "
|
|
2122
|
-
"bytes":
|
|
2121
|
+
"sha256": "93ca7df8ae1ae5e29c29470a6fb947e05b2def481c2b3d8decf4a5dbe8fd8e1c",
|
|
2122
|
+
"bytes": 7611
|
|
2123
2123
|
},
|
|
2124
2124
|
"v2/infra/local/sha256/index.d.ts": {
|
|
2125
2125
|
"sha256": "8a727b7e54a38275ca6f9f1b8730f97cfc0a212df035df1bdc58e716e6824230",
|
|
@@ -2386,12 +2386,12 @@
|
|
|
2386
2386
|
"bytes": 732
|
|
2387
2387
|
},
|
|
2388
2388
|
"v2/projections/resume-ranking.d.ts": {
|
|
2389
|
-
"sha256": "
|
|
2390
|
-
"bytes":
|
|
2389
|
+
"sha256": "5f15f10b632b8e771c74e1f3823616f761be4142493d1142176583e6495528b2",
|
|
2390
|
+
"bytes": 3531
|
|
2391
2391
|
},
|
|
2392
2392
|
"v2/projections/resume-ranking.js": {
|
|
2393
|
-
"sha256": "
|
|
2394
|
-
"bytes":
|
|
2393
|
+
"sha256": "b9d48c8e08ae8b794771b44fc592158422e832ff64633817fa11093f64282715",
|
|
2394
|
+
"bytes": 6782
|
|
2395
2395
|
},
|
|
2396
2396
|
"v2/projections/run-context.d.ts": {
|
|
2397
2397
|
"sha256": "a4d57470a435ac9860f60b3244d1b828853995027cd510d8da42762d21b2a687",
|
|
@@ -2458,12 +2458,12 @@
|
|
|
2458
2458
|
"bytes": 77
|
|
2459
2459
|
},
|
|
2460
2460
|
"v2/usecases/enumerate-sessions.d.ts": {
|
|
2461
|
-
"sha256": "
|
|
2462
|
-
"bytes":
|
|
2461
|
+
"sha256": "230eda9e0f377741cb9018edba4b8c26cecde9439e2db68b249b0cab3e9e50aa",
|
|
2462
|
+
"bytes": 809
|
|
2463
2463
|
},
|
|
2464
2464
|
"v2/usecases/enumerate-sessions.js": {
|
|
2465
|
-
"sha256": "
|
|
2466
|
-
"bytes":
|
|
2465
|
+
"sha256": "7fd54b65e914487ea0cfbc60e7059aa1134b3f9850ae2af0fdba340f9aa0b282",
|
|
2466
|
+
"bytes": 1091
|
|
2467
2467
|
},
|
|
2468
2468
|
"v2/usecases/execution-session-gate.d.ts": {
|
|
2469
2469
|
"sha256": "339c4a8e02a77416e725e063a57d39a20788244498ae2c7a31dc48d111af6280",
|
|
@@ -14,7 +14,7 @@ function toMcpResult(result) {
|
|
|
14
14
|
switch (result.type) {
|
|
15
15
|
case 'success': {
|
|
16
16
|
if (!jsonResponsesOverride) {
|
|
17
|
-
const formatted = (0, v2_response_formatter_js_1.formatV2ExecutionResponse)(result.data);
|
|
17
|
+
const formatted = (0, v2_response_formatter_js_1.formatV2ExecutionResponse)(result.data) ?? (0, v2_response_formatter_js_1.formatV2ResumeResponse)(result.data);
|
|
18
18
|
if (formatted !== null) {
|
|
19
19
|
const content = [{ type: 'text', text: formatted.primary }];
|
|
20
20
|
if (formatted.references != null) {
|
|
@@ -25,6 +25,8 @@ async function handleV2ResumeSession(input, ctx) {
|
|
|
25
25
|
gitHeadSha: input.gitHeadSha ?? anchorValue(anchors, 'git_head_sha'),
|
|
26
26
|
gitBranch: input.gitBranch ?? anchorValue(anchors, 'git_branch'),
|
|
27
27
|
freeTextQuery: input.query,
|
|
28
|
+
runId: input.runId,
|
|
29
|
+
sessionId: input.sessionId,
|
|
28
30
|
};
|
|
29
31
|
const resumeResult = await (0, resume_session_js_1.resumeSession)(query, v2.sessionSummaryProvider);
|
|
30
32
|
if (resumeResult.isErr()) {
|
|
@@ -75,6 +77,9 @@ function mintCandidateTokens(candidates, ports) {
|
|
|
75
77
|
resumeToken: resumeTokenRes.value,
|
|
76
78
|
snippet: candidate.snippet,
|
|
77
79
|
whyMatched: [...candidate.whyMatched],
|
|
80
|
+
pendingStepId: candidate.pendingStepId,
|
|
81
|
+
isComplete: candidate.isComplete,
|
|
82
|
+
lastModifiedMs: candidate.lastModifiedMs,
|
|
78
83
|
nextCall: {
|
|
79
84
|
tool: 'continue_workflow',
|
|
80
85
|
params: { continueToken: resumeTokenRes.value, intent: 'rehydrate' },
|
|
@@ -1162,7 +1162,10 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1162
1162
|
workflowId: z.ZodString;
|
|
1163
1163
|
resumeToken: z.ZodString;
|
|
1164
1164
|
snippet: z.ZodString;
|
|
1165
|
-
|
|
1165
|
+
pendingStepId: z.ZodNullable<z.ZodString>;
|
|
1166
|
+
isComplete: z.ZodBoolean;
|
|
1167
|
+
lastModifiedMs: z.ZodNullable<z.ZodNumber>;
|
|
1168
|
+
whyMatched: z.ZodArray<z.ZodEnum<["matched_exact_id", "matched_head_sha", "matched_branch", "matched_notes", "matched_notes_partial", "matched_workflow_id", "recency_fallback"]>, "many">;
|
|
1166
1169
|
nextCall: z.ZodObject<{
|
|
1167
1170
|
tool: z.ZodLiteral<"continue_workflow">;
|
|
1168
1171
|
params: z.ZodObject<{
|
|
@@ -1190,8 +1193,9 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1190
1193
|
}>;
|
|
1191
1194
|
}, "strip", z.ZodTypeAny, {
|
|
1192
1195
|
workflowId: string;
|
|
1193
|
-
sessionId: string;
|
|
1194
1196
|
runId: string;
|
|
1197
|
+
sessionId: string;
|
|
1198
|
+
isComplete: boolean;
|
|
1195
1199
|
nextCall: {
|
|
1196
1200
|
params: {
|
|
1197
1201
|
continueToken: string;
|
|
@@ -1201,11 +1205,14 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1201
1205
|
};
|
|
1202
1206
|
resumeToken: string;
|
|
1203
1207
|
snippet: string;
|
|
1204
|
-
|
|
1208
|
+
pendingStepId: string | null;
|
|
1209
|
+
lastModifiedMs: number | null;
|
|
1210
|
+
whyMatched: ("matched_exact_id" | "matched_head_sha" | "matched_branch" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "recency_fallback")[];
|
|
1205
1211
|
}, {
|
|
1206
1212
|
workflowId: string;
|
|
1207
|
-
sessionId: string;
|
|
1208
1213
|
runId: string;
|
|
1214
|
+
sessionId: string;
|
|
1215
|
+
isComplete: boolean;
|
|
1209
1216
|
nextCall: {
|
|
1210
1217
|
params: {
|
|
1211
1218
|
continueToken: string;
|
|
@@ -1215,14 +1222,17 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1215
1222
|
};
|
|
1216
1223
|
resumeToken: string;
|
|
1217
1224
|
snippet: string;
|
|
1218
|
-
|
|
1225
|
+
pendingStepId: string | null;
|
|
1226
|
+
lastModifiedMs: number | null;
|
|
1227
|
+
whyMatched: ("matched_exact_id" | "matched_head_sha" | "matched_branch" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "recency_fallback")[];
|
|
1219
1228
|
}>, "many">;
|
|
1220
1229
|
totalEligible: z.ZodNumber;
|
|
1221
1230
|
}, "strip", z.ZodTypeAny, {
|
|
1222
1231
|
candidates: {
|
|
1223
1232
|
workflowId: string;
|
|
1224
|
-
sessionId: string;
|
|
1225
1233
|
runId: string;
|
|
1234
|
+
sessionId: string;
|
|
1235
|
+
isComplete: boolean;
|
|
1226
1236
|
nextCall: {
|
|
1227
1237
|
params: {
|
|
1228
1238
|
continueToken: string;
|
|
@@ -1232,14 +1242,17 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1232
1242
|
};
|
|
1233
1243
|
resumeToken: string;
|
|
1234
1244
|
snippet: string;
|
|
1235
|
-
|
|
1245
|
+
pendingStepId: string | null;
|
|
1246
|
+
lastModifiedMs: number | null;
|
|
1247
|
+
whyMatched: ("matched_exact_id" | "matched_head_sha" | "matched_branch" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "recency_fallback")[];
|
|
1236
1248
|
}[];
|
|
1237
1249
|
totalEligible: number;
|
|
1238
1250
|
}, {
|
|
1239
1251
|
candidates: {
|
|
1240
1252
|
workflowId: string;
|
|
1241
|
-
sessionId: string;
|
|
1242
1253
|
runId: string;
|
|
1254
|
+
sessionId: string;
|
|
1255
|
+
isComplete: boolean;
|
|
1243
1256
|
nextCall: {
|
|
1244
1257
|
params: {
|
|
1245
1258
|
continueToken: string;
|
|
@@ -1249,7 +1262,9 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
1249
1262
|
};
|
|
1250
1263
|
resumeToken: string;
|
|
1251
1264
|
snippet: string;
|
|
1252
|
-
|
|
1265
|
+
pendingStepId: string | null;
|
|
1266
|
+
lastModifiedMs: number | null;
|
|
1267
|
+
whyMatched: ("matched_exact_id" | "matched_head_sha" | "matched_branch" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "recency_fallback")[];
|
|
1253
1268
|
}[];
|
|
1254
1269
|
totalEligible: number;
|
|
1255
1270
|
}>;
|
|
@@ -244,14 +244,21 @@ exports.V2ResumeSessionOutputSchema = zod_1.z.object({
|
|
|
244
244
|
workflowId: zod_1.z.string().min(1),
|
|
245
245
|
resumeToken: zod_1.z.string().regex(token_patterns_js_1.STATE_TOKEN_PATTERN, 'Invalid resumeToken format'),
|
|
246
246
|
snippet: zod_1.z.string().max(1024),
|
|
247
|
+
pendingStepId: zod_1.z.string().nullable().describe('The current pending step ID (e.g. "phase-3-implement") if the workflow is in progress. ' +
|
|
248
|
+
'Null if the workflow is complete or the step could not be determined.'),
|
|
249
|
+
isComplete: zod_1.z.boolean().describe('Whether the workflow run has completed. Completed sessions are deprioritized in ranking.'),
|
|
250
|
+
lastModifiedMs: zod_1.z.number().nullable().describe('Filesystem modification time (epoch ms) of the session. Null if unavailable.'),
|
|
247
251
|
whyMatched: zod_1.z.array(zod_1.z.enum([
|
|
252
|
+
'matched_exact_id',
|
|
248
253
|
'matched_head_sha',
|
|
249
254
|
'matched_branch',
|
|
250
255
|
'matched_notes',
|
|
256
|
+
'matched_notes_partial',
|
|
251
257
|
'matched_workflow_id',
|
|
252
258
|
'recency_fallback',
|
|
253
259
|
])).describe('Match signals explaining why this candidate was ranked. ' +
|
|
254
|
-
'
|
|
260
|
+
'matched_exact_id/head_sha/branch/notes = strong signal. ' +
|
|
261
|
+
'matched_notes_partial = moderate signal (some query words matched). ' +
|
|
255
262
|
'recency_fallback = no strong signal; inspect the snippet before resuming.'),
|
|
256
263
|
nextCall: exports.V2ResumeNextCallSchema,
|
|
257
264
|
})).max(5),
|
package/dist/mcp/server.js
CHANGED
package/dist/mcp/v2/tools.d.ts
CHANGED
|
@@ -147,17 +147,23 @@ export declare const V2ContinueWorkflowInput: z.ZodEffects<z.ZodEffects<z.ZodObj
|
|
|
147
147
|
export type V2ContinueWorkflowInput = z.infer<typeof V2ContinueWorkflowInput>;
|
|
148
148
|
export declare const V2ResumeSessionInput: z.ZodObject<{
|
|
149
149
|
query: z.ZodOptional<z.ZodString>;
|
|
150
|
+
runId: z.ZodOptional<z.ZodString>;
|
|
151
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
150
152
|
gitBranch: z.ZodOptional<z.ZodString>;
|
|
151
153
|
gitHeadSha: z.ZodOptional<z.ZodString>;
|
|
152
154
|
workspacePath: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
153
155
|
}, "strict", z.ZodTypeAny, {
|
|
154
156
|
workspacePath?: string | undefined;
|
|
155
157
|
query?: string | undefined;
|
|
158
|
+
runId?: string | undefined;
|
|
159
|
+
sessionId?: string | undefined;
|
|
156
160
|
gitBranch?: string | undefined;
|
|
157
161
|
gitHeadSha?: string | undefined;
|
|
158
162
|
}, {
|
|
159
163
|
workspacePath?: string | undefined;
|
|
160
164
|
query?: string | undefined;
|
|
165
|
+
runId?: string | undefined;
|
|
166
|
+
sessionId?: string | undefined;
|
|
161
167
|
gitBranch?: string | undefined;
|
|
162
168
|
gitHeadSha?: string | undefined;
|
|
163
169
|
}>;
|
package/dist/mcp/v2/tools.js
CHANGED
|
@@ -85,7 +85,12 @@ exports.V2ContinueWorkflowInput = exports.V2ContinueWorkflowInputShape
|
|
|
85
85
|
});
|
|
86
86
|
exports.V2ResumeSessionInput = zod_1.z.object({
|
|
87
87
|
query: zod_1.z.string().min(1).max(256).optional().describe('Free text search to find a relevant session. Matches against recap notes and workflow IDs. ' +
|
|
88
|
+
'Tip: use the user\'s exact words (e.g. "mr ownership", "ACEI-1234"). ' +
|
|
88
89
|
'Without query, only git-context matching runs — the semantic (notes) tier is skipped.'),
|
|
90
|
+
runId: zod_1.z.string().regex(/^run_[a-z0-9]+$/).optional().describe('Exact run ID to find (e.g. "run_tbi2ag7njfjgc2aitt4qg5eaiq"). ' +
|
|
91
|
+
'When provided, the matching session is returned as the sole top-priority candidate.'),
|
|
92
|
+
sessionId: zod_1.z.string().regex(/^sess_[a-zA-Z0-9_]+$/).optional().describe('Exact session ID to find (e.g. "sess_s5o2ieem4mwypoqnn6ztzyyag4"). ' +
|
|
93
|
+
'When provided, the matching session is returned as the sole top-priority candidate.'),
|
|
89
94
|
gitBranch: zod_1.z.string().max(256).optional().describe('Git branch name to match against session observations. Overrides auto-detected branch.'),
|
|
90
95
|
gitHeadSha: zod_1.z.string().regex(/^[0-9a-f]{40}$/).optional().describe('Git HEAD SHA to match against session observations. Overrides auto-detected HEAD.'),
|
|
91
96
|
workspacePath: zod_1.z.string()
|
|
@@ -9,3 +9,4 @@ export interface FormattedResponse {
|
|
|
9
9
|
readonly supplements?: readonly FormattedSupplement[];
|
|
10
10
|
}
|
|
11
11
|
export declare function formatV2ExecutionResponse(data: unknown): FormattedResponse | null;
|
|
12
|
+
export declare function formatV2ResumeResponse(data: unknown): FormattedResponse | null;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatV2ExecutionResponse = formatV2ExecutionResponse;
|
|
4
|
+
exports.formatV2ResumeResponse = formatV2ResumeResponse;
|
|
4
5
|
const render_envelope_js_1 = require("./render-envelope.js");
|
|
5
6
|
const response_supplements_js_1 = require("./response-supplements.js");
|
|
6
7
|
function isV2ExecutionResponse(data) {
|
|
@@ -388,3 +389,150 @@ function formatV2Clean(data) {
|
|
|
388
389
|
primary: formatCleanSuccess(data),
|
|
389
390
|
};
|
|
390
391
|
}
|
|
392
|
+
function isResumeSessionResponse(data) {
|
|
393
|
+
if (typeof data !== 'object' || data === null)
|
|
394
|
+
return false;
|
|
395
|
+
const d = data;
|
|
396
|
+
return (Array.isArray(d.candidates) &&
|
|
397
|
+
typeof d.totalEligible === 'number' &&
|
|
398
|
+
!('pending' in d) &&
|
|
399
|
+
!('nextIntent' in d));
|
|
400
|
+
}
|
|
401
|
+
const WHY_MATCHED_LABELS = {
|
|
402
|
+
matched_exact_id: 'Exact ID match',
|
|
403
|
+
matched_head_sha: 'Same git commit (HEAD SHA)',
|
|
404
|
+
matched_branch: 'Same git branch',
|
|
405
|
+
matched_notes: 'Query matched session notes',
|
|
406
|
+
matched_notes_partial: 'Query partially matched session notes',
|
|
407
|
+
matched_workflow_id: 'Query matched workflow type',
|
|
408
|
+
recency_fallback: 'No strong match signal (recent session)',
|
|
409
|
+
};
|
|
410
|
+
function formatRelativeTime(epochMs) {
|
|
411
|
+
const diffMs = Date.now() - epochMs;
|
|
412
|
+
if (diffMs < 0)
|
|
413
|
+
return 'just now';
|
|
414
|
+
const minutes = Math.floor(diffMs / 60000);
|
|
415
|
+
if (minutes < 1)
|
|
416
|
+
return 'just now';
|
|
417
|
+
if (minutes < 60)
|
|
418
|
+
return `${minutes} minute${minutes === 1 ? '' : 's'} ago`;
|
|
419
|
+
const hours = Math.floor(minutes / 60);
|
|
420
|
+
if (hours < 24)
|
|
421
|
+
return `${hours} hour${hours === 1 ? '' : 's'} ago`;
|
|
422
|
+
const days = Math.floor(hours / 24);
|
|
423
|
+
if (days < 7)
|
|
424
|
+
return `${days} day${days === 1 ? '' : 's'} ago`;
|
|
425
|
+
const weeks = Math.floor(days / 7);
|
|
426
|
+
if (weeks < 5)
|
|
427
|
+
return `${weeks} week${weeks === 1 ? '' : 's'} ago`;
|
|
428
|
+
const months = Math.floor(days / 30);
|
|
429
|
+
return `${months} month${months === 1 ? '' : 's'} ago`;
|
|
430
|
+
}
|
|
431
|
+
function formatResumeCandidate(c, index) {
|
|
432
|
+
const lines = [];
|
|
433
|
+
const matchLabel = c.whyMatched.map(w => WHY_MATCHED_LABELS[w] ?? w).join(', ');
|
|
434
|
+
const isWeak = c.whyMatched.every(w => w === 'recency_fallback');
|
|
435
|
+
const statusTag = c.isComplete ? ' (completed)' : '';
|
|
436
|
+
lines.push(`### Candidate ${index + 1}: \`${c.workflowId}\`${statusTag}${isWeak ? ' (weak match)' : ''}`);
|
|
437
|
+
lines.push(`- **Session**: \`${c.sessionId}\``);
|
|
438
|
+
lines.push(`- **Run**: \`${c.runId}\``);
|
|
439
|
+
lines.push(`- **Match reason**: ${matchLabel}`);
|
|
440
|
+
if (c.pendingStepId) {
|
|
441
|
+
lines.push(`- **Current step**: \`${c.pendingStepId}\``);
|
|
442
|
+
}
|
|
443
|
+
else if (c.isComplete) {
|
|
444
|
+
lines.push('- **Status**: Workflow completed');
|
|
445
|
+
}
|
|
446
|
+
if (c.lastModifiedMs != null) {
|
|
447
|
+
lines.push(`- **Last active**: ${formatRelativeTime(c.lastModifiedMs)}`);
|
|
448
|
+
}
|
|
449
|
+
if (c.snippet) {
|
|
450
|
+
const preview = c.snippet.length > 200 ? c.snippet.slice(0, 200) + '...' : c.snippet;
|
|
451
|
+
lines.push(`- **Preview**: ${preview.replace(/\n/g, ' ')}`);
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
lines.push('- **Preview**: (no recap notes available)');
|
|
455
|
+
}
|
|
456
|
+
if (c.isComplete) {
|
|
457
|
+
lines.push('');
|
|
458
|
+
lines.push('> This workflow has already completed. Resuming it will show the final state.');
|
|
459
|
+
}
|
|
460
|
+
lines.push('');
|
|
461
|
+
lines.push('To resume, call `continue_workflow` with:');
|
|
462
|
+
lines.push('```json');
|
|
463
|
+
lines.push(JSON.stringify(c.nextCall.params, null, 2));
|
|
464
|
+
lines.push('```');
|
|
465
|
+
return lines.join('\n');
|
|
466
|
+
}
|
|
467
|
+
const SEARCH_PARAMS_HELP = [
|
|
468
|
+
'**To narrow results, call `resume_session` again with any of these parameters:**',
|
|
469
|
+
'- `query`: Free text keywords from the session (e.g. "mr ownership", "ACEI-1234", "login feature")',
|
|
470
|
+
'- `runId`: Exact run ID if the user has one (e.g. "run_abc123def456")',
|
|
471
|
+
'- `sessionId`: Exact session ID if the user has one (e.g. "sess_abc123")',
|
|
472
|
+
'- `workspacePath`: Absolute path to the workspace (helps match by git branch/commit)',
|
|
473
|
+
].join('\n');
|
|
474
|
+
function formatV2ResumeResponse(data) {
|
|
475
|
+
if (!isResumeSessionResponse(data))
|
|
476
|
+
return null;
|
|
477
|
+
const { candidates, totalEligible } = data;
|
|
478
|
+
const lines = [];
|
|
479
|
+
if (candidates.length === 0) {
|
|
480
|
+
lines.push('## No Resumable Sessions Found');
|
|
481
|
+
lines.push('');
|
|
482
|
+
lines.push(`Searched ${totalEligible} session(s) but none matched your query or workspace context.`);
|
|
483
|
+
lines.push('');
|
|
484
|
+
lines.push('**What to do**: Ask the user for more details about which session they want to resume. They might know:');
|
|
485
|
+
lines.push('- A description of what they were working on (pass as `query`)');
|
|
486
|
+
lines.push('- A run ID or session ID (pass as `runId` or `sessionId`)');
|
|
487
|
+
lines.push('- Or start a fresh workflow with `start_workflow`.');
|
|
488
|
+
lines.push('');
|
|
489
|
+
lines.push(SEARCH_PARAMS_HELP);
|
|
490
|
+
return { primary: lines.join('\n') };
|
|
491
|
+
}
|
|
492
|
+
const hasStrongMatch = candidates.some(c => !c.whyMatched.every(w => w === 'recency_fallback'));
|
|
493
|
+
const allRecencyFallback = !hasStrongMatch;
|
|
494
|
+
if (allRecencyFallback) {
|
|
495
|
+
lines.push('## Recent Workflow Sessions');
|
|
496
|
+
lines.push('');
|
|
497
|
+
lines.push(`No specific search criteria matched, so here are the **${candidates.length} most recent** sessions (out of ${totalEligible} total).`);
|
|
498
|
+
lines.push('');
|
|
499
|
+
lines.push('**Action required**: Present these to the user and ask which one they want to resume. If none of these are right, ask the user to describe what they were working on so you can search more specifically.');
|
|
500
|
+
lines.push('');
|
|
501
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
502
|
+
lines.push(formatResumeCandidate(candidates[i], i));
|
|
503
|
+
lines.push('');
|
|
504
|
+
}
|
|
505
|
+
if (totalEligible > candidates.length) {
|
|
506
|
+
lines.push('---');
|
|
507
|
+
lines.push(`${totalEligible - candidates.length} more session(s) not shown.`);
|
|
508
|
+
lines.push('');
|
|
509
|
+
}
|
|
510
|
+
lines.push(SEARCH_PARAMS_HELP);
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
lines.push('## Resumable Workflow Sessions');
|
|
514
|
+
lines.push('');
|
|
515
|
+
lines.push(`Found **${totalEligible}** session(s) total. Showing the top ${candidates.length} ranked by match strength.`);
|
|
516
|
+
lines.push('');
|
|
517
|
+
const best = candidates[0];
|
|
518
|
+
const bestIsExact = best.whyMatched.includes('matched_exact_id');
|
|
519
|
+
if (bestIsExact) {
|
|
520
|
+
lines.push(`**Recommendation**: Candidate 1 is an exact ID match. Resume it directly.`);
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
lines.push(`**Recommendation**: Candidate 1 has the strongest match signal. Present the top candidates to the user and let them confirm which one to resume.`);
|
|
524
|
+
}
|
|
525
|
+
lines.push('');
|
|
526
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
527
|
+
lines.push(formatResumeCandidate(candidates[i], i));
|
|
528
|
+
lines.push('');
|
|
529
|
+
}
|
|
530
|
+
if (totalEligible > candidates.length) {
|
|
531
|
+
lines.push('---');
|
|
532
|
+
lines.push(`${totalEligible - candidates.length} more session(s) not shown.`);
|
|
533
|
+
lines.push('');
|
|
534
|
+
lines.push(SEARCH_PARAMS_HELP);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return { primary: lines.join('\n') };
|
|
538
|
+
}
|
|
@@ -165,42 +165,42 @@ exports.CHECKPOINT_WORKFLOW_PROTOCOL = {
|
|
|
165
165
|
exports.RESUME_SESSION_PROTOCOL = {
|
|
166
166
|
canonicalParams: {
|
|
167
167
|
required: [],
|
|
168
|
-
optional: ['query', 'gitBranch', 'gitHeadSha', 'workspacePath'],
|
|
168
|
+
optional: ['query', 'runId', 'sessionId', 'gitBranch', 'gitHeadSha', 'workspacePath'],
|
|
169
169
|
},
|
|
170
170
|
descriptions: {
|
|
171
171
|
standard: {
|
|
172
|
-
purpose: 'Find and reconnect to an existing WorkRail
|
|
173
|
-
whenToUse: 'Use this when
|
|
172
|
+
purpose: 'Find and reconnect to an existing WorkRail workflow session. WorkRail is a workflow engine that persists session state across chat conversations. When a user says "resume my workflow", this is the tool to call.',
|
|
173
|
+
whenToUse: 'Use this when the user wants to resume, continue, or reconnect to a previously started workflow. The user may provide a session ID, run ID, a description of what they were working on, or nothing at all. This tool searches stored sessions and returns the best matches.',
|
|
174
174
|
rules: [
|
|
175
|
-
'
|
|
176
|
-
'
|
|
177
|
-
'
|
|
178
|
-
'
|
|
179
|
-
'
|
|
180
|
-
'If
|
|
175
|
+
'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
|
+
'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) so WorkRail can also match by git context (branch, commit).',
|
|
178
|
+
'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"). The response will give you the full session context.',
|
|
180
|
+
'If no candidates match, ask the user for more details or suggest starting a fresh workflow with start_workflow.',
|
|
181
181
|
],
|
|
182
182
|
examplePayload: {
|
|
183
183
|
workspacePath: '/Users/you/git/my-project',
|
|
184
184
|
query: 'resume the coding task workflow for protocol drift',
|
|
185
185
|
},
|
|
186
|
-
returns: 'Up to 5 ranked candidates,
|
|
186
|
+
returns: 'Up to 5 ranked candidates with match signals, session previews, and ready-to-use continuation templates. The response explains which candidate to pick and exactly how to resume it.',
|
|
187
187
|
},
|
|
188
188
|
authoritative: {
|
|
189
|
-
purpose: 'Find an existing WorkRail
|
|
190
|
-
whenToUse: 'Call this when resuming a workflow
|
|
189
|
+
purpose: 'Find an existing WorkRail workflow session and reconnect to it. WorkRail persists workflow state across chat conversations. When a user says "resume my workflow", call this tool.',
|
|
190
|
+
whenToUse: 'Call this when resuming a workflow. The user may provide a run ID, session ID, a description, or nothing.',
|
|
191
191
|
rules: [
|
|
192
|
-
'
|
|
193
|
-
'
|
|
194
|
-
'
|
|
195
|
-
'
|
|
196
|
-
'
|
|
197
|
-
'
|
|
192
|
+
'If the user provides a run ID (run_...) or session ID (sess_...), pass it as runId or sessionId for exact lookup.',
|
|
193
|
+
'If the user describes their task, pass their words as query to search session notes.',
|
|
194
|
+
'Always pass workspacePath from your system parameters for git-context matching.',
|
|
195
|
+
'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").',
|
|
197
|
+
'If no candidates match, ask for more details or start a fresh workflow.',
|
|
198
198
|
],
|
|
199
199
|
examplePayload: {
|
|
200
200
|
workspacePath: '/Users/you/git/my-project',
|
|
201
201
|
query: 'resume the coding task workflow for protocol drift',
|
|
202
202
|
},
|
|
203
|
-
returns: 'Up to 5 ranked candidates
|
|
203
|
+
returns: 'Up to 5 ranked candidates with match signals, previews, and ready-to-use continuation templates.',
|
|
204
204
|
},
|
|
205
205
|
},
|
|
206
206
|
};
|
|
@@ -2183,8 +2183,8 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
|
|
|
2183
2183
|
bytes: z.ZodNumber;
|
|
2184
2184
|
}, "strip", z.ZodTypeAny, {
|
|
2185
2185
|
kind: "segment_closed";
|
|
2186
|
-
sha256: string;
|
|
2187
2186
|
sessionId: string;
|
|
2187
|
+
sha256: string;
|
|
2188
2188
|
v: 1;
|
|
2189
2189
|
manifestIndex: number;
|
|
2190
2190
|
firstEventIndex: number;
|
|
@@ -2193,8 +2193,8 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
|
|
|
2193
2193
|
bytes: number;
|
|
2194
2194
|
}, {
|
|
2195
2195
|
kind: "segment_closed";
|
|
2196
|
-
sha256: string;
|
|
2197
2196
|
sessionId: string;
|
|
2197
|
+
sha256: string;
|
|
2198
2198
|
v: 1;
|
|
2199
2199
|
manifestIndex: number;
|
|
2200
2200
|
firstEventIndex: number;
|
|
@@ -4601,8 +4601,8 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
|
|
|
4601
4601
|
})[];
|
|
4602
4602
|
manifest: ({
|
|
4603
4603
|
kind: "segment_closed";
|
|
4604
|
-
sha256: string;
|
|
4605
4604
|
sessionId: string;
|
|
4605
|
+
sha256: string;
|
|
4606
4606
|
v: 1;
|
|
4607
4607
|
manifestIndex: number;
|
|
4608
4608
|
firstEventIndex: number;
|
|
@@ -5113,8 +5113,8 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
|
|
|
5113
5113
|
})[];
|
|
5114
5114
|
manifest: ({
|
|
5115
5115
|
kind: "segment_closed";
|
|
5116
|
-
sha256: string;
|
|
5117
5116
|
sessionId: string;
|
|
5117
|
+
sha256: string;
|
|
5118
5118
|
v: 1;
|
|
5119
5119
|
manifestIndex: number;
|
|
5120
5120
|
firstEventIndex: number;
|
|
@@ -7305,8 +7305,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
7305
7305
|
bytes: z.ZodNumber;
|
|
7306
7306
|
}, "strip", z.ZodTypeAny, {
|
|
7307
7307
|
kind: "segment_closed";
|
|
7308
|
-
sha256: string;
|
|
7309
7308
|
sessionId: string;
|
|
7309
|
+
sha256: string;
|
|
7310
7310
|
v: 1;
|
|
7311
7311
|
manifestIndex: number;
|
|
7312
7312
|
firstEventIndex: number;
|
|
@@ -7315,8 +7315,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
7315
7315
|
bytes: number;
|
|
7316
7316
|
}, {
|
|
7317
7317
|
kind: "segment_closed";
|
|
7318
|
-
sha256: string;
|
|
7319
7318
|
sessionId: string;
|
|
7319
|
+
sha256: string;
|
|
7320
7320
|
v: 1;
|
|
7321
7321
|
manifestIndex: number;
|
|
7322
7322
|
firstEventIndex: number;
|
|
@@ -9723,8 +9723,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
9723
9723
|
})[];
|
|
9724
9724
|
manifest: ({
|
|
9725
9725
|
kind: "segment_closed";
|
|
9726
|
-
sha256: string;
|
|
9727
9726
|
sessionId: string;
|
|
9727
|
+
sha256: string;
|
|
9728
9728
|
v: 1;
|
|
9729
9729
|
manifestIndex: number;
|
|
9730
9730
|
firstEventIndex: number;
|
|
@@ -10235,8 +10235,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
10235
10235
|
})[];
|
|
10236
10236
|
manifest: ({
|
|
10237
10237
|
kind: "segment_closed";
|
|
10238
|
-
sha256: string;
|
|
10239
10238
|
sessionId: string;
|
|
10239
|
+
sha256: string;
|
|
10240
10240
|
v: 1;
|
|
10241
10241
|
manifestIndex: number;
|
|
10242
10242
|
firstEventIndex: number;
|
|
@@ -10776,8 +10776,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
10776
10776
|
})[];
|
|
10777
10777
|
manifest: ({
|
|
10778
10778
|
kind: "segment_closed";
|
|
10779
|
-
sha256: string;
|
|
10780
10779
|
sessionId: string;
|
|
10780
|
+
sha256: string;
|
|
10781
10781
|
v: 1;
|
|
10782
10782
|
manifestIndex: number;
|
|
10783
10783
|
firstEventIndex: number;
|
|
@@ -11305,8 +11305,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
11305
11305
|
})[];
|
|
11306
11306
|
manifest: ({
|
|
11307
11307
|
kind: "segment_closed";
|
|
11308
|
-
sha256: string;
|
|
11309
11308
|
sessionId: string;
|
|
11309
|
+
sha256: string;
|
|
11310
11310
|
v: 1;
|
|
11311
11311
|
manifestIndex: number;
|
|
11312
11312
|
firstEventIndex: number;
|
|
@@ -11,8 +11,8 @@ export declare const ManifestRecordV1Schema: z.ZodDiscriminatedUnion<"kind", [z.
|
|
|
11
11
|
bytes: z.ZodNumber;
|
|
12
12
|
}, "strip", z.ZodTypeAny, {
|
|
13
13
|
kind: "segment_closed";
|
|
14
|
-
sha256: string;
|
|
15
14
|
sessionId: string;
|
|
15
|
+
sha256: string;
|
|
16
16
|
v: 1;
|
|
17
17
|
manifestIndex: number;
|
|
18
18
|
firstEventIndex: number;
|
|
@@ -21,8 +21,8 @@ export declare const ManifestRecordV1Schema: z.ZodDiscriminatedUnion<"kind", [z.
|
|
|
21
21
|
bytes: number;
|
|
22
22
|
}, {
|
|
23
23
|
kind: "segment_closed";
|
|
24
|
-
sha256: string;
|
|
25
24
|
sessionId: string;
|
|
25
|
+
sha256: string;
|
|
26
26
|
v: 1;
|
|
27
27
|
manifestIndex: number;
|
|
28
28
|
firstEventIndex: number;
|
|
@@ -14,13 +14,13 @@ export declare const StateTokenPayloadV1Schema: z.ZodObject<{
|
|
|
14
14
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
15
15
|
workflowHashRef: z.ZodEffects<z.ZodString, WorkflowHashRef, string>;
|
|
16
16
|
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
runId: string & {
|
|
18
|
+
readonly __brand: "v2.RunId";
|
|
19
|
+
};
|
|
17
20
|
sessionId: string & {
|
|
18
21
|
readonly __brand: "v2.SessionId";
|
|
19
22
|
};
|
|
20
23
|
tokenKind: "state";
|
|
21
|
-
runId: string & {
|
|
22
|
-
readonly __brand: "v2.RunId";
|
|
23
|
-
};
|
|
24
24
|
nodeId: string & {
|
|
25
25
|
readonly __brand: "v2.NodeId";
|
|
26
26
|
};
|
|
@@ -29,9 +29,9 @@ export declare const StateTokenPayloadV1Schema: z.ZodObject<{
|
|
|
29
29
|
};
|
|
30
30
|
tokenVersion: 1;
|
|
31
31
|
}, {
|
|
32
|
+
runId: string;
|
|
32
33
|
sessionId: string;
|
|
33
34
|
tokenKind: "state";
|
|
34
|
-
runId: string;
|
|
35
35
|
nodeId: string;
|
|
36
36
|
workflowHashRef: string;
|
|
37
37
|
tokenVersion: 1;
|
|
@@ -52,13 +52,13 @@ export declare const AckTokenPayloadV1Schema: z.ZodObject<{
|
|
|
52
52
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
53
53
|
attemptId: z.ZodEffects<z.ZodString, AttemptId, string>;
|
|
54
54
|
}, "strip", z.ZodTypeAny, {
|
|
55
|
+
runId: string & {
|
|
56
|
+
readonly __brand: "v2.RunId";
|
|
57
|
+
};
|
|
55
58
|
sessionId: string & {
|
|
56
59
|
readonly __brand: "v2.SessionId";
|
|
57
60
|
};
|
|
58
61
|
tokenKind: "ack";
|
|
59
|
-
runId: string & {
|
|
60
|
-
readonly __brand: "v2.RunId";
|
|
61
|
-
};
|
|
62
62
|
nodeId: string & {
|
|
63
63
|
readonly __brand: "v2.NodeId";
|
|
64
64
|
};
|
|
@@ -67,9 +67,9 @@ export declare const AckTokenPayloadV1Schema: z.ZodObject<{
|
|
|
67
67
|
};
|
|
68
68
|
tokenVersion: 1;
|
|
69
69
|
}, {
|
|
70
|
+
runId: string;
|
|
70
71
|
sessionId: string;
|
|
71
72
|
tokenKind: "ack";
|
|
72
|
-
runId: string;
|
|
73
73
|
nodeId: string;
|
|
74
74
|
attemptId: string;
|
|
75
75
|
tokenVersion: 1;
|
|
@@ -90,13 +90,13 @@ export declare const CheckpointTokenPayloadV1Schema: z.ZodObject<{
|
|
|
90
90
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
91
91
|
attemptId: z.ZodEffects<z.ZodString, AttemptId, string>;
|
|
92
92
|
}, "strip", z.ZodTypeAny, {
|
|
93
|
+
runId: string & {
|
|
94
|
+
readonly __brand: "v2.RunId";
|
|
95
|
+
};
|
|
93
96
|
sessionId: string & {
|
|
94
97
|
readonly __brand: "v2.SessionId";
|
|
95
98
|
};
|
|
96
99
|
tokenKind: "checkpoint";
|
|
97
|
-
runId: string & {
|
|
98
|
-
readonly __brand: "v2.RunId";
|
|
99
|
-
};
|
|
100
100
|
nodeId: string & {
|
|
101
101
|
readonly __brand: "v2.NodeId";
|
|
102
102
|
};
|
|
@@ -105,9 +105,9 @@ export declare const CheckpointTokenPayloadV1Schema: z.ZodObject<{
|
|
|
105
105
|
};
|
|
106
106
|
tokenVersion: 1;
|
|
107
107
|
}, {
|
|
108
|
+
runId: string;
|
|
108
109
|
sessionId: string;
|
|
109
110
|
tokenKind: "checkpoint";
|
|
110
|
-
runId: string;
|
|
111
111
|
nodeId: string;
|
|
112
112
|
attemptId: string;
|
|
113
113
|
tokenVersion: 1;
|
|
@@ -128,13 +128,13 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
128
128
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
129
129
|
workflowHashRef: z.ZodEffects<z.ZodString, WorkflowHashRef, string>;
|
|
130
130
|
}, "strip", z.ZodTypeAny, {
|
|
131
|
+
runId: string & {
|
|
132
|
+
readonly __brand: "v2.RunId";
|
|
133
|
+
};
|
|
131
134
|
sessionId: string & {
|
|
132
135
|
readonly __brand: "v2.SessionId";
|
|
133
136
|
};
|
|
134
137
|
tokenKind: "state";
|
|
135
|
-
runId: string & {
|
|
136
|
-
readonly __brand: "v2.RunId";
|
|
137
|
-
};
|
|
138
138
|
nodeId: string & {
|
|
139
139
|
readonly __brand: "v2.NodeId";
|
|
140
140
|
};
|
|
@@ -143,9 +143,9 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
143
143
|
};
|
|
144
144
|
tokenVersion: 1;
|
|
145
145
|
}, {
|
|
146
|
+
runId: string;
|
|
146
147
|
sessionId: string;
|
|
147
148
|
tokenKind: "state";
|
|
148
|
-
runId: string;
|
|
149
149
|
nodeId: string;
|
|
150
150
|
workflowHashRef: string;
|
|
151
151
|
tokenVersion: 1;
|
|
@@ -157,13 +157,13 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
157
157
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
158
158
|
attemptId: z.ZodEffects<z.ZodString, AttemptId, string>;
|
|
159
159
|
}, "strip", z.ZodTypeAny, {
|
|
160
|
+
runId: string & {
|
|
161
|
+
readonly __brand: "v2.RunId";
|
|
162
|
+
};
|
|
160
163
|
sessionId: string & {
|
|
161
164
|
readonly __brand: "v2.SessionId";
|
|
162
165
|
};
|
|
163
166
|
tokenKind: "ack";
|
|
164
|
-
runId: string & {
|
|
165
|
-
readonly __brand: "v2.RunId";
|
|
166
|
-
};
|
|
167
167
|
nodeId: string & {
|
|
168
168
|
readonly __brand: "v2.NodeId";
|
|
169
169
|
};
|
|
@@ -172,9 +172,9 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
172
172
|
};
|
|
173
173
|
tokenVersion: 1;
|
|
174
174
|
}, {
|
|
175
|
+
runId: string;
|
|
175
176
|
sessionId: string;
|
|
176
177
|
tokenKind: "ack";
|
|
177
|
-
runId: string;
|
|
178
178
|
nodeId: string;
|
|
179
179
|
attemptId: string;
|
|
180
180
|
tokenVersion: 1;
|
|
@@ -186,13 +186,13 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
186
186
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
187
187
|
attemptId: z.ZodEffects<z.ZodString, AttemptId, string>;
|
|
188
188
|
}, "strip", z.ZodTypeAny, {
|
|
189
|
+
runId: string & {
|
|
190
|
+
readonly __brand: "v2.RunId";
|
|
191
|
+
};
|
|
189
192
|
sessionId: string & {
|
|
190
193
|
readonly __brand: "v2.SessionId";
|
|
191
194
|
};
|
|
192
195
|
tokenKind: "checkpoint";
|
|
193
|
-
runId: string & {
|
|
194
|
-
readonly __brand: "v2.RunId";
|
|
195
|
-
};
|
|
196
196
|
nodeId: string & {
|
|
197
197
|
readonly __brand: "v2.NodeId";
|
|
198
198
|
};
|
|
@@ -201,9 +201,9 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
201
201
|
};
|
|
202
202
|
tokenVersion: 1;
|
|
203
203
|
}, {
|
|
204
|
+
runId: string;
|
|
204
205
|
sessionId: string;
|
|
205
206
|
tokenKind: "checkpoint";
|
|
206
|
-
runId: string;
|
|
207
207
|
nodeId: string;
|
|
208
208
|
attemptId: string;
|
|
209
209
|
tokenVersion: 1;
|
|
@@ -2,12 +2,14 @@ import type { ResultAsync } from 'neverthrow';
|
|
|
2
2
|
import type { DirectoryListingPortV2 } from '../../../ports/directory-listing.port.js';
|
|
3
3
|
import type { DataDirPortV2 } from '../../../ports/data-dir.port.js';
|
|
4
4
|
import type { SessionEventLogReadonlyStorePortV2 } from '../../../ports/session-event-log-store.port.js';
|
|
5
|
+
import type { SnapshotStorePortV2 } from '../../../ports/snapshot-store.port.js';
|
|
5
6
|
import type { SessionSummaryProviderPortV2, SessionSummaryError } from '../../../ports/session-summary-provider.port.js';
|
|
6
7
|
import type { HealthySessionSummary } from '../../../projections/resume-ranking.js';
|
|
7
8
|
export interface LocalSessionSummaryProviderPorts {
|
|
8
9
|
readonly directoryListing: DirectoryListingPortV2;
|
|
9
10
|
readonly dataDir: DataDirPortV2;
|
|
10
11
|
readonly sessionStore: SessionEventLogReadonlyStorePortV2;
|
|
12
|
+
readonly snapshotStore?: SnapshotStorePortV2;
|
|
11
13
|
}
|
|
12
14
|
export declare class LocalSessionSummaryProviderV2 implements SessionSummaryProviderPortV2 {
|
|
13
15
|
private readonly ports;
|
|
@@ -7,9 +7,10 @@ const enumerate_sessions_js_1 = require("../../../usecases/enumerate-sessions.js
|
|
|
7
7
|
const session_health_js_1 = require("../../../projections/session-health.js");
|
|
8
8
|
const run_dag_js_1 = require("../../../projections/run-dag.js");
|
|
9
9
|
const node_outputs_js_1 = require("../../../projections/node-outputs.js");
|
|
10
|
+
const snapshot_state_js_1 = require("../../../durable-core/projections/snapshot-state.js");
|
|
10
11
|
const index_js_1 = require("../../../durable-core/ids/index.js");
|
|
11
12
|
const constants_js_1 = require("../../../durable-core/constants.js");
|
|
12
|
-
const MAX_SESSIONS_TO_SCAN =
|
|
13
|
+
const MAX_SESSIONS_TO_SCAN = 200;
|
|
13
14
|
const MAX_RECAP_ANCESTOR_DEPTH = 100;
|
|
14
15
|
const EMPTY_OBSERVATIONS = {
|
|
15
16
|
gitHeadSha: null,
|
|
@@ -29,20 +30,48 @@ class LocalSessionSummaryProviderV2 {
|
|
|
29
30
|
code: 'SESSION_SUMMARY_ENUMERATION_FAILED',
|
|
30
31
|
message: `Failed to enumerate sessions: ${fsErr.message}`,
|
|
31
32
|
}))
|
|
32
|
-
.andThen((
|
|
33
|
+
.andThen((entries) => collectHealthySummaries(entries.slice(0, MAX_SESSIONS_TO_SCAN), this.ports.sessionStore, this.ports.snapshotStore ?? null));
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
exports.LocalSessionSummaryProviderV2 = LocalSessionSummaryProviderV2;
|
|
36
|
-
function collectHealthySummaries(
|
|
37
|
-
return
|
|
37
|
+
function collectHealthySummaries(entries, sessionStore, snapshotStore) {
|
|
38
|
+
return entries.reduce((acc, entry) => acc.andThen((summaries) => loadSessionSummary(entry, sessionStore, snapshotStore).map((summary) => summary !== null ? [...summaries, summary] : summaries)), (0, neverthrow_1.okAsync)([]));
|
|
38
39
|
}
|
|
39
|
-
function loadSessionSummary(
|
|
40
|
+
function loadSessionSummary(entry, sessionStore, snapshotStore) {
|
|
40
41
|
return sessionStore
|
|
41
|
-
.load(sessionId)
|
|
42
|
-
.
|
|
42
|
+
.load(entry.sessionId)
|
|
43
|
+
.andThen((truth) => {
|
|
44
|
+
const projected = projectSessionSummary(entry.sessionId, truth, entry.mtimeMs);
|
|
45
|
+
if (!projected)
|
|
46
|
+
return (0, neverthrow_1.okAsync)(null);
|
|
47
|
+
if (!snapshotStore)
|
|
48
|
+
return (0, neverthrow_1.okAsync)(projected.summary);
|
|
49
|
+
const ref = safeSnapshotRef(projected.tipSnapshotRef);
|
|
50
|
+
if (!ref)
|
|
51
|
+
return (0, neverthrow_1.okAsync)(projected.summary);
|
|
52
|
+
return snapshotStore.getExecutionSnapshotV1(ref)
|
|
53
|
+
.map((snapshot) => {
|
|
54
|
+
if (!snapshot)
|
|
55
|
+
return projected.summary;
|
|
56
|
+
const engineState = snapshot.enginePayload.engineState;
|
|
57
|
+
const pending = (0, snapshot_state_js_1.derivePendingStep)(engineState);
|
|
58
|
+
const isComplete = (0, snapshot_state_js_1.deriveIsComplete)(engineState);
|
|
59
|
+
return {
|
|
60
|
+
...projected.summary,
|
|
61
|
+
pendingStepId: pending?.stepId ?? null,
|
|
62
|
+
isComplete,
|
|
63
|
+
};
|
|
64
|
+
})
|
|
65
|
+
.orElse(() => (0, neverthrow_1.okAsync)(projected.summary));
|
|
66
|
+
})
|
|
43
67
|
.orElse(() => (0, neverthrow_1.okAsync)(null));
|
|
44
68
|
}
|
|
45
|
-
function
|
|
69
|
+
function safeSnapshotRef(raw) {
|
|
70
|
+
if (!raw || !constants_js_1.SHA256_DIGEST_PATTERN.test(raw))
|
|
71
|
+
return null;
|
|
72
|
+
return (0, index_js_1.asSnapshotRef)((0, index_js_1.asSha256Digest)(raw));
|
|
73
|
+
}
|
|
74
|
+
function projectSessionSummary(sessionId, truth, mtimeMs) {
|
|
46
75
|
const health = (0, session_health_js_1.projectSessionHealthV2)(truth);
|
|
47
76
|
if (health.isErr() || health.value.kind !== 'healthy')
|
|
48
77
|
return null;
|
|
@@ -60,15 +89,21 @@ function projectSessionSummary(sessionId, truth) {
|
|
|
60
89
|
? extractAggregateRecap(outputsRes.value, bestRun.run, bestRun.tipNodeId)
|
|
61
90
|
: null;
|
|
62
91
|
return {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
92
|
+
summary: {
|
|
93
|
+
sessionId,
|
|
94
|
+
runId: bestRun.run.runId,
|
|
95
|
+
preferredTip: {
|
|
96
|
+
nodeId: bestRun.tipNodeId,
|
|
97
|
+
lastActivityEventIndex: bestRun.lastActivityEventIndex,
|
|
98
|
+
},
|
|
99
|
+
recapSnippet,
|
|
100
|
+
observations: extractObservations(truth.events),
|
|
101
|
+
workflow,
|
|
102
|
+
lastModifiedMs: mtimeMs,
|
|
103
|
+
pendingStepId: null,
|
|
104
|
+
isComplete: false,
|
|
68
105
|
},
|
|
69
|
-
|
|
70
|
-
observations: extractObservations(truth.events),
|
|
71
|
-
workflow,
|
|
106
|
+
tipSnapshotRef: bestRun.tipSnapshotRef,
|
|
72
107
|
};
|
|
73
108
|
}
|
|
74
109
|
function selectBestRun(runs) {
|
|
@@ -77,7 +112,9 @@ function selectBestRun(runs) {
|
|
|
77
112
|
if (!tipNodeId)
|
|
78
113
|
return [];
|
|
79
114
|
const tipNode = r.nodesById[tipNodeId];
|
|
80
|
-
|
|
115
|
+
if (!tipNode)
|
|
116
|
+
return [];
|
|
117
|
+
return [{ run: r, tipNodeId, tipSnapshotRef: tipNode.snapshotRef, lastActivityEventIndex: tipNode.createdAtEventIndex }];
|
|
81
118
|
});
|
|
82
119
|
if (runsWithTip.length === 0)
|
|
83
120
|
return null;
|
|
@@ -28,9 +28,16 @@ export interface HealthySessionSummary {
|
|
|
28
28
|
readonly recapSnippet: RecapSnippet | null;
|
|
29
29
|
readonly observations: SessionObservations;
|
|
30
30
|
readonly workflow: IdentifiedWorkflow;
|
|
31
|
+
readonly lastModifiedMs: number | null;
|
|
32
|
+
readonly pendingStepId: string | null;
|
|
33
|
+
readonly isComplete: boolean;
|
|
31
34
|
}
|
|
32
|
-
export type WhyMatched = 'matched_head_sha' | 'matched_branch' | 'matched_notes' | 'matched_workflow_id' | 'recency_fallback';
|
|
35
|
+
export type WhyMatched = 'matched_exact_id' | 'matched_head_sha' | 'matched_branch' | 'matched_notes' | 'matched_notes_partial' | 'matched_workflow_id' | 'recency_fallback';
|
|
33
36
|
export type TierAssignment = {
|
|
37
|
+
readonly tier: 0;
|
|
38
|
+
readonly kind: 'matched_exact_id';
|
|
39
|
+
readonly matchField: 'runId' | 'sessionId';
|
|
40
|
+
} | {
|
|
34
41
|
readonly tier: 1;
|
|
35
42
|
readonly kind: 'matched_head_sha';
|
|
36
43
|
} | {
|
|
@@ -42,17 +49,26 @@ export type TierAssignment = {
|
|
|
42
49
|
readonly kind: 'matched_notes';
|
|
43
50
|
} | {
|
|
44
51
|
readonly tier: 4;
|
|
45
|
-
readonly kind: '
|
|
52
|
+
readonly kind: 'matched_notes_partial';
|
|
53
|
+
readonly matchRatio: number;
|
|
46
54
|
} | {
|
|
47
55
|
readonly tier: 5;
|
|
56
|
+
readonly kind: 'matched_workflow_id';
|
|
57
|
+
} | {
|
|
58
|
+
readonly tier: 6;
|
|
48
59
|
readonly kind: 'recency_fallback';
|
|
49
60
|
};
|
|
50
61
|
export declare function normalizeToTokens(text: string): ReadonlySet<string>;
|
|
51
62
|
export declare function allQueryTokensMatch(queryTokens: ReadonlySet<string>, candidateTokens: ReadonlySet<string>): boolean;
|
|
63
|
+
export declare function queryTokenMatchRatio(queryTokens: ReadonlySet<string>, candidateTokens: ReadonlySet<string>): number;
|
|
64
|
+
export declare function fuzzyTokenMatch(queryToken: string, candidateTokens: ReadonlySet<string>): boolean;
|
|
65
|
+
export declare function fuzzyQueryTokenMatchRatio(queryTokens: ReadonlySet<string>, candidateTokens: ReadonlySet<string>): number;
|
|
52
66
|
export interface ResumeQuery {
|
|
53
67
|
readonly gitHeadSha?: string;
|
|
54
68
|
readonly gitBranch?: string;
|
|
55
69
|
readonly freeTextQuery?: string;
|
|
70
|
+
readonly runId?: string;
|
|
71
|
+
readonly sessionId?: string;
|
|
56
72
|
}
|
|
57
73
|
export declare function assignTier(summary: HealthySessionSummary, query: ResumeQuery): TierAssignment;
|
|
58
74
|
export interface RankedResumeCandidate {
|
|
@@ -65,6 +81,9 @@ export interface RankedResumeCandidate {
|
|
|
65
81
|
readonly lastActivityEventIndex: number;
|
|
66
82
|
readonly workflowHash: WorkflowHash;
|
|
67
83
|
readonly workflowId: WorkflowId;
|
|
84
|
+
readonly pendingStepId: string | null;
|
|
85
|
+
readonly isComplete: boolean;
|
|
86
|
+
readonly lastModifiedMs: number | null;
|
|
68
87
|
}
|
|
69
88
|
export declare const MAX_RESUME_CANDIDATES = 5;
|
|
70
89
|
export declare function rankResumeCandidates(summaries: readonly HealthySessionSummary[], query: ResumeQuery): readonly RankedResumeCandidate[];
|
|
@@ -4,6 +4,9 @@ exports.MAX_RESUME_CANDIDATES = void 0;
|
|
|
4
4
|
exports.asRecapSnippet = asRecapSnippet;
|
|
5
5
|
exports.normalizeToTokens = normalizeToTokens;
|
|
6
6
|
exports.allQueryTokensMatch = allQueryTokensMatch;
|
|
7
|
+
exports.queryTokenMatchRatio = queryTokenMatchRatio;
|
|
8
|
+
exports.fuzzyTokenMatch = fuzzyTokenMatch;
|
|
9
|
+
exports.fuzzyQueryTokenMatchRatio = fuzzyQueryTokenMatchRatio;
|
|
7
10
|
exports.assignTier = assignTier;
|
|
8
11
|
exports.rankResumeCandidates = rankResumeCandidates;
|
|
9
12
|
const constants_js_1 = require("../durable-core/constants.js");
|
|
@@ -36,7 +39,45 @@ function allQueryTokensMatch(queryTokens, candidateTokens) {
|
|
|
36
39
|
}
|
|
37
40
|
return true;
|
|
38
41
|
}
|
|
42
|
+
function queryTokenMatchRatio(queryTokens, candidateTokens) {
|
|
43
|
+
if (queryTokens.size === 0 || candidateTokens.size === 0)
|
|
44
|
+
return 0;
|
|
45
|
+
let matched = 0;
|
|
46
|
+
for (const token of queryTokens) {
|
|
47
|
+
if (candidateTokens.has(token))
|
|
48
|
+
matched++;
|
|
49
|
+
}
|
|
50
|
+
return matched / queryTokens.size;
|
|
51
|
+
}
|
|
52
|
+
function fuzzyTokenMatch(queryToken, candidateTokens) {
|
|
53
|
+
if (queryToken.length < 3)
|
|
54
|
+
return false;
|
|
55
|
+
for (const ct of candidateTokens) {
|
|
56
|
+
if (ct.length < 3)
|
|
57
|
+
continue;
|
|
58
|
+
if (ct.includes(queryToken) || queryToken.includes(ct))
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
function fuzzyQueryTokenMatchRatio(queryTokens, candidateTokens) {
|
|
64
|
+
if (queryTokens.size === 0 || candidateTokens.size === 0)
|
|
65
|
+
return 0;
|
|
66
|
+
let matched = 0;
|
|
67
|
+
for (const qt of queryTokens) {
|
|
68
|
+
if (candidateTokens.has(qt) || fuzzyTokenMatch(qt, candidateTokens))
|
|
69
|
+
matched++;
|
|
70
|
+
}
|
|
71
|
+
return matched / queryTokens.size;
|
|
72
|
+
}
|
|
73
|
+
const MIN_PARTIAL_MATCH_RATIO = 0.4;
|
|
39
74
|
function assignTier(summary, query) {
|
|
75
|
+
if (query.runId && summary.runId === query.runId) {
|
|
76
|
+
return { tier: 0, kind: 'matched_exact_id', matchField: 'runId' };
|
|
77
|
+
}
|
|
78
|
+
if (query.sessionId && String(summary.sessionId) === query.sessionId) {
|
|
79
|
+
return { tier: 0, kind: 'matched_exact_id', matchField: 'sessionId' };
|
|
80
|
+
}
|
|
40
81
|
if (query.gitHeadSha && summary.observations.gitHeadSha === query.gitHeadSha) {
|
|
41
82
|
return { tier: 1, kind: 'matched_head_sha' };
|
|
42
83
|
}
|
|
@@ -49,27 +90,36 @@ function assignTier(summary, query) {
|
|
|
49
90
|
return { tier: 2, kind: 'matched_branch', matchType: 'prefix' };
|
|
50
91
|
}
|
|
51
92
|
}
|
|
52
|
-
|
|
53
|
-
|
|
93
|
+
const queryTokens = query.freeTextQuery ? normalizeToTokens(query.freeTextQuery) : null;
|
|
94
|
+
if (queryTokens && queryTokens.size > 0 && summary.recapSnippet) {
|
|
54
95
|
const noteTokens = normalizeToTokens(summary.recapSnippet);
|
|
55
96
|
if (allQueryTokensMatch(queryTokens, noteTokens)) {
|
|
56
97
|
return { tier: 3, kind: 'matched_notes' };
|
|
57
98
|
}
|
|
99
|
+
const ratio = fuzzyQueryTokenMatchRatio(queryTokens, noteTokens);
|
|
100
|
+
if (ratio >= MIN_PARTIAL_MATCH_RATIO) {
|
|
101
|
+
return { tier: 4, kind: 'matched_notes_partial', matchRatio: ratio };
|
|
102
|
+
}
|
|
58
103
|
}
|
|
59
|
-
if (
|
|
60
|
-
const queryTokens = normalizeToTokens(query.freeTextQuery);
|
|
104
|
+
if (queryTokens && queryTokens.size > 0 && summary.workflow.kind === 'identified') {
|
|
61
105
|
const workflowTokens = normalizeToTokens(String(summary.workflow.workflowId));
|
|
62
106
|
if (allQueryTokensMatch(queryTokens, workflowTokens)) {
|
|
63
|
-
return { tier:
|
|
107
|
+
return { tier: 5, kind: 'matched_workflow_id' };
|
|
108
|
+
}
|
|
109
|
+
const ratio = fuzzyQueryTokenMatchRatio(queryTokens, workflowTokens);
|
|
110
|
+
if (ratio >= MIN_PARTIAL_MATCH_RATIO) {
|
|
111
|
+
return { tier: 5, kind: 'matched_workflow_id' };
|
|
64
112
|
}
|
|
65
113
|
}
|
|
66
|
-
return { tier:
|
|
114
|
+
return { tier: 6, kind: 'recency_fallback' };
|
|
67
115
|
}
|
|
68
116
|
function tierToWhyMatched(tier) {
|
|
69
117
|
switch (tier.kind) {
|
|
118
|
+
case 'matched_exact_id': return 'matched_exact_id';
|
|
70
119
|
case 'matched_head_sha': return 'matched_head_sha';
|
|
71
120
|
case 'matched_branch': return 'matched_branch';
|
|
72
121
|
case 'matched_notes': return 'matched_notes';
|
|
122
|
+
case 'matched_notes_partial': return 'matched_notes_partial';
|
|
73
123
|
case 'matched_workflow_id': return 'matched_workflow_id';
|
|
74
124
|
case 'recency_fallback': return 'recency_fallback';
|
|
75
125
|
}
|
|
@@ -83,6 +133,13 @@ function rankResumeCandidates(summaries, query) {
|
|
|
83
133
|
const sorted = [...withTier].sort((a, b) => {
|
|
84
134
|
if (a.tier.tier !== b.tier.tier)
|
|
85
135
|
return a.tier.tier - b.tier.tier;
|
|
136
|
+
if (a.summary.isComplete !== b.summary.isComplete) {
|
|
137
|
+
return a.summary.isComplete ? 1 : -1;
|
|
138
|
+
}
|
|
139
|
+
if (a.tier.kind === 'matched_notes_partial' && b.tier.kind === 'matched_notes_partial') {
|
|
140
|
+
if (a.tier.matchRatio !== b.tier.matchRatio)
|
|
141
|
+
return b.tier.matchRatio - a.tier.matchRatio;
|
|
142
|
+
}
|
|
86
143
|
const actA = a.summary.preferredTip.lastActivityEventIndex;
|
|
87
144
|
const actB = b.summary.preferredTip.lastActivityEventIndex;
|
|
88
145
|
if (actA !== actB)
|
|
@@ -99,5 +156,8 @@ function rankResumeCandidates(summaries, query) {
|
|
|
99
156
|
lastActivityEventIndex: summary.preferredTip.lastActivityEventIndex,
|
|
100
157
|
workflowHash: summary.workflow.workflowHash,
|
|
101
158
|
workflowId: summary.workflow.workflowId,
|
|
159
|
+
pendingStepId: summary.pendingStepId,
|
|
160
|
+
isComplete: summary.isComplete,
|
|
161
|
+
lastModifiedMs: summary.lastModifiedMs,
|
|
102
162
|
}));
|
|
103
163
|
}
|
|
@@ -7,7 +7,11 @@ export declare function enumerateSessions(ports: {
|
|
|
7
7
|
readonly directoryListing: DirectoryListingPortV2;
|
|
8
8
|
readonly dataDir: DataDirPortV2;
|
|
9
9
|
}): ResultAsync<readonly SessionId[], FsError>;
|
|
10
|
+
export interface SessionWithMtime {
|
|
11
|
+
readonly sessionId: SessionId;
|
|
12
|
+
readonly mtimeMs: number;
|
|
13
|
+
}
|
|
10
14
|
export declare function enumerateSessionsByRecency(ports: {
|
|
11
15
|
readonly directoryListing: DirectoryListingPortV2;
|
|
12
16
|
readonly dataDir: DataDirPortV2;
|
|
13
|
-
}): ResultAsync<readonly
|
|
17
|
+
}): ResultAsync<readonly SessionWithMtime[], FsError>;
|
|
@@ -22,5 +22,5 @@ function enumerateSessionsByRecency(ports) {
|
|
|
22
22
|
return b.mtimeMs - a.mtimeMs;
|
|
23
23
|
return a.name.localeCompare(b.name);
|
|
24
24
|
})
|
|
25
|
-
.map((entry) => (0, index_js_1.asSessionId)(entry.name)));
|
|
25
|
+
.map((entry) => ({ sessionId: (0, index_js_1.asSessionId)(entry.name), mtimeMs: entry.mtimeMs })));
|
|
26
26
|
}
|