@exaudeus/workrail 0.4.0 → 0.5.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/documentation-service.d.ts +20 -0
- package/dist/application/services/documentation-service.js +155 -0
- package/dist/application/use-cases/get-workflow-docs.d.ts +4 -0
- package/dist/application/use-cases/get-workflow-docs.js +12 -0
- package/dist/application/use-cases/get-workrail-help.d.ts +4 -0
- package/dist/application/use-cases/get-workrail-help.js +12 -0
- package/dist/types/documentation-types.d.ts +37 -0
- package/dist/types/documentation-types.js +2 -0
- package/dist/utils/condition-evaluator.d.ts +4 -0
- package/dist/utils/condition-evaluator.js +67 -5
- package/package.json +1 -1
- package/workflows/coding-task-workflow-with-loops.json +2 -1
- package/workflows/deep-documentation-workflow.json +429 -0
- package/workflows/documentation-update-workflow.json +361 -0
- package/workflows/mr-review-workflow.json +8 -2
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IWorkflowStorage } from '../../types/storage';
|
|
2
|
+
import { ValidationEngine } from './validation-engine';
|
|
3
|
+
import { DocumentationResult } from '../../types/documentation-types';
|
|
4
|
+
export interface IDocumentationService {
|
|
5
|
+
resolveDocumentation(workflowId: string, mode?: 'preview' | 'full', sections?: string[], format?: string): Promise<DocumentationResult>;
|
|
6
|
+
isDocumentationAvailable(workflowId: string): Promise<boolean>;
|
|
7
|
+
getWorkrailHelp(section?: string, format?: string): Promise<DocumentationResult>;
|
|
8
|
+
}
|
|
9
|
+
export declare class DefaultDocumentationService implements IDocumentationService {
|
|
10
|
+
private readonly storage;
|
|
11
|
+
private readonly validationEngine;
|
|
12
|
+
constructor(storage: IWorkflowStorage, validationEngine: ValidationEngine);
|
|
13
|
+
resolveDocumentation(workflowId: string, mode?: 'preview' | 'full', sections?: string[], format?: string): Promise<DocumentationResult>;
|
|
14
|
+
isDocumentationAvailable(workflowId: string): Promise<boolean>;
|
|
15
|
+
getWorkrailHelp(section?: string, format?: string): Promise<DocumentationResult>;
|
|
16
|
+
private parseMarkdownSections;
|
|
17
|
+
private createPreview;
|
|
18
|
+
private generateFallbackDocumentation;
|
|
19
|
+
private generateWorkrailHelp;
|
|
20
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultDocumentationService = void 0;
|
|
4
|
+
const error_handler_1 = require("../../core/error-handler");
|
|
5
|
+
class DefaultDocumentationService {
|
|
6
|
+
constructor(storage, validationEngine) {
|
|
7
|
+
this.storage = storage;
|
|
8
|
+
this.validationEngine = validationEngine;
|
|
9
|
+
}
|
|
10
|
+
async resolveDocumentation(workflowId, mode = 'preview', sections, format = 'text') {
|
|
11
|
+
try {
|
|
12
|
+
const workflow = await this.storage.getWorkflowById(workflowId);
|
|
13
|
+
if (!workflow) {
|
|
14
|
+
throw new error_handler_1.WorkflowNotFoundError(workflowId);
|
|
15
|
+
}
|
|
16
|
+
if (workflow.documentation) {
|
|
17
|
+
return {
|
|
18
|
+
source: 'json',
|
|
19
|
+
format: 'json',
|
|
20
|
+
content: workflow.documentation
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (this.storage.getWorkflowReadme) {
|
|
24
|
+
const readme = await this.storage.getWorkflowReadme(workflowId);
|
|
25
|
+
if (readme) {
|
|
26
|
+
const sections = this.parseMarkdownSections(readme);
|
|
27
|
+
return {
|
|
28
|
+
source: 'readme',
|
|
29
|
+
format: 'markdown',
|
|
30
|
+
content: mode === 'preview' ? this.createPreview(readme) : readme,
|
|
31
|
+
sections
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return this.generateFallbackDocumentation(workflow, format);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error instanceof error_handler_1.WorkflowNotFoundError) {
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
source: 'fallback',
|
|
43
|
+
format: 'text',
|
|
44
|
+
content: `Documentation unavailable for workflow: ${workflowId}. Error: ${error instanceof Error ? error.message : String(error)}`
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async isDocumentationAvailable(workflowId) {
|
|
49
|
+
try {
|
|
50
|
+
const workflow = await this.storage.getWorkflowById(workflowId);
|
|
51
|
+
if (!workflow) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (workflow.documentation) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (this.storage.hasDocumentation) {
|
|
58
|
+
return await this.storage.hasDocumentation(workflowId);
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async getWorkrailHelp(section, format = 'text') {
|
|
67
|
+
const helpContent = this.generateWorkrailHelp(section);
|
|
68
|
+
return {
|
|
69
|
+
source: 'fallback',
|
|
70
|
+
format: 'text',
|
|
71
|
+
content: helpContent
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
parseMarkdownSections(markdown) {
|
|
75
|
+
const sections = {};
|
|
76
|
+
const lines = markdown.split('\n');
|
|
77
|
+
let currentSection = '';
|
|
78
|
+
let currentContent = [];
|
|
79
|
+
for (const line of lines) {
|
|
80
|
+
if (line.startsWith('# ') || line.startsWith('## ')) {
|
|
81
|
+
if (currentSection && currentContent.length > 0) {
|
|
82
|
+
sections[currentSection] = currentContent.join('\n').trim();
|
|
83
|
+
}
|
|
84
|
+
currentSection = line.replace(/^#+\s*/, '').toLowerCase().replace(/\s+/g, '-');
|
|
85
|
+
currentContent = [];
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
currentContent.push(line);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (currentSection && currentContent.length > 0) {
|
|
92
|
+
sections[currentSection] = currentContent.join('\n').trim();
|
|
93
|
+
}
|
|
94
|
+
return sections;
|
|
95
|
+
}
|
|
96
|
+
createPreview(content) {
|
|
97
|
+
const lines = content.split('\n');
|
|
98
|
+
const previewLines = [];
|
|
99
|
+
let lineCount = 0;
|
|
100
|
+
const maxLines = 20;
|
|
101
|
+
for (const line of lines) {
|
|
102
|
+
if (lineCount >= maxLines) {
|
|
103
|
+
previewLines.push('\n[... content truncated for preview mode ...]');
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
previewLines.push(line);
|
|
107
|
+
lineCount++;
|
|
108
|
+
}
|
|
109
|
+
return previewLines.join('\n');
|
|
110
|
+
}
|
|
111
|
+
generateFallbackDocumentation(workflow, format) {
|
|
112
|
+
const content = `# ${workflow.name}
|
|
113
|
+
|
|
114
|
+
${workflow.description}
|
|
115
|
+
|
|
116
|
+
**Version:** ${workflow.version}
|
|
117
|
+
**Steps:** ${workflow.steps?.length || 0} steps
|
|
118
|
+
|
|
119
|
+
${workflow.preconditions?.length ? `**Prerequisites:**\n${workflow.preconditions.map((p) => `- ${p}`).join('\n')}\n` : ''}
|
|
120
|
+
|
|
121
|
+
*This is auto-generated documentation. For detailed guidance, consider adding a documentation object to the workflow JSON or creating a README file.*`;
|
|
122
|
+
return {
|
|
123
|
+
source: 'fallback',
|
|
124
|
+
format: 'text',
|
|
125
|
+
content
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
generateWorkrailHelp(section) {
|
|
129
|
+
const baseHelp = `# WorkRail Documentation System
|
|
130
|
+
|
|
131
|
+
WorkRail provides structured workflow orchestration with built-in documentation support.
|
|
132
|
+
|
|
133
|
+
## Available Commands
|
|
134
|
+
- \`workflow_list\` - List all available workflows
|
|
135
|
+
- \`workflow_get\` - Get detailed workflow information
|
|
136
|
+
- \`workflow_docs\` - Get workflow-specific documentation
|
|
137
|
+
- \`workrail_help\` - Get general platform help (this command)
|
|
138
|
+
|
|
139
|
+
## Documentation Sources
|
|
140
|
+
WorkRail resolves documentation in this priority order:
|
|
141
|
+
1. **JSON Documentation** - Structured metadata in workflow files
|
|
142
|
+
2. **README Files** - Markdown documentation alongside workflows
|
|
143
|
+
3. **Fallback** - Auto-generated from workflow metadata
|
|
144
|
+
|
|
145
|
+
## Getting Help
|
|
146
|
+
- Use \`workflow_docs\` for specific workflow documentation
|
|
147
|
+
- Use \`workrail_help\` for general platform information
|
|
148
|
+
- Check workflow descriptions in \`workflow_list\` output`;
|
|
149
|
+
if (section) {
|
|
150
|
+
return `${baseHelp}\n\n*Note: Section-specific help for "${section}" is not yet implemented.*`;
|
|
151
|
+
}
|
|
152
|
+
return baseHelp;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
exports.DefaultDocumentationService = DefaultDocumentationService;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { IDocumentationService } from '../services/documentation-service';
|
|
2
|
+
import { DocumentationResult } from '../../types/documentation-types';
|
|
3
|
+
export declare function createGetWorkflowDocs(service: IDocumentationService): (id: string, mode?: "preview" | "full", sections?: string[], format?: string) => Promise<DocumentationResult>;
|
|
4
|
+
export declare function getWorkflowDocs(service: IDocumentationService, id: string, mode?: 'preview' | 'full', sections?: string[], format?: string): Promise<DocumentationResult>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createGetWorkflowDocs = createGetWorkflowDocs;
|
|
4
|
+
exports.getWorkflowDocs = getWorkflowDocs;
|
|
5
|
+
function createGetWorkflowDocs(service) {
|
|
6
|
+
return async (id, mode, sections, format) => {
|
|
7
|
+
return await service.resolveDocumentation(id, mode, sections, format);
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
async function getWorkflowDocs(service, id, mode, sections, format) {
|
|
11
|
+
return createGetWorkflowDocs(service)(id, mode, sections, format);
|
|
12
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { IDocumentationService } from '../services/documentation-service';
|
|
2
|
+
import { DocumentationResult } from '../../types/documentation-types';
|
|
3
|
+
export declare function createGetWorkrailHelp(service: IDocumentationService): (section?: string, format?: string) => Promise<DocumentationResult>;
|
|
4
|
+
export declare function getWorkrailHelp(service: IDocumentationService, section?: string, format?: string): Promise<DocumentationResult>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createGetWorkrailHelp = createGetWorkrailHelp;
|
|
4
|
+
exports.getWorkrailHelp = getWorkrailHelp;
|
|
5
|
+
function createGetWorkrailHelp(service) {
|
|
6
|
+
return async (section, format) => {
|
|
7
|
+
return await service.getWorkrailHelp(section, format);
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
async function getWorkrailHelp(service, section, format) {
|
|
11
|
+
return createGetWorkrailHelp(service)(section, format);
|
|
12
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface DocumentationInput {
|
|
2
|
+
name: string;
|
|
3
|
+
required?: boolean;
|
|
4
|
+
description?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DocumentationMetadata {
|
|
7
|
+
summary: string;
|
|
8
|
+
whenToUse: string[];
|
|
9
|
+
whenNotToUse?: string[];
|
|
10
|
+
inputs: DocumentationInput[];
|
|
11
|
+
outputs: string[];
|
|
12
|
+
assumptions?: string[];
|
|
13
|
+
risks: string[];
|
|
14
|
+
relatedWorkflows?: string[];
|
|
15
|
+
helpHint?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface SensitivityMetadata {
|
|
18
|
+
level?: string;
|
|
19
|
+
notes?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface DocumentationResult {
|
|
22
|
+
source: 'json' | 'readme' | 'fallback';
|
|
23
|
+
format: 'json' | 'markdown' | 'text';
|
|
24
|
+
content: DocumentationMetadata | string;
|
|
25
|
+
sections?: Record<string, string>;
|
|
26
|
+
}
|
|
27
|
+
export interface DocumentationOptions {
|
|
28
|
+
mode?: 'preview' | 'full';
|
|
29
|
+
sections?: string[];
|
|
30
|
+
format?: 'text' | 'markdown' | 'json';
|
|
31
|
+
}
|
|
32
|
+
export interface DocumentationAvailability {
|
|
33
|
+
hasJsonDocs: boolean;
|
|
34
|
+
hasReadme: boolean;
|
|
35
|
+
hasAnyDocs: boolean;
|
|
36
|
+
helpHint?: string;
|
|
37
|
+
}
|
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.evaluateCondition = evaluateCondition;
|
|
4
4
|
exports.validateCondition = validateCondition;
|
|
5
|
+
function lenientEquals(a, b) {
|
|
6
|
+
if (a == null && b == null) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
if (a == null || b == null) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
13
|
+
return a.trim().toLowerCase() === b.trim().toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
if ((typeof a === 'string' && typeof b === 'number') ||
|
|
16
|
+
(typeof a === 'number' && typeof b === 'string')) {
|
|
17
|
+
const numA = Number(a);
|
|
18
|
+
const numB = Number(b);
|
|
19
|
+
if (!isNaN(numA) && !isNaN(numB)) {
|
|
20
|
+
return numA === numB;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (typeof a === 'string' && typeof b === 'boolean') {
|
|
24
|
+
const lowerA = a.trim().toLowerCase();
|
|
25
|
+
return (b === true && (lowerA === 'true' || lowerA === '1' || lowerA === 'yes')) ||
|
|
26
|
+
(b === false && (lowerA === 'false' || lowerA === '0' || lowerA === 'no'));
|
|
27
|
+
}
|
|
28
|
+
if (typeof b === 'string' && typeof a === 'boolean') {
|
|
29
|
+
return lenientEquals(b, a);
|
|
30
|
+
}
|
|
31
|
+
return a === b;
|
|
32
|
+
}
|
|
33
|
+
function normalizeToString(value) {
|
|
34
|
+
if (value == null) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
return String(value).trim();
|
|
38
|
+
}
|
|
5
39
|
function evaluateCondition(condition, context = {}) {
|
|
6
40
|
if (!condition || typeof condition !== 'object') {
|
|
7
41
|
return true;
|
|
@@ -20,11 +54,11 @@ function evaluateCondition(condition, context = {}) {
|
|
|
20
54
|
function evaluateConditionUnsafe(condition, context) {
|
|
21
55
|
if (condition.var !== undefined) {
|
|
22
56
|
const value = context[condition.var];
|
|
23
|
-
if (
|
|
24
|
-
return value
|
|
57
|
+
if ('equals' in condition) {
|
|
58
|
+
return lenientEquals(value, condition.equals);
|
|
25
59
|
}
|
|
26
|
-
if (
|
|
27
|
-
return value
|
|
60
|
+
if ('not_equals' in condition) {
|
|
61
|
+
return !lenientEquals(value, condition.not_equals);
|
|
28
62
|
}
|
|
29
63
|
if (condition.gt !== undefined) {
|
|
30
64
|
return typeof value === 'number' && value > condition.gt;
|
|
@@ -38,6 +72,32 @@ function evaluateConditionUnsafe(condition, context) {
|
|
|
38
72
|
if (condition.lte !== undefined) {
|
|
39
73
|
return typeof value === 'number' && value <= condition.lte;
|
|
40
74
|
}
|
|
75
|
+
if (condition.contains !== undefined) {
|
|
76
|
+
const valueStr = normalizeToString(value).toLowerCase();
|
|
77
|
+
const searchStr = normalizeToString(condition.contains).toLowerCase();
|
|
78
|
+
return valueStr.includes(searchStr);
|
|
79
|
+
}
|
|
80
|
+
if (condition.startsWith !== undefined) {
|
|
81
|
+
const valueStr = normalizeToString(value).toLowerCase();
|
|
82
|
+
const searchStr = normalizeToString(condition.startsWith).toLowerCase();
|
|
83
|
+
return valueStr.startsWith(searchStr);
|
|
84
|
+
}
|
|
85
|
+
if (condition.endsWith !== undefined) {
|
|
86
|
+
const valueStr = normalizeToString(value).toLowerCase();
|
|
87
|
+
const searchStr = normalizeToString(condition.endsWith).toLowerCase();
|
|
88
|
+
return valueStr.endsWith(searchStr);
|
|
89
|
+
}
|
|
90
|
+
if (condition.matches !== undefined) {
|
|
91
|
+
const valueStr = normalizeToString(value);
|
|
92
|
+
try {
|
|
93
|
+
const regex = new RegExp(condition.matches, 'i');
|
|
94
|
+
return regex.test(valueStr);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.warn('Invalid regex pattern in condition:', condition.matches);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
41
101
|
return !!value;
|
|
42
102
|
}
|
|
43
103
|
if (condition.and !== undefined) {
|
|
@@ -62,7 +122,9 @@ function validateCondition(condition) {
|
|
|
62
122
|
return;
|
|
63
123
|
}
|
|
64
124
|
const supportedKeys = [
|
|
65
|
-
'var', 'equals', 'not_equals', 'gt', 'gte', 'lt', 'lte',
|
|
125
|
+
'var', 'equals', 'not_equals', 'gt', 'gte', 'lt', 'lte',
|
|
126
|
+
'contains', 'startsWith', 'endsWith', 'matches',
|
|
127
|
+
'and', 'or', 'not'
|
|
66
128
|
];
|
|
67
129
|
const conditionKeys = Object.keys(condition);
|
|
68
130
|
const unsupportedKeys = conditionKeys.filter(key => !supportedKeys.includes(key));
|
package/package.json
CHANGED
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"Maintain existing coding conventions and architectural patterns found in the codebase.",
|
|
44
44
|
"COMMIT STRATEGY: Auto-commit after successful steps for High automation; suggest for Medium/Low. Use conventional format: type(scope): description. Commit at milestones and after verification passes.",
|
|
45
45
|
"When you see function calls like updateDecisionLog() or createFile(spec.md), refer to the function definitions above for full instructions.",
|
|
46
|
-
"For resumption: Include function definitions in CONTEXT.md so new sessions understand these references. Always provide explicit workflow_get and workflow_next instructions."
|
|
46
|
+
"For resumption: Include function definitions in CONTEXT.md so new sessions understand these references. Always provide explicit workflow_get and workflow_next instructions.",
|
|
47
|
+
"Auto-advance: after completing each step, immediately get the next step; only pause for explicit requireConfirmation or missing critical inputs."
|
|
47
48
|
],
|
|
48
49
|
"steps": [
|
|
49
50
|
{
|