@outputai/cli 0.14.1-next.8f66bb1.0 → 0.14.1-next.bb8708e.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.
@@ -80,7 +80,7 @@ services:
80
80
  condition: service_healthy
81
81
  worker:
82
82
  condition: service_healthy
83
- image: outputai/api:${OUTPUT_API_VERSION:-0.14.1-next.8f66bb1.0}
83
+ image: outputai/api:${OUTPUT_API_VERSION:-0.14.1-next.bb8708e.0}
84
84
  init: true
85
85
  networks:
86
86
  - main
@@ -1,3 +1,3 @@
1
1
  {
2
- "framework": "0.14.1-next.8f66bb1.0"
2
+ "framework": "0.14.1-next.bb8708e.0"
3
3
  }
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- import { load as parseYaml } from 'js-yaml';
3
+ import yaml from 'js-yaml';
4
4
  const ARRAY_ACCESS_PATTERN = /^(\w+)\[(\d+)\]$/;
5
5
  function tokenCost(tokens, pricePerMillion) {
6
6
  return (tokens / 1_000_000) * pricePerMillion;
@@ -144,7 +144,7 @@ export function extractValue(obj, path) {
144
144
  }, obj);
145
145
  }
146
146
  function loadYaml(filePath) {
147
- return parseYaml(readFileSync(filePath, 'utf-8'));
147
+ return yaml.load(readFileSync(filePath, 'utf-8'));
148
148
  }
149
149
  export function loadPricingConfig(configPath) {
150
150
  const bundledPath = new URL('../assets/config/costs.yml', import.meta.url).pathname;
@@ -7,7 +7,7 @@ vi.mock('node:fs', () => ({
7
7
  }));
8
8
  const mockLoad = vi.fn();
9
9
  vi.mock('js-yaml', () => ({
10
- load: (...args) => mockLoad(...args)
10
+ default: { load: (...args) => mockLoad(...args) }
11
11
  }));
12
12
  import { extractValue, findLLMCalls, findHTTPCalls, identifyService, calculateServiceCost, calculateCost, loadPricingConfig } from '#services/cost_calculator.js';
13
13
  // ---------------------------------------------------------------------------
@@ -1,7 +1,7 @@
1
1
  import { readFile, writeFile, readdir, mkdir } from 'node:fs/promises';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { resolve, join } from 'node:path';
4
- import { load as parseYaml, dump as stringifyYaml } from 'js-yaml';
4
+ import yaml from 'js-yaml';
5
5
  import { DatasetSchema } from '@outputai/evals';
6
6
  import { getTrace } from '#services/trace_reader.js';
7
7
  import { sanitizeSecrets } from '#utils/secret_sanitizer.js';
@@ -27,7 +27,7 @@ export async function resolveDefaultDatasetsDir(workflowName, basePath, workflow
27
27
  return resolve(basePath ?? getWorkflowsBasePath(), WORKFLOWS_PATHS[0], workflowName, DATASETS_DIR);
28
28
  }
29
29
  export async function readDatasetFile(filePath) {
30
- const raw = parseYaml(await readFile(filePath, 'utf-8'));
30
+ const raw = yaml.load(await readFile(filePath, 'utf-8'));
31
31
  if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
32
32
  throw new Error(`Invalid dataset file: ${filePath}`);
33
33
  }
@@ -69,13 +69,13 @@ export async function writeDataset(dataset, filePath) {
69
69
  if (!existsSync(dir)) {
70
70
  await mkdir(dir, { recursive: true });
71
71
  }
72
- const loaded = existsSync(filePath) ? parseYaml(await readFile(filePath, 'utf-8')) : null;
72
+ const loaded = existsSync(filePath) ? yaml.load(await readFile(filePath, 'utf-8')) : null;
73
73
  const fileObj = (loaded && typeof loaded === 'object' && !Array.isArray(loaded)) ?
74
74
  loaded :
75
75
  {};
76
76
  const { name, _source, ...caseBody } = dataset;
77
77
  fileObj[name] = { ...fileObj[name], ...caseBody };
78
- await writeFile(filePath, stringifyYaml(fileObj, { lineWidth: 120, noRefs: true, sortKeys: false }), 'utf-8');
78
+ await writeFile(filePath, yaml.dump(fileObj, { lineWidth: 120, noRefs: true, sortKeys: false }), 'utf-8');
79
79
  }
80
80
  export async function listDatasets(workflowName, basePath) {
81
81
  const dir = await resolveDatasetsDir(workflowName, basePath);
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
2
  import { mkdtemp, rm, writeFile, readFile, mkdir } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
- import { load as parseYaml, dump as stringifyYaml } from 'js-yaml';
5
+ import yaml from 'js-yaml';
6
6
  import { readDatasetFile, readAllDatasets, writeDataset, listDatasets, resolveDefaultDatasetsDir, datasetFilePath } from './datasets.js';
7
7
  import * as catalog from '#api/workflow_catalog.js';
8
8
  vi.mock('#api/workflow_catalog.js', () => ({
@@ -20,7 +20,7 @@ afterEach(async () => {
20
20
  await rm(ctx.tmpDir, { recursive: true, force: true });
21
21
  });
22
22
  function writeYaml(filePath, obj) {
23
- return writeFile(filePath, stringifyYaml(obj, { lineWidth: 120, noRefs: true, sortKeys: false }), 'utf-8');
23
+ return writeFile(filePath, yaml.dump(obj, { lineWidth: 120, noRefs: true, sortKeys: false }), 'utf-8');
24
24
  }
25
25
  // ---------------------------------------------------------------------------
26
26
  // readDatasetFile
@@ -142,7 +142,7 @@ describe('writeDataset', () => {
142
142
  const filePath = join(ctx.tmpDir, 'cases.yml');
143
143
  const dataset = { name: 'new_case', input: { q: 'hello' } };
144
144
  await writeDataset(dataset, filePath);
145
- const raw = parseYaml(await readFile(filePath, 'utf-8'));
145
+ const raw = yaml.load(await readFile(filePath, 'utf-8'));
146
146
  expect(raw).toHaveProperty('new_case');
147
147
  expect(raw.new_case.input).toEqual({ q: 'hello' });
148
148
  expect(raw.new_case).not.toHaveProperty('name');
@@ -151,7 +151,7 @@ describe('writeDataset', () => {
151
151
  const filePath = join(ctx.tmpDir, 'cases.yml');
152
152
  const dataset = { name: 'my_case', input: { q: 'x' }, _source: '/some/path.yml' };
153
153
  await writeDataset(dataset, filePath);
154
- const raw = parseYaml(await readFile(filePath, 'utf-8'));
154
+ const raw = yaml.load(await readFile(filePath, 'utf-8'));
155
155
  expect(raw.my_case).not.toHaveProperty('_source');
156
156
  });
157
157
  it('updates only the target case, leaving other cases untouched', async () => {
@@ -161,7 +161,7 @@ describe('writeDataset', () => {
161
161
  case_b: { input: { x: 2 }, ground_truth: { expected: 2 } }
162
162
  });
163
163
  await writeDataset({ name: 'case_a', input: { x: 1 }, last_output: { output: { result: 1 }, date: '2026-01-01T00:00:00.000Z' } }, filePath);
164
- const raw = parseYaml(await readFile(filePath, 'utf-8'));
164
+ const raw = yaml.load(await readFile(filePath, 'utf-8'));
165
165
  expect(raw).toHaveProperty('case_b');
166
166
  expect(raw.case_b.ground_truth).toEqual({ expected: 2 });
167
167
  });
@@ -175,7 +175,7 @@ describe('writeDataset', () => {
175
175
  name: 'my_case', input: { q: 'hello' },
176
176
  last_eval: { output: { datasetName: 'my_case', verdict: 'pass', evaluators: [] }, date: '2026-01-01T00:01:00.000Z' }
177
177
  }, filePath);
178
- const raw = parseYaml(await readFile(filePath, 'utf-8'));
178
+ const raw = yaml.load(await readFile(filePath, 'utf-8'));
179
179
  const caseObj = raw.my_case;
180
180
  expect(caseObj).toHaveProperty('last_output');
181
181
  expect(caseObj).toHaveProperty('last_eval');
@@ -184,14 +184,14 @@ describe('writeDataset', () => {
184
184
  it('creates parent directories if they do not exist', async () => {
185
185
  const filePath = join(ctx.tmpDir, 'deep', 'nested', 'cases.yml');
186
186
  await writeDataset({ name: 'my_case', input: { q: 'x' } }, filePath);
187
- const raw = parseYaml(await readFile(filePath, 'utf-8'));
187
+ const raw = yaml.load(await readFile(filePath, 'utf-8'));
188
188
  expect(raw).toHaveProperty('my_case');
189
189
  });
190
190
  it('recovers gracefully when existing file contains non-object YAML', async () => {
191
191
  const filePath = join(ctx.tmpDir, 'cases.yml');
192
192
  await writeFile(filePath, 'just a string', 'utf-8');
193
193
  await writeDataset({ name: 'my_case', input: { q: 'x' } }, filePath);
194
- const raw = parseYaml(await readFile(filePath, 'utf-8'));
194
+ const raw = yaml.load(await readFile(filePath, 'utf-8'));
195
195
  expect(raw).toHaveProperty('my_case');
196
196
  });
197
197
  });
@@ -1521,6 +1521,81 @@
1521
1521
  "test.js"
1522
1522
  ]
1523
1523
  },
1524
+ "workflow:runs:list": {
1525
+ "aliases": [],
1526
+ "args": {
1527
+ "workflowName": {
1528
+ "description": "Filter by workflow type/name",
1529
+ "name": "workflowName",
1530
+ "required": false
1531
+ }
1532
+ },
1533
+ "description": "List workflow runs with optional filtering by workflow type",
1534
+ "examples": [
1535
+ "<%= config.bin %> <%= command.id %>",
1536
+ "<%= config.bin %> <%= command.id %> simple",
1537
+ "<%= config.bin %> <%= command.id %> simple --limit 10",
1538
+ "<%= config.bin %> <%= command.id %> --catalog my-catalog",
1539
+ "<%= config.bin %> <%= command.id %> --json",
1540
+ "<%= config.bin %> <%= command.id %> --format table"
1541
+ ],
1542
+ "flags": {
1543
+ "json": {
1544
+ "description": "Format output as json.",
1545
+ "helpGroup": "GLOBAL",
1546
+ "name": "json",
1547
+ "allowNo": false,
1548
+ "type": "boolean"
1549
+ },
1550
+ "catalog": {
1551
+ "char": "c",
1552
+ "description": "Filter runs by catalog (defaults to OUTPUT_CATALOG_ID)",
1553
+ "env": "OUTPUT_CATALOG_ID",
1554
+ "name": "catalog",
1555
+ "hasDynamicHelp": false,
1556
+ "multiple": false,
1557
+ "type": "option"
1558
+ },
1559
+ "limit": {
1560
+ "char": "l",
1561
+ "description": "Maximum number of runs to return",
1562
+ "name": "limit",
1563
+ "default": 100,
1564
+ "hasDynamicHelp": false,
1565
+ "multiple": false,
1566
+ "type": "option"
1567
+ },
1568
+ "format": {
1569
+ "char": "f",
1570
+ "description": "Output format (use --json for JSON output)",
1571
+ "name": "format",
1572
+ "default": "table",
1573
+ "hasDynamicHelp": false,
1574
+ "multiple": false,
1575
+ "options": [
1576
+ "table",
1577
+ "text"
1578
+ ],
1579
+ "type": "option"
1580
+ }
1581
+ },
1582
+ "hasDynamicHelp": false,
1583
+ "hiddenAliases": [],
1584
+ "id": "workflow:runs:list",
1585
+ "pluginAlias": "@outputai/cli",
1586
+ "pluginName": "@outputai/cli",
1587
+ "pluginType": "core",
1588
+ "strict": true,
1589
+ "enableJsonFlag": true,
1590
+ "isESM": true,
1591
+ "relativePath": [
1592
+ "dist",
1593
+ "commands",
1594
+ "workflow",
1595
+ "runs",
1596
+ "list.js"
1597
+ ]
1598
+ },
1524
1599
  "workflow:dataset:generate": {
1525
1600
  "aliases": [],
1526
1601
  "args": {
@@ -1675,82 +1750,7 @@
1675
1750
  "dataset",
1676
1751
  "list.js"
1677
1752
  ]
1678
- },
1679
- "workflow:runs:list": {
1680
- "aliases": [],
1681
- "args": {
1682
- "workflowName": {
1683
- "description": "Filter by workflow type/name",
1684
- "name": "workflowName",
1685
- "required": false
1686
- }
1687
- },
1688
- "description": "List workflow runs with optional filtering by workflow type",
1689
- "examples": [
1690
- "<%= config.bin %> <%= command.id %>",
1691
- "<%= config.bin %> <%= command.id %> simple",
1692
- "<%= config.bin %> <%= command.id %> simple --limit 10",
1693
- "<%= config.bin %> <%= command.id %> --catalog my-catalog",
1694
- "<%= config.bin %> <%= command.id %> --json",
1695
- "<%= config.bin %> <%= command.id %> --format table"
1696
- ],
1697
- "flags": {
1698
- "json": {
1699
- "description": "Format output as json.",
1700
- "helpGroup": "GLOBAL",
1701
- "name": "json",
1702
- "allowNo": false,
1703
- "type": "boolean"
1704
- },
1705
- "catalog": {
1706
- "char": "c",
1707
- "description": "Filter runs by catalog (defaults to OUTPUT_CATALOG_ID)",
1708
- "env": "OUTPUT_CATALOG_ID",
1709
- "name": "catalog",
1710
- "hasDynamicHelp": false,
1711
- "multiple": false,
1712
- "type": "option"
1713
- },
1714
- "limit": {
1715
- "char": "l",
1716
- "description": "Maximum number of runs to return",
1717
- "name": "limit",
1718
- "default": 100,
1719
- "hasDynamicHelp": false,
1720
- "multiple": false,
1721
- "type": "option"
1722
- },
1723
- "format": {
1724
- "char": "f",
1725
- "description": "Output format (use --json for JSON output)",
1726
- "name": "format",
1727
- "default": "table",
1728
- "hasDynamicHelp": false,
1729
- "multiple": false,
1730
- "options": [
1731
- "table",
1732
- "text"
1733
- ],
1734
- "type": "option"
1735
- }
1736
- },
1737
- "hasDynamicHelp": false,
1738
- "hiddenAliases": [],
1739
- "id": "workflow:runs:list",
1740
- "pluginAlias": "@outputai/cli",
1741
- "pluginName": "@outputai/cli",
1742
- "pluginType": "core",
1743
- "strict": true,
1744
- "enableJsonFlag": true,
1745
- "isESM": true,
1746
- "relativePath": [
1747
- "dist",
1748
- "commands",
1749
- "workflow",
1750
- "runs",
1751
- "list.js"
1752
- ]
1753
1753
  }
1754
1754
  },
1755
- "version": "0.14.1-next.8f66bb1.0"
1755
+ "version": "0.14.1-next.bb8708e.0"
1756
1756
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outputai/cli",
3
- "version": "0.14.1-next.8f66bb1.0",
3
+ "version": "0.14.1-next.bb8708e.0",
4
4
  "description": "CLI for Output.ai workflow generation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,7 +17,7 @@
17
17
  "output": "./bin/run.js"
18
18
  },
19
19
  "dependencies": {
20
- "@anthropic-ai/claude-agent-sdk": "0.3.281",
20
+ "@anthropic-ai/claude-agent-sdk": "0.3.278",
21
21
  "@hackylabs/deep-redact": "3.0.5",
22
22
  "@inquirer/prompts": "8.7.2",
23
23
  "@oclif/core": "4.10.6",
@@ -30,15 +30,15 @@
30
30
  "handlebars": "4.7.9",
31
31
  "ink": "7.0.1",
32
32
  "ink-spinner": "5.0.0",
33
- "js-yaml": "5.4.2",
33
+ "js-yaml": "4.3.2",
34
34
  "json-schema-library": "11.6.2",
35
35
  "ky": "2.0.2",
36
36
  "react": "19.3.0",
37
37
  "semver": "7.8.5",
38
38
  "undici": "8.11.0",
39
- "@outputai/core": "0.14.1-next.8f66bb1.0",
40
- "@outputai/evals": "0.14.1-next.8f66bb1.0",
41
- "@outputai/llm": "0.14.1-next.8f66bb1.0"
39
+ "@outputai/core": "0.14.1-next.bb8708e.0",
40
+ "@outputai/evals": "0.14.1-next.bb8708e.0",
41
+ "@outputai/llm": "0.14.1-next.bb8708e.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/cli-progress": "3.11.6",
@@ -47,7 +47,7 @@
47
47
  "@types/react": "19.3.0",
48
48
  "@types/semver": "7.8.0",
49
49
  "oclif": "4.23.10",
50
- "orval": "8.37.0"
50
+ "orval": "8.35.0"
51
51
  },
52
52
  "license": "Apache-2.0",
53
53
  "publishConfig": {