@outputai/cli 0.9.1-dev.000c5f3.0 → 0.9.1-dev.667788.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/dist/assets/docker/docker-compose-dev.yml +1 -1
- package/dist/generated/framework_version.json +1 -1
- package/dist/views/dev/dev_app.js +3 -17
- package/dist/views/dev/modals/steps_modal.js +1 -1
- package/dist/views/dev/panels/runs_panel.js +2 -7
- package/dist/views/dev/panels/workflows_panel.js +1 -1
- package/dist/views/dev/state/ui_state.d.ts +0 -8
- package/dist/views/dev/state/ui_state.js +1 -5
- package/oclif.manifest.json +1 -81
- package/package.json +4 -4
- package/dist/commands/workflow/history.d.ts +0 -19
- package/dist/commands/workflow/history.js +0 -99
- package/dist/commands/workflow/history.spec.d.ts +0 -1
- package/dist/commands/workflow/history.spec.js +0 -26
- package/dist/services/workflow_history/correlator.d.ts +0 -26
- package/dist/services/workflow_history/correlator.js +0 -261
- package/dist/services/workflow_history/correlator.spec.d.ts +0 -1
- package/dist/services/workflow_history/correlator.spec.js +0 -116
- package/dist/services/workflow_history.d.ts +0 -23
- package/dist/services/workflow_history.js +0 -79
- package/dist/services/workflow_history.spec.d.ts +0 -1
- package/dist/services/workflow_history.spec.js +0 -87
- package/dist/utils/span_labels.d.ts +0 -11
- package/dist/utils/span_labels.js +0 -22
- package/dist/utils/span_labels.spec.d.ts +0 -1
- package/dist/utils/span_labels.spec.js +0 -36
- package/dist/utils/waterfall.d.ts +0 -31
- package/dist/utils/waterfall.js +0 -192
- package/dist/utils/waterfall.spec.d.ts +0 -1
- package/dist/utils/waterfall.spec.js +0 -100
- package/dist/views/dev/hooks/use_step_graph.d.ts +0 -22
- package/dist/views/dev/hooks/use_step_graph.js +0 -76
- package/dist/views/dev/modals/step_graph_modal.d.ts +0 -6
- package/dist/views/dev/modals/step_graph_modal.js +0 -148
- /package/dist/views/dev/utils/{ui_constants.d.ts → constants.d.ts} +0 -0
- /package/dist/views/dev/utils/{ui_constants.js → constants.js} +0 -0
|
@@ -18,8 +18,7 @@ import { HELP_HINTS, HELP_SECTION_COUNT, HelpPanel } from '#views/dev/panels/hel
|
|
|
18
18
|
import { RunModal } from '#views/dev/modals/run_modal.js';
|
|
19
19
|
import { ExpandedJsonModal } from '#views/dev/modals/expanded_json_modal.js';
|
|
20
20
|
import { StepsModal } from '#views/dev/modals/steps_modal.js';
|
|
21
|
-
import {
|
|
22
|
-
import { MIN_TERMINAL_COLUMNS, MIN_TERMINAL_ROWS } from '#views/dev/utils/ui_constants.js';
|
|
21
|
+
import { MIN_TERMINAL_COLUMNS, MIN_TERMINAL_ROWS } from '#views/dev/utils/constants.js';
|
|
23
22
|
const TAB_NUMBER_KEYS = {
|
|
24
23
|
1: 'workflows',
|
|
25
24
|
2: 'runs',
|
|
@@ -66,7 +65,7 @@ const useGlobalInput = (opts) => {
|
|
|
66
65
|
.catch(err => exit(err instanceof Error ? err : new Error(String(err))));
|
|
67
66
|
return;
|
|
68
67
|
}
|
|
69
|
-
if (ui.search.open || ui.runModal.open || ui.expandedJson.open ||
|
|
68
|
+
if (ui.search.open || ui.runModal.open || ui.expandedJson.open || opts.runDetailOpen) {
|
|
70
69
|
return;
|
|
71
70
|
}
|
|
72
71
|
// Esc on a list view drops an active filter. Skip when we're on
|
|
@@ -134,14 +133,9 @@ const footerFor = (opts) => {
|
|
|
134
133
|
return { hints: HELP_HINTS, itemCount: HELP_SECTION_COUNT, itemLabel: 'sections' };
|
|
135
134
|
};
|
|
136
135
|
const overlayFor = (opts) => {
|
|
137
|
-
// expandedJson sits on top of everything — it's popped from another overlay
|
|
138
|
-
// (e.g. the step graph's `e`), so it must win when both are open.
|
|
139
136
|
if (opts.ui.expandedJson.open) {
|
|
140
137
|
return _jsx(ExpandedJsonModal, {});
|
|
141
138
|
}
|
|
142
|
-
if (opts.ui.stepGraph.open && opts.stepGraphRun) {
|
|
143
|
-
return _jsx(StepGraphModal, { run: opts.stepGraphRun, height: opts.rows });
|
|
144
|
-
}
|
|
145
139
|
if (opts.ui.runModal.open) {
|
|
146
140
|
return _jsx(RunModal, { workflowName: opts.ui.runModal.workflowName, workflowPath: opts.ui.runModal.workflowPath });
|
|
147
141
|
}
|
|
@@ -183,14 +177,6 @@ const Shell = ({ dockerComposePath, onCleanup }) => {
|
|
|
183
177
|
runs.find(r => r.runId === ui.selection.runId && r.workflowId === ui.selection.workflowId) :
|
|
184
178
|
undefined;
|
|
185
179
|
const runDetailOpen = ui.runsView === 'detail' && detailRun !== undefined;
|
|
186
|
-
// Re-resolve the step-graph run from the polled list each render so its
|
|
187
|
-
// status/duration stay live; fall back to the snapshot captured at open.
|
|
188
|
-
const stepGraphRun = useMemo(() => {
|
|
189
|
-
const captured = ui.stepGraph.open ? ui.stepGraph.run : null;
|
|
190
|
-
return captured ?
|
|
191
|
-
(runs.find(r => r.runId === captured.runId && r.workflowId === captured.workflowId) ?? captured) :
|
|
192
|
-
undefined;
|
|
193
|
-
}, [ui.stepGraph.open, ui.stepGraph.run, runs]);
|
|
194
180
|
useGlobalInput({ onCleanup, runDetailOpen });
|
|
195
181
|
const failingServices = useMemo(() => services.filter(isServiceFailed).length, [services]);
|
|
196
182
|
const serviceBadge = useMemo(() => {
|
|
@@ -224,7 +210,7 @@ const Shell = ({ dockerComposePath, onCleanup }) => {
|
|
|
224
210
|
serviceCount: services.length,
|
|
225
211
|
phase
|
|
226
212
|
});
|
|
227
|
-
const overlay = overlayFor({ ui, detailRun,
|
|
213
|
+
const overlay = overlayFor({ ui, detailRun, runDetailOpen, rows });
|
|
228
214
|
if (terminalTooSmall) {
|
|
229
215
|
return _jsx(TerminalTooSmall, { rows: rows, cols: cols });
|
|
230
216
|
}
|
|
@@ -9,7 +9,7 @@ import { useUiState } from '#views/dev/state/ui_state.js';
|
|
|
9
9
|
import { useRunDetail } from '#views/dev/hooks/use_run_detail.js';
|
|
10
10
|
import { JsonView } from '#views/dev/utils/json_render.js';
|
|
11
11
|
import { cycleValue, formatContentTitle, truncate, useListSelection } from '#views/dev/utils/panel_helpers.js';
|
|
12
|
-
import { RUN_DETAIL_VISIBLE_STEPS } from '#views/dev/utils/
|
|
12
|
+
import { RUN_DETAIL_VISIBLE_STEPS } from '#views/dev/utils/constants.js';
|
|
13
13
|
import { ContentTitle, getHeight as getContentTitleHeight } from '#views/dev/components/content_title.js';
|
|
14
14
|
import { MasterDetailPanel } from '#views/dev/components/master_detail_panel.js';
|
|
15
15
|
import { ModalFrame, getHeight as getModalFrameHeight } from '#views/dev/modals/modal_frame.js';
|
|
@@ -14,7 +14,7 @@ import { JsonView } from '#views/dev/utils/json_render.js';
|
|
|
14
14
|
import { RunInfoSidebar } from '#views/dev/components/run_info_sidebar.js';
|
|
15
15
|
import { MasterDetailPanel } from '#views/dev/components/master_detail_panel.js';
|
|
16
16
|
import { capitalize, cycleValue, formatContentTitle, formatStartedShort, hasJsonValue, truncate, useListSelection } from '#views/dev/utils/panel_helpers.js';
|
|
17
|
-
import { CATALOG_WORKFLOW_NAME, RUNS_VISIBLE_ROWS } from '#views/dev/utils/
|
|
17
|
+
import { CATALOG_WORKFLOW_NAME, RUNS_VISIBLE_ROWS } from '#views/dev/utils/constants.js';
|
|
18
18
|
const TEMPORAL_UI_BASE = 'http://localhost:8080';
|
|
19
19
|
const STATUS_ORDER = {
|
|
20
20
|
running: 0,
|
|
@@ -121,7 +121,6 @@ const DetailPane = ({ run, pane, rows }) => {
|
|
|
121
121
|
export const RUNS_HINTS = [
|
|
122
122
|
{ key: '↑/↓', label: 'navigate' },
|
|
123
123
|
{ key: 'enter', label: 'open' },
|
|
124
|
-
{ key: 'g', label: 'graph' },
|
|
125
124
|
{ key: '←/→', label: 'switch pane' },
|
|
126
125
|
{ key: 'e', label: 'expand' },
|
|
127
126
|
{ key: 'o', label: 'temporal' }
|
|
@@ -174,10 +173,6 @@ export const RunsPanel = ({ runs, height }) => {
|
|
|
174
173
|
ui.setRunsView('detail');
|
|
175
174
|
return;
|
|
176
175
|
}
|
|
177
|
-
if (input === 'g' && selectedRun?.workflowId) {
|
|
178
|
-
ui.openStepGraph(selectedRun);
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
176
|
if (key.leftArrow || key.rightArrow) {
|
|
182
177
|
ui.setRunListPaneTab(cycleValue(RUN_INFO_TAB_ORDER, ui.runListPaneTab, key.rightArrow ? 1 : -1));
|
|
183
178
|
return;
|
|
@@ -188,7 +183,7 @@ export const RunsPanel = ({ runs, height }) => {
|
|
|
188
183
|
const title = formatContentTitle(['Recent Runs', `Workflow "${selectedRun?.workflowType ?? ''}"`, capitalize(activePane)]);
|
|
189
184
|
ui.openExpandedJson(content, title);
|
|
190
185
|
}
|
|
191
|
-
}, { isActive: ui.tab === 'runs' && ui.runsView === 'list' && !ui.search.open
|
|
186
|
+
}, { isActive: ui.tab === 'runs' && ui.runsView === 'list' && !ui.search.open });
|
|
192
187
|
if (runs.length === 0) {
|
|
193
188
|
return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { dimColor: true, children: "No runs yet. Trigger one from the Workflows tab or with `output workflow run \u2026`." }) }));
|
|
194
189
|
}
|
|
@@ -8,7 +8,7 @@ import { SelectionIndicator } from '#views/dev/chrome/selection_indicator.js';
|
|
|
8
8
|
import { useUiState } from '#views/dev/state/ui_state.js';
|
|
9
9
|
import { MasterDetailPanel } from '#views/dev/components/master_detail_panel.js';
|
|
10
10
|
import { formatStartedShort, useListSelection } from '#views/dev/utils/panel_helpers.js';
|
|
11
|
-
import { WORKFLOWS_VISIBLE_ROWS, WORKFLOWS_RECENT_RUNS_LIMIT } from '#views/dev/utils/
|
|
11
|
+
import { WORKFLOWS_VISIBLE_ROWS, WORKFLOWS_RECENT_RUNS_LIMIT } from '#views/dev/utils/constants.js';
|
|
12
12
|
const COL = {
|
|
13
13
|
indicator: 3,
|
|
14
14
|
name: 30
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { WorkflowRun } from '#services/workflow_runs.js';
|
|
3
2
|
export type Tab = 'workflows' | 'runs' | 'services' | 'help';
|
|
4
3
|
export declare const TAB_ORDER: Tab[];
|
|
5
4
|
export declare const TAB_LABELS: Record<Tab, string>;
|
|
@@ -26,10 +25,6 @@ export interface ExpandedJsonState {
|
|
|
26
25
|
value: unknown;
|
|
27
26
|
title: string;
|
|
28
27
|
}
|
|
29
|
-
export interface StepGraphState {
|
|
30
|
-
open: boolean;
|
|
31
|
-
run: WorkflowRun | null;
|
|
32
|
-
}
|
|
33
28
|
export interface Toast {
|
|
34
29
|
id: number;
|
|
35
30
|
message: string;
|
|
@@ -45,7 +40,6 @@ export interface UiState {
|
|
|
45
40
|
runsView: RunsView;
|
|
46
41
|
runModal: RunModalState;
|
|
47
42
|
expandedJson: ExpandedJsonState;
|
|
48
|
-
stepGraph: StepGraphState;
|
|
49
43
|
toasts: Toast[];
|
|
50
44
|
setTab: (tab: Tab) => void;
|
|
51
45
|
nextTab: () => void;
|
|
@@ -62,8 +56,6 @@ export interface UiState {
|
|
|
62
56
|
closeRunModal: () => void;
|
|
63
57
|
openExpandedJson: (value: unknown, title: string) => void;
|
|
64
58
|
closeExpandedJson: () => void;
|
|
65
|
-
openStepGraph: (run: WorkflowRun) => void;
|
|
66
|
-
closeStepGraph: () => void;
|
|
67
59
|
pushToast: (message: string, tone?: Toast['tone']) => void;
|
|
68
60
|
dismissToast: (id: number) => void;
|
|
69
61
|
}
|
|
@@ -18,7 +18,6 @@ export const UiStateProvider = ({ children }) => {
|
|
|
18
18
|
const [runsView, setRunsView] = useState('list');
|
|
19
19
|
const [runModal, setRunModal] = useState({ open: false, workflowName: '' });
|
|
20
20
|
const [expandedJson, setExpandedJson] = useState({ open: false, value: null, title: '' });
|
|
21
|
-
const [stepGraph, setStepGraph] = useState({ open: false, run: null });
|
|
22
21
|
const [toasts, setToasts] = useState([]);
|
|
23
22
|
const toastIdRef = useRef(0);
|
|
24
23
|
const value = useMemo(() => ({
|
|
@@ -30,7 +29,6 @@ export const UiStateProvider = ({ children }) => {
|
|
|
30
29
|
runsView,
|
|
31
30
|
runModal,
|
|
32
31
|
expandedJson,
|
|
33
|
-
stepGraph,
|
|
34
32
|
toasts,
|
|
35
33
|
setTab: next => {
|
|
36
34
|
setTab(current => {
|
|
@@ -66,14 +64,12 @@ export const UiStateProvider = ({ children }) => {
|
|
|
66
64
|
closeRunModal: () => setRunModal({ open: false, workflowName: '' }),
|
|
67
65
|
openExpandedJson: (value, title) => setExpandedJson({ open: true, value, title }),
|
|
68
66
|
closeExpandedJson: () => setExpandedJson({ open: false, value: null, title: '' }),
|
|
69
|
-
openStepGraph: (run) => setStepGraph({ open: true, run }),
|
|
70
|
-
closeStepGraph: () => setStepGraph({ open: false, run: null }),
|
|
71
67
|
pushToast: (message, tone = 'info') => {
|
|
72
68
|
const id = ++toastIdRef.current;
|
|
73
69
|
setToasts(prev => [...prev, { id, message, tone }].slice(-MAX_VISIBLE_TOASTS));
|
|
74
70
|
},
|
|
75
71
|
dismissToast: (id) => setToasts(prev => prev.filter(t => t.id !== id))
|
|
76
|
-
}), [tab, search, selection, runListPaneTab, runStepPaneTab, runsView, runModal, expandedJson,
|
|
72
|
+
}), [tab, search, selection, runListPaneTab, runStepPaneTab, runsView, runModal, expandedJson, toasts]);
|
|
77
73
|
return _jsx(UiStateContext.Provider, { value: value, children: children });
|
|
78
74
|
};
|
|
79
75
|
export const useUiState = () => {
|
package/oclif.manifest.json
CHANGED
|
@@ -682,86 +682,6 @@
|
|
|
682
682
|
"generate.js"
|
|
683
683
|
]
|
|
684
684
|
},
|
|
685
|
-
"workflow:history": {
|
|
686
|
-
"aliases": [],
|
|
687
|
-
"args": {
|
|
688
|
-
"workflowId": {
|
|
689
|
-
"description": "The workflow ID to show history for",
|
|
690
|
-
"name": "workflowId",
|
|
691
|
-
"required": true
|
|
692
|
-
}
|
|
693
|
-
},
|
|
694
|
-
"description": "Show a workflow run's step timeline as a waterfall (durations and start times)",
|
|
695
|
-
"examples": [
|
|
696
|
-
"<%= config.bin %> <%= command.id %> wf-12345",
|
|
697
|
-
"<%= config.bin %> <%= command.id %> wf-12345 --run-id 2fe0b36b-...",
|
|
698
|
-
"<%= config.bin %> <%= command.id %> wf-12345 --format json",
|
|
699
|
-
"<%= config.bin %> <%= command.id %> wf-12345 --raw --include-payloads"
|
|
700
|
-
],
|
|
701
|
-
"flags": {
|
|
702
|
-
"run-id": {
|
|
703
|
-
"char": "r",
|
|
704
|
-
"description": "Show a specific run (defaults to the latest run)",
|
|
705
|
-
"name": "run-id",
|
|
706
|
-
"hasDynamicHelp": false,
|
|
707
|
-
"multiple": false,
|
|
708
|
-
"type": "option"
|
|
709
|
-
},
|
|
710
|
-
"format": {
|
|
711
|
-
"char": "f",
|
|
712
|
-
"description": "Output format",
|
|
713
|
-
"name": "format",
|
|
714
|
-
"default": "text",
|
|
715
|
-
"hasDynamicHelp": false,
|
|
716
|
-
"multiple": false,
|
|
717
|
-
"options": [
|
|
718
|
-
"text",
|
|
719
|
-
"json"
|
|
720
|
-
],
|
|
721
|
-
"type": "option"
|
|
722
|
-
},
|
|
723
|
-
"raw": {
|
|
724
|
-
"description": "Print the history endpoint's raw response (workflow + events)",
|
|
725
|
-
"name": "raw",
|
|
726
|
-
"allowNo": false,
|
|
727
|
-
"type": "boolean"
|
|
728
|
-
},
|
|
729
|
-
"include-payloads": {
|
|
730
|
-
"description": "Include decoded step input/output payloads",
|
|
731
|
-
"name": "include-payloads",
|
|
732
|
-
"allowNo": false,
|
|
733
|
-
"type": "boolean"
|
|
734
|
-
},
|
|
735
|
-
"width": {
|
|
736
|
-
"description": "Override the detected terminal width",
|
|
737
|
-
"name": "width",
|
|
738
|
-
"hasDynamicHelp": false,
|
|
739
|
-
"multiple": false,
|
|
740
|
-
"type": "option"
|
|
741
|
-
},
|
|
742
|
-
"color": {
|
|
743
|
-
"description": "Colorize the waterfall (use --no-color to disable)",
|
|
744
|
-
"name": "color",
|
|
745
|
-
"allowNo": true,
|
|
746
|
-
"type": "boolean"
|
|
747
|
-
}
|
|
748
|
-
},
|
|
749
|
-
"hasDynamicHelp": false,
|
|
750
|
-
"hiddenAliases": [],
|
|
751
|
-
"id": "workflow:history",
|
|
752
|
-
"pluginAlias": "@outputai/cli",
|
|
753
|
-
"pluginName": "@outputai/cli",
|
|
754
|
-
"pluginType": "core",
|
|
755
|
-
"strict": true,
|
|
756
|
-
"enableJsonFlag": false,
|
|
757
|
-
"isESM": true,
|
|
758
|
-
"relativePath": [
|
|
759
|
-
"dist",
|
|
760
|
-
"commands",
|
|
761
|
-
"workflow",
|
|
762
|
-
"history.js"
|
|
763
|
-
]
|
|
764
|
-
},
|
|
765
685
|
"workflow:list": {
|
|
766
686
|
"aliases": [],
|
|
767
687
|
"args": {},
|
|
@@ -1534,5 +1454,5 @@
|
|
|
1534
1454
|
]
|
|
1535
1455
|
}
|
|
1536
1456
|
},
|
|
1537
|
-
"version": "0.9.1-dev.
|
|
1457
|
+
"version": "0.9.1-dev.667788.0"
|
|
1538
1458
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@outputai/cli",
|
|
3
|
-
"version": "0.9.1-dev.
|
|
3
|
+
"version": "0.9.1-dev.667788.0",
|
|
4
4
|
"description": "CLI for Output.ai workflow generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"semver": "7.7.4",
|
|
37
37
|
"undici": "8.5.0",
|
|
38
38
|
"yaml": "^2.8.3",
|
|
39
|
-
"@outputai/
|
|
40
|
-
"@outputai/
|
|
41
|
-
"@outputai/
|
|
39
|
+
"@outputai/credentials": "0.9.1-dev.667788.0",
|
|
40
|
+
"@outputai/evals": "0.9.1-dev.667788.0",
|
|
41
|
+
"@outputai/llm": "0.9.1-dev.667788.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/cli-progress": "3.11.6",
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
2
|
-
export default class WorkflowHistory extends Command {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static args: {
|
|
6
|
-
workflowId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
-
};
|
|
8
|
-
static flags: {
|
|
9
|
-
'run-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
-
raw: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
-
'include-payloads': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
-
width: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
-
color: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
-
};
|
|
16
|
-
run(): Promise<void>;
|
|
17
|
-
private buildHeader;
|
|
18
|
-
catch(error: Error): Promise<void>;
|
|
19
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
-
import { fetchWorkflowHistory } from '#services/workflow_history.js';
|
|
3
|
-
import buildSpanLabels from '#utils/span_labels.js';
|
|
4
|
-
import renderWaterfall, { formatDurationLabel } from '#utils/waterfall.js';
|
|
5
|
-
import { handleApiError } from '#utils/error_handler.js';
|
|
6
|
-
const DEFAULT_WIDTH = 80;
|
|
7
|
-
const OUTPUT_FORMAT = { JSON: 'json', TEXT: 'text' };
|
|
8
|
-
export default class WorkflowHistory extends Command {
|
|
9
|
-
static description = 'Show a workflow run\'s step timeline as a waterfall (durations and start times)';
|
|
10
|
-
static examples = [
|
|
11
|
-
'<%= config.bin %> <%= command.id %> wf-12345',
|
|
12
|
-
'<%= config.bin %> <%= command.id %> wf-12345 --run-id 2fe0b36b-...',
|
|
13
|
-
'<%= config.bin %> <%= command.id %> wf-12345 --format json',
|
|
14
|
-
'<%= config.bin %> <%= command.id %> wf-12345 --raw --include-payloads'
|
|
15
|
-
];
|
|
16
|
-
static args = {
|
|
17
|
-
workflowId: Args.string({
|
|
18
|
-
description: 'The workflow ID to show history for',
|
|
19
|
-
required: true
|
|
20
|
-
})
|
|
21
|
-
};
|
|
22
|
-
static flags = {
|
|
23
|
-
'run-id': Flags.string({
|
|
24
|
-
char: 'r',
|
|
25
|
-
description: 'Show a specific run (defaults to the latest run)'
|
|
26
|
-
}),
|
|
27
|
-
format: Flags.string({
|
|
28
|
-
char: 'f',
|
|
29
|
-
description: 'Output format',
|
|
30
|
-
options: [OUTPUT_FORMAT.TEXT, OUTPUT_FORMAT.JSON],
|
|
31
|
-
default: OUTPUT_FORMAT.TEXT
|
|
32
|
-
}),
|
|
33
|
-
raw: Flags.boolean({
|
|
34
|
-
description: 'Print the history endpoint\'s raw response (workflow + events)',
|
|
35
|
-
default: false
|
|
36
|
-
}),
|
|
37
|
-
'include-payloads': Flags.boolean({
|
|
38
|
-
description: 'Include decoded step input/output payloads',
|
|
39
|
-
default: false
|
|
40
|
-
}),
|
|
41
|
-
width: Flags.integer({
|
|
42
|
-
description: 'Override the detected terminal width'
|
|
43
|
-
}),
|
|
44
|
-
color: Flags.boolean({
|
|
45
|
-
description: 'Colorize the waterfall (use --no-color to disable)',
|
|
46
|
-
default: true,
|
|
47
|
-
allowNo: true
|
|
48
|
-
})
|
|
49
|
-
};
|
|
50
|
-
async run() {
|
|
51
|
-
const { args, flags } = await this.parse(WorkflowHistory);
|
|
52
|
-
const result = await fetchWorkflowHistory({
|
|
53
|
-
workflowId: args.workflowId,
|
|
54
|
-
runId: flags['run-id'],
|
|
55
|
-
includePayloads: flags['include-payloads']
|
|
56
|
-
});
|
|
57
|
-
if (flags.raw) {
|
|
58
|
-
this.log(JSON.stringify({
|
|
59
|
-
workflow: result.workflow,
|
|
60
|
-
runId: result.runId,
|
|
61
|
-
events: result.events
|
|
62
|
-
}, null, 2));
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (flags.format === OUTPUT_FORMAT.JSON) {
|
|
66
|
-
this.log(JSON.stringify({
|
|
67
|
-
workflow: result.workflow,
|
|
68
|
-
runId: result.runId,
|
|
69
|
-
totalDurationMs: result.totalDurationMs,
|
|
70
|
-
spans: result.spans
|
|
71
|
-
}, null, 2));
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
const labels = buildSpanLabels(result.spans);
|
|
75
|
-
const width = flags.width ?? process.stdout.columns ?? DEFAULT_WIDTH;
|
|
76
|
-
const color = flags.color && !process.env.NO_COLOR &&
|
|
77
|
-
(!!process.env.FORCE_COLOR || process.stdout.isTTY === true);
|
|
78
|
-
this.log(renderWaterfall(result.spans, result.totalDurationMs, {
|
|
79
|
-
width,
|
|
80
|
-
color,
|
|
81
|
-
labels,
|
|
82
|
-
header: this.buildHeader(args.workflowId, result.runId, result.workflow?.status, result.totalDurationMs)
|
|
83
|
-
}));
|
|
84
|
-
// Failure reasons live in the payloads the server strips by default, so a
|
|
85
|
-
// failed run shows red bars but no messages until payloads are requested.
|
|
86
|
-
if (!flags['include-payloads'] && result.spans.some(span => span.status === 'failed')) {
|
|
87
|
-
this.log('\nSome steps failed — re-run with --include-payloads to see their error messages.');
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
buildHeader(workflowId, runId, status, totalDurationMs) {
|
|
91
|
-
const shortRun = runId ? runId.slice(0, 8) : 'unknown';
|
|
92
|
-
return `${workflowId} · run ${shortRun} · ${status ?? 'unknown'} · ${formatDurationLabel(totalDurationMs)}`;
|
|
93
|
-
}
|
|
94
|
-
async catch(error) {
|
|
95
|
-
return handleApiError(error, (...args) => this.error(...args), {
|
|
96
|
-
404: 'Workflow not found. Check the workflow ID.'
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
// Isolate the command module from the API/service layer at import time.
|
|
3
|
-
vi.mock('../../services/workflow_history.js', () => ({
|
|
4
|
-
fetchWorkflowHistory: vi.fn()
|
|
5
|
-
}));
|
|
6
|
-
describe('workflow history command', () => {
|
|
7
|
-
it('exports a valid OCLIF command with a workflowId arg', async () => {
|
|
8
|
-
const WorkflowHistory = (await import('./history.js')).default;
|
|
9
|
-
expect(WorkflowHistory).toBeDefined();
|
|
10
|
-
expect(WorkflowHistory.description).toContain('waterfall');
|
|
11
|
-
expect(WorkflowHistory.args).toHaveProperty('workflowId');
|
|
12
|
-
expect(WorkflowHistory.args.workflowId.required).toBe(true);
|
|
13
|
-
});
|
|
14
|
-
it('declares the expected flags and defaults', async () => {
|
|
15
|
-
const WorkflowHistory = (await import('./history.js')).default;
|
|
16
|
-
const flags = WorkflowHistory.flags;
|
|
17
|
-
expect(flags).toHaveProperty('run-id');
|
|
18
|
-
expect(flags).toHaveProperty('raw');
|
|
19
|
-
expect(flags).toHaveProperty('include-payloads');
|
|
20
|
-
expect(flags).toHaveProperty('color');
|
|
21
|
-
expect(flags).toHaveProperty('width');
|
|
22
|
-
expect(flags.format.options).toEqual(['text', 'json']);
|
|
23
|
-
expect(flags.format.default).toBe('text');
|
|
24
|
-
expect(flags.raw.default).toBe(false);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export type SpanStatus = 'pending' | 'running' | 'completed' | 'failed';
|
|
2
|
-
export type SpanKind = 'activity' | 'child_workflow';
|
|
3
|
-
export interface Span {
|
|
4
|
-
id: string;
|
|
5
|
-
name: string;
|
|
6
|
-
technicalName: string;
|
|
7
|
-
description: string | null;
|
|
8
|
-
status: SpanStatus;
|
|
9
|
-
kind: SpanKind;
|
|
10
|
-
attempt: number;
|
|
11
|
-
startedAt: string | null;
|
|
12
|
-
scheduledAt: string | null;
|
|
13
|
-
completedAt: string | null;
|
|
14
|
-
startOffsetMs: number;
|
|
15
|
-
endOffsetMs: number;
|
|
16
|
-
durationMs: number;
|
|
17
|
-
failureMessage: string | null;
|
|
18
|
-
input?: unknown;
|
|
19
|
-
output?: unknown;
|
|
20
|
-
}
|
|
21
|
-
export type HistoryEvent = Record<string, unknown>;
|
|
22
|
-
/**
|
|
23
|
-
* @param events - flat Temporal history events, in chronological order
|
|
24
|
-
* @param workflowStartTimeMs - epoch ms used as the timeline origin (0 offset)
|
|
25
|
-
*/
|
|
26
|
-
export declare function correlate(events: HistoryEvent[], workflowStartTimeMs: number | null): Span[];
|