@nt-ai-lab/deterministic-agent-workflow-cli 0.3.6 → 0.4.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.
@@ -3,4 +3,4 @@ import type { RunnerResult } from '../../../platform/domain/workflow-runner-type
3
3
  /** @riviere-role cli-entrypoint */
4
4
  export declare function handleRecordReviewRoute<TWorkflow extends RehydratableWorkflow<TState>, TState extends BaseWorkflowState<TStateName>, TDeps, TStateName extends string, TOperation extends string>(engine: {
5
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;
6
+ }, engineDeps: WorkflowEngineDeps, workflowDefinition: WorkflowDefinition<TWorkflow, TState, TDeps, TStateName, TOperation>, args: readonly string[], getSessionId: (() => string) | undefined): RunnerResult;
@@ -18,70 +18,44 @@ function blockedResult(output) {
18
18
  exitCode: EXIT_BLOCK,
19
19
  };
20
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);
21
+ function parseReviewArguments(args) {
22
+ const reviewType = args[1];
23
+ const reviewJson = args[2];
24
+ if (args.length !== 3 || typeof reviewType !== 'string' || typeof reviewJson !== 'string') {
25
+ return {
26
+ ok: false,
27
+ message: 'record-review requires <review-type> and <review-json> arguments',
28
+ };
29
+ }
30
+ if (reviewType.length === 0) {
31
+ return {
32
+ ok: false,
33
+ message: 'record-review requires a non-empty review type',
34
+ };
40
35
  }
41
36
  return {
42
37
  ok: true,
43
- flags,
38
+ reviewType,
39
+ reviewJson,
44
40
  };
45
41
  }
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
42
  function isReviewAllowed(allowedWorkflowOperations) {
58
43
  return allowedWorkflowOperations.some((allowedWorkflowOperation) => allowedWorkflowOperation === 'record-review');
59
44
  }
60
45
  /** @riviere-role cli-entrypoint */
61
- export function handleRecordReviewRoute(engine, engineDeps, workflowDefinition, args, readStdin, getSessionId) {
46
+ export function handleRecordReviewRoute(engine, engineDeps, workflowDefinition, args, getSessionId) {
62
47
  if (getSessionId === undefined) {
63
48
  return errorResult('record-review requires an active workflow session');
64
49
  }
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');
50
+ const parsedArguments = parseReviewArguments(args);
51
+ if (!parsedArguments.ok) {
52
+ return errorResult(parsedArguments.message);
79
53
  }
80
54
  const sessionId = getSessionId();
81
55
  if (!engine.hasSessionStarted(sessionId)) {
82
56
  return errorResult(`Session ${sessionId} has not been started`);
83
57
  }
84
- const reviewPayloadResult = parseReviewPayload(readStdin);
58
+ const reviewPayloadResult = parseReviewPayload(parsedArguments.reviewJson);
85
59
  if (!reviewPayloadResult.ok) {
86
60
  return errorResult(reviewPayloadResult.message);
87
61
  }
@@ -99,7 +73,7 @@ export function handleRecordReviewRoute(engine, engineDeps, workflowDefinition,
99
73
  }
100
74
  const createdAt = engineDeps.now();
101
75
  const stored = engineDeps.store.recordReviewWithEvent(sessionId, createdAt, {
102
- reviewType,
76
+ reviewType: parsedArguments.reviewType,
103
77
  sourceState: currentStateName,
104
78
  ...parsedReview.data,
105
79
  }, currentStateName);
@@ -108,7 +82,7 @@ export function handleRecordReviewRoute(engine, engineDeps, workflowDefinition,
108
82
  id: stored.id,
109
83
  sessionId,
110
84
  createdAt: stored.createdAt,
111
- reviewType,
85
+ reviewType: parsedArguments.reviewType,
112
86
  verdict: parsedReview.data.verdict,
113
87
  });
114
88
  }
@@ -116,11 +90,11 @@ function computeCurrentState(workflowDefinition, storedEvents) {
116
90
  const state = reduceWorkflowStateFromStoredEvents(workflowDefinition, storedEvents);
117
91
  return state.currentStateMachineState;
118
92
  }
119
- function parseReviewPayload(readStdin) {
93
+ function parseReviewPayload(reviewJson) {
120
94
  try {
121
95
  return {
122
96
  ok: true,
123
- payload: JSON.parse(readStdin()),
97
+ payload: JSON.parse(reviewJson),
124
98
  };
125
99
  }
126
100
  catch (error) {
@@ -170,20 +170,20 @@ function createEngineDeps(store) {
170
170
  transcriptReader: { readMessages: () => [] },
171
171
  };
172
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);
173
+ function recordReview(store, reviewJson, sessionId = 'test-session') {
174
+ return handleRecordReviewRoute({ hasSessionStarted: (candidateSessionId) => store.hasSessionStarted(candidateSessionId) }, createEngineDeps(store), workflowDefinition, ['record-review', 'custom-review', reviewJson], () => sessionId);
175
175
  }
176
176
  describe('handleRecordReviewRoute', () => {
177
- it('returns error when stdin is invalid JSON', () => {
177
+ it('returns error when review JSON argument is invalid JSON', () => {
178
178
  const store = new ReviewRouteStore();
179
- const result = recordReview(store, () => '{');
179
+ const result = recordReview(store, '{');
180
180
  expect(result.exitCode).toBe(EXIT_ERROR);
181
181
  expect(result.output).toContain('Invalid review JSON');
182
182
  expect(store.storedReviews).toStrictEqual([]);
183
183
  });
184
184
  it('returns error when verdict is unknown', () => {
185
185
  const store = new ReviewRouteStore();
186
- const result = recordReview(store, () => JSON.stringify({
186
+ const result = recordReview(store, JSON.stringify({
187
187
  verdict: 'MAYBE',
188
188
  findings: []
189
189
  }));
@@ -193,7 +193,7 @@ describe('handleRecordReviewRoute', () => {
193
193
  });
194
194
  it('returns error when session has not started', () => {
195
195
  const store = new ReviewRouteStore();
196
- const result = recordReview(store, () => JSON.stringify({
196
+ const result = recordReview(store, JSON.stringify({
197
197
  verdict: 'PASS',
198
198
  findings: []
199
199
  }), 'missing-session');
@@ -204,7 +204,7 @@ describe('handleRecordReviewRoute', () => {
204
204
  });
205
205
  it('records review row and review event when payload is valid', () => {
206
206
  const store = new ReviewRouteStore();
207
- const result = recordReview(store, () => JSON.stringify({
207
+ const result = recordReview(store, JSON.stringify({
208
208
  verdict: 'FAIL',
209
209
  findings: [{ title: 'Missing command tests' }],
210
210
  }));
@@ -234,11 +234,11 @@ describe('handleRecordReviewRoute', () => {
234
234
  });
235
235
  it('preserves repeated review attempts', () => {
236
236
  const store = new ReviewRouteStore();
237
- recordReview(store, () => JSON.stringify({
237
+ recordReview(store, JSON.stringify({
238
238
  verdict: 'FAIL',
239
239
  findings: [{ title: 'First failure' }]
240
240
  }));
241
- recordReview(store, () => JSON.stringify({
241
+ recordReview(store, JSON.stringify({
242
242
  verdict: 'PASS',
243
243
  findings: []
244
244
  }));
@@ -259,7 +259,7 @@ describe('handleRecordReviewRoute', () => {
259
259
  });
260
260
  it('returns blocked when current state disallows record-review', () => {
261
261
  const store = new ReviewRouteStore('PLANNING');
262
- const result = recordReview(store, () => JSON.stringify({
262
+ const result = recordReview(store, JSON.stringify({
263
263
  verdict: 'PASS',
264
264
  findings: []
265
265
  }));
@@ -166,7 +166,7 @@ function resolveBuiltinRoute(engine, engineDeps, config, args, routeName, readSt
166
166
  case 'record-reflection':
167
167
  return handleRecordReflectionRoute(engine, engineDeps, args, readStdin, getSessionId);
168
168
  case 'record-review':
169
- return handleRecordReviewRoute(engine, engineDeps, config.workflowDefinition, args, readStdin, getSessionId);
169
+ return handleRecordReviewRoute(engine, engineDeps, config.workflowDefinition, args, getSessionId);
170
170
  case 'write-journal':
171
171
  return handleWriteJournalRoute(engine, args, getSessionId);
172
172
  default:
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@nt-ai-lab/deterministic-agent-workflow-cli",
3
- "version": "0.3.6",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/NTCoding/deterministic-agent-workflows.git",
9
+ "directory": "packages/deterministic-agent-workflows-cli"
10
+ },
6
11
  "exports": {
7
12
  ".": "./dist/index.js"
8
13
  },
@@ -12,9 +17,9 @@
12
17
  ],
13
18
  "dependencies": {
14
19
  "zod": "^3.25.76",
15
- "@nt-ai-lab/deterministic-agent-workflow-engine": "0.3.6",
16
- "@nt-ai-lab/deterministic-agent-workflow-dsl": "0.3.6",
17
- "@nt-ai-lab/deterministic-agent-workflow-event-store": "0.3.6"
20
+ "@nt-ai-lab/deterministic-agent-workflow-engine": "0.4.0",
21
+ "@nt-ai-lab/deterministic-agent-workflow-dsl": "0.4.0",
22
+ "@nt-ai-lab/deterministic-agent-workflow-event-store": "0.4.0"
18
23
  },
19
24
  "devDependencies": {
20
25
  "vitest": "^2.1.9"