@exaudeus/workrail 3.11.2 → 3.13.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/console/assets/index-DW78t31j.css +1 -0
- package/dist/console/assets/index-EsSXrC_a.js +28 -0
- package/dist/console/index.html +2 -2
- package/dist/di/container.js +8 -0
- package/dist/di/tokens.d.ts +1 -0
- package/dist/di/tokens.js +1 -0
- package/dist/infrastructure/session/HttpServer.js +2 -14
- package/dist/manifest.json +139 -91
- package/dist/mcp/boundary-coercion.d.ts +2 -0
- package/dist/mcp/boundary-coercion.js +73 -0
- package/dist/mcp/handler-factory.d.ts +1 -1
- package/dist/mcp/handler-factory.js +13 -6
- package/dist/mcp/handlers/shared/request-workflow-reader.d.ts +10 -2
- package/dist/mcp/handlers/shared/request-workflow-reader.js +27 -10
- package/dist/mcp/handlers/shared/workflow-source-visibility.d.ts +3 -1
- package/dist/mcp/handlers/shared/workflow-source-visibility.js +7 -3
- package/dist/mcp/handlers/v2-execution/replay.js +25 -1
- package/dist/mcp/handlers/v2-execution/start.js +23 -17
- package/dist/mcp/handlers/v2-manage-workflow-source.d.ts +7 -0
- package/dist/mcp/handlers/v2-manage-workflow-source.js +50 -0
- package/dist/mcp/handlers/v2-workflow.js +123 -8
- package/dist/mcp/output-schemas.d.ts +393 -0
- package/dist/mcp/output-schemas.js +49 -1
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/tool-descriptions.js +20 -0
- package/dist/mcp/tools.js +6 -0
- package/dist/mcp/types/tool-description-types.d.ts +1 -1
- package/dist/mcp/types/tool-description-types.js +1 -0
- package/dist/mcp/types/workflow-tool-edition.d.ts +1 -1
- package/dist/mcp/types.d.ts +2 -0
- package/dist/mcp/v2/tool-registry.js +8 -0
- package/dist/mcp/v2/tools.d.ts +15 -0
- package/dist/mcp/v2/tools.js +8 -1
- package/dist/v2/durable-core/constants.d.ts +1 -0
- package/dist/v2/durable-core/constants.js +2 -1
- package/dist/v2/durable-core/domain/observation-builder.d.ts +4 -1
- package/dist/v2/durable-core/domain/observation-builder.js +9 -0
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +76 -16
- package/dist/v2/durable-core/schemas/session/events.d.ts +26 -5
- package/dist/v2/durable-core/schemas/session/events.js +2 -1
- package/dist/v2/infra/in-memory/managed-source-store/index.d.ts +8 -0
- package/dist/v2/infra/in-memory/managed-source-store/index.js +33 -0
- package/dist/v2/infra/local/data-dir/index.d.ts +2 -0
- package/dist/v2/infra/local/data-dir/index.js +6 -0
- package/dist/v2/infra/local/managed-source-store/index.d.ts +15 -0
- package/dist/v2/infra/local/managed-source-store/index.js +164 -0
- package/dist/v2/infra/local/session-summary-provider/index.js +2 -0
- package/dist/v2/infra/local/workspace-anchor/index.js +1 -0
- package/dist/v2/ports/data-dir.port.d.ts +2 -0
- package/dist/v2/ports/managed-source-store.port.d.ts +25 -0
- package/dist/v2/ports/managed-source-store.port.js +2 -0
- package/dist/v2/ports/workspace-anchor.port.d.ts +3 -0
- package/dist/v2/projections/resume-ranking.d.ts +1 -0
- package/dist/v2/usecases/console-routes.js +26 -0
- package/dist/v2/usecases/console-service.js +25 -6
- package/dist/v2/usecases/console-types.d.ts +22 -1
- package/dist/v2/usecases/worktree-service.d.ts +10 -0
- package/dist/v2/usecases/worktree-service.js +136 -0
- package/package.json +1 -1
- package/workflows/adaptive-ticket-creation.json +276 -282
- package/workflows/architecture-scalability-audit.json +317 -0
- package/workflows/document-creation-workflow.json +70 -191
- package/workflows/documentation-update-workflow.json +59 -309
- package/workflows/intelligent-test-case-generation.json +37 -212
- package/workflows/personal-learning-materials-creation-branched.json +1 -21
- package/workflows/presentation-creation.json +143 -308
- package/workflows/relocation-workflow-us.json +161 -535
- package/workflows/routines/tension-driven-design.json +5 -5
- package/workflows/scoped-documentation-workflow.json +110 -181
- package/workflows/workflow-for-workflows.v2.json +21 -5
- package/dist/console/assets/index-C5C4nDs4.css +0 -1
- package/dist/console/assets/index-CSUqsoQl.js +0 -28
- package/workflows/CHANGELOG-bug-investigation.md +0 -298
- package/workflows/bug-investigation.agentic.json +0 -212
- package/workflows/bug-investigation.json +0 -112
- package/workflows/mr-review-workflow.agentic.json +0 -538
- package/workflows/mr-review-workflow.json +0 -277
|
@@ -4,6 +4,7 @@ exports.toMcpResult = toMcpResult;
|
|
|
4
4
|
exports.createHandler = createHandler;
|
|
5
5
|
exports.createValidatingHandler = createValidatingHandler;
|
|
6
6
|
const types_js_1 = require("./types.js");
|
|
7
|
+
const boundary_coercion_js_1 = require("./boundary-coercion.js");
|
|
7
8
|
const index_js_1 = require("./validation/index.js");
|
|
8
9
|
const bounded_json_js_1 = require("./validation/bounded-json.js");
|
|
9
10
|
const v2_execution_helpers_js_1 = require("./handlers/v2-execution-helpers.js");
|
|
@@ -56,12 +57,15 @@ function toMcpResult(result) {
|
|
|
56
57
|
}
|
|
57
58
|
function createHandler(schema, handler, shapeSchema, aliasMap) {
|
|
58
59
|
return async (args, ctx) => {
|
|
59
|
-
const
|
|
60
|
+
const normalizedArgs = shapeSchema !== undefined
|
|
61
|
+
? (0, boundary_coercion_js_1.coerceJsonStringObjectFields)(args, shapeSchema, aliasMap)
|
|
62
|
+
: args;
|
|
63
|
+
const parseResult = schema.safeParse(normalizedArgs);
|
|
60
64
|
if (!parseResult.success) {
|
|
61
65
|
const introspectionSchema = shapeSchema ?? schema;
|
|
62
|
-
const suggestionResult = (0, index_js_1.generateSuggestions)(
|
|
66
|
+
const suggestionResult = (0, index_js_1.generateSuggestions)(normalizedArgs, introspectionSchema, index_js_1.DEFAULT_SUGGESTION_CONFIG, aliasMap);
|
|
63
67
|
const suggestionDetails = (0, index_js_1.formatSuggestionDetails)(suggestionResult);
|
|
64
|
-
const patchedTemplate = (0, index_js_1.patchTemplateForFailedOptionals)(suggestionDetails.correctTemplate ?? null,
|
|
68
|
+
const patchedTemplate = (0, index_js_1.patchTemplateForFailedOptionals)(suggestionDetails.correctTemplate ?? null, normalizedArgs, parseResult.error.errors, introspectionSchema, index_js_1.DEFAULT_SUGGESTION_CONFIG.maxTemplateDepth);
|
|
65
69
|
const patchedDetails = patchedTemplate !== suggestionDetails.correctTemplate
|
|
66
70
|
? { ...suggestionDetails, correctTemplate: patchedTemplate }
|
|
67
71
|
: suggestionDetails;
|
|
@@ -82,9 +86,12 @@ function createHandler(schema, handler, shapeSchema, aliasMap) {
|
|
|
82
86
|
}
|
|
83
87
|
};
|
|
84
88
|
}
|
|
85
|
-
function createValidatingHandler(schema, preValidate, handler) {
|
|
89
|
+
function createValidatingHandler(schema, preValidate, handler, shapeSchema, aliasMap) {
|
|
86
90
|
return async (args, ctx) => {
|
|
87
|
-
const
|
|
91
|
+
const normalizedArgs = shapeSchema !== undefined
|
|
92
|
+
? (0, boundary_coercion_js_1.coerceJsonStringObjectFields)(args, shapeSchema, aliasMap)
|
|
93
|
+
: args;
|
|
94
|
+
const pre = preValidate(normalizedArgs);
|
|
88
95
|
if (!pre.ok) {
|
|
89
96
|
const error = pre.error;
|
|
90
97
|
const details = error.details && typeof error.details === 'object' ? error.details : {};
|
|
@@ -103,6 +110,6 @@ function createValidatingHandler(schema, preValidate, handler) {
|
|
|
103
110
|
}
|
|
104
111
|
return toMcpResult(error);
|
|
105
112
|
}
|
|
106
|
-
return createHandler(schema, handler)(
|
|
113
|
+
return createHandler(schema, handler, shapeSchema, aliasMap)(normalizedArgs, ctx);
|
|
107
114
|
};
|
|
108
115
|
}
|
|
@@ -18,5 +18,13 @@ export declare function resolveRequestWorkspaceDirectory(options: {
|
|
|
18
18
|
readonly serverCwd?: string;
|
|
19
19
|
}): string;
|
|
20
20
|
export declare function toProjectWorkflowDirectory(workspaceDirectory: string): string;
|
|
21
|
-
export
|
|
22
|
-
|
|
21
|
+
export interface WorkflowRootDiscoveryResult {
|
|
22
|
+
readonly discovered: readonly string[];
|
|
23
|
+
readonly stale: readonly string[];
|
|
24
|
+
}
|
|
25
|
+
export declare function discoverRootedWorkflowDirectories(roots: readonly string[]): Promise<WorkflowRootDiscoveryResult>;
|
|
26
|
+
export interface WorkflowReaderForRequestResult {
|
|
27
|
+
readonly reader: IWorkflowReader;
|
|
28
|
+
readonly stalePaths: readonly string[];
|
|
29
|
+
}
|
|
30
|
+
export declare function createWorkflowReaderForRequest(options: RequestWorkflowReaderOptions): Promise<WorkflowReaderForRequestResult>;
|
|
@@ -37,10 +37,15 @@ function toProjectWorkflowDirectory(workspaceDirectory) {
|
|
|
37
37
|
async function discoverRootedWorkflowDirectories(roots) {
|
|
38
38
|
const discoveredByPath = new Set();
|
|
39
39
|
const discoveredPaths = [];
|
|
40
|
+
const stalePaths = [];
|
|
40
41
|
for (const root of roots) {
|
|
41
42
|
const rootPath = path_1.default.resolve(root);
|
|
42
|
-
const
|
|
43
|
-
|
|
43
|
+
const result = await discoverWorkflowDirectoriesUnderRoot(rootPath);
|
|
44
|
+
if (result.stale) {
|
|
45
|
+
stalePaths.push(rootPath);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
for (const nextPath of result.discovered) {
|
|
44
49
|
const normalizedPath = path_1.default.resolve(nextPath);
|
|
45
50
|
if (discoveredByPath.has(normalizedPath))
|
|
46
51
|
continue;
|
|
@@ -48,19 +53,20 @@ async function discoverRootedWorkflowDirectories(roots) {
|
|
|
48
53
|
discoveredPaths.push(normalizedPath);
|
|
49
54
|
}
|
|
50
55
|
}
|
|
51
|
-
return discoveredPaths;
|
|
56
|
+
return { discovered: discoveredPaths, stale: stalePaths };
|
|
52
57
|
}
|
|
53
58
|
async function createWorkflowReaderForRequest(options) {
|
|
54
59
|
const workspaceDirectory = resolveRequestWorkspaceDirectory(options);
|
|
55
60
|
const projectWorkflowDirectory = toProjectWorkflowDirectory(workspaceDirectory);
|
|
56
61
|
const rememberedRoots = await listRememberedRoots(options.rememberedRootsStore);
|
|
57
|
-
const rootedWorkflowDirectories = await discoverRootedWorkflowDirectories(rememberedRoots);
|
|
62
|
+
const { discovered: rootedWorkflowDirectories, stale: stalePaths } = await discoverRootedWorkflowDirectories(rememberedRoots);
|
|
58
63
|
const customPaths = rootedWorkflowDirectories.filter((directory) => directory !== projectWorkflowDirectory);
|
|
59
|
-
const storage =
|
|
64
|
+
const storage = (0, enhanced_multi_source_workflow_storage_js_1.createEnhancedMultiSourceWorkflowStorage)({
|
|
60
65
|
customPaths,
|
|
61
66
|
projectPath: projectWorkflowDirectory,
|
|
62
|
-
}, options.featureFlags);
|
|
63
|
-
|
|
67
|
+
}, options.featureFlags ?? undefined);
|
|
68
|
+
const reader = new schema_validating_workflow_storage_js_1.SchemaValidatingCompositeWorkflowStorage(storage);
|
|
69
|
+
return { reader, stalePaths };
|
|
64
70
|
}
|
|
65
71
|
async function listRememberedRoots(rememberedRootsStore) {
|
|
66
72
|
if (!rememberedRootsStore)
|
|
@@ -74,8 +80,16 @@ async function listRememberedRoots(rememberedRootsStore) {
|
|
|
74
80
|
}
|
|
75
81
|
async function discoverWorkflowDirectoriesUnderRoot(rootPath) {
|
|
76
82
|
const discoveredPaths = [];
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
try {
|
|
84
|
+
await walkForRootedWorkflowDirectories(rootPath, discoveredPaths);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
if (err.code === 'ENOENT') {
|
|
88
|
+
return { discovered: [], stale: true };
|
|
89
|
+
}
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
return { discovered: discoveredPaths, stale: false };
|
|
79
93
|
}
|
|
80
94
|
async function walkForRootedWorkflowDirectories(currentDirectory, discoveredPaths) {
|
|
81
95
|
const entries = await promises_1.default.readdir(currentDirectory, { withFileTypes: true });
|
|
@@ -93,7 +107,10 @@ async function walkForRootedWorkflowDirectories(currentDirectory, discoveredPath
|
|
|
93
107
|
}
|
|
94
108
|
continue;
|
|
95
109
|
}
|
|
96
|
-
await walkForRootedWorkflowDirectories(entryPath, discoveredPaths)
|
|
110
|
+
await walkForRootedWorkflowDirectories(entryPath, discoveredPaths).catch((err) => {
|
|
111
|
+
if (err.code !== 'ENOENT')
|
|
112
|
+
throw err;
|
|
113
|
+
});
|
|
97
114
|
}
|
|
98
115
|
}
|
|
99
116
|
function shouldSkipDirectory(name) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Workflow, WorkflowSourceInfo } from '../../../types/workflow.js';
|
|
2
|
-
import type { IWorkflowReader } from '../../../types/storage.js';
|
|
2
|
+
import type { ICompositeWorkflowStorage, IWorkflowReader } from '../../../types/storage.js';
|
|
3
3
|
import type { RememberedRootRecordV2 } from '../../../v2/ports/remembered-roots-store.port.js';
|
|
4
4
|
export interface PublicWorkflowSource {
|
|
5
5
|
readonly kind: WorkflowSourceInfo['kind'];
|
|
@@ -31,3 +31,5 @@ export declare function detectWorkflowMigrationGuidance(options: {
|
|
|
31
31
|
readonly workflowReader: IWorkflowReader;
|
|
32
32
|
readonly rememberedRoots: readonly RememberedRootRecordV2[];
|
|
33
33
|
}): Promise<WorkflowMigrationGuidance | undefined>;
|
|
34
|
+
export declare function isCompositeWorkflowReader(reader: unknown): reader is ICompositeWorkflowStorage;
|
|
35
|
+
export declare function deriveGroupLabel(rootPath: string, sourcePath: string): string;
|
|
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.toWorkflowVisibility = toWorkflowVisibility;
|
|
7
7
|
exports.detectWorkflowMigrationGuidance = detectWorkflowMigrationGuidance;
|
|
8
|
+
exports.isCompositeWorkflowReader = isCompositeWorkflowReader;
|
|
9
|
+
exports.deriveGroupLabel = deriveGroupLabel;
|
|
8
10
|
const path_1 = __importDefault(require("path"));
|
|
9
11
|
function toWorkflowVisibility(workflow, rememberedRoots, options = {}) {
|
|
10
12
|
const source = {
|
|
@@ -56,9 +58,11 @@ async function detectWorkflowMigrationGuidance(options) {
|
|
|
56
58
|
}
|
|
57
59
|
return undefined;
|
|
58
60
|
}
|
|
59
|
-
function isCompositeWorkflowReader(
|
|
60
|
-
return (
|
|
61
|
-
|
|
61
|
+
function isCompositeWorkflowReader(reader) {
|
|
62
|
+
return (typeof reader === 'object' &&
|
|
63
|
+
reader !== null &&
|
|
64
|
+
reader.kind === 'composite' &&
|
|
65
|
+
typeof reader.getStorageInstances === 'function');
|
|
62
66
|
}
|
|
63
67
|
function deriveRootedSharingContext(workflow, rememberedRoots) {
|
|
64
68
|
if (workflow.source.kind !== 'custom')
|
|
@@ -14,8 +14,9 @@ const v2_token_ops_js_1 = require("../v2-token-ops.js");
|
|
|
14
14
|
const v2_state_conversion_js_1 = require("../v2-state-conversion.js");
|
|
15
15
|
const constants_js_1 = require("../../../v2/durable-core/constants.js");
|
|
16
16
|
const index_js_2 = require("./index.js");
|
|
17
|
+
const assessments_js_1 = require("../../../v2/projections/assessments.js");
|
|
17
18
|
function buildAdvancedReplayResponse(args) {
|
|
18
|
-
const { sessionId, runId, toNodeId, attemptId, toSnapshot, workflow, truth, workflowHash, ports, sha256, aliasStore, entropy } = args;
|
|
19
|
+
const { sessionId, runId, fromNodeId, toNodeId, attemptId, toSnapshot, workflow, truth, workflowHash, ports, sha256, aliasStore, entropy } = args;
|
|
19
20
|
const toNodeIdBranded = (0, index_js_1.asNodeId)(String(toNodeId));
|
|
20
21
|
const pending = (0, snapshot_state_js_1.derivePendingStep)(toSnapshot.enginePayload.engineState);
|
|
21
22
|
const isComplete = (0, snapshot_state_js_1.deriveIsComplete)(toSnapshot.enginePayload.engineState);
|
|
@@ -116,6 +117,7 @@ function buildAdvancedReplayResponse(args) {
|
|
|
116
117
|
}
|
|
117
118
|
const preferences = (0, v2_execution_helpers_js_1.derivePreferencesOrDefault)({ truth, runId, nodeId: toNodeIdBranded });
|
|
118
119
|
const nextIntent = (0, v2_state_conversion_js_1.deriveNextIntent)({ rehydrateOnly: false, isComplete, pending: okMeta });
|
|
120
|
+
const stepContext = buildStepContext(truth.events, fromNodeId);
|
|
119
121
|
return nextTokensMint.andThen((nextTokens) => (0, neverthrow_1.okAsync)(output_schemas_js_1.V2ContinueWorkflowOutputSchema.parse({
|
|
120
122
|
kind: 'ok',
|
|
121
123
|
continueToken: pending ? nextTokens.continueToken : undefined,
|
|
@@ -125,8 +127,30 @@ function buildAdvancedReplayResponse(args) {
|
|
|
125
127
|
preferences,
|
|
126
128
|
nextIntent,
|
|
127
129
|
nextCall: (0, index_js_2.buildNextCall)({ continueToken: pending ? nextTokens.continueToken : undefined, isComplete, pending: okMeta }),
|
|
130
|
+
stepContext,
|
|
128
131
|
})));
|
|
129
132
|
}
|
|
133
|
+
function buildStepContext(events, completedNodeId) {
|
|
134
|
+
const projection = (0, assessments_js_1.projectAssessmentsV2)(events);
|
|
135
|
+
if (projection.isErr()) {
|
|
136
|
+
console.warn(`[workrail:replay] stepContext projection failed for node '${String(completedNodeId)}' — stepContext will be absent: ${projection.error.message}`);
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
const recorded = (0, assessments_js_1.getLatestAssessmentForNode)(projection.value, String(completedNodeId));
|
|
140
|
+
if (!recorded)
|
|
141
|
+
return undefined;
|
|
142
|
+
return {
|
|
143
|
+
assessments: {
|
|
144
|
+
assessmentId: recorded.assessmentId,
|
|
145
|
+
dimensions: recorded.dimensions.map((d) => ({
|
|
146
|
+
dimensionId: d.dimensionId,
|
|
147
|
+
level: d.level,
|
|
148
|
+
...(d.rationale !== undefined ? { rationale: d.rationale } : {}),
|
|
149
|
+
})),
|
|
150
|
+
normalizationNotes: recorded.normalizationNotes,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
130
154
|
function replayFromRecordedAdvance(args) {
|
|
131
155
|
const { recordedEvent, truth, sessionId, runId, nodeId, workflowHash, attemptId, pinnedWorkflow, snapshotStore, sha256, tokenCodecPorts, aliasStore, entropy, } = args;
|
|
132
156
|
if (recordedEvent.data.outcome.kind === 'blocked') {
|
|
@@ -216,23 +216,28 @@ function executeStartWorkflow(input, ctx) {
|
|
|
216
216
|
workspacePath: input.workspacePath,
|
|
217
217
|
resolvedRootUris: ctx.v2.resolvedRootUris,
|
|
218
218
|
});
|
|
219
|
-
const
|
|
220
|
-
? {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
219
|
+
const readerRA = shouldUseRequestReader
|
|
220
|
+
? neverthrow_1.ResultAsync.fromPromise((0, request_workflow_reader_js_1.createWorkflowReaderForRequest)({
|
|
221
|
+
featureFlags: ctx.featureFlags,
|
|
222
|
+
workspacePath: input.workspacePath,
|
|
223
|
+
resolvedRootUris: ctx.v2.resolvedRootUris,
|
|
224
|
+
rememberedRootsStore: ctx.v2.rememberedRootsStore,
|
|
225
|
+
}), (err) => ({
|
|
226
|
+
kind: 'precondition_failed',
|
|
227
|
+
message: `Failed to initialize workflow reader: ${String(err)}`,
|
|
228
|
+
})).map(({ reader, stalePaths }) => ({
|
|
229
|
+
workflowReader: {
|
|
230
|
+
getWorkflowById: async (workflowId) => {
|
|
231
|
+
const requestResult = await reader.getWorkflowById(workflowId);
|
|
232
|
+
if (requestResult != null)
|
|
233
|
+
return requestResult;
|
|
234
|
+
return ctx.workflowService.getWorkflowById(workflowId);
|
|
235
|
+
},
|
|
232
236
|
},
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
237
|
+
stalePaths,
|
|
238
|
+
}))
|
|
239
|
+
: (0, neverthrow_1.okAsync)({ workflowReader: ctx.workflowService, stalePaths: [] });
|
|
240
|
+
return readerRA.andThen(({ workflowReader, stalePaths }) => loadAndPinWorkflow({
|
|
236
241
|
workflowId: input.workflowId,
|
|
237
242
|
workflowReader,
|
|
238
243
|
crypto,
|
|
@@ -345,10 +350,11 @@ function executeStartWorkflow(input, ctx) {
|
|
|
345
350
|
preferences,
|
|
346
351
|
nextIntent,
|
|
347
352
|
nextCall: (0, index_js_2.buildNextCall)({ continueToken: tokens.continueToken, isComplete: false, pending }),
|
|
353
|
+
...(stalePaths.length > 0 ? { staleRoots: [...stalePaths] } : {}),
|
|
348
354
|
});
|
|
349
355
|
return (0, neverthrow_1.okAsync)({ response: parsed, contentEnvelope });
|
|
350
356
|
});
|
|
351
|
-
});
|
|
357
|
+
}));
|
|
352
358
|
}
|
|
353
359
|
function enrichPinnedSnapshotWithResolvedReferences(snapshot, references, workspacePath) {
|
|
354
360
|
if (references.length === 0) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ToolContext, ToolResult } from '../types.js';
|
|
2
|
+
import type { V2ManageWorkflowSourceInput } from '../v2/tools.js';
|
|
3
|
+
export interface ManageWorkflowSourceOutput {
|
|
4
|
+
readonly action: 'attach' | 'detach';
|
|
5
|
+
readonly path: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function handleV2ManageWorkflowSource(input: V2ManageWorkflowSourceInput, ctx: ToolContext): Promise<ToolResult<ManageWorkflowSourceOutput>>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleV2ManageWorkflowSource = handleV2ManageWorkflowSource;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const assert_never_js_1 = require("../../runtime/assert-never.js");
|
|
9
|
+
const types_js_1 = require("../types.js");
|
|
10
|
+
function mapManagedSourceErrorToToolError(error) {
|
|
11
|
+
switch (error.code) {
|
|
12
|
+
case 'MANAGED_SOURCE_BUSY':
|
|
13
|
+
return (0, types_js_1.errRetryAfterMs)('INTERNAL_ERROR', 'WorkRail is temporarily busy updating managed workflow sources.', error.retry.afterMs, {
|
|
14
|
+
suggestion: 'Wait a moment and retry. Another WorkRail process may be updating managed workflow sources.',
|
|
15
|
+
});
|
|
16
|
+
case 'MANAGED_SOURCE_IO_ERROR':
|
|
17
|
+
return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', 'WorkRail could not update the managed workflow sources store.', {
|
|
18
|
+
suggestion: 'Fix WorkRail local storage access and retry. Check that the ~/.workrail data directory exists and is writable.',
|
|
19
|
+
details: { errorMessage: error.message },
|
|
20
|
+
});
|
|
21
|
+
case 'MANAGED_SOURCE_CORRUPTION':
|
|
22
|
+
return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', 'WorkRail managed workflow sources store is corrupted.', {
|
|
23
|
+
suggestion: 'The managed sources file may need to be deleted and re-created. Check the ~/.workrail/data/managed-sources directory.',
|
|
24
|
+
details: { errorMessage: error.message },
|
|
25
|
+
});
|
|
26
|
+
default: {
|
|
27
|
+
const _exhaustive = error;
|
|
28
|
+
return (0, assert_never_js_1.assertNever)(_exhaustive);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function handleV2ManageWorkflowSource(input, ctx) {
|
|
33
|
+
const guard = (0, types_js_1.requireV2Context)(ctx);
|
|
34
|
+
if (!guard.ok)
|
|
35
|
+
return guard.error;
|
|
36
|
+
const { managedSourceStore } = guard.ctx.v2;
|
|
37
|
+
if (!managedSourceStore) {
|
|
38
|
+
return (0, types_js_1.errNotRetryable)('PRECONDITION_FAILED', 'Managed workflow source store is not available.', {
|
|
39
|
+
suggestion: 'Ensure WorkRail v2 is fully initialized. The managedSourceStore dependency may not be wired in this environment.',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const operation = input.action === 'attach'
|
|
43
|
+
? managedSourceStore.attach(input.path)
|
|
44
|
+
: managedSourceStore.detach(input.path);
|
|
45
|
+
const result = await operation;
|
|
46
|
+
if (result.isErr()) {
|
|
47
|
+
return mapManagedSourceErrorToToolError(result.error);
|
|
48
|
+
}
|
|
49
|
+
return (0, types_js_1.success)({ action: input.action, path: path_1.default.resolve(input.path) });
|
|
50
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.handleV2ListWorkflows = handleV2ListWorkflows;
|
|
4
7
|
exports.handleV2InspectWorkflow = handleV2InspectWorkflow;
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
5
9
|
const neverthrow_1 = require("neverthrow");
|
|
6
10
|
const types_js_1 = require("../types.js");
|
|
7
11
|
const error_mapper_js_1 = require("../error-mapper.js");
|
|
@@ -29,7 +33,7 @@ async function handleV2ListWorkflows(input, ctx) {
|
|
|
29
33
|
return rememberedRootRecordsResult;
|
|
30
34
|
const rememberedRootRecords = rememberedRootRecordsResult;
|
|
31
35
|
const { crypto, pinnedStore } = guard.ctx.v2;
|
|
32
|
-
const
|
|
36
|
+
const readerResult = (0, request_workflow_reader_js_1.hasRequestWorkspaceSignal)({
|
|
33
37
|
workspacePath: input.workspacePath,
|
|
34
38
|
resolvedRootUris: guard.ctx.v2.resolvedRootUris,
|
|
35
39
|
})
|
|
@@ -39,7 +43,9 @@ async function handleV2ListWorkflows(input, ctx) {
|
|
|
39
43
|
resolvedRootUris: guard.ctx.v2.resolvedRootUris,
|
|
40
44
|
rememberedRootsStore: guard.ctx.v2.rememberedRootsStore,
|
|
41
45
|
})
|
|
42
|
-
: ctx.workflowService;
|
|
46
|
+
: { reader: ctx.workflowService, stalePaths: [] };
|
|
47
|
+
const workflowReader = readerResult.reader;
|
|
48
|
+
const stalePaths = readerResult.stalePaths;
|
|
43
49
|
return neverthrow_1.ResultAsync.fromPromise((0, with_timeout_js_1.withTimeout)(workflowReader.listWorkflowSummaries(), TIMEOUT_MS, 'list_workflows'), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err))
|
|
44
50
|
.andThen((summaries) => neverthrow_1.ResultAsync.combine(summaries.map((s) => neverthrow_1.ResultAsync.fromPromise(buildV2WorkflowListItem({
|
|
45
51
|
summary: s,
|
|
@@ -48,11 +54,30 @@ async function handleV2ListWorkflows(input, ctx) {
|
|
|
48
54
|
crypto,
|
|
49
55
|
pinnedStore,
|
|
50
56
|
}), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err)))))
|
|
51
|
-
.
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
.andThen((compiled) => {
|
|
58
|
+
if (!input.includeSources) {
|
|
59
|
+
const payload = output_schemas_js_1.V2WorkflowListOutputSchema.parse({
|
|
60
|
+
workflows: compiled.sort((a, b) => a.workflowId.localeCompare(b.workflowId)),
|
|
61
|
+
...(stalePaths.length > 0 ? { staleRoots: [...stalePaths] } : {}),
|
|
62
|
+
});
|
|
63
|
+
return (0, neverthrow_1.okAsync)((0, types_js_1.success)(payload));
|
|
64
|
+
}
|
|
65
|
+
if (!(0, workflow_source_visibility_js_1.isCompositeWorkflowReader)(workflowReader)) {
|
|
66
|
+
const payload = output_schemas_js_1.V2WorkflowListOutputSchema.parse({
|
|
67
|
+
workflows: compiled.sort((a, b) => a.workflowId.localeCompare(b.workflowId)),
|
|
68
|
+
...(stalePaths.length > 0 ? { staleRoots: [...stalePaths] } : {}),
|
|
69
|
+
sources: [],
|
|
70
|
+
});
|
|
71
|
+
return (0, neverthrow_1.okAsync)((0, types_js_1.success)(payload));
|
|
72
|
+
}
|
|
73
|
+
return neverthrow_1.ResultAsync.fromPromise((0, with_timeout_js_1.withTimeout)(buildSourceCatalog(workflowReader, rememberedRootRecords), TIMEOUT_MS, 'list_workflow_sources'), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err)).map((sources) => {
|
|
74
|
+
const payload = output_schemas_js_1.V2WorkflowListOutputSchema.parse({
|
|
75
|
+
workflows: compiled.sort((a, b) => a.workflowId.localeCompare(b.workflowId)),
|
|
76
|
+
...(stalePaths.length > 0 ? { staleRoots: [...stalePaths] } : {}),
|
|
77
|
+
sources,
|
|
78
|
+
});
|
|
79
|
+
return (0, types_js_1.success)(payload);
|
|
54
80
|
});
|
|
55
|
-
return (0, types_js_1.success)(payload);
|
|
56
81
|
})
|
|
57
82
|
.match((result) => Promise.resolve(result), (err) => Promise.resolve(err));
|
|
58
83
|
}
|
|
@@ -68,7 +93,7 @@ async function handleV2InspectWorkflow(input, ctx) {
|
|
|
68
93
|
return rememberedRootRecordsResult;
|
|
69
94
|
const rememberedRootRecords = rememberedRootRecordsResult;
|
|
70
95
|
const { crypto, pinnedStore } = guard.ctx.v2;
|
|
71
|
-
const
|
|
96
|
+
const readerResult = (0, request_workflow_reader_js_1.hasRequestWorkspaceSignal)({
|
|
72
97
|
workspacePath: input.workspacePath,
|
|
73
98
|
resolvedRootUris: guard.ctx.v2.resolvedRootUris,
|
|
74
99
|
})
|
|
@@ -78,7 +103,9 @@ async function handleV2InspectWorkflow(input, ctx) {
|
|
|
78
103
|
resolvedRootUris: guard.ctx.v2.resolvedRootUris,
|
|
79
104
|
rememberedRootsStore: guard.ctx.v2.rememberedRootsStore,
|
|
80
105
|
})
|
|
81
|
-
: ctx.workflowService;
|
|
106
|
+
: { reader: ctx.workflowService, stalePaths: [] };
|
|
107
|
+
const workflowReader = readerResult.reader;
|
|
108
|
+
const stalePaths = readerResult.stalePaths;
|
|
82
109
|
return neverthrow_1.ResultAsync.fromPromise((0, with_timeout_js_1.withTimeout)(workflowReader.getWorkflowById(input.workflowId), TIMEOUT_MS, 'inspect_workflow'), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err))
|
|
83
110
|
.andThen((workflow) => {
|
|
84
111
|
if (!workflow) {
|
|
@@ -113,6 +140,7 @@ async function handleV2InspectWorkflow(input, ctx) {
|
|
|
113
140
|
mode: input.mode,
|
|
114
141
|
compiled: body,
|
|
115
142
|
...(visibility ? { visibility } : {}),
|
|
143
|
+
...(stalePaths.length > 0 ? { staleRoots: [...stalePaths] } : {}),
|
|
116
144
|
...(references != null && references.length > 0 ? { references } : {}),
|
|
117
145
|
});
|
|
118
146
|
return (0, neverthrow_1.okAsync)((0, types_js_1.success)(payload));
|
|
@@ -181,3 +209,90 @@ async function buildV2WorkflowListItem(options) {
|
|
|
181
209
|
visibility,
|
|
182
210
|
};
|
|
183
211
|
}
|
|
212
|
+
async function buildSourceCatalog(workflowReader, rememberedRootRecords) {
|
|
213
|
+
const instances = workflowReader.getStorageInstances();
|
|
214
|
+
const seenIds = new Set();
|
|
215
|
+
const sourceEntryDataReversed = [];
|
|
216
|
+
for (let i = instances.length - 1; i >= 0; i--) {
|
|
217
|
+
const instance = instances[i];
|
|
218
|
+
const summaries = await instance.listWorkflowSummaries();
|
|
219
|
+
const allIds = summaries.map((s) => s.id);
|
|
220
|
+
const effectiveIds = allIds.filter((id) => !seenIds.has(id));
|
|
221
|
+
for (const id of allIds)
|
|
222
|
+
seenIds.add(id);
|
|
223
|
+
sourceEntryDataReversed.push({ source: instance.source, allIds, effectiveIds });
|
|
224
|
+
}
|
|
225
|
+
const sourceEntryData = sourceEntryDataReversed.reverse();
|
|
226
|
+
return sourceEntryData.map((data) => deriveSourceCatalogEntry({ ...data, rememberedRootRecords, sourceEntryData }));
|
|
227
|
+
}
|
|
228
|
+
function deriveSourceCatalogEntry(options) {
|
|
229
|
+
const { source, allIds, effectiveIds, rememberedRootRecords, sourceEntryData } = options;
|
|
230
|
+
const total = allIds.length;
|
|
231
|
+
const effective = effectiveIds.length;
|
|
232
|
+
const shadowed = total - effective;
|
|
233
|
+
const sourceKey = deriveSourceKey(source);
|
|
234
|
+
const displayName = deriveDisplayName(source);
|
|
235
|
+
switch (source.kind) {
|
|
236
|
+
case 'bundled':
|
|
237
|
+
return { sourceKey, category: 'built_in', source: { kind: source.kind, displayName }, sourceMode: 'built_in', effectiveWorkflowCount: effective, totalWorkflowCount: total, shadowedWorkflowCount: shadowed };
|
|
238
|
+
case 'user':
|
|
239
|
+
return { sourceKey, category: 'personal', source: { kind: source.kind, displayName }, sourceMode: 'personal', effectiveWorkflowCount: effective, totalWorkflowCount: total, shadowedWorkflowCount: shadowed };
|
|
240
|
+
case 'project': {
|
|
241
|
+
const thisIds = new Set(allIds);
|
|
242
|
+
const hasMigrationOverlap = sourceEntryData.some((e) => {
|
|
243
|
+
if (e.source === source || e.source.kind !== 'custom')
|
|
244
|
+
return false;
|
|
245
|
+
const rootedSharing = deriveRootedSharingForPath(e.source.directoryPath, rememberedRootRecords);
|
|
246
|
+
return rootedSharing != null && e.allIds.some((id) => thisIds.has(id));
|
|
247
|
+
});
|
|
248
|
+
const migration = hasMigrationOverlap
|
|
249
|
+
? { preferredSource: 'rooted_sharing', currentSource: 'legacy_project', reason: 'legacy_project_precedence', summary: 'Project-scoped ./workflows currently overrides rooted .workrail/workflows during migration. Prefer rooted sharing for new team-shared workflows.' }
|
|
250
|
+
: undefined;
|
|
251
|
+
return { sourceKey, category: 'legacy_project', source: { kind: source.kind, displayName }, sourceMode: 'legacy_project', effectiveWorkflowCount: effective, totalWorkflowCount: total, shadowedWorkflowCount: shadowed, ...(migration ? { migration } : {}) };
|
|
252
|
+
}
|
|
253
|
+
case 'custom': {
|
|
254
|
+
const rootedSharing = deriveRootedSharingForPath(source.directoryPath, rememberedRootRecords);
|
|
255
|
+
const category = rootedSharing ? 'rooted_sharing' : 'external';
|
|
256
|
+
const sourceMode = rootedSharing ? 'rooted_sharing' : 'live_directory';
|
|
257
|
+
return { sourceKey, category, source: { kind: source.kind, displayName }, sourceMode, effectiveWorkflowCount: effective, totalWorkflowCount: total, shadowedWorkflowCount: shadowed, ...(rootedSharing ? { rootedSharing } : {}) };
|
|
258
|
+
}
|
|
259
|
+
case 'git':
|
|
260
|
+
case 'remote':
|
|
261
|
+
case 'plugin':
|
|
262
|
+
return { sourceKey, category: 'external', source: { kind: source.kind, displayName }, sourceMode: 'live_directory', effectiveWorkflowCount: effective, totalWorkflowCount: total, shadowedWorkflowCount: shadowed };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function deriveSourceKey(source) {
|
|
266
|
+
switch (source.kind) {
|
|
267
|
+
case 'bundled': return 'built_in';
|
|
268
|
+
case 'user': return `user:${source.directoryPath}`;
|
|
269
|
+
case 'project': return `project:${source.directoryPath}`;
|
|
270
|
+
case 'custom': return `custom:${source.directoryPath}`;
|
|
271
|
+
case 'git': return `git:${source.repositoryUrl}`;
|
|
272
|
+
case 'remote': return `remote:${source.registryUrl}`;
|
|
273
|
+
case 'plugin': return `plugin:${source.pluginName}`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function deriveDisplayName(source) {
|
|
277
|
+
switch (source.kind) {
|
|
278
|
+
case 'bundled': return 'Built-in';
|
|
279
|
+
case 'user': return 'User Library';
|
|
280
|
+
case 'project': return 'Project';
|
|
281
|
+
case 'custom': return source.label ?? path_1.default.basename(source.directoryPath);
|
|
282
|
+
case 'git': return source.repositoryUrl;
|
|
283
|
+
case 'remote': return source.registryUrl;
|
|
284
|
+
case 'plugin': return source.pluginName;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function deriveRootedSharingForPath(sourcePath, rememberedRoots) {
|
|
288
|
+
const resolved = path_1.default.resolve(sourcePath);
|
|
289
|
+
for (const record of rememberedRoots) {
|
|
290
|
+
const rootPath = path_1.default.resolve(record.path);
|
|
291
|
+
const relative = path_1.default.relative(rootPath, resolved);
|
|
292
|
+
const isUnderRoot = relative.length === 0 || (!relative.startsWith('..') && !path_1.default.isAbsolute(relative));
|
|
293
|
+
if (!isUnderRoot)
|
|
294
|
+
continue;
|
|
295
|
+
return { kind: 'remembered_root', rootPath, groupLabel: (0, workflow_source_visibility_js_1.deriveGroupLabel)(rootPath, resolved) };
|
|
296
|
+
}
|
|
297
|
+
return undefined;
|
|
298
|
+
}
|