@outputai/cli 0.7.1-next.ae5bab4.0 → 0.7.1-next.bd6bd49.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 +1 -1
- package/dist/api/generated/api.d.ts +38 -0
- package/dist/assets/docker/docker-compose-dev.yml +1 -1
- package/dist/commands/update.js +1 -1
- package/dist/generated/framework_version.json +1 -1
- package/dist/hooks/init.js +12 -3
- package/dist/hooks/init.spec.js +18 -8
- package/dist/scripts/refresh_version_check.d.ts +1 -0
- package/dist/scripts/refresh_version_check.js +9 -0
- package/dist/services/cost_calculator.d.ts +1 -5
- package/dist/services/cost_calculator.js +214 -102
- package/dist/services/cost_calculator.spec.js +329 -253
- package/dist/services/npm_update_service.js +11 -3
- package/dist/services/npm_update_service.spec.js +20 -7
- package/dist/services/version_check.d.ts +19 -1
- package/dist/services/version_check.js +53 -17
- package/dist/services/version_check.spec.js +88 -58
- package/dist/types/cost.d.ts +64 -23
- package/dist/types/cost.js +4 -0
- package/dist/utils/cost_formatter.js +65 -43
- package/dist/utils/proxy.d.ts +3 -2
- package/dist/utils/proxy.js +4 -3
- package/dist/utils/proxy.spec.js +4 -4
- package/oclif.manifest.json +1428 -0
- package/package.json +6 -5
package/bin/run.js
CHANGED
|
@@ -7,7 +7,7 @@ import { loadCredentialRefs } from '../dist/utils/credentials_loader.js';
|
|
|
7
7
|
|
|
8
8
|
// Load environment variables from .env files before executing CLI
|
|
9
9
|
loadEnvironment();
|
|
10
|
-
bootstrapProxy();
|
|
10
|
+
await bootstrapProxy();
|
|
11
11
|
loadCredentialRefs();
|
|
12
12
|
|
|
13
13
|
await execute( { dir: import.meta.url } );
|
|
@@ -226,6 +226,39 @@ export declare const WorkflowResultResponseStatus: {
|
|
|
226
226
|
readonly timed_out: "timed_out";
|
|
227
227
|
readonly continued: "continued";
|
|
228
228
|
};
|
|
229
|
+
/**
|
|
230
|
+
* Structured failure details if the workflow failed, null otherwise
|
|
231
|
+
* @nullable
|
|
232
|
+
*/
|
|
233
|
+
export type WorkflowResultResponseErrorDetails = {
|
|
234
|
+
/**
|
|
235
|
+
* Friendly failure message (from the underlying application error)
|
|
236
|
+
* @nullable
|
|
237
|
+
*/
|
|
238
|
+
message?: string | null;
|
|
239
|
+
/**
|
|
240
|
+
* Error name/type (the original error's class)
|
|
241
|
+
* @nullable
|
|
242
|
+
*/
|
|
243
|
+
name?: string | null;
|
|
244
|
+
/**
|
|
245
|
+
* Whether Temporal flagged the failure retryable; null if unknown
|
|
246
|
+
* @nullable
|
|
247
|
+
*/
|
|
248
|
+
retryable?: boolean | null;
|
|
249
|
+
/**
|
|
250
|
+
* Failing activity key ("workflow#step"); null if no activity failed
|
|
251
|
+
* @nullable
|
|
252
|
+
*/
|
|
253
|
+
activityId?: string | null;
|
|
254
|
+
/**
|
|
255
|
+
* Sanitized error cause chain (name/message per level, no stack)
|
|
256
|
+
* @nullable
|
|
257
|
+
*/
|
|
258
|
+
cause?: {
|
|
259
|
+
[key: string]: unknown;
|
|
260
|
+
} | null;
|
|
261
|
+
} | null | null;
|
|
229
262
|
export interface WorkflowResultResponse {
|
|
230
263
|
/** The workflow execution id */
|
|
231
264
|
workflowId?: string;
|
|
@@ -248,6 +281,11 @@ export interface WorkflowResultResponse {
|
|
|
248
281
|
* @nullable
|
|
249
282
|
*/
|
|
250
283
|
error?: string | null;
|
|
284
|
+
/**
|
|
285
|
+
* Structured failure details if the workflow failed, null otherwise
|
|
286
|
+
* @nullable
|
|
287
|
+
*/
|
|
288
|
+
errorDetails?: WorkflowResultResponseErrorDetails;
|
|
251
289
|
}
|
|
252
290
|
export interface StopWorkflowResponse {
|
|
253
291
|
workflowId?: string;
|
package/dist/commands/update.js
CHANGED
|
@@ -31,7 +31,7 @@ export default class Update extends Command {
|
|
|
31
31
|
async updateCli() {
|
|
32
32
|
const latest = await fetchLatestVersion();
|
|
33
33
|
if (!latest) {
|
|
34
|
-
this.error('Could not fetch the latest version from npm.
|
|
34
|
+
this.error('Could not fetch the latest version from the npm registry. Run with DEBUG=output-cli:npm-update for details.');
|
|
35
35
|
}
|
|
36
36
|
this.log(`\nLatest @outputai/cli version: v${latest}\n`);
|
|
37
37
|
await this.handleGlobalUpdate(latest);
|
package/dist/hooks/init.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ux } from '@oclif/core';
|
|
2
|
-
import
|
|
2
|
+
import debugFactory from 'debug';
|
|
3
|
+
import { readCachedResult, spawnBackgroundRefresh } from '#services/version_check.js';
|
|
3
4
|
import { setNonInteractive } from '#utils/interactive.js';
|
|
5
|
+
const debug = debugFactory('output-cli:init');
|
|
4
6
|
export const INTERACTIVE_FLAGS = ['--yes', '--non-interactive'];
|
|
5
7
|
export const GLOBAL_FLAGS = new Set(INTERACTIVE_FLAGS);
|
|
6
8
|
export const hasInteractiveFlag = (argv) => argv.some(arg => INTERACTIVE_FLAGS.includes(arg));
|
|
@@ -18,7 +20,13 @@ const hook = async function (opts) {
|
|
|
18
20
|
setNonInteractive(true);
|
|
19
21
|
}
|
|
20
22
|
try {
|
|
21
|
-
|
|
23
|
+
// Only the local cache is read here; the registry roundtrip happens in a
|
|
24
|
+
// detached child so it never delays the invoked command.
|
|
25
|
+
const result = await readCachedResult(this.config.version, this.config.cacheDir);
|
|
26
|
+
if (!result) {
|
|
27
|
+
spawnBackgroundRefresh(this.config.version, this.config.cacheDir);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
22
30
|
if (!result.updateAvailable) {
|
|
23
31
|
return;
|
|
24
32
|
}
|
|
@@ -39,8 +47,9 @@ const hook = async function (opts) {
|
|
|
39
47
|
ux.stdout(border);
|
|
40
48
|
ux.stdout('');
|
|
41
49
|
}
|
|
42
|
-
catch {
|
|
50
|
+
catch (error) {
|
|
43
51
|
// Never block CLI execution
|
|
52
|
+
debug('Version banner failed: %O', error);
|
|
44
53
|
}
|
|
45
54
|
};
|
|
46
55
|
export default hook;
|
package/dist/hooks/init.spec.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
3
|
-
import {
|
|
3
|
+
import { readCachedResult, spawnBackgroundRefresh } from '#services/version_check.js';
|
|
4
4
|
import { setNonInteractive } from '#utils/interactive.js';
|
|
5
5
|
vi.mock('#services/version_check.js', () => ({
|
|
6
|
-
|
|
6
|
+
readCachedResult: vi.fn(),
|
|
7
|
+
spawnBackgroundRefresh: vi.fn()
|
|
7
8
|
}));
|
|
8
9
|
vi.mock('#utils/interactive.js', () => ({
|
|
9
10
|
setNonInteractive: vi.fn()
|
|
@@ -23,15 +24,16 @@ describe('init hook', () => {
|
|
|
23
24
|
const createHookContext = (version = '0.8.4') => ({
|
|
24
25
|
config: { version, cacheDir: '/tmp/test-cache' }
|
|
25
26
|
});
|
|
26
|
-
it('should display warning when update is available', async () => {
|
|
27
|
-
vi.mocked(
|
|
27
|
+
it('should display warning when cached result says an update is available', async () => {
|
|
28
|
+
vi.mocked(readCachedResult).mockResolvedValue({
|
|
28
29
|
updateAvailable: true,
|
|
29
30
|
currentVersion: '0.8.4',
|
|
30
31
|
latestVersion: '1.0.0'
|
|
31
32
|
});
|
|
32
33
|
const ctx = createHookContext();
|
|
33
34
|
await hook.call(ctx, { argv: [], id: undefined });
|
|
34
|
-
expect(
|
|
35
|
+
expect(readCachedResult).toHaveBeenCalledWith('0.8.4', '/tmp/test-cache');
|
|
36
|
+
expect(spawnBackgroundRefresh).not.toHaveBeenCalled();
|
|
35
37
|
expect(ux.stdout).toHaveBeenCalled();
|
|
36
38
|
const output = vi.mocked(ux.stdout).mock.calls.map(c => c[0]).join('\n');
|
|
37
39
|
expect(output).toContain('Uhoh');
|
|
@@ -40,17 +42,25 @@ describe('init hook', () => {
|
|
|
40
42
|
expect(output).toContain('npx output update');
|
|
41
43
|
});
|
|
42
44
|
it('should not display anything when up to date', async () => {
|
|
43
|
-
vi.mocked(
|
|
45
|
+
vi.mocked(readCachedResult).mockResolvedValue({
|
|
44
46
|
updateAvailable: false,
|
|
45
47
|
currentVersion: '0.8.4',
|
|
46
48
|
latestVersion: '0.8.4'
|
|
47
49
|
});
|
|
48
50
|
const ctx = createHookContext();
|
|
49
51
|
await hook.call(ctx, { argv: [], id: undefined });
|
|
52
|
+
expect(spawnBackgroundRefresh).not.toHaveBeenCalled();
|
|
53
|
+
expect(ux.stdout).not.toHaveBeenCalled();
|
|
54
|
+
});
|
|
55
|
+
it('should kick off a background refresh and stay silent when the cache is stale', async () => {
|
|
56
|
+
vi.mocked(readCachedResult).mockResolvedValue(null);
|
|
57
|
+
const ctx = createHookContext();
|
|
58
|
+
await hook.call(ctx, { argv: [], id: undefined });
|
|
59
|
+
expect(spawnBackgroundRefresh).toHaveBeenCalledWith('0.8.4', '/tmp/test-cache');
|
|
50
60
|
expect(ux.stdout).not.toHaveBeenCalled();
|
|
51
61
|
});
|
|
52
62
|
it('should silently handle errors', async () => {
|
|
53
|
-
vi.mocked(
|
|
63
|
+
vi.mocked(readCachedResult).mockRejectedValue(new Error('cache failure'));
|
|
54
64
|
const ctx = createHookContext();
|
|
55
65
|
await hook.call(ctx, { argv: [], id: undefined });
|
|
56
66
|
expect(ux.stdout).not.toHaveBeenCalled();
|
|
@@ -58,7 +68,7 @@ describe('init hook', () => {
|
|
|
58
68
|
describe('global interactive flags', () => {
|
|
59
69
|
const originalArgv = process.argv;
|
|
60
70
|
beforeEach(() => {
|
|
61
|
-
vi.mocked(
|
|
71
|
+
vi.mocked(readCachedResult).mockResolvedValue({
|
|
62
72
|
updateAvailable: false,
|
|
63
73
|
currentVersion: '0.8.4',
|
|
64
74
|
latestVersion: '0.8.4'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Detached helper spawned by spawnBackgroundRefresh (version_check.ts):
|
|
2
|
+
// refreshes the version-check cache off the critical path.
|
|
3
|
+
// Args: <currentVersion> <cacheDir>
|
|
4
|
+
import debugFactory from 'debug';
|
|
5
|
+
import { bootstrapProxy } from '#utils/proxy.js';
|
|
6
|
+
import { runRefresh } from '#services/version_check.js';
|
|
7
|
+
const debug = debugFactory('output-cli:version-check');
|
|
8
|
+
await bootstrapProxy().catch(error => debug('Proxy bootstrap failed: %O', error));
|
|
9
|
+
process.exitCode = await runRefresh(process.argv);
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import type { TraceNode, LLMCall, HTTPCall,
|
|
1
|
+
import type { TraceNode, LLMCall, HTTPCall, PricingConfig, ServiceConfig, ServiceCostResult, CostReport } from '#types/cost.js';
|
|
2
2
|
export declare function extractValue(obj: unknown, path: string): unknown;
|
|
3
3
|
export declare function loadPricingConfig(configPath?: string): PricingConfig;
|
|
4
4
|
export declare function findLLMCalls(node: TraceNode, parentStepName?: string | null, seenIds?: Set<string>): LLMCall[];
|
|
5
5
|
export declare function findHTTPCalls(node: TraceNode, parentStepName?: string | null, seenIds?: Set<string>): HTTPCall[];
|
|
6
|
-
export declare function calculateLLMCallCost(usage: TokenUsage, modelPricing: ModelPricing | undefined): {
|
|
7
|
-
cost: number;
|
|
8
|
-
warning?: string;
|
|
9
|
-
};
|
|
10
6
|
export declare function identifyService(httpCall: HTTPCall, services: Record<string, ServiceConfig>): {
|
|
11
7
|
serviceName: string;
|
|
12
8
|
config: ServiceConfig;
|