@nt-ai-lab/deterministic-agent-workflow-cli 0.3.1 → 0.3.3
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/features/workflow-runner/entrypoint/review-routes.d.ts +6 -0
- package/dist/features/workflow-runner/entrypoint/review-routes.js +134 -0
- package/dist/features/workflow-runner/entrypoint/review-routes.spec.d.ts +1 -0
- package/dist/features/workflow-runner/entrypoint/review-routes.spec.js +272 -0
- package/dist/features/workflow-runner/entrypoint/workflow-runner.js +3 -0
- package/package.json +7 -4
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BaseWorkflowState, RehydratableWorkflow, WorkflowDefinition, WorkflowEngineDeps } from '@nt-ai-lab/deterministic-agent-workflow-engine';
|
|
2
|
+
import type { RunnerResult } from '../../../platform/domain/workflow-runner-types';
|
|
3
|
+
/** @riviere-role cli-entrypoint */
|
|
4
|
+
export declare function handleRecordReviewRoute<TWorkflow extends RehydratableWorkflow<TState>, TState extends BaseWorkflowState<TStateName>, TDeps, TStateName extends string, TOperation extends string>(engine: {
|
|
5
|
+
readonly hasSessionStarted: (sessionId: string) => boolean;
|
|
6
|
+
}, engineDeps: WorkflowEngineDeps, workflowDefinition: WorkflowDefinition<TWorkflow, TState, TDeps, TStateName, TOperation>, args: readonly string[], readStdin: (() => string) | undefined, getSessionId: (() => string) | undefined): RunnerResult;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { flattenStoredEvent, reviewPayloadSchema, } from '@nt-ai-lab/deterministic-agent-workflow-engine';
|
|
2
|
+
import { EXIT_ALLOW, EXIT_BLOCK, EXIT_ERROR, } from '../../../shell/exit-codes.js';
|
|
3
|
+
function jsonResult(value) {
|
|
4
|
+
return {
|
|
5
|
+
output: JSON.stringify(value, null, 2),
|
|
6
|
+
exitCode: EXIT_ALLOW,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function errorResult(output) {
|
|
10
|
+
return {
|
|
11
|
+
output,
|
|
12
|
+
exitCode: EXIT_ERROR,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function blockedResult(output) {
|
|
16
|
+
return {
|
|
17
|
+
output,
|
|
18
|
+
exitCode: EXIT_BLOCK,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function parseFlagArgs(args) {
|
|
22
|
+
const flags = new Map();
|
|
23
|
+
for (const [index, key] of args.entries()) {
|
|
24
|
+
if (index % 2 === 1)
|
|
25
|
+
continue;
|
|
26
|
+
const value = args[index + 1];
|
|
27
|
+
if (!key.startsWith('--')) {
|
|
28
|
+
return {
|
|
29
|
+
ok: false,
|
|
30
|
+
message: `Invalid flag: ${String(key)}`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
message: `Missing value for flag: ${key}`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
flags.set(key, value);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
ok: true,
|
|
43
|
+
flags,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function validateReviewFlags(flags) {
|
|
47
|
+
for (const key of flags.keys()) {
|
|
48
|
+
if (key !== '--type') {
|
|
49
|
+
return `Unknown flag: ${key}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (!flags.has('--type')) {
|
|
53
|
+
return 'record-review requires --type';
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
function isReviewAllowed(allowedWorkflowOperations) {
|
|
58
|
+
return allowedWorkflowOperations.some((allowedWorkflowOperation) => allowedWorkflowOperation === 'record-review');
|
|
59
|
+
}
|
|
60
|
+
/** @riviere-role cli-entrypoint */
|
|
61
|
+
export function handleRecordReviewRoute(engine, engineDeps, workflowDefinition, args, readStdin, getSessionId) {
|
|
62
|
+
if (getSessionId === undefined) {
|
|
63
|
+
return errorResult('record-review requires an active workflow session');
|
|
64
|
+
}
|
|
65
|
+
if (readStdin === undefined) {
|
|
66
|
+
return errorResult('record-review requires JSON on stdin');
|
|
67
|
+
}
|
|
68
|
+
const parsedFlags = parseFlagArgs(args.slice(1));
|
|
69
|
+
if (!parsedFlags.ok) {
|
|
70
|
+
return errorResult(parsedFlags.message);
|
|
71
|
+
}
|
|
72
|
+
const flagError = validateReviewFlags(parsedFlags.flags);
|
|
73
|
+
if (flagError !== null) {
|
|
74
|
+
return errorResult(flagError);
|
|
75
|
+
}
|
|
76
|
+
const reviewType = parsedFlags.flags.get('--type');
|
|
77
|
+
if (reviewType === undefined) {
|
|
78
|
+
return errorResult('record-review requires a non-empty --type value');
|
|
79
|
+
}
|
|
80
|
+
const sessionId = getSessionId();
|
|
81
|
+
if (!engine.hasSessionStarted(sessionId)) {
|
|
82
|
+
return errorResult(`Session ${sessionId} has not been started`);
|
|
83
|
+
}
|
|
84
|
+
const reviewPayloadResult = parseReviewPayload(readStdin);
|
|
85
|
+
if (!reviewPayloadResult.ok) {
|
|
86
|
+
return errorResult(reviewPayloadResult.message);
|
|
87
|
+
}
|
|
88
|
+
const parsedReview = reviewPayloadSchema.safeParse(reviewPayloadResult.payload);
|
|
89
|
+
if (!parsedReview.success) {
|
|
90
|
+
return errorResult(`Invalid review payload: ${parsedReview.error.message}`);
|
|
91
|
+
}
|
|
92
|
+
const currentStateName = computeCurrentState(workflowDefinition, engineDeps.store.readEvents(sessionId));
|
|
93
|
+
const allowedWorkflowOperations = workflowDefinition
|
|
94
|
+
.getRegistry()[currentStateName]
|
|
95
|
+
.allowedWorkflowOperations
|
|
96
|
+
.map((allowedWorkflowOperation) => String(allowedWorkflowOperation));
|
|
97
|
+
if (!isReviewAllowed(allowedWorkflowOperations)) {
|
|
98
|
+
return blockedResult(`record-review is not allowed in state ${currentStateName}.`);
|
|
99
|
+
}
|
|
100
|
+
const createdAt = engineDeps.now();
|
|
101
|
+
const stored = engineDeps.store.recordReviewWithEvent(sessionId, createdAt, {
|
|
102
|
+
reviewType,
|
|
103
|
+
sourceState: currentStateName,
|
|
104
|
+
...parsedReview.data,
|
|
105
|
+
}, currentStateName);
|
|
106
|
+
return jsonResult({
|
|
107
|
+
ok: true,
|
|
108
|
+
id: stored.id,
|
|
109
|
+
sessionId,
|
|
110
|
+
createdAt: stored.createdAt,
|
|
111
|
+
reviewType,
|
|
112
|
+
verdict: parsedReview.data.verdict,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function computeCurrentState(workflowDefinition, storedEvents) {
|
|
116
|
+
const state = storedEvents
|
|
117
|
+
.map(flattenStoredEvent)
|
|
118
|
+
.reduce((currentState, event) => workflowDefinition.fold(currentState, event), workflowDefinition.initialState());
|
|
119
|
+
return state.currentStateMachineState;
|
|
120
|
+
}
|
|
121
|
+
function parseReviewPayload(readStdin) {
|
|
122
|
+
try {
|
|
123
|
+
return {
|
|
124
|
+
ok: true,
|
|
125
|
+
payload: JSON.parse(readStdin()),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
return {
|
|
130
|
+
ok: false,
|
|
131
|
+
message: `Invalid review JSON: ${String(error)}`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { describe, expect, it, } from 'vitest';
|
|
2
|
+
import { pass, toPayload, WorkflowStateError, } from '@nt-ai-lab/deterministic-agent-workflow-engine';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { EXIT_ALLOW, EXIT_BLOCK, EXIT_ERROR } from '../../../shell/exit-codes.js';
|
|
5
|
+
import { handleRecordReviewRoute } from './review-routes.js';
|
|
6
|
+
class ReviewRouteWorkflow {
|
|
7
|
+
state;
|
|
8
|
+
constructor(state) {
|
|
9
|
+
this.state = state;
|
|
10
|
+
}
|
|
11
|
+
getState() {
|
|
12
|
+
return this.state;
|
|
13
|
+
}
|
|
14
|
+
appendEvent(_event) {
|
|
15
|
+
void _event;
|
|
16
|
+
}
|
|
17
|
+
getPendingEvents() {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
startSession(_transcriptPath, _repository) {
|
|
21
|
+
void _transcriptPath;
|
|
22
|
+
void _repository;
|
|
23
|
+
}
|
|
24
|
+
getTranscriptPath() {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
registerAgent(_agentType, _agentId) {
|
|
28
|
+
void _agentType;
|
|
29
|
+
void _agentId;
|
|
30
|
+
return pass();
|
|
31
|
+
}
|
|
32
|
+
handleTeammateIdle(_agentName) {
|
|
33
|
+
void _agentName;
|
|
34
|
+
return pass();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
class ReviewRouteStore {
|
|
38
|
+
storedReviews = [];
|
|
39
|
+
storedEvents;
|
|
40
|
+
constructor(initialState = 'REVIEWING') {
|
|
41
|
+
this.storedEvents = [buildStoredEvent('test-session', 'session-started', '2026-01-01T00:00:00.000Z', initialState, { currentState: initialState })];
|
|
42
|
+
}
|
|
43
|
+
readEvents(sessionId) {
|
|
44
|
+
return sessionId === 'test-session' ? this.storedEvents : [];
|
|
45
|
+
}
|
|
46
|
+
appendEvents(sessionId, events) {
|
|
47
|
+
void sessionId;
|
|
48
|
+
this.storedEvents.push(...events);
|
|
49
|
+
}
|
|
50
|
+
sessionExists(sessionId) {
|
|
51
|
+
return sessionId === 'test-session';
|
|
52
|
+
}
|
|
53
|
+
hasSessionStarted(sessionId) {
|
|
54
|
+
return sessionId === 'test-session';
|
|
55
|
+
}
|
|
56
|
+
recordReflection(_sessionId, _createdAt, _input) {
|
|
57
|
+
void _sessionId;
|
|
58
|
+
void _createdAt;
|
|
59
|
+
void _input;
|
|
60
|
+
throw new WorkflowStateError('Reflection storage is not configured');
|
|
61
|
+
}
|
|
62
|
+
listReflections(_sessionId) {
|
|
63
|
+
void _sessionId;
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
recordReview(_sessionId, _createdAt, _input) {
|
|
67
|
+
void _sessionId;
|
|
68
|
+
void _createdAt;
|
|
69
|
+
void _input;
|
|
70
|
+
throw new WorkflowStateError('Use recordReviewWithEvent for review recording');
|
|
71
|
+
}
|
|
72
|
+
recordReviewWithEvent(sessionId, createdAt, input, eventState) {
|
|
73
|
+
const storedReview = {
|
|
74
|
+
id: this.storedReviews.length + 1,
|
|
75
|
+
sessionId,
|
|
76
|
+
createdAt,
|
|
77
|
+
...input,
|
|
78
|
+
};
|
|
79
|
+
this.storedReviews.push(storedReview);
|
|
80
|
+
this.storedEvents.push(buildStoredEvent(sessionId, 'review-recorded', createdAt, eventState, {
|
|
81
|
+
reviewId: storedReview.id,
|
|
82
|
+
reviewType: input.reviewType,
|
|
83
|
+
verdict: input.verdict,
|
|
84
|
+
}));
|
|
85
|
+
return storedReview;
|
|
86
|
+
}
|
|
87
|
+
listSessionReviews(sessionId) {
|
|
88
|
+
return this.storedReviews.filter((review) => review.sessionId === sessionId);
|
|
89
|
+
}
|
|
90
|
+
listReviews(_filters) {
|
|
91
|
+
void _filters;
|
|
92
|
+
return this.storedReviews;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function buildStoredEvent(sessionId, type, at, state, payload) {
|
|
96
|
+
void sessionId;
|
|
97
|
+
const event = {
|
|
98
|
+
type,
|
|
99
|
+
at,
|
|
100
|
+
...payload,
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
envelope: {
|
|
104
|
+
type,
|
|
105
|
+
at,
|
|
106
|
+
state,
|
|
107
|
+
},
|
|
108
|
+
payload: toPayload(event),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const workflowDefinition = {
|
|
112
|
+
fold(state, event) {
|
|
113
|
+
if (event.type === 'session-started') {
|
|
114
|
+
if (event.currentState !== 'PLANNING' && event.currentState !== 'REVIEWING')
|
|
115
|
+
return state;
|
|
116
|
+
return { currentStateMachineState: event.currentState };
|
|
117
|
+
}
|
|
118
|
+
if (event.type !== 'transitioned')
|
|
119
|
+
return state;
|
|
120
|
+
if (event.to !== 'PLANNING' && event.to !== 'REVIEWING')
|
|
121
|
+
return state;
|
|
122
|
+
return { currentStateMachineState: event.to };
|
|
123
|
+
},
|
|
124
|
+
buildWorkflow(state) {
|
|
125
|
+
return new ReviewRouteWorkflow(state);
|
|
126
|
+
},
|
|
127
|
+
stateSchema: z.enum(['PLANNING', 'REVIEWING']),
|
|
128
|
+
initialState() {
|
|
129
|
+
return { currentStateMachineState: 'REVIEWING' };
|
|
130
|
+
},
|
|
131
|
+
getRegistry() {
|
|
132
|
+
return {
|
|
133
|
+
PLANNING: {
|
|
134
|
+
emoji: '🧠',
|
|
135
|
+
agentInstructions: 'planning.md',
|
|
136
|
+
canTransitionTo: ['REVIEWING'],
|
|
137
|
+
allowedWorkflowOperations: [],
|
|
138
|
+
},
|
|
139
|
+
REVIEWING: {
|
|
140
|
+
emoji: '🔍',
|
|
141
|
+
agentInstructions: 'reviewing.md',
|
|
142
|
+
canTransitionTo: ['PLANNING'],
|
|
143
|
+
allowedWorkflowOperations: ['record-review'],
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
},
|
|
147
|
+
buildTransitionContext(state, from, to) {
|
|
148
|
+
return {
|
|
149
|
+
state,
|
|
150
|
+
from,
|
|
151
|
+
to,
|
|
152
|
+
gitInfo: {
|
|
153
|
+
currentBranch: 'main',
|
|
154
|
+
workingTreeClean: true,
|
|
155
|
+
headCommit: 'abc123',
|
|
156
|
+
changedFilesVsDefault: [],
|
|
157
|
+
hasCommitsVsDefault: false,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
function createEngineDeps(store) {
|
|
163
|
+
return {
|
|
164
|
+
store,
|
|
165
|
+
getPluginRoot: () => '',
|
|
166
|
+
getEnvFilePath: () => '',
|
|
167
|
+
readFile: () => '',
|
|
168
|
+
appendToFile: () => undefined,
|
|
169
|
+
now: () => '2026-01-01T00:01:00.000Z',
|
|
170
|
+
transcriptReader: { readMessages: () => [] },
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function recordReview(store, readStdin, sessionId = 'test-session') {
|
|
174
|
+
return handleRecordReviewRoute({ hasSessionStarted: (candidateSessionId) => store.hasSessionStarted(candidateSessionId) }, createEngineDeps(store), workflowDefinition, ['record-review', '--type', 'custom-review'], readStdin, () => sessionId);
|
|
175
|
+
}
|
|
176
|
+
describe('handleRecordReviewRoute', () => {
|
|
177
|
+
it('returns error when stdin is invalid JSON', () => {
|
|
178
|
+
const store = new ReviewRouteStore();
|
|
179
|
+
const result = recordReview(store, () => '{');
|
|
180
|
+
expect(result.exitCode).toBe(EXIT_ERROR);
|
|
181
|
+
expect(result.output).toContain('Invalid review JSON');
|
|
182
|
+
expect(store.storedReviews).toStrictEqual([]);
|
|
183
|
+
});
|
|
184
|
+
it('returns error when verdict is unknown', () => {
|
|
185
|
+
const store = new ReviewRouteStore();
|
|
186
|
+
const result = recordReview(store, () => JSON.stringify({
|
|
187
|
+
verdict: 'MAYBE',
|
|
188
|
+
findings: []
|
|
189
|
+
}));
|
|
190
|
+
expect(result.exitCode).toBe(EXIT_ERROR);
|
|
191
|
+
expect(result.output).toContain('Invalid review payload');
|
|
192
|
+
expect(store.storedReviews).toStrictEqual([]);
|
|
193
|
+
});
|
|
194
|
+
it('returns error when session has not started', () => {
|
|
195
|
+
const store = new ReviewRouteStore();
|
|
196
|
+
const result = recordReview(store, () => JSON.stringify({
|
|
197
|
+
verdict: 'PASS',
|
|
198
|
+
findings: []
|
|
199
|
+
}), 'missing-session');
|
|
200
|
+
expect(result).toStrictEqual({
|
|
201
|
+
exitCode: EXIT_ERROR,
|
|
202
|
+
output: 'Session missing-session has not been started',
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
it('records review row and review event when payload is valid', () => {
|
|
206
|
+
const store = new ReviewRouteStore();
|
|
207
|
+
const result = recordReview(store, () => JSON.stringify({
|
|
208
|
+
verdict: 'FAIL',
|
|
209
|
+
findings: [{ title: 'Missing command tests' }],
|
|
210
|
+
}));
|
|
211
|
+
expect(result.exitCode).toBe(EXIT_ALLOW);
|
|
212
|
+
expect(JSON.parse(result.output)).toStrictEqual({
|
|
213
|
+
ok: true,
|
|
214
|
+
id: 1,
|
|
215
|
+
sessionId: 'test-session',
|
|
216
|
+
createdAt: '2026-01-01T00:01:00.000Z',
|
|
217
|
+
reviewType: 'custom-review',
|
|
218
|
+
verdict: 'FAIL',
|
|
219
|
+
});
|
|
220
|
+
expect(store.storedReviews).toStrictEqual([{
|
|
221
|
+
id: 1,
|
|
222
|
+
sessionId: 'test-session',
|
|
223
|
+
createdAt: '2026-01-01T00:01:00.000Z',
|
|
224
|
+
reviewType: 'custom-review',
|
|
225
|
+
sourceState: 'REVIEWING',
|
|
226
|
+
verdict: 'FAIL',
|
|
227
|
+
findings: [{ title: 'Missing command tests' }],
|
|
228
|
+
}]);
|
|
229
|
+
expect(store.storedEvents.at(-1)).toStrictEqual(buildStoredEvent('test-session', 'review-recorded', '2026-01-01T00:01:00.000Z', 'REVIEWING', {
|
|
230
|
+
reviewId: 1,
|
|
231
|
+
reviewType: 'custom-review',
|
|
232
|
+
verdict: 'FAIL',
|
|
233
|
+
}));
|
|
234
|
+
});
|
|
235
|
+
it('preserves repeated review attempts', () => {
|
|
236
|
+
const store = new ReviewRouteStore();
|
|
237
|
+
recordReview(store, () => JSON.stringify({
|
|
238
|
+
verdict: 'FAIL',
|
|
239
|
+
findings: [{ title: 'First failure' }]
|
|
240
|
+
}));
|
|
241
|
+
recordReview(store, () => JSON.stringify({
|
|
242
|
+
verdict: 'PASS',
|
|
243
|
+
findings: []
|
|
244
|
+
}));
|
|
245
|
+
expect(store.storedReviews.map((review) => ({
|
|
246
|
+
id: review.id,
|
|
247
|
+
verdict: review.verdict
|
|
248
|
+
}))).toStrictEqual([
|
|
249
|
+
{
|
|
250
|
+
id: 1,
|
|
251
|
+
verdict: 'FAIL'
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
id: 2,
|
|
255
|
+
verdict: 'PASS'
|
|
256
|
+
},
|
|
257
|
+
]);
|
|
258
|
+
expect(store.storedEvents.filter((event) => event.envelope.type === 'review-recorded')).toHaveLength(2);
|
|
259
|
+
});
|
|
260
|
+
it('returns blocked when current state disallows record-review', () => {
|
|
261
|
+
const store = new ReviewRouteStore('PLANNING');
|
|
262
|
+
const result = recordReview(store, () => JSON.stringify({
|
|
263
|
+
verdict: 'PASS',
|
|
264
|
+
findings: []
|
|
265
|
+
}));
|
|
266
|
+
expect(result).toStrictEqual({
|
|
267
|
+
exitCode: EXIT_BLOCK,
|
|
268
|
+
output: 'record-review is not allowed in state PLANNING.',
|
|
269
|
+
});
|
|
270
|
+
expect(store.storedReviews).toStrictEqual([]);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
@@ -5,6 +5,7 @@ import { hookCommonInputSchema, preToolUseInputSchema, subagentStartInputSchema,
|
|
|
5
5
|
import { createPreToolUseHandler } from '../../../platform/domain/pre-tool-use-handler.js';
|
|
6
6
|
import { getRepositoryName } from '../../../platform/infra/external-clients/git/repository-name.js';
|
|
7
7
|
import { handleGetReflectionProcessRoute, handleRecordReflectionRoute, } from './reflection-routes.js';
|
|
8
|
+
import { handleRecordReviewRoute } from './review-routes.js';
|
|
8
9
|
function resolvePreToolUseHandler(config) {
|
|
9
10
|
const hasPolicy = config.bashForbidden !== undefined || config.isWriteAllowed !== undefined || config.customGates !== undefined;
|
|
10
11
|
if (config.preToolUseHandler !== undefined) {
|
|
@@ -172,6 +173,8 @@ function resolveBuiltinRoute(engine, engineDeps, config, args, routeName, readSt
|
|
|
172
173
|
return handleGetReflectionProcessRoute(engine, engineDeps, config, args, getSessionId, getSessionTranscriptPath, getSessionRepository, getRepositoryRoot, getWorkflowEventsDbPath);
|
|
173
174
|
case 'record-reflection':
|
|
174
175
|
return handleRecordReflectionRoute(engine, engineDeps, args, readStdin, getSessionId);
|
|
176
|
+
case 'record-review':
|
|
177
|
+
return handleRecordReviewRoute(engine, engineDeps, config.workflowDefinition, args, readStdin, getSessionId);
|
|
175
178
|
case 'write-journal':
|
|
176
179
|
return handleWriteJournalRoute(engine, engineDeps, args, getSessionId);
|
|
177
180
|
default:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nt-ai-lab/deterministic-agent-workflow-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -12,9 +12,12 @@
|
|
|
12
12
|
],
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"zod": "^3.25.76",
|
|
15
|
-
"@nt-ai-lab/deterministic-agent-workflow-engine": "0.3.
|
|
16
|
-
"@nt-ai-lab/deterministic-agent-workflow-dsl": "0.3.
|
|
17
|
-
"@nt-ai-lab/deterministic-agent-workflow-event-store": "0.3.
|
|
15
|
+
"@nt-ai-lab/deterministic-agent-workflow-engine": "0.3.3",
|
|
16
|
+
"@nt-ai-lab/deterministic-agent-workflow-dsl": "0.3.3",
|
|
17
|
+
"@nt-ai-lab/deterministic-agent-workflow-event-store": "0.3.3"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"vitest": "^2.1.9"
|
|
18
21
|
},
|
|
19
22
|
"publishConfig": {
|
|
20
23
|
"access": "public"
|