@exaudeus/workrail 3.31.1 → 3.33.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.
Files changed (82) hide show
  1. package/dist/cli/commands/index.d.ts +1 -0
  2. package/dist/cli/commands/index.js +3 -1
  3. package/dist/cli/commands/worktrain-await.js +11 -9
  4. package/dist/cli/commands/worktrain-daemon-install.d.ts +35 -0
  5. package/dist/cli/commands/worktrain-daemon-install.js +291 -0
  6. package/dist/cli/commands/worktrain-daemon.d.ts +31 -0
  7. package/dist/cli/commands/worktrain-daemon.js +272 -0
  8. package/dist/cli/commands/worktrain-spawn.js +11 -9
  9. package/dist/cli-worktrain.js +329 -0
  10. package/dist/cli.js +4 -22
  11. package/dist/console/standalone-console.d.ts +28 -0
  12. package/dist/console/standalone-console.js +142 -0
  13. package/dist/{console/assets/index-6H9DeFxj.js → console-ui/assets/index-BuJFLLfY.js} +1 -1
  14. package/dist/{console → console-ui}/index.html +1 -1
  15. package/dist/daemon/agent-loop.d.ts +26 -0
  16. package/dist/daemon/agent-loop.js +53 -2
  17. package/dist/daemon/daemon-events.d.ts +103 -0
  18. package/dist/daemon/daemon-events.js +56 -0
  19. package/dist/daemon/workflow-runner.d.ts +6 -3
  20. package/dist/daemon/workflow-runner.js +229 -33
  21. package/dist/infrastructure/session/HttpServer.js +133 -34
  22. package/dist/manifest.json +134 -70
  23. package/dist/mcp/output-schemas.d.ts +30 -30
  24. package/dist/mcp/transports/bridge-events.d.ts +4 -0
  25. package/dist/mcp/transports/fatal-exit.js +4 -0
  26. package/dist/mcp/transports/http-entry.js +2 -0
  27. package/dist/mcp/transports/stdio-entry.js +26 -6
  28. package/dist/mcp/v2/tools.d.ts +4 -4
  29. package/dist/trigger/adapters/github-poller.d.ts +44 -0
  30. package/dist/trigger/adapters/github-poller.js +190 -0
  31. package/dist/trigger/adapters/gitlab-poller.d.ts +27 -0
  32. package/dist/trigger/adapters/gitlab-poller.js +81 -0
  33. package/dist/trigger/delivery-client.d.ts +2 -1
  34. package/dist/trigger/delivery-client.js +4 -1
  35. package/dist/trigger/index.d.ts +4 -1
  36. package/dist/trigger/index.js +5 -1
  37. package/dist/trigger/polled-event-store.d.ts +22 -0
  38. package/dist/trigger/polled-event-store.js +173 -0
  39. package/dist/trigger/polling-scheduler.d.ts +20 -0
  40. package/dist/trigger/polling-scheduler.js +249 -0
  41. package/dist/trigger/trigger-listener.d.ts +5 -0
  42. package/dist/trigger/trigger-listener.js +53 -4
  43. package/dist/trigger/trigger-router.d.ts +4 -2
  44. package/dist/trigger/trigger-router.js +7 -4
  45. package/dist/trigger/trigger-store.js +114 -33
  46. package/dist/trigger/types.d.ts +17 -1
  47. package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +224 -224
  48. package/dist/v2/durable-core/schemas/session/events.d.ts +42 -42
  49. package/dist/v2/durable-core/schemas/session/manifest.d.ts +6 -6
  50. package/dist/v2/durable-core/schemas/session/validation-event.d.ts +2 -2
  51. package/dist/v2/durable-core/tokens/payloads.d.ts +52 -52
  52. package/dist/v2/usecases/console-routes.js +3 -3
  53. package/dist/v2/usecases/console-service.js +133 -9
  54. package/dist/v2/usecases/console-types.d.ts +7 -0
  55. package/docs/design/daemon-conversation-logging-plan.md +98 -0
  56. package/docs/design/daemon-conversation-logging-review.md +55 -0
  57. package/docs/design/daemon-conversation-logging.md +129 -0
  58. package/docs/design/github-polling-adapter-design-candidates.md +226 -0
  59. package/docs/design/github-polling-adapter-design-review-findings.md +131 -0
  60. package/docs/design/github-polling-adapter-implementation-plan.md +284 -0
  61. package/docs/design/implementation_plan.md +192 -0
  62. package/docs/design/workflow-id-validation-at-startup.md +146 -0
  63. package/docs/design/workflow-id-validation-design-review.md +87 -0
  64. package/docs/design/workflow-id-validation-implementation-plan.md +185 -0
  65. package/docs/design/worktrain-system-prompt-report-issue-candidates.md +135 -0
  66. package/docs/design/worktrain-system-prompt-report-issue-design-review.md +73 -0
  67. package/docs/ideas/backlog.md +465 -0
  68. package/package.json +1 -1
  69. package/workflows/architecture-scalability-audit.json +1 -1
  70. package/workflows/bug-investigation.agentic.v2.json +3 -3
  71. package/workflows/coding-task-workflow-agentic.json +32 -32
  72. package/workflows/coding-task-workflow-agentic.lean.v2.json +1 -1
  73. package/workflows/coding-task-workflow-agentic.v2.json +7 -7
  74. package/workflows/mr-review-workflow.agentic.v2.json +21 -12
  75. package/workflows/personal-learning-materials-creation-branched.json +2 -2
  76. package/workflows/production-readiness-audit.json +1 -1
  77. package/workflows/relocation-workflow-us.json +2 -2
  78. package/workflows/ui-ux-design-workflow.json +14 -14
  79. package/workflows/workflow-for-workflows.json +3 -3
  80. package/workflows/workflow-for-workflows.v2.json +2 -2
  81. package/workflows/wr.discovery.json +1 -1
  82. /package/dist/{console → console-ui}/assets/index-8dh0Psu-.css +0 -0
@@ -43,7 +43,7 @@ class AgentLoop {
43
43
  }
44
44
  }
45
45
  async _runLoop() {
46
- const { client, modelId, systemPrompt, tools, maxTokens = 8192 } = this._options;
46
+ const { client, modelId, systemPrompt, tools, maxTokens = 8192, callbacks } = this._options;
47
47
  while (true) {
48
48
  if (this._aborted || this._abortController.signal.aborted) {
49
49
  this._appendErrorMessage('aborted');
@@ -56,6 +56,10 @@ class AgentLoop {
56
56
  description: t.description,
57
57
  input_schema: t.inputSchema,
58
58
  }));
59
+ try {
60
+ callbacks?.onLlmTurnStarted?.({ messageCount: apiMessages.length });
61
+ }
62
+ catch { }
59
63
  let response;
60
64
  try {
61
65
  response = await client.messages.create({
@@ -74,6 +78,20 @@ class AgentLoop {
74
78
  await this._emitEvent({ type: 'agent_end' });
75
79
  return;
76
80
  }
81
+ {
82
+ const toolNamesRequested = response.content
83
+ .filter((block) => block.type === 'tool_use')
84
+ .map((block) => block.name);
85
+ try {
86
+ callbacks?.onLlmTurnCompleted?.({
87
+ stopReason: response.stop_reason ?? 'unknown',
88
+ outputTokens: response.usage.output_tokens,
89
+ inputTokens: response.usage.input_tokens,
90
+ toolNamesRequested,
91
+ });
92
+ }
93
+ catch { }
94
+ }
77
95
  const stopReason = this._mapStopReason(response.stop_reason);
78
96
  const assistantMsg = {
79
97
  role: 'assistant',
@@ -116,6 +134,7 @@ class AgentLoop {
116
134
  }
117
135
  }
118
136
  async _executeTools(toolUseBlocks) {
137
+ const { callbacks } = this._options;
119
138
  const results = [];
120
139
  for (const block of toolUseBlocks) {
121
140
  if (this._abortController.signal.aborted) {
@@ -141,7 +160,39 @@ class AgentLoop {
141
160
  continue;
142
161
  }
143
162
  const params = (block.input ?? {});
144
- const result = await tool.execute(block.id, params);
163
+ const argsSummary = JSON.stringify(params).slice(0, 200);
164
+ try {
165
+ callbacks?.onToolCallStarted?.({ toolName: block.name, argsSummary });
166
+ }
167
+ catch { }
168
+ const toolStartMs = Date.now();
169
+ let result;
170
+ try {
171
+ result = await tool.execute(block.id, params);
172
+ }
173
+ catch (err) {
174
+ const durationMs = Date.now() - toolStartMs;
175
+ const message = err instanceof Error ? err.message : String(err);
176
+ try {
177
+ callbacks?.onToolCallFailed?.({ toolName: block.name, durationMs, errorMessage: message.slice(0, 200) });
178
+ }
179
+ catch { }
180
+ results.push({
181
+ toolCallId: block.id,
182
+ toolName: block.name,
183
+ result: { content: [{ type: 'text', text: `Tool execution failed: ${message}` }], details: null },
184
+ isError: true,
185
+ });
186
+ continue;
187
+ }
188
+ {
189
+ const durationMs = Date.now() - toolStartMs;
190
+ const resultSummary = (result.content[0]?.text ?? '(no output)').slice(0, 200);
191
+ try {
192
+ callbacks?.onToolCallCompleted?.({ toolName: block.name, durationMs, resultSummary });
193
+ }
194
+ catch { }
195
+ }
145
196
  results.push({
146
197
  toolCallId: block.id,
147
198
  toolName: block.name,
@@ -0,0 +1,103 @@
1
+ export interface DaemonStartedEvent {
2
+ readonly kind: 'daemon_started';
3
+ readonly port: number;
4
+ readonly workspacePath: string;
5
+ }
6
+ export interface TriggerFiredEvent {
7
+ readonly kind: 'trigger_fired';
8
+ readonly triggerId: string;
9
+ readonly workflowId: string;
10
+ }
11
+ export interface SessionQueuedEvent {
12
+ readonly kind: 'session_queued';
13
+ readonly triggerId: string;
14
+ readonly workflowId: string;
15
+ }
16
+ export interface SessionStartedEvent {
17
+ readonly kind: 'session_started';
18
+ readonly sessionId: string;
19
+ readonly workflowId: string;
20
+ readonly workspacePath: string;
21
+ readonly workrailSessionId?: string;
22
+ }
23
+ export interface ToolCalledEvent {
24
+ readonly kind: 'tool_called';
25
+ readonly sessionId: string;
26
+ readonly toolName: string;
27
+ readonly summary?: string;
28
+ readonly workrailSessionId?: string;
29
+ }
30
+ export interface ToolErrorEvent {
31
+ readonly kind: 'tool_error';
32
+ readonly sessionId: string;
33
+ readonly toolName: string;
34
+ readonly error: string;
35
+ readonly workrailSessionId?: string;
36
+ }
37
+ export interface StepAdvancedEvent {
38
+ readonly kind: 'step_advanced';
39
+ readonly sessionId: string;
40
+ readonly workrailSessionId?: string;
41
+ }
42
+ export interface SessionCompletedEvent {
43
+ readonly kind: 'session_completed';
44
+ readonly sessionId: string;
45
+ readonly workflowId: string;
46
+ readonly outcome: 'success' | 'error' | 'timeout';
47
+ readonly detail?: string;
48
+ readonly workrailSessionId?: string;
49
+ }
50
+ export interface DeliveryAttemptedEvent {
51
+ readonly kind: 'delivery_attempted';
52
+ readonly callbackUrl: string;
53
+ readonly outcome: 'success' | 'http_error' | 'network_error';
54
+ readonly statusCode?: number;
55
+ }
56
+ export interface IssueReportedEvent {
57
+ readonly kind: 'issue_reported';
58
+ readonly sessionId: string;
59
+ readonly issueKind: 'tool_failure' | 'blocked' | 'unexpected_behavior' | 'needs_human' | 'self_correction';
60
+ readonly severity: 'info' | 'warn' | 'error' | 'fatal';
61
+ readonly summary: string;
62
+ readonly continueToken?: string;
63
+ }
64
+ export interface LlmTurnStartedEvent {
65
+ readonly kind: 'llm_turn_started';
66
+ readonly sessionId: string;
67
+ readonly messageCount: number;
68
+ }
69
+ export interface LlmTurnCompletedEvent {
70
+ readonly kind: 'llm_turn_completed';
71
+ readonly sessionId: string;
72
+ readonly stopReason: string;
73
+ readonly outputTokens: number;
74
+ readonly inputTokens: number;
75
+ readonly toolNamesRequested: readonly string[];
76
+ }
77
+ export interface ToolCallStartedEvent {
78
+ readonly kind: 'tool_call_started';
79
+ readonly sessionId: string;
80
+ readonly toolName: string;
81
+ readonly argsSummary: string;
82
+ }
83
+ export interface ToolCallCompletedEvent {
84
+ readonly kind: 'tool_call_completed';
85
+ readonly sessionId: string;
86
+ readonly toolName: string;
87
+ readonly durationMs: number;
88
+ readonly resultSummary: string;
89
+ }
90
+ export interface ToolCallFailedEvent {
91
+ readonly kind: 'tool_call_failed';
92
+ readonly sessionId: string;
93
+ readonly toolName: string;
94
+ readonly durationMs: number;
95
+ readonly errorMessage: string;
96
+ }
97
+ export type DaemonEvent = DaemonStartedEvent | TriggerFiredEvent | SessionQueuedEvent | SessionStartedEvent | ToolCalledEvent | ToolErrorEvent | StepAdvancedEvent | SessionCompletedEvent | DeliveryAttemptedEvent | IssueReportedEvent | LlmTurnStartedEvent | LlmTurnCompletedEvent | ToolCallStartedEvent | ToolCallCompletedEvent | ToolCallFailedEvent;
98
+ export declare class DaemonEventEmitter {
99
+ private readonly _dir;
100
+ constructor(dirOverride?: string);
101
+ emit(event: DaemonEvent): void;
102
+ private _append;
103
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DaemonEventEmitter = void 0;
37
+ const fs = __importStar(require("node:fs/promises"));
38
+ const path = __importStar(require("node:path"));
39
+ const os = __importStar(require("node:os"));
40
+ class DaemonEventEmitter {
41
+ constructor(dirOverride) {
42
+ this._dir = dirOverride ?? path.join(os.homedir(), '.workrail', 'events', 'daemon');
43
+ }
44
+ emit(event) {
45
+ void this._append(event).catch(() => {
46
+ });
47
+ }
48
+ async _append(event) {
49
+ const date = new Date().toISOString().slice(0, 10);
50
+ const filePath = path.join(this._dir, `${date}.jsonl`);
51
+ await fs.mkdir(this._dir, { recursive: true });
52
+ const line = JSON.stringify({ ...event, ts: Date.now() }) + '\n';
53
+ await fs.appendFile(filePath, line, 'utf8');
54
+ }
55
+ }
56
+ exports.DaemonEventEmitter = DaemonEventEmitter;
@@ -4,6 +4,7 @@ import type { V2ToolContext } from '../mcp/types.js';
4
4
  import { executeContinueWorkflow } from '../mcp/handlers/v2-execution/index.js';
5
5
  import type { DaemonRegistry } from '../v2/infra/in-memory/daemon-registry/index.js';
6
6
  import type { V2StartWorkflowOutputSchema } from '../mcp/output-schemas.js';
7
+ import type { DaemonEventEmitter } from './daemon-events.js';
7
8
  export declare const DAEMON_SESSIONS_DIR: string;
8
9
  export { DAEMON_SOUL_DEFAULT, DAEMON_SOUL_TEMPLATE } from './soul-template.js';
9
10
  export interface WorkflowTrigger {
@@ -31,6 +32,7 @@ export interface WorkflowRunError {
31
32
  readonly workflowId: string;
32
33
  readonly message: string;
33
34
  readonly stopReason: string;
35
+ readonly lastStepNotes?: string;
34
36
  }
35
37
  export interface WorkflowRunTimeout {
36
38
  readonly _tag: 'timeout';
@@ -58,8 +60,9 @@ export declare function readDaemonSessionState(sessionId: string): Promise<{
58
60
  } | null>;
59
61
  export declare function readAllDaemonSessions(sessionsDir?: string): Promise<OrphanedSession[]>;
60
62
  export declare function runStartupRecovery(sessionsDir?: string): Promise<void>;
61
- export declare function makeContinueWorkflowTool(sessionId: string, ctx: V2ToolContext, onAdvance: (nextStepText: string, continueToken: string) => void, onComplete: (notes: string | undefined) => void, schemas: Record<string, any>, _executeContinueWorkflowFn?: typeof executeContinueWorkflow): AgentTool;
62
- export declare function makeBashTool(workspacePath: string, schemas: Record<string, any>): AgentTool;
63
+ export declare function makeContinueWorkflowTool(sessionId: string, ctx: V2ToolContext, onAdvance: (nextStepText: string, continueToken: string) => void, onComplete: (notes: string | undefined) => void, schemas: Record<string, any>, _executeContinueWorkflowFn?: typeof executeContinueWorkflow, emitter?: DaemonEventEmitter, workrailSessionId?: string | null): AgentTool;
64
+ export declare function makeBashTool(workspacePath: string, schemas: Record<string, any>, sessionId?: string, emitter?: DaemonEventEmitter, workrailSessionId?: string | null): AgentTool;
65
+ export declare function makeReportIssueTool(sessionId: string, emitter?: DaemonEventEmitter, issuesDirOverride?: string): AgentTool;
63
66
  export declare function buildSessionRecap(notes: readonly string[]): string;
64
67
  export declare function buildSystemPrompt(trigger: WorkflowTrigger, sessionState: string, soulContent: string, workspaceContext: string | null): string;
65
- export declare function runWorkflow(trigger: WorkflowTrigger, ctx: V2ToolContext, apiKey: string, daemonRegistry?: DaemonRegistry): Promise<WorkflowRunResult>;
68
+ export declare function runWorkflow(trigger: WorkflowTrigger, ctx: V2ToolContext, apiKey: string, daemonRegistry?: DaemonRegistry, emitter?: DaemonEventEmitter): Promise<WorkflowRunResult>;