@exaudeus/workrail 3.15.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/application/services/workflow-service.d.ts +2 -0
- package/dist/application/services/workflow-service.js +3 -0
- package/dist/application/use-cases/raw-workflow-file-scanner.js +10 -13
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.js +2 -1
- package/dist/cli/commands/init.d.ts +10 -0
- package/dist/cli/commands/init.js +72 -0
- package/dist/cli.js +13 -1
- package/dist/config/config-file.d.ts +8 -0
- package/dist/config/config-file.js +141 -0
- package/dist/config/feature-flags.js +8 -0
- package/dist/console/assets/index-BZNM03t1.css +1 -0
- package/dist/console/assets/index-BwJelCXK.js +28 -0
- package/dist/console/index.html +2 -2
- package/dist/di/container.d.ts +1 -0
- package/dist/di/container.js +24 -7
- package/dist/infrastructure/session/HttpServer.d.ts +3 -4
- package/dist/infrastructure/session/HttpServer.js +58 -106
- package/dist/infrastructure/storage/caching-workflow-storage.d.ts +2 -0
- package/dist/infrastructure/storage/caching-workflow-storage.js +15 -6
- package/dist/infrastructure/storage/file-workflow-storage.js +3 -4
- package/dist/infrastructure/storage/schema-validating-workflow-storage.js +9 -8
- package/dist/manifest.json +303 -247
- package/dist/mcp/assert-output.d.ts +37 -0
- package/dist/mcp/assert-output.js +53 -0
- package/dist/mcp/boundary-coercion.d.ts +1 -0
- package/dist/mcp/boundary-coercion.js +44 -0
- package/dist/mcp/dev-mode.d.ts +2 -0
- package/dist/mcp/dev-mode.js +16 -0
- package/dist/mcp/handler-factory.d.ts +1 -1
- package/dist/mcp/handler-factory.js +20 -16
- package/dist/mcp/handlers/session.js +8 -9
- package/dist/mcp/handlers/shared/request-workflow-reader.d.ts +1 -0
- package/dist/mcp/handlers/shared/request-workflow-reader.js +90 -20
- package/dist/mcp/handlers/v2-advance-core/event-builders.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/event-builders.js +6 -6
- package/dist/mcp/handlers/v2-advance-core/index.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/index.js +4 -3
- package/dist/mcp/handlers/v2-advance-core/input-validation.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/input-validation.js +32 -9
- package/dist/mcp/handlers/v2-advance-core/outcome-blocked.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-blocked.js +1 -1
- package/dist/mcp/handlers/v2-advance-core/outcome-success.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-success.js +1 -1
- package/dist/mcp/handlers/v2-checkpoint.d.ts +1 -1
- package/dist/mcp/handlers/v2-checkpoint.js +5 -6
- package/dist/mcp/handlers/v2-execution/advance.d.ts +4 -2
- package/dist/mcp/handlers/v2-execution/advance.js +5 -7
- package/dist/mcp/handlers/v2-execution/continue-advance.d.ts +1 -0
- package/dist/mcp/handlers/v2-execution/continue-advance.js +59 -27
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +2 -1
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +11 -10
- package/dist/mcp/handlers/v2-execution/index.js +2 -0
- package/dist/mcp/handlers/v2-execution/replay.d.ts +8 -4
- package/dist/mcp/handlers/v2-execution/replay.js +50 -30
- package/dist/mcp/handlers/v2-execution/start.d.ts +2 -3
- package/dist/mcp/handlers/v2-execution/start.js +58 -30
- package/dist/mcp/handlers/v2-execution/workflow-object-cache.d.ts +5 -0
- package/dist/mcp/handlers/v2-execution/workflow-object-cache.js +19 -0
- package/dist/mcp/handlers/v2-execution-helpers.d.ts +1 -0
- package/dist/mcp/handlers/v2-execution-helpers.js +23 -7
- package/dist/mcp/handlers/v2-resume.d.ts +1 -1
- package/dist/mcp/handlers/v2-resume.js +3 -4
- package/dist/mcp/handlers/v2-state-conversion.js +5 -1
- package/dist/mcp/handlers/v2-workflow.d.ts +80 -0
- package/dist/mcp/handlers/v2-workflow.js +40 -23
- package/dist/mcp/handlers/workflow.d.ts +2 -5
- package/dist/mcp/handlers/workflow.js +15 -12
- package/dist/mcp/output-schemas.d.ts +25 -27
- package/dist/mcp/output-schemas.js +7 -7
- package/dist/mcp/server.js +23 -4
- package/dist/mcp/tool-call-timing.d.ts +24 -0
- package/dist/mcp/tool-call-timing.js +85 -0
- package/dist/mcp/transports/http-entry.js +3 -2
- package/dist/mcp/transports/http-listener.d.ts +1 -0
- package/dist/mcp/transports/http-listener.js +25 -0
- package/dist/mcp/transports/shutdown-hooks.d.ts +4 -1
- package/dist/mcp/transports/shutdown-hooks.js +3 -2
- package/dist/mcp/transports/stdio-entry.js +6 -28
- package/dist/mcp/v2-response-formatter.d.ts +1 -1
- package/dist/mcp/v2-response-formatter.js +2 -5
- package/dist/mcp/validation/schema-introspection.d.ts +1 -0
- package/dist/mcp/validation/schema-introspection.js +15 -5
- package/dist/mcp/validation/suggestion-generator.js +2 -2
- package/dist/runtime/adapters/node-process-signals.d.ts +1 -0
- package/dist/runtime/adapters/node-process-signals.js +5 -0
- package/dist/runtime/adapters/noop-process-signals.d.ts +1 -0
- package/dist/runtime/adapters/noop-process-signals.js +2 -0
- package/dist/runtime/ports/process-signals.d.ts +1 -0
- package/dist/types/workflow-definition.d.ts +5 -1
- package/dist/types/workflow-definition.js +2 -0
- package/dist/types/workflow.d.ts +3 -0
- package/dist/types/workflow.js +35 -26
- package/dist/v2/durable-core/domain/context-template-resolver.js +2 -2
- package/dist/v2/durable-core/domain/function-definition-expander.js +2 -17
- package/dist/v2/durable-core/domain/prompt-renderer.d.ts +2 -0
- package/dist/v2/durable-core/domain/prompt-renderer.js +22 -18
- package/dist/v2/durable-core/domain/recap-recovery.js +23 -16
- package/dist/v2/durable-core/domain/retrieval-contract.js +13 -7
- package/dist/v2/durable-core/schemas/compiled-workflow/index.js +4 -3
- package/dist/v2/durable-core/session-index.d.ts +22 -0
- package/dist/v2/durable-core/session-index.js +58 -0
- package/dist/v2/durable-core/sorted-event-log.d.ts +6 -0
- package/dist/v2/durable-core/sorted-event-log.js +15 -0
- package/dist/v2/infra/local/fs/index.js +8 -8
- package/dist/v2/infra/local/pinned-workflow-store/index.d.ts +2 -0
- package/dist/v2/infra/local/pinned-workflow-store/index.js +49 -0
- package/dist/v2/infra/local/remembered-roots-store/index.d.ts +3 -1
- package/dist/v2/infra/local/remembered-roots-store/index.js +6 -3
- package/dist/v2/infra/local/session-store/index.d.ts +1 -1
- package/dist/v2/infra/local/session-store/index.js +71 -61
- package/dist/v2/infra/local/session-summary-provider/index.js +9 -4
- package/dist/v2/infra/local/snapshot-store/index.js +2 -1
- package/dist/v2/infra/local/workspace-anchor/index.js +4 -2
- package/dist/v2/ports/pinned-workflow-store.port.d.ts +2 -0
- package/dist/v2/ports/session-event-log-store.port.d.ts +1 -1
- package/dist/v2/projections/assessment-consequences.d.ts +2 -1
- package/dist/v2/projections/assessment-consequences.js +0 -5
- package/dist/v2/projections/assessments.d.ts +2 -1
- package/dist/v2/projections/assessments.js +2 -4
- package/dist/v2/projections/gaps.d.ts +2 -1
- package/dist/v2/projections/gaps.js +0 -5
- package/dist/v2/projections/preferences.d.ts +2 -1
- package/dist/v2/projections/preferences.js +0 -5
- package/dist/v2/projections/run-context.d.ts +2 -2
- package/dist/v2/projections/run-context.js +0 -5
- package/dist/v2/projections/run-dag.js +7 -1
- package/dist/v2/projections/run-execution-trace.d.ts +8 -0
- package/dist/v2/projections/run-execution-trace.js +124 -0
- package/dist/v2/projections/run-status-signals.d.ts +2 -2
- package/dist/v2/usecases/console-routes.d.ts +3 -1
- package/dist/v2/usecases/console-routes.js +124 -25
- package/dist/v2/usecases/console-service.d.ts +1 -0
- package/dist/v2/usecases/console-service.js +83 -25
- package/dist/v2/usecases/console-types.d.ts +53 -0
- package/dist/v2/usecases/worktree-service.js +32 -1
- package/package.json +6 -5
- package/spec/workflow.schema.json +18 -0
- package/workflows/adaptive-ticket-creation.json +23 -16
- package/workflows/architecture-scalability-audit.json +29 -22
- package/workflows/bug-investigation.agentic.v2.json +7 -0
- package/workflows/coding-task-workflow-agentic.json +7 -0
- package/workflows/coding-task-workflow-agentic.lean.v2.json +16 -8
- package/workflows/coding-task-workflow-agentic.v2.json +7 -0
- package/workflows/cross-platform-code-conversion.v2.json +7 -0
- package/workflows/document-creation-workflow.json +15 -8
- package/workflows/documentation-update-workflow.json +15 -8
- package/workflows/intelligent-test-case-generation.json +7 -0
- package/workflows/learner-centered-course-workflow.json +9 -2
- package/workflows/mr-review-workflow.agentic.v2.json +7 -0
- package/workflows/personal-learning-materials-creation-branched.json +15 -8
- package/workflows/presentation-creation.json +12 -5
- package/workflows/production-readiness-audit.json +7 -0
- package/workflows/relocation-workflow-us.json +39 -32
- package/workflows/scoped-documentation-workflow.json +33 -26
- package/workflows/ui-ux-design-workflow.json +7 -0
- package/workflows/workflow-diagnose-environment.json +6 -0
- package/workflows/workflow-for-workflows.json +7 -0
- package/workflows/workflow-for-workflows.v2.json +23 -11
- package/workflows/wr.discovery.json +8 -1
- package/dist/console/assets/index-BZYIjrzJ.js +0 -28
- package/dist/console/assets/index-OLCKbDdm.css +0 -1
- package/dist/mcp/handlers/v2-resolve-refs-envelope.d.ts +0 -5
- package/dist/mcp/handlers/v2-resolve-refs-envelope.js +0 -17
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare function assertOutput<T>(data: T, check: (data: T) => void): T;
|
|
2
|
+
type BlockerPointer = {
|
|
3
|
+
readonly kind: 'context_key';
|
|
4
|
+
readonly key: string;
|
|
5
|
+
} | {
|
|
6
|
+
readonly kind: 'context_budget';
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: 'output_contract';
|
|
9
|
+
readonly contractRef: string;
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: 'capability';
|
|
12
|
+
readonly capability: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: 'assessment_dimension';
|
|
15
|
+
readonly assessmentId: string;
|
|
16
|
+
readonly dimensionId: string;
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: 'workflow_step';
|
|
19
|
+
readonly stepId: string;
|
|
20
|
+
};
|
|
21
|
+
type BlockerLike = {
|
|
22
|
+
readonly code: string;
|
|
23
|
+
readonly pointer: BlockerPointer;
|
|
24
|
+
};
|
|
25
|
+
type BlockerReportLike = {
|
|
26
|
+
readonly blockers: readonly BlockerLike[];
|
|
27
|
+
};
|
|
28
|
+
export declare function assertBlockerReportInvariants(report: BlockerReportLike): void;
|
|
29
|
+
type PendingLike = {
|
|
30
|
+
readonly stepId: string;
|
|
31
|
+
} | null;
|
|
32
|
+
type ContinueTokenHolder = {
|
|
33
|
+
readonly continueToken?: string | null | undefined;
|
|
34
|
+
readonly pending: PendingLike;
|
|
35
|
+
};
|
|
36
|
+
export declare function assertContinueTokenPresence(data: ContinueTokenHolder): void;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertOutput = assertOutput;
|
|
4
|
+
exports.assertBlockerReportInvariants = assertBlockerReportInvariants;
|
|
5
|
+
exports.assertContinueTokenPresence = assertContinueTokenPresence;
|
|
6
|
+
const dev_mode_js_1 = require("./dev-mode.js");
|
|
7
|
+
function assertOutput(data, check) {
|
|
8
|
+
if ((0, dev_mode_js_1.isDevMode)()) {
|
|
9
|
+
check(data);
|
|
10
|
+
}
|
|
11
|
+
return data;
|
|
12
|
+
}
|
|
13
|
+
function assertBlockerReportInvariants(report) {
|
|
14
|
+
const keyFor = (b) => {
|
|
15
|
+
const p = b.pointer;
|
|
16
|
+
let ptrStable;
|
|
17
|
+
switch (p.kind) {
|
|
18
|
+
case 'context_key':
|
|
19
|
+
ptrStable = p.key;
|
|
20
|
+
break;
|
|
21
|
+
case 'output_contract':
|
|
22
|
+
ptrStable = p.contractRef;
|
|
23
|
+
break;
|
|
24
|
+
case 'capability':
|
|
25
|
+
ptrStable = p.capability;
|
|
26
|
+
break;
|
|
27
|
+
case 'assessment_dimension':
|
|
28
|
+
ptrStable = `${p.assessmentId}|${p.dimensionId}`;
|
|
29
|
+
break;
|
|
30
|
+
case 'workflow_step':
|
|
31
|
+
ptrStable = p.stepId;
|
|
32
|
+
break;
|
|
33
|
+
case 'context_budget':
|
|
34
|
+
ptrStable = '';
|
|
35
|
+
break;
|
|
36
|
+
default: {
|
|
37
|
+
const _exhaustive = p;
|
|
38
|
+
ptrStable = String(_exhaustive);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return `${b.code}|${p.kind}|${String(ptrStable)}`;
|
|
42
|
+
};
|
|
43
|
+
for (let i = 1; i < report.blockers.length; i++) {
|
|
44
|
+
if (keyFor(report.blockers[i - 1]) > keyFor(report.blockers[i])) {
|
|
45
|
+
throw new Error('assertOutput: blockers must be deterministically sorted by composite key');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function assertContinueTokenPresence(data) {
|
|
50
|
+
if (data.pending != null && data.continueToken == null) {
|
|
51
|
+
throw new Error('assertOutput: continueToken is required when a pending step exists');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
export declare function buildCoercionFn(shapeSchema: z.ZodObject<z.ZodRawShape>, aliasMap?: Readonly<Record<string, string>>): (args: unknown) => unknown;
|
|
2
3
|
export declare function coerceJsonStringObjectFields(args: unknown, shapeSchema: z.ZodObject<z.ZodRawShape>, aliasMap?: Readonly<Record<string, string>>): unknown;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildCoercionFn = buildCoercionFn;
|
|
3
4
|
exports.coerceJsonStringObjectFields = coerceJsonStringObjectFields;
|
|
4
5
|
const zod_1 = require("zod");
|
|
6
|
+
const schema_introspection_js_1 = require("./validation/schema-introspection.js");
|
|
5
7
|
function unwrapToBaseType(schema) {
|
|
6
8
|
let current = schema;
|
|
7
9
|
for (;;) {
|
|
@@ -32,6 +34,48 @@ function tryParseJsonObject(value) {
|
|
|
32
34
|
return null;
|
|
33
35
|
}
|
|
34
36
|
}
|
|
37
|
+
function buildCoercionFn(shapeSchema, aliasMap) {
|
|
38
|
+
const shape = (0, schema_introspection_js_1.getCachedShape)(shapeSchema);
|
|
39
|
+
const objectFields = new Set();
|
|
40
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
41
|
+
if (expectsObjectValue(fieldSchema)) {
|
|
42
|
+
objectFields.add(key);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const aliasesToCoerce = new Set();
|
|
46
|
+
if (aliasMap) {
|
|
47
|
+
for (const [alias, canonical] of Object.entries(aliasMap)) {
|
|
48
|
+
if (objectFields.has(canonical)) {
|
|
49
|
+
aliasesToCoerce.add(alias);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const hasCoercibleFields = objectFields.size > 0 || aliasesToCoerce.size > 0;
|
|
54
|
+
return (args) => {
|
|
55
|
+
if (!hasCoercibleFields)
|
|
56
|
+
return args;
|
|
57
|
+
if (typeof args !== 'object' || args === null)
|
|
58
|
+
return args;
|
|
59
|
+
const input = args;
|
|
60
|
+
let result = null;
|
|
61
|
+
const coerceField = (key) => {
|
|
62
|
+
const value = input[key];
|
|
63
|
+
if (typeof value !== 'string')
|
|
64
|
+
return;
|
|
65
|
+
const parsed = tryParseJsonObject(value);
|
|
66
|
+
if (parsed === null)
|
|
67
|
+
return;
|
|
68
|
+
if (result === null)
|
|
69
|
+
result = { ...input };
|
|
70
|
+
result[key] = parsed;
|
|
71
|
+
};
|
|
72
|
+
for (const key of objectFields)
|
|
73
|
+
coerceField(key);
|
|
74
|
+
for (const alias of aliasesToCoerce)
|
|
75
|
+
coerceField(alias);
|
|
76
|
+
return result ?? args;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
35
79
|
function coerceJsonStringObjectFields(args, shapeSchema, aliasMap) {
|
|
36
80
|
if (typeof args !== 'object' || args === null)
|
|
37
81
|
return args;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEV_MODE = void 0;
|
|
4
|
+
exports.isDevMode = isDevMode;
|
|
5
|
+
const container_js_1 = require("../di/container.js");
|
|
6
|
+
const tokens_js_1 = require("../di/tokens.js");
|
|
7
|
+
function isDevMode() {
|
|
8
|
+
try {
|
|
9
|
+
const flags = container_js_1.container.resolve(tokens_js_1.DI.Infra.FeatureFlags);
|
|
10
|
+
return flags.isEnabled('devMode');
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return process.env['WORKRAIL_DEV'] === '1';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.DEV_MODE = process.env['WORKRAIL_DEV'] === '1';
|
|
@@ -2,6 +2,6 @@ import { z } from 'zod';
|
|
|
2
2
|
import type { ToolContext, ToolResult } from './types.js';
|
|
3
3
|
import type { PreValidateResult } from './validation/workflow-next-prevalidate.js';
|
|
4
4
|
import type { WrappedToolHandler, McpCallToolResult } from './types/workflow-tool-edition.js';
|
|
5
|
-
export declare function toMcpResult<T>(result: ToolResult<T
|
|
5
|
+
export declare function toMcpResult<T>(result: ToolResult<T>, ctx?: ToolContext): McpCallToolResult;
|
|
6
6
|
export declare function createHandler<TInput extends z.ZodType, TOutput>(schema: TInput, handler: (input: z.infer<TInput>, ctx: ToolContext) => Promise<ToolResult<TOutput>>, shapeSchema?: z.ZodObject<z.ZodRawShape>, aliasMap?: Readonly<Record<string, string>>): WrappedToolHandler;
|
|
7
7
|
export declare function createValidatingHandler<TInput extends z.ZodType, TOutput>(schema: TInput, preValidate: (args: unknown) => PreValidateResult, handler: (input: z.infer<TInput>, ctx: ToolContext) => Promise<ToolResult<TOutput>>, shapeSchema?: z.ZodObject<z.ZodRawShape>, aliasMap?: Readonly<Record<string, string>>): WrappedToolHandler;
|
|
@@ -11,11 +11,12 @@ const v2_execution_helpers_js_1 = require("./handlers/v2-execution-helpers.js");
|
|
|
11
11
|
const v2_response_formatter_js_1 = require("./v2-response-formatter.js");
|
|
12
12
|
const render_envelope_js_1 = require("./render-envelope.js");
|
|
13
13
|
const jsonResponsesOverride = process.env.WORKRAIL_JSON_RESPONSES === 'true';
|
|
14
|
-
function toMcpResult(result) {
|
|
14
|
+
function toMcpResult(result, ctx) {
|
|
15
15
|
switch (result.type) {
|
|
16
16
|
case 'success': {
|
|
17
|
+
const cleanResponseFormat = ctx?.featureFlags.isEnabled('cleanResponseFormat') ?? false;
|
|
17
18
|
if (!jsonResponsesOverride) {
|
|
18
|
-
const formatted = (0, v2_response_formatter_js_1.formatV2ExecutionResponse)(result.data) ?? (0, v2_response_formatter_js_1.formatV2ResumeResponse)(result.data);
|
|
19
|
+
const formatted = (0, v2_response_formatter_js_1.formatV2ExecutionResponse)(result.data, cleanResponseFormat) ?? (0, v2_response_formatter_js_1.formatV2ResumeResponse)(result.data);
|
|
19
20
|
if (formatted !== null) {
|
|
20
21
|
const content = [{ type: 'text', text: formatted.primary }];
|
|
21
22
|
if (formatted.references != null) {
|
|
@@ -36,7 +37,7 @@ function toMcpResult(result) {
|
|
|
36
37
|
return {
|
|
37
38
|
content: [{
|
|
38
39
|
type: 'text',
|
|
39
|
-
text: JSON.stringify(jsonPayload
|
|
40
|
+
text: JSON.stringify(jsonPayload),
|
|
40
41
|
}],
|
|
41
42
|
};
|
|
42
43
|
}
|
|
@@ -49,17 +50,18 @@ function toMcpResult(result) {
|
|
|
49
50
|
message: result.message,
|
|
50
51
|
retry: result.retry,
|
|
51
52
|
...(result.details !== undefined ? { details: result.details } : {}),
|
|
52
|
-
}
|
|
53
|
+
}),
|
|
53
54
|
}],
|
|
54
55
|
isError: true,
|
|
55
56
|
};
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
function createHandler(schema, handler, shapeSchema, aliasMap) {
|
|
60
|
+
const coerce = shapeSchema !== undefined
|
|
61
|
+
? (0, boundary_coercion_js_1.buildCoercionFn)(shapeSchema, aliasMap)
|
|
62
|
+
: null;
|
|
59
63
|
return async (args, ctx) => {
|
|
60
|
-
const normalizedArgs =
|
|
61
|
-
? (0, boundary_coercion_js_1.coerceJsonStringObjectFields)(args, shapeSchema, aliasMap)
|
|
62
|
-
: args;
|
|
64
|
+
const normalizedArgs = coerce !== null ? coerce(args) : args;
|
|
63
65
|
const parseResult = schema.safeParse(normalizedArgs);
|
|
64
66
|
if (!parseResult.success) {
|
|
65
67
|
const introspectionSchema = shapeSchema ?? schema;
|
|
@@ -75,22 +77,24 @@ function createHandler(schema, handler, shapeSchema, aliasMap) {
|
|
|
75
77
|
message: e.message,
|
|
76
78
|
})),
|
|
77
79
|
...patchedDetails,
|
|
78
|
-
}));
|
|
80
|
+
}), ctx);
|
|
79
81
|
}
|
|
80
82
|
try {
|
|
81
|
-
return toMcpResult(await handler(parseResult.data, ctx));
|
|
83
|
+
return toMcpResult(await handler(parseResult.data, ctx), ctx);
|
|
82
84
|
}
|
|
83
85
|
catch (err) {
|
|
84
86
|
console.error('[WorkRail] Unhandled exception in tool handler:', err);
|
|
85
|
-
return toMcpResult((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', 'WorkRail encountered an unexpected error. This is not caused by your input.', { suggestion: (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal error.') }));
|
|
87
|
+
return toMcpResult((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', 'WorkRail encountered an unexpected error. This is not caused by your input.', { suggestion: (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal error.') }), ctx);
|
|
86
88
|
}
|
|
87
89
|
};
|
|
88
90
|
}
|
|
89
91
|
function createValidatingHandler(schema, preValidate, handler, shapeSchema, aliasMap) {
|
|
92
|
+
const coerce = shapeSchema !== undefined
|
|
93
|
+
? (0, boundary_coercion_js_1.buildCoercionFn)(shapeSchema, aliasMap)
|
|
94
|
+
: null;
|
|
95
|
+
const innerHandler = createHandler(schema, handler, shapeSchema);
|
|
90
96
|
return async (args, ctx) => {
|
|
91
|
-
const normalizedArgs =
|
|
92
|
-
? (0, boundary_coercion_js_1.coerceJsonStringObjectFields)(args, shapeSchema, aliasMap)
|
|
93
|
-
: args;
|
|
97
|
+
const normalizedArgs = coerce !== null ? coerce(args) : args;
|
|
94
98
|
const pre = preValidate(normalizedArgs);
|
|
95
99
|
if (!pre.ok) {
|
|
96
100
|
const error = pre.error;
|
|
@@ -106,10 +110,10 @@ function createValidatingHandler(schema, preValidate, handler, shapeSchema, alia
|
|
|
106
110
|
...error,
|
|
107
111
|
details: boundedDetails,
|
|
108
112
|
};
|
|
109
|
-
return toMcpResult(boundedError);
|
|
113
|
+
return toMcpResult(boundedError, ctx);
|
|
110
114
|
}
|
|
111
|
-
return toMcpResult(error);
|
|
115
|
+
return toMcpResult(error, ctx);
|
|
112
116
|
}
|
|
113
|
-
return
|
|
117
|
+
return innerHandler(normalizedArgs, ctx);
|
|
114
118
|
};
|
|
115
119
|
}
|
|
@@ -5,7 +5,6 @@ exports.handleUpdateSession = handleUpdateSession;
|
|
|
5
5
|
exports.handleReadSession = handleReadSession;
|
|
6
6
|
exports.handleOpenDashboard = handleOpenDashboard;
|
|
7
7
|
const types_js_1 = require("../types.js");
|
|
8
|
-
const output_schemas_js_1 = require("../output-schemas.js");
|
|
9
8
|
const SESSION_SCHEMA_OVERVIEW = {
|
|
10
9
|
description: 'Bug Investigation Session Data Structure',
|
|
11
10
|
mainSections: {
|
|
@@ -58,13 +57,13 @@ async function handleCreateSession(input, ctx) {
|
|
|
58
57
|
const session = res.value;
|
|
59
58
|
const baseUrl = httpServer.getBaseUrl();
|
|
60
59
|
const dashboardUrl = baseUrl ? `${baseUrl}?session=${input.sessionId}` : null;
|
|
61
|
-
const payload =
|
|
60
|
+
const payload = {
|
|
62
61
|
sessionId: session.id,
|
|
63
62
|
workflowId: session.workflowId,
|
|
64
63
|
path: sessionManager.getSessionPath(input.workflowId, input.sessionId),
|
|
65
64
|
dashboardUrl,
|
|
66
65
|
createdAt: session.createdAt,
|
|
67
|
-
}
|
|
66
|
+
};
|
|
68
67
|
return (0, types_js_1.success)(payload);
|
|
69
68
|
}
|
|
70
69
|
async function handleUpdateSession(input, ctx) {
|
|
@@ -81,7 +80,7 @@ async function handleUpdateSession(input, ctx) {
|
|
|
81
80
|
}
|
|
82
81
|
return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', res.error.message);
|
|
83
82
|
}
|
|
84
|
-
const payload =
|
|
83
|
+
const payload = { updatedAt: new Date().toISOString() };
|
|
85
84
|
return (0, types_js_1.success)(payload);
|
|
86
85
|
}
|
|
87
86
|
async function handleReadSession(input, ctx) {
|
|
@@ -90,10 +89,10 @@ async function handleReadSession(input, ctx) {
|
|
|
90
89
|
return guardError;
|
|
91
90
|
const sessionManager = ctx.sessionManager;
|
|
92
91
|
if (input.path === '$schema') {
|
|
93
|
-
const payload =
|
|
92
|
+
const payload = {
|
|
94
93
|
query: '$schema',
|
|
95
94
|
schema: SESSION_SCHEMA_OVERVIEW,
|
|
96
|
-
}
|
|
95
|
+
};
|
|
97
96
|
return (0, types_js_1.success)(payload);
|
|
98
97
|
}
|
|
99
98
|
const res = await sessionManager.readSession(input.workflowId, input.sessionId, input.path);
|
|
@@ -105,10 +104,10 @@ async function handleReadSession(input, ctx) {
|
|
|
105
104
|
}
|
|
106
105
|
return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', res.error.message);
|
|
107
106
|
}
|
|
108
|
-
const payload =
|
|
107
|
+
const payload = {
|
|
109
108
|
query: input.path ?? '(full session)',
|
|
110
109
|
data: res.value,
|
|
111
|
-
}
|
|
110
|
+
};
|
|
112
111
|
return (0, types_js_1.success)(payload);
|
|
113
112
|
}
|
|
114
113
|
async function handleOpenDashboard(input, ctx) {
|
|
@@ -118,7 +117,7 @@ async function handleOpenDashboard(input, ctx) {
|
|
|
118
117
|
const httpServer = ctx.httpServer;
|
|
119
118
|
try {
|
|
120
119
|
const url = await httpServer.openDashboard(input.sessionId);
|
|
121
|
-
const payload =
|
|
120
|
+
const payload = { url };
|
|
122
121
|
return (0, types_js_1.success)(payload);
|
|
123
122
|
}
|
|
124
123
|
catch (err) {
|
|
@@ -2,6 +2,7 @@ import type { IWorkflowReader } from '../../../types/storage.js';
|
|
|
2
2
|
import type { IFeatureFlagProvider } from '../../../config/feature-flags.js';
|
|
3
3
|
import type { RememberedRootsStorePortV2 } from '../../../v2/ports/remembered-roots-store.port.js';
|
|
4
4
|
import type { ManagedSourceRecordV2, ManagedSourceStorePortV2 } from '../../../v2/ports/managed-source-store.port.js';
|
|
5
|
+
export declare function clearWalkCacheForTesting(): void;
|
|
5
6
|
export interface RequestWorkflowReaderOptions {
|
|
6
7
|
readonly featureFlags: IFeatureFlagProvider;
|
|
7
8
|
readonly workspacePath?: string;
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.clearWalkCacheForTesting = clearWalkCacheForTesting;
|
|
6
7
|
exports.hasRequestWorkspaceSignal = hasRequestWorkspaceSignal;
|
|
7
8
|
exports.resolveRequestWorkspaceDirectory = resolveRequestWorkspaceDirectory;
|
|
8
9
|
exports.toProjectWorkflowDirectory = toProjectWorkflowDirectory;
|
|
@@ -13,6 +14,27 @@ const path_1 = __importDefault(require("path"));
|
|
|
13
14
|
const url_1 = require("url");
|
|
14
15
|
const enhanced_multi_source_workflow_storage_js_1 = require("../../../infrastructure/storage/enhanced-multi-source-workflow-storage.js");
|
|
15
16
|
const schema_validating_workflow_storage_js_1 = require("../../../infrastructure/storage/schema-validating-workflow-storage.js");
|
|
17
|
+
const with_timeout_js_1 = require("./with-timeout.js");
|
|
18
|
+
const SKIP_DIRS = new Set([
|
|
19
|
+
'.git', 'node_modules',
|
|
20
|
+
'build', 'dist', 'out', 'target',
|
|
21
|
+
'.gradle', '.gradle-cache', '.cache',
|
|
22
|
+
'DerivedData', 'Pods',
|
|
23
|
+
'vendor',
|
|
24
|
+
'__pycache__', '.venv', 'venv',
|
|
25
|
+
'.next', '.nuxt', '.turbo', '.parcel-cache',
|
|
26
|
+
'.claude', '.claude-worktrees', '.firebender',
|
|
27
|
+
'coverage', '.nyc_output',
|
|
28
|
+
]);
|
|
29
|
+
const MAX_WALK_DEPTH = 5;
|
|
30
|
+
const WALK_CACHE_TTL_MS = 300000;
|
|
31
|
+
const walkCache = new Map();
|
|
32
|
+
const walkInFlight = new Map();
|
|
33
|
+
function clearWalkCacheForTesting() {
|
|
34
|
+
walkCache.clear();
|
|
35
|
+
walkInFlight.clear();
|
|
36
|
+
}
|
|
37
|
+
const DISCOVERY_TIMEOUT_MS = 10000;
|
|
16
38
|
function hasRequestWorkspaceSignal(options) {
|
|
17
39
|
return Boolean(options.workspacePath) || (options.resolvedRootUris?.length ?? 0) > 0;
|
|
18
40
|
}
|
|
@@ -34,18 +56,38 @@ function toProjectWorkflowDirectory(workspaceDirectory) {
|
|
|
34
56
|
? workspaceDirectory
|
|
35
57
|
: path_1.default.join(workspaceDirectory, 'workflows');
|
|
36
58
|
}
|
|
37
|
-
|
|
59
|
+
function discoverRootedWorkflowDirectories(roots) {
|
|
60
|
+
const cacheKey = roots.map((r) => path_1.default.resolve(r)).sort().join('\0');
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
const cached = walkCache.get(cacheKey);
|
|
63
|
+
if (cached && cached.expiresAt > now) {
|
|
64
|
+
return Promise.resolve(cached.result);
|
|
65
|
+
}
|
|
66
|
+
const inFlight = walkInFlight.get(cacheKey);
|
|
67
|
+
if (inFlight)
|
|
68
|
+
return inFlight;
|
|
69
|
+
const promise = _doWalk(cacheKey, roots, now);
|
|
70
|
+
walkInFlight.set(cacheKey, promise);
|
|
71
|
+
promise.then(() => walkInFlight.delete(cacheKey), () => walkInFlight.delete(cacheKey));
|
|
72
|
+
return promise;
|
|
73
|
+
}
|
|
74
|
+
async function _doWalk(cacheKey, roots, now) {
|
|
38
75
|
const discoveredByPath = new Set();
|
|
39
76
|
const discoveredPaths = [];
|
|
40
77
|
const stalePaths = [];
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
78
|
+
const resolvedRoots = roots.map((r) => path_1.default.resolve(r));
|
|
79
|
+
const rootResults = await Promise.allSettled(resolvedRoots.map((rootPath) => discoverWorkflowDirectoriesUnderRoot(rootPath)));
|
|
80
|
+
for (let i = 0; i < resolvedRoots.length; i++) {
|
|
81
|
+
const rootPath = resolvedRoots[i];
|
|
82
|
+
const rootResult = rootResults[i];
|
|
83
|
+
if (rootResult.status === 'rejected') {
|
|
84
|
+
throw rootResult.reason;
|
|
85
|
+
}
|
|
86
|
+
if (rootResult.value.stale) {
|
|
45
87
|
stalePaths.push(rootPath);
|
|
46
88
|
continue;
|
|
47
89
|
}
|
|
48
|
-
for (const nextPath of
|
|
90
|
+
for (const nextPath of rootResult.value.discovered) {
|
|
49
91
|
const normalizedPath = path_1.default.resolve(nextPath);
|
|
50
92
|
if (discoveredByPath.has(normalizedPath))
|
|
51
93
|
continue;
|
|
@@ -53,13 +95,22 @@ async function discoverRootedWorkflowDirectories(roots) {
|
|
|
53
95
|
discoveredPaths.push(normalizedPath);
|
|
54
96
|
}
|
|
55
97
|
}
|
|
56
|
-
|
|
98
|
+
const result = { discovered: discoveredPaths, stale: stalePaths };
|
|
99
|
+
walkCache.set(cacheKey, { result, expiresAt: now + WALK_CACHE_TTL_MS });
|
|
100
|
+
return result;
|
|
57
101
|
}
|
|
58
102
|
async function createWorkflowReaderForRequest(options) {
|
|
59
103
|
const workspaceDirectory = resolveRequestWorkspaceDirectory(options);
|
|
60
104
|
const projectWorkflowDirectory = toProjectWorkflowDirectory(workspaceDirectory);
|
|
61
105
|
const rememberedRoots = await listRememberedRoots(options.rememberedRootsStore);
|
|
62
|
-
|
|
106
|
+
let discoveryResult;
|
|
107
|
+
try {
|
|
108
|
+
discoveryResult = await (0, with_timeout_js_1.withTimeout)(discoverRootedWorkflowDirectories(rememberedRoots), DISCOVERY_TIMEOUT_MS, 'workflow_root_discovery');
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
discoveryResult = { discovered: [], stale: [] };
|
|
112
|
+
}
|
|
113
|
+
const { discovered: rootedWorkflowDirectories, stale: stalePaths } = discoveryResult;
|
|
63
114
|
const rootedCustomPaths = rootedWorkflowDirectories.filter((directory) => directory !== projectWorkflowDirectory);
|
|
64
115
|
const { records: allManagedRecords, storeError: managedStoreError } = await listManagedSourceRecords(options.managedSourceStore);
|
|
65
116
|
const envCustomPaths = parseWorkflowStoragePathEnv();
|
|
@@ -70,17 +121,30 @@ async function createWorkflowReaderForRequest(options) {
|
|
|
70
121
|
const additionalManagedPaths = [];
|
|
71
122
|
const activeManagedRecords = [];
|
|
72
123
|
const staleManagedRecords = [];
|
|
124
|
+
const alreadyCovered = [];
|
|
125
|
+
const needsStatCheck = [];
|
|
73
126
|
for (const record of allManagedRecords) {
|
|
74
127
|
if (normalizedCustom.has(path_1.default.resolve(record.path))) {
|
|
75
|
-
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (await isDirectory(record.path)) {
|
|
79
|
-
additionalManagedPaths.push(record.path);
|
|
80
|
-
activeManagedRecords.push(record);
|
|
128
|
+
alreadyCovered.push(record);
|
|
81
129
|
}
|
|
82
130
|
else {
|
|
83
|
-
|
|
131
|
+
needsStatCheck.push(record);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
activeManagedRecords.push(...alreadyCovered);
|
|
135
|
+
if (needsStatCheck.length > 0) {
|
|
136
|
+
const statResults = await (0, with_timeout_js_1.withTimeout)(Promise.allSettled(needsStatCheck.map((record) => isDirectory(record.path))), DISCOVERY_TIMEOUT_MS, 'managed_source_stat').catch(() => null);
|
|
137
|
+
for (let i = 0; i < needsStatCheck.length; i++) {
|
|
138
|
+
const record = needsStatCheck[i];
|
|
139
|
+
const result = statResults?.[i];
|
|
140
|
+
const isDir = result?.status === 'fulfilled' && result.value === true;
|
|
141
|
+
if (isDir) {
|
|
142
|
+
additionalManagedPaths.push(record.path);
|
|
143
|
+
activeManagedRecords.push(record);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
staleManagedRecords.push(record);
|
|
147
|
+
}
|
|
84
148
|
}
|
|
85
149
|
}
|
|
86
150
|
const customPaths = [...rootedCustomPaths, ...additionalManagedPaths];
|
|
@@ -118,8 +182,8 @@ async function listRememberedRoots(rememberedRootsStore) {
|
|
|
118
182
|
return [];
|
|
119
183
|
const result = await rememberedRootsStore.listRoots();
|
|
120
184
|
if (result.isErr()) {
|
|
121
|
-
|
|
122
|
-
|
|
185
|
+
console.error(`[workrail] Failed to load remembered workflow roots: ${result.error.code}: ${result.error.message}`);
|
|
186
|
+
return [];
|
|
123
187
|
}
|
|
124
188
|
return result.value.map((root) => path_1.default.resolve(root));
|
|
125
189
|
}
|
|
@@ -136,7 +200,7 @@ async function discoverWorkflowDirectoriesUnderRoot(rootPath) {
|
|
|
136
200
|
}
|
|
137
201
|
return { discovered: discoveredPaths, stale: false };
|
|
138
202
|
}
|
|
139
|
-
async function walkForRootedWorkflowDirectories(currentDirectory, discoveredPaths) {
|
|
203
|
+
async function walkForRootedWorkflowDirectories(currentDirectory, discoveredPaths, depth = 0) {
|
|
140
204
|
const entries = await promises_1.default.readdir(currentDirectory, { withFileTypes: true });
|
|
141
205
|
const sortedEntries = [...entries].sort((a, b) => a.name.localeCompare(b.name));
|
|
142
206
|
for (const entry of sortedEntries) {
|
|
@@ -152,14 +216,20 @@ async function walkForRootedWorkflowDirectories(currentDirectory, discoveredPath
|
|
|
152
216
|
}
|
|
153
217
|
continue;
|
|
154
218
|
}
|
|
155
|
-
|
|
219
|
+
if (depth >= MAX_WALK_DEPTH) {
|
|
220
|
+
if (process.env['WORKRAIL_DEV'] === '1') {
|
|
221
|
+
console.error(`[workrail] walk depth limit (${MAX_WALK_DEPTH}) reached at: ${entryPath}`);
|
|
222
|
+
}
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
await walkForRootedWorkflowDirectories(entryPath, discoveredPaths, depth + 1).catch((err) => {
|
|
156
226
|
if (err.code !== 'ENOENT')
|
|
157
227
|
throw err;
|
|
158
228
|
});
|
|
159
229
|
}
|
|
160
230
|
}
|
|
161
231
|
function shouldSkipDirectory(name) {
|
|
162
|
-
return
|
|
232
|
+
return SKIP_DIRS.has(name);
|
|
163
233
|
}
|
|
164
234
|
async function isDirectory(targetPath) {
|
|
165
235
|
try {
|
|
@@ -10,8 +10,10 @@ import type { V2ContinueWorkflowInput } from '../../v2/tools.js';
|
|
|
10
10
|
import { type OutputToAppend } from '../../../v2/durable-core/domain/outputs.js';
|
|
11
11
|
import type { InternalError } from '../v2-error-mapping.js';
|
|
12
12
|
import type { AdvanceCorePorts } from './index.js';
|
|
13
|
+
import type { SessionIndex } from '../../../v2/durable-core/session-index.js';
|
|
13
14
|
type BuildAppendPlanArgs = {
|
|
14
15
|
readonly truth: LoadedSessionTruthV2;
|
|
16
|
+
readonly lockedIndex: SessionIndex;
|
|
15
17
|
readonly sessionId: SessionId;
|
|
16
18
|
readonly runId: RunId;
|
|
17
19
|
readonly currentNodeId: NodeId;
|
|
@@ -11,15 +11,15 @@ const outputs_js_1 = require("../../../v2/durable-core/domain/outputs.js");
|
|
|
11
11
|
const ack_advance_append_plan_js_1 = require("../../../v2/durable-core/domain/ack-advance-append-plan.js");
|
|
12
12
|
const constants_js_1 = require("../../../v2/durable-core/constants.js");
|
|
13
13
|
function buildAndAppendPlan(args) {
|
|
14
|
-
const { truth, sessionId, runId, currentNodeId, attemptId, workflowHash, extraEventsToAppend, sessionStore, idFactory, lock } = args;
|
|
15
|
-
const nextEventIndex =
|
|
14
|
+
const { truth, lockedIndex, sessionId, runId, currentNodeId, attemptId, workflowHash, extraEventsToAppend, sessionStore, idFactory, lock } = args;
|
|
15
|
+
const nextEventIndex = lockedIndex.nextEventIndex;
|
|
16
16
|
const evtAdvanceRecorded = idFactory.mintEventId();
|
|
17
17
|
if (args.kind === 'blocked') {
|
|
18
18
|
const toNodeId = String(idFactory.mintNodeId());
|
|
19
19
|
const evtNodeCreated = idFactory.mintEventId();
|
|
20
20
|
const evtEdgeCreated = idFactory.mintEventId();
|
|
21
21
|
const outputEventIds = (args.outputsToAppend ?? []).map(() => idFactory.mintEventId());
|
|
22
|
-
const hasChildren =
|
|
22
|
+
const hasChildren = lockedIndex.hasChildEdgeByFromNodeId.has(String(currentNodeId));
|
|
23
23
|
const causeKind = hasChildren ? constants_js_1.EDGE_CAUSE.NON_TIP_ADVANCE : constants_js_1.EDGE_CAUSE.INTENTIONAL_FORK;
|
|
24
24
|
const planRes = (0, ack_advance_append_plan_js_1.buildAckAdvanceAppendPlanV1)({
|
|
25
25
|
sessionId: String(sessionId),
|
|
@@ -44,12 +44,12 @@ function buildAndAppendPlan(args) {
|
|
|
44
44
|
});
|
|
45
45
|
if (planRes.isErr())
|
|
46
46
|
return (0, neverthrow_1.errAsync)({ kind: 'invariant_violation', message: planRes.error.message });
|
|
47
|
-
return sessionStore.append(lock, planRes.value);
|
|
47
|
+
return sessionStore.append(lock, planRes.value, truth);
|
|
48
48
|
}
|
|
49
49
|
const toNodeId = String(idFactory.mintNodeId());
|
|
50
50
|
const evtNodeCreated = idFactory.mintEventId();
|
|
51
51
|
const evtEdgeCreated = idFactory.mintEventId();
|
|
52
|
-
const hasChildren =
|
|
52
|
+
const hasChildren = lockedIndex.hasChildEdgeByFromNodeId.has(String(currentNodeId));
|
|
53
53
|
const causeKind = hasChildren ? constants_js_1.EDGE_CAUSE.NON_TIP_ADVANCE : constants_js_1.EDGE_CAUSE.INTENTIONAL_FORK;
|
|
54
54
|
const normalizedOutputs = (0, outputs_js_1.normalizeOutputsForAppend)(args.outputsToAppend);
|
|
55
55
|
const outputEventIds = normalizedOutputs.map(() => idFactory.mintEventId());
|
|
@@ -76,7 +76,7 @@ function buildAndAppendPlan(args) {
|
|
|
76
76
|
});
|
|
77
77
|
if (planRes.isErr())
|
|
78
78
|
return (0, neverthrow_1.errAsync)({ kind: 'invariant_violation', message: planRes.error.message });
|
|
79
|
-
return sessionStore.append(lock, planRes.value);
|
|
79
|
+
return sessionStore.append(lock, planRes.value, truth);
|
|
80
80
|
}
|
|
81
81
|
function buildNotesOutputs(allowNotesAppend, attemptId, inputOutput) {
|
|
82
82
|
if (!allowNotesAppend || !inputOutput?.notesMarkdown)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ResultAsync as RA } from 'neverthrow';
|
|
2
|
+
import type { SessionIndex } from '../../../v2/durable-core/session-index.js';
|
|
2
3
|
import type { ExecutionSnapshotFileV1, EngineStateV1 } from '../../../v2/durable-core/schemas/execution-snapshot/index.js';
|
|
3
4
|
import type { SessionId, RunId, NodeId, WorkflowHash } from '../../../v2/durable-core/ids/index.js';
|
|
4
5
|
import type { AttemptId } from '../../../v2/durable-core/tokens/index.js';
|
|
@@ -63,4 +64,5 @@ export declare function executeAdvanceCore(args: {
|
|
|
63
64
|
readonly lock: WithHealthySessionLock;
|
|
64
65
|
readonly pinnedWorkflow: ReturnType<typeof createWorkflow>;
|
|
65
66
|
readonly ports: AdvanceCorePorts;
|
|
67
|
+
readonly lockedIndex: SessionIndex;
|
|
66
68
|
}): RA<void, InternalError | SessionEventLogStoreError | SnapshotStoreError>;
|
|
@@ -39,6 +39,7 @@ function executeAdvanceCore(args) {
|
|
|
39
39
|
}
|
|
40
40
|
const validatedRes = (0, input_validation_js_1.validateAdvanceInputs)({
|
|
41
41
|
truth, runId, currentNodeId, inputContext, inputOutput, pinnedWorkflow, pendingStep,
|
|
42
|
+
precomputedIndex: args.lockedIndex,
|
|
42
43
|
});
|
|
43
44
|
if (validatedRes.isErr())
|
|
44
45
|
return errAsync(validatedRes.error);
|
|
@@ -71,7 +72,7 @@ function executeAdvanceCore(args) {
|
|
|
71
72
|
const ctx = { truth, sessionId, runId, currentNodeId, attemptId, workflowHash, inputOutput, pinnedWorkflow, engineState, pendingStep };
|
|
72
73
|
const computed = { reasons: effectiveReasons, outputRequirement, validation: evalValidation };
|
|
73
74
|
const portsLocal = { snapshotStore, sessionStore, sha256, idFactory };
|
|
74
|
-
return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, v, lock, ports: portsLocal });
|
|
75
|
+
return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, v, lock, ports: portsLocal, lockedIndex: args.lockedIndex });
|
|
75
76
|
}
|
|
76
77
|
const validation = phase.validation;
|
|
77
78
|
const effectiveValidation = v.assessmentValidation && !v.assessmentValidation.validation.valid
|
|
@@ -110,9 +111,9 @@ function executeAdvanceCore(args) {
|
|
|
110
111
|
const computed = { reasons, outputRequirement, validation: effectiveValidation };
|
|
111
112
|
const ports = { snapshotStore, sessionStore, sha256, idFactory };
|
|
112
113
|
if (shouldBlockNow) {
|
|
113
|
-
return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, v, lock, ports });
|
|
114
|
+
return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, v, lock, ports, lockedIndex: args.lockedIndex });
|
|
114
115
|
}
|
|
115
|
-
return (0, outcome_success_js_1.buildSuccessOutcome)({ mode, ctx, computed, v, lock, ports });
|
|
116
|
+
return (0, outcome_success_js_1.buildSuccessOutcome)({ mode, ctx, computed, v, lock, ports, lockedIndex: args.lockedIndex });
|
|
116
117
|
});
|
|
117
118
|
}
|
|
118
119
|
function derivePendingStepForMode(mode, engineState) {
|
|
@@ -9,6 +9,7 @@ import type { AssessmentArtifactV1 } from '../../../v2/durable-core/schemas/arti
|
|
|
9
9
|
import type { RecordedAssessmentV1 } from '../../../v2/durable-core/domain/assessment-record.js';
|
|
10
10
|
import type { TriggeredAssessmentConsequenceV1 } from './assessment-consequences.js';
|
|
11
11
|
import type { InternalError } from '../v2-error-mapping.js';
|
|
12
|
+
import type { SessionIndex } from '../../../v2/durable-core/session-index.js';
|
|
12
13
|
export interface ValidatedAdvanceInputs {
|
|
13
14
|
readonly pendingStep: {
|
|
14
15
|
readonly stepId: string;
|
|
@@ -50,4 +51,5 @@ export declare function validateAdvanceInputs(args: {
|
|
|
50
51
|
readonly iteration: number;
|
|
51
52
|
}[];
|
|
52
53
|
};
|
|
54
|
+
readonly precomputedIndex?: SessionIndex;
|
|
53
55
|
}): Result<ValidatedAdvanceInputs, InternalError>;
|