@outputai/cli 0.1.13-dev.98dfd72.0 → 0.1.13-dev.e3e3291.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/bin/run.js +0 -2
- package/dist/api/generated/api.d.ts +319 -85
- package/dist/api/generated/api.js +66 -8
- package/dist/assets/docker/docker-compose-dev.yml +1 -1
- package/dist/commands/fix.js +1 -1
- package/dist/commands/fix.spec.js +2 -2
- package/dist/commands/update.js +1 -1
- package/dist/commands/update.spec.js +2 -2
- package/dist/commands/workflow/plan.js +1 -5
- package/dist/commands/workflow/plan.spec.js +2 -3
- package/dist/commands/workflow/run.js +1 -2
- package/dist/commands/workflow/run.spec.js +0 -1
- package/dist/commands/workflow/start.js +1 -2
- package/dist/commands/workflow/start.spec.js +0 -1
- package/dist/commands/workflow/test_eval.js +2 -2
- package/dist/generated/framework_version.json +1 -1
- package/dist/hooks/init.js +0 -4
- package/dist/services/coding_agents.js +1 -1
- package/dist/services/coding_agents.spec.js +6 -6
- package/dist/services/credentials_configurator.js +1 -1
- package/dist/services/datasets.d.ts +1 -1
- package/dist/services/datasets.js +41 -37
- package/dist/services/datasets.test.js +202 -0
- package/dist/services/env_configurator.js +1 -1
- package/dist/services/env_configurator.spec.js +12 -12
- package/dist/services/project_scaffold.js +2 -2
- package/dist/services/project_scaffold.spec.js +6 -6
- package/dist/services/workflow_builder.js +1 -5
- package/dist/services/workflow_builder.spec.js +2 -3
- package/dist/utils/format_workflow_result.d.ts +3 -3
- package/package.json +4 -5
- package/dist/commands/credentials/set.d.ts +0 -14
- package/dist/commands/credentials/set.js +0 -57
- package/dist/commands/credentials/set.spec.js +0 -95
- package/dist/utils/interactive.d.ts +0 -2
- package/dist/utils/interactive.js +0 -5
- package/dist/utils/interactive.spec.d.ts +0 -1
- package/dist/utils/interactive.spec.js +0 -40
- package/dist/utils/prompt.d.ts +0 -17
- package/dist/utils/prompt.js +0 -20
- package/dist/utils/prompt.spec.d.ts +0 -1
- package/dist/utils/prompt.spec.js +0 -74
- package/dist/utils/proxy.d.ts +0 -1
- package/dist/utils/proxy.js +0 -9
- package/dist/utils/proxy.spec.d.ts +0 -1
- package/dist/utils/proxy.spec.js +0 -39
- /package/dist/{commands/credentials/set.spec.d.ts → services/datasets.test.d.ts} +0 -0
|
@@ -24,11 +24,7 @@ export const WorkflowRunInfoStatus = {
|
|
|
24
24
|
timed_out: 'timed_out',
|
|
25
25
|
continued: 'continued',
|
|
26
26
|
};
|
|
27
|
-
export const
|
|
28
|
-
completed: 'completed',
|
|
29
|
-
failed: 'failed',
|
|
30
|
-
};
|
|
31
|
-
export const GetWorkflowIdStatus200Status = {
|
|
27
|
+
export const WorkflowStatusResponseStatus = {
|
|
32
28
|
canceled: 'canceled',
|
|
33
29
|
completed: 'completed',
|
|
34
30
|
continued_as_new: 'continued_as_new',
|
|
@@ -38,7 +34,7 @@ export const GetWorkflowIdStatus200Status = {
|
|
|
38
34
|
timed_out: 'timed_out',
|
|
39
35
|
unspecified: 'unspecified',
|
|
40
36
|
};
|
|
41
|
-
export const
|
|
37
|
+
export const WorkflowResultResponseStatus = {
|
|
42
38
|
completed: 'completed',
|
|
43
39
|
failed: 'failed',
|
|
44
40
|
canceled: 'canceled',
|
|
@@ -46,6 +42,10 @@ export const GetWorkflowIdResult200Status = {
|
|
|
46
42
|
timed_out: 'timed_out',
|
|
47
43
|
continued: 'continued',
|
|
48
44
|
};
|
|
45
|
+
export const PostWorkflowRun200Status = {
|
|
46
|
+
completed: 'completed',
|
|
47
|
+
failed: 'failed',
|
|
48
|
+
};
|
|
49
49
|
;
|
|
50
50
|
export const getGetHealthUrl = () => {
|
|
51
51
|
return `/health`;
|
|
@@ -87,6 +87,24 @@ export const getWorkflowIdStatus = async (id, options) => {
|
|
|
87
87
|
method: 'GET'
|
|
88
88
|
});
|
|
89
89
|
};
|
|
90
|
+
export const getGetWorkflowIdRunsRidStatusUrl = (id, rid) => {
|
|
91
|
+
return `/workflow/${id}/runs/${rid}/status`;
|
|
92
|
+
};
|
|
93
|
+
export const getWorkflowIdRunsRidStatus = async (id, rid, options) => {
|
|
94
|
+
return customFetchInstance(getGetWorkflowIdRunsRidStatusUrl(id, rid), {
|
|
95
|
+
...options,
|
|
96
|
+
method: 'GET'
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
export const getPatchWorkflowIdRunsRidStopUrl = (id, rid) => {
|
|
100
|
+
return `/workflow/${id}/runs/${rid}/stop`;
|
|
101
|
+
};
|
|
102
|
+
export const patchWorkflowIdRunsRidStop = async (id, rid, options) => {
|
|
103
|
+
return customFetchInstance(getPatchWorkflowIdRunsRidStopUrl(id, rid), {
|
|
104
|
+
...options,
|
|
105
|
+
method: 'PATCH'
|
|
106
|
+
});
|
|
107
|
+
};
|
|
90
108
|
export const getPatchWorkflowIdStopUrl = (id) => {
|
|
91
109
|
return `/workflow/${id}/stop`;
|
|
92
110
|
};
|
|
@@ -96,6 +114,17 @@ export const patchWorkflowIdStop = async (id, options) => {
|
|
|
96
114
|
method: 'PATCH'
|
|
97
115
|
});
|
|
98
116
|
};
|
|
117
|
+
export const getPostWorkflowIdRunsRidTerminateUrl = (id, rid) => {
|
|
118
|
+
return `/workflow/${id}/runs/${rid}/terminate`;
|
|
119
|
+
};
|
|
120
|
+
export const postWorkflowIdRunsRidTerminate = async (id, rid, postWorkflowIdRunsRidTerminateBody, options) => {
|
|
121
|
+
return customFetchInstance(getPostWorkflowIdRunsRidTerminateUrl(id, rid), {
|
|
122
|
+
...options,
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: { 'Content-Type': 'application/json', ...options?.headers },
|
|
125
|
+
body: JSON.stringify(postWorkflowIdRunsRidTerminateBody)
|
|
126
|
+
});
|
|
127
|
+
};
|
|
99
128
|
export const getPostWorkflowIdTerminateUrl = (id) => {
|
|
100
129
|
return `/workflow/${id}/terminate`;
|
|
101
130
|
};
|
|
@@ -107,15 +136,26 @@ export const postWorkflowIdTerminate = async (id, postWorkflowIdTerminateBody, o
|
|
|
107
136
|
body: JSON.stringify(postWorkflowIdTerminateBody)
|
|
108
137
|
});
|
|
109
138
|
};
|
|
139
|
+
export const getPostWorkflowIdRunsRidResetUrl = (id, rid) => {
|
|
140
|
+
return `/workflow/${id}/runs/${rid}/reset`;
|
|
141
|
+
};
|
|
142
|
+
export const postWorkflowIdRunsRidReset = async (id, rid, resetWorkflowRequest, options) => {
|
|
143
|
+
return customFetchInstance(getPostWorkflowIdRunsRidResetUrl(id, rid), {
|
|
144
|
+
...options,
|
|
145
|
+
method: 'POST',
|
|
146
|
+
headers: { 'Content-Type': 'application/json', ...options?.headers },
|
|
147
|
+
body: JSON.stringify(resetWorkflowRequest)
|
|
148
|
+
});
|
|
149
|
+
};
|
|
110
150
|
export const getPostWorkflowIdResetUrl = (id) => {
|
|
111
151
|
return `/workflow/${id}/reset`;
|
|
112
152
|
};
|
|
113
|
-
export const postWorkflowIdReset = async (id,
|
|
153
|
+
export const postWorkflowIdReset = async (id, resetWorkflowRequest, options) => {
|
|
114
154
|
return customFetchInstance(getPostWorkflowIdResetUrl(id), {
|
|
115
155
|
...options,
|
|
116
156
|
method: 'POST',
|
|
117
157
|
headers: { 'Content-Type': 'application/json', ...options?.headers },
|
|
118
|
-
body: JSON.stringify(
|
|
158
|
+
body: JSON.stringify(resetWorkflowRequest)
|
|
119
159
|
});
|
|
120
160
|
};
|
|
121
161
|
export const getGetWorkflowIdResultUrl = (id) => {
|
|
@@ -127,6 +167,15 @@ export const getWorkflowIdResult = async (id, options) => {
|
|
|
127
167
|
method: 'GET'
|
|
128
168
|
});
|
|
129
169
|
};
|
|
170
|
+
export const getGetWorkflowIdRunsRidResultUrl = (id, rid) => {
|
|
171
|
+
return `/workflow/${id}/runs/${rid}/result`;
|
|
172
|
+
};
|
|
173
|
+
export const getWorkflowIdRunsRidResult = async (id, rid, options) => {
|
|
174
|
+
return customFetchInstance(getGetWorkflowIdRunsRidResultUrl(id, rid), {
|
|
175
|
+
...options,
|
|
176
|
+
method: 'GET'
|
|
177
|
+
});
|
|
178
|
+
};
|
|
130
179
|
export const getGetWorkflowIdTraceLogUrl = (id) => {
|
|
131
180
|
return `/workflow/${id}/trace-log`;
|
|
132
181
|
};
|
|
@@ -136,6 +185,15 @@ export const getWorkflowIdTraceLog = async (id, options) => {
|
|
|
136
185
|
method: 'GET'
|
|
137
186
|
});
|
|
138
187
|
};
|
|
188
|
+
export const getGetWorkflowIdRunsRidTraceLogUrl = (id, rid) => {
|
|
189
|
+
return `/workflow/${id}/runs/${rid}/trace-log`;
|
|
190
|
+
};
|
|
191
|
+
export const getWorkflowIdRunsRidTraceLog = async (id, rid, options) => {
|
|
192
|
+
return customFetchInstance(getGetWorkflowIdRunsRidTraceLogUrl(id, rid), {
|
|
193
|
+
...options,
|
|
194
|
+
method: 'GET'
|
|
195
|
+
});
|
|
196
|
+
};
|
|
139
197
|
export const getGetWorkflowCatalogIdUrl = (id) => {
|
|
140
198
|
return `/workflow/catalog/${id}`;
|
|
141
199
|
};
|
package/dist/commands/fix.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import { confirm } from '
|
|
2
|
+
import { confirm } from '@inquirer/prompts';
|
|
3
3
|
import { applyFix, planFix } from '#services/fix_package.js';
|
|
4
4
|
import { getErrorMessage } from '#utils/error_utils.js';
|
|
5
5
|
const Ansi = {
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
3
3
|
import Fix from './fix.js';
|
|
4
4
|
import * as fixService from '#services/fix_package.js';
|
|
5
|
-
import { confirm } from '
|
|
5
|
+
import { confirm } from '@inquirer/prompts';
|
|
6
6
|
vi.mock('#services/fix_package.js', () => ({
|
|
7
7
|
planFix: vi.fn(),
|
|
8
8
|
applyFix: vi.fn()
|
|
9
9
|
}));
|
|
10
|
-
vi.mock('
|
|
10
|
+
vi.mock('@inquirer/prompts', () => ({
|
|
11
11
|
confirm: vi.fn()
|
|
12
12
|
}));
|
|
13
13
|
const basePlan = () => ({
|
package/dist/commands/update.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import { confirm } from '
|
|
2
|
+
import { confirm } from '@inquirer/prompts';
|
|
3
3
|
import { fetchLatestVersion, getGlobalInstalledVersion, getLocalInstalledVersion, updateGlobal, updateLocal, isOutdated } from '#services/npm_update_service.js';
|
|
4
4
|
import { ensureClaudePlugin } from '#services/coding_agents.js';
|
|
5
5
|
import { getErrorMessage } from '#utils/error_utils.js';
|
|
@@ -3,7 +3,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
|
3
3
|
import Update from './update.js';
|
|
4
4
|
import { fetchLatestVersion, getGlobalInstalledVersion, getLocalInstalledVersion, updateGlobal, updateLocal, isOutdated } from '#services/npm_update_service.js';
|
|
5
5
|
import { ensureClaudePlugin } from '#services/coding_agents.js';
|
|
6
|
-
import { confirm } from '
|
|
6
|
+
import { confirm } from '@inquirer/prompts';
|
|
7
7
|
vi.mock('#services/npm_update_service.js', () => ({
|
|
8
8
|
fetchLatestVersion: vi.fn(),
|
|
9
9
|
getGlobalInstalledVersion: vi.fn(),
|
|
@@ -15,7 +15,7 @@ vi.mock('#services/npm_update_service.js', () => ({
|
|
|
15
15
|
vi.mock('#services/coding_agents.js', () => ({
|
|
16
16
|
ensureClaudePlugin: vi.fn()
|
|
17
17
|
}));
|
|
18
|
-
vi.mock('
|
|
18
|
+
vi.mock('@inquirer/prompts', () => ({
|
|
19
19
|
confirm: vi.fn()
|
|
20
20
|
}));
|
|
21
21
|
describe('update command', () => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Command, Flags, ux } from '@oclif/core';
|
|
2
|
-
import { input } from '
|
|
3
|
-
import { isInteractive } from '#utils/interactive.js';
|
|
2
|
+
import { input } from '@inquirer/prompts';
|
|
4
3
|
import { generatePlanName, updateAgentTemplates, writePlanFile } from '#services/workflow_planner.js';
|
|
5
4
|
import { ensureOutputAISystem } from '#services/coding_agents.js';
|
|
6
5
|
import { invokePlanWorkflow, PLAN_COMMAND_OPTIONS, replyToClaude } from '#services/claude_client.js';
|
|
@@ -46,9 +45,6 @@ export default class WorkflowPlan extends Command {
|
|
|
46
45
|
this.log('=========');
|
|
47
46
|
this.log(originalPlanContent);
|
|
48
47
|
this.log('=========');
|
|
49
|
-
if (!isInteractive()) {
|
|
50
|
-
return originalPlanContent;
|
|
51
|
-
}
|
|
52
48
|
const modifications = await input({
|
|
53
49
|
message: ux.colorize('gray', `Reply or type ${acceptKey} to accept the plan as is: `),
|
|
54
50
|
validate: (value) => value.length >= 10 || value === acceptKey
|
|
@@ -3,12 +3,11 @@ import WorkflowPlan from './plan.js';
|
|
|
3
3
|
import { generatePlanName, writePlanFile, updateAgentTemplates } from '#services/workflow_planner.js';
|
|
4
4
|
import { ensureOutputAISystem } from '#services/coding_agents.js';
|
|
5
5
|
import { invokePlanWorkflow, replyToClaude, ClaudeInvocationError } from '#services/claude_client.js';
|
|
6
|
-
import { input } from '
|
|
6
|
+
import { input } from '@inquirer/prompts';
|
|
7
7
|
vi.mock('#services/workflow_planner.js');
|
|
8
8
|
vi.mock('#services/coding_agents.js');
|
|
9
9
|
vi.mock('#services/claude_client.js');
|
|
10
|
-
vi.mock('
|
|
11
|
-
vi.mock('#utils/interactive.js', () => ({ isInteractive: () => true }));
|
|
10
|
+
vi.mock('@inquirer/prompts');
|
|
12
11
|
describe('WorkflowPlan Command', () => {
|
|
13
12
|
const createCommand = () => {
|
|
14
13
|
const cmd = new WorkflowPlan([], {});
|
|
@@ -55,8 +55,7 @@ export default class WorkflowRun extends Command {
|
|
|
55
55
|
}),
|
|
56
56
|
'task-queue': Flags.string({
|
|
57
57
|
char: 'q',
|
|
58
|
-
description: 'Task queue name for workflow execution
|
|
59
|
-
env: 'OUTPUT_CATALOG_ID'
|
|
58
|
+
description: 'Task queue name for workflow execution'
|
|
60
59
|
}),
|
|
61
60
|
format: Flags.string({
|
|
62
61
|
char: 'f',
|
|
@@ -13,7 +13,6 @@ vi.mock('#utils/sleep.js', () => ({
|
|
|
13
13
|
describe('workflow run command', () => {
|
|
14
14
|
beforeEach(async () => {
|
|
15
15
|
vi.clearAllMocks();
|
|
16
|
-
delete process.env.OUTPUT_CATALOG_ID;
|
|
17
16
|
const { resolveInput } = await import('#utils/resolve_input.js');
|
|
18
17
|
const { sleep } = await import('#utils/sleep.js');
|
|
19
18
|
vi.mocked(resolveInput).mockResolvedValue({});
|
|
@@ -28,8 +28,7 @@ export default class WorkflowStart extends Command {
|
|
|
28
28
|
}),
|
|
29
29
|
'task-queue': Flags.string({
|
|
30
30
|
char: 'q',
|
|
31
|
-
description: 'Task queue name for workflow execution
|
|
32
|
-
env: 'OUTPUT_CATALOG_ID'
|
|
31
|
+
description: 'Task queue name for workflow execution'
|
|
33
32
|
})
|
|
34
33
|
};
|
|
35
34
|
async run() {
|
|
@@ -5,7 +5,6 @@ vi.mock('../../api/generated/api.js', () => ({
|
|
|
5
5
|
describe('workflow start command', () => {
|
|
6
6
|
beforeEach(() => {
|
|
7
7
|
vi.clearAllMocks();
|
|
8
|
-
delete process.env.OUTPUT_CATALOG_ID;
|
|
9
8
|
});
|
|
10
9
|
describe('command definition', () => {
|
|
11
10
|
it('should export a valid OCLIF command', async () => {
|
|
@@ -114,7 +114,7 @@ export default class WorkflowTest extends Command {
|
|
|
114
114
|
}
|
|
115
115
|
};
|
|
116
116
|
if (save) {
|
|
117
|
-
const filePath = join(dir, `${dataset.name}.yml`);
|
|
117
|
+
const filePath = dataset._source ?? join(dir, `${dataset.name}.yml`);
|
|
118
118
|
await writeDataset(updated, filePath);
|
|
119
119
|
this.log(` Saved output to ${filePath}`);
|
|
120
120
|
}
|
|
@@ -137,7 +137,7 @@ export default class WorkflowTest extends Command {
|
|
|
137
137
|
date: now
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
|
-
const filePath = join(dir, `${dataset.name}.yml`);
|
|
140
|
+
const filePath = dataset._source ?? join(dir, `${dataset.name}.yml`);
|
|
141
141
|
await writeDataset(updated, filePath);
|
|
142
142
|
this.log(` Saved eval result to ${filePath}`);
|
|
143
143
|
}
|
package/dist/hooks/init.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { ux } from '@oclif/core';
|
|
2
2
|
import { checkForUpdate } from '#services/version_check.js';
|
|
3
|
-
import { setNonInteractive } from '#utils/interactive.js';
|
|
4
3
|
const hook = async function () {
|
|
5
|
-
if (process.argv.includes('--yes') || process.argv.includes('--non-interactive') || !process.stdin.isTTY) {
|
|
6
|
-
setNonInteractive(true);
|
|
7
|
-
}
|
|
8
4
|
try {
|
|
9
5
|
const result = await checkForUpdate(this.config.version, this.config.cacheDir);
|
|
10
6
|
if (!result.updateAvailable) {
|
|
@@ -7,7 +7,7 @@ import { access } from 'node:fs/promises';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { join } from 'node:path';
|
|
9
9
|
import { ux } from '@oclif/core';
|
|
10
|
-
import { confirm } from '
|
|
10
|
+
import { confirm } from '@inquirer/prompts';
|
|
11
11
|
import debugFactory from 'debug';
|
|
12
12
|
import { getTemplateDir } from '#utils/paths.js';
|
|
13
13
|
import { executeClaudeCommand } from '#utils/claude.js';
|
|
@@ -19,7 +19,7 @@ vi.mock('@oclif/core', () => ({
|
|
|
19
19
|
colorize: vi.fn().mockImplementation((_color, text) => text)
|
|
20
20
|
}
|
|
21
21
|
}));
|
|
22
|
-
vi.mock('
|
|
22
|
+
vi.mock('@inquirer/prompts', () => ({
|
|
23
23
|
confirm: vi.fn()
|
|
24
24
|
}));
|
|
25
25
|
describe('coding_agents service', () => {
|
|
@@ -157,7 +157,7 @@ describe('coding_agents service', () => {
|
|
|
157
157
|
});
|
|
158
158
|
it('should show error and prompt user when plugin commands fail', async () => {
|
|
159
159
|
const { executeClaudeCommand } = await import('../utils/claude.js');
|
|
160
|
-
const { confirm } = await import('
|
|
160
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
161
161
|
vi.mocked(executeClaudeCommand)
|
|
162
162
|
.mockResolvedValueOnce(undefined) // marketplace add
|
|
163
163
|
.mockRejectedValueOnce(new Error('Plugin update failed')); // marketplace update
|
|
@@ -169,7 +169,7 @@ describe('coding_agents service', () => {
|
|
|
169
169
|
});
|
|
170
170
|
it('should allow user to proceed without plugin setup if they confirm', async () => {
|
|
171
171
|
const { executeClaudeCommand } = await import('../utils/claude.js');
|
|
172
|
-
const { confirm } = await import('
|
|
172
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
173
173
|
vi.mocked(executeClaudeCommand)
|
|
174
174
|
.mockRejectedValue(new Error('All plugin commands fail'));
|
|
175
175
|
vi.mocked(confirm).mockResolvedValue(true);
|
|
@@ -219,7 +219,7 @@ describe('coding_agents service', () => {
|
|
|
219
219
|
});
|
|
220
220
|
it('should show error and prompt user when registerPluginMarketplace fails', async () => {
|
|
221
221
|
const { executeClaudeCommand } = await import('../utils/claude.js');
|
|
222
|
-
const { confirm } = await import('
|
|
222
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
223
223
|
vi.mocked(executeClaudeCommand)
|
|
224
224
|
.mockResolvedValueOnce(undefined) // marketplace add
|
|
225
225
|
.mockRejectedValueOnce(new Error('Plugin update failed')); // marketplace update
|
|
@@ -231,7 +231,7 @@ describe('coding_agents service', () => {
|
|
|
231
231
|
});
|
|
232
232
|
it('should show error and prompt user when installOutputAIPlugin fails', async () => {
|
|
233
233
|
const { executeClaudeCommand } = await import('../utils/claude.js');
|
|
234
|
-
const { confirm } = await import('
|
|
234
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
235
235
|
vi.mocked(executeClaudeCommand)
|
|
236
236
|
.mockResolvedValueOnce(undefined) // marketplace add
|
|
237
237
|
.mockResolvedValueOnce(undefined) // marketplace update
|
|
@@ -244,7 +244,7 @@ describe('coding_agents service', () => {
|
|
|
244
244
|
});
|
|
245
245
|
it('should allow user to proceed without plugin setup if they confirm', async () => {
|
|
246
246
|
const { executeClaudeCommand } = await import('../utils/claude.js');
|
|
247
|
-
const { confirm } = await import('
|
|
247
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
248
248
|
vi.mocked(executeClaudeCommand)
|
|
249
249
|
.mockRejectedValue(new Error('All plugin commands fail'));
|
|
250
250
|
vi.mocked(confirm).mockResolvedValue(true);
|
|
@@ -8,7 +8,7 @@ export interface DatasetInfo {
|
|
|
8
8
|
}
|
|
9
9
|
export declare function resolveDatasetsDir(workflowName: string, basePath?: string): string | null;
|
|
10
10
|
export declare function resolveDefaultDatasetsDir(workflowName: string, basePath?: string): string;
|
|
11
|
-
export declare function
|
|
11
|
+
export declare function readDatasetFile(filePath: string): Promise<Dataset[]>;
|
|
12
12
|
export declare function readAllDatasets(workflowName: string, filterNames?: string[], basePath?: string): Promise<{
|
|
13
13
|
datasets: Dataset[];
|
|
14
14
|
dir: string;
|
|
@@ -24,10 +24,19 @@ export function resolveDefaultDatasetsDir(workflowName, basePath = process.cwd()
|
|
|
24
24
|
// Default to first workflows path
|
|
25
25
|
return resolve(basePath, WORKFLOWS_PATHS[0], workflowName, DATASETS_DIR);
|
|
26
26
|
}
|
|
27
|
-
export async function
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
export async function readDatasetFile(filePath) {
|
|
28
|
+
const raw = yaml.load(await readFile(filePath, 'utf-8'));
|
|
29
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
30
|
+
throw new Error(`Invalid dataset file: ${filePath}`);
|
|
31
|
+
}
|
|
32
|
+
return Object.entries(raw).map(([name, body]) => {
|
|
33
|
+
if (!body || typeof body !== 'object' || !('input' in body)) {
|
|
34
|
+
throw new Error(`Dataset case "${name}" in ${filePath} is missing required "input" field`);
|
|
35
|
+
}
|
|
36
|
+
const dataset = DatasetSchema.parse({ name, ...body });
|
|
37
|
+
dataset._source = filePath;
|
|
38
|
+
return dataset;
|
|
39
|
+
});
|
|
31
40
|
}
|
|
32
41
|
export async function readAllDatasets(workflowName, filterNames, basePath) {
|
|
33
42
|
const dir = resolveDatasetsDir(workflowName, basePath);
|
|
@@ -36,42 +45,35 @@ export async function readAllDatasets(workflowName, filterNames, basePath) {
|
|
|
36
45
|
}
|
|
37
46
|
const files = await readdir(dir);
|
|
38
47
|
const ymlFiles = files.filter(f => f.endsWith('.yml') || f.endsWith('.yaml'));
|
|
48
|
+
const seen = new Set();
|
|
39
49
|
const datasets = [];
|
|
40
50
|
for (const file of ymlFiles) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
const cases = await readDatasetFile(join(dir, file));
|
|
52
|
+
for (const dataset of cases) {
|
|
53
|
+
if (seen.has(dataset.name)) {
|
|
54
|
+
throw new Error(`Duplicate dataset case name "${dataset.name}" found in ${file}`);
|
|
55
|
+
}
|
|
56
|
+
seen.add(dataset.name);
|
|
57
|
+
if (filterNames && !filterNames.includes(dataset.name)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
datasets.push(dataset);
|
|
44
61
|
}
|
|
45
|
-
datasets.push(dataset);
|
|
46
62
|
}
|
|
47
63
|
return { datasets, dir };
|
|
48
64
|
}
|
|
49
|
-
async function mergeWithExisting(dataset, filePath) {
|
|
50
|
-
if (!existsSync(filePath)) {
|
|
51
|
-
return dataset;
|
|
52
|
-
}
|
|
53
|
-
try {
|
|
54
|
-
const existing = await readDataset(filePath);
|
|
55
|
-
return {
|
|
56
|
-
...existing,
|
|
57
|
-
...dataset,
|
|
58
|
-
ground_truth: dataset.ground_truth ?? existing.ground_truth,
|
|
59
|
-
last_output: dataset.last_output ?? existing.last_output,
|
|
60
|
-
last_eval: dataset.last_eval ?? existing.last_eval
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return dataset;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
65
|
export async function writeDataset(dataset, filePath) {
|
|
68
|
-
const merged = await mergeWithExisting(dataset, filePath);
|
|
69
66
|
const dir = resolve(filePath, '..');
|
|
70
67
|
if (!existsSync(dir)) {
|
|
71
68
|
await mkdir(dir, { recursive: true });
|
|
72
69
|
}
|
|
73
|
-
const
|
|
74
|
-
|
|
70
|
+
const loaded = existsSync(filePath) ? yaml.load(await readFile(filePath, 'utf-8')) : null;
|
|
71
|
+
const fileObj = (loaded && typeof loaded === 'object' && !Array.isArray(loaded)) ?
|
|
72
|
+
loaded :
|
|
73
|
+
{};
|
|
74
|
+
const { name, _source, ...caseBody } = dataset;
|
|
75
|
+
fileObj[name] = { ...fileObj[name], ...caseBody };
|
|
76
|
+
await writeFile(filePath, yaml.dump(fileObj, { lineWidth: 120, noRefs: true, sortKeys: false }), 'utf-8');
|
|
75
77
|
}
|
|
76
78
|
export async function listDatasets(workflowName, basePath) {
|
|
77
79
|
const dir = resolveDatasetsDir(workflowName, basePath);
|
|
@@ -84,14 +86,16 @@ export async function listDatasets(workflowName, basePath) {
|
|
|
84
86
|
for (const file of ymlFiles) {
|
|
85
87
|
const filePath = join(dir, file);
|
|
86
88
|
try {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
const cases = await readDatasetFile(filePath);
|
|
90
|
+
for (const dataset of cases) {
|
|
91
|
+
results.push({
|
|
92
|
+
name: dataset.name,
|
|
93
|
+
path: filePath,
|
|
94
|
+
hasLastOutput: dataset.last_output?.output !== undefined,
|
|
95
|
+
lastOutputDate: dataset.last_output?.date,
|
|
96
|
+
lastEvalDate: dataset.last_eval?.date
|
|
97
|
+
});
|
|
98
|
+
}
|
|
95
99
|
}
|
|
96
100
|
catch {
|
|
97
101
|
results.push({
|