pipeline-worker 0.1.26 → 0.1.28

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.
Files changed (56) hide show
  1. package/README.md +6 -2
  2. package/dist/agent/claude.js +32 -1
  3. package/dist/agent/claude.js.map +1 -1
  4. package/dist/agent/types.d.ts +18 -0
  5. package/dist/cli.js +30 -4
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config/loader.js +25 -3
  8. package/dist/config/loader.js.map +1 -1
  9. package/dist/forge/github.js +7 -0
  10. package/dist/forge/github.js.map +1 -1
  11. package/dist/forge/gitlab.js +7 -0
  12. package/dist/forge/gitlab.js.map +1 -1
  13. package/dist/forge/types.d.ts +9 -0
  14. package/dist/state/runState.d.ts +10 -1
  15. package/dist/state/runState.js +20 -2
  16. package/dist/state/runState.js.map +1 -1
  17. package/dist/types.d.ts +4 -0
  18. package/dist/ui/format.d.ts +19 -0
  19. package/dist/ui/format.js +89 -0
  20. package/dist/ui/format.js.map +1 -0
  21. package/dist/ui/renderer.d.ts +41 -0
  22. package/dist/ui/renderer.js +93 -0
  23. package/dist/ui/renderer.js.map +1 -0
  24. package/dist/ui/runTree.d.ts +106 -0
  25. package/dist/ui/runTree.js +133 -0
  26. package/dist/ui/runTree.js.map +1 -0
  27. package/dist/ui/sessions.js +11 -4
  28. package/dist/ui/sessions.js.map +1 -1
  29. package/dist/ui/steps.d.ts +92 -35
  30. package/dist/ui/steps.js +177 -93
  31. package/dist/ui/steps.js.map +1 -1
  32. package/dist/ui/treeRenderer.d.ts +89 -0
  33. package/dist/ui/treeRenderer.js +271 -0
  34. package/dist/ui/treeRenderer.js.map +1 -0
  35. package/dist/ui/welcome.js +15 -9
  36. package/dist/ui/welcome.js.map +1 -1
  37. package/dist/workflow/adoptBranch.js +16 -10
  38. package/dist/workflow/adoptBranch.js.map +1 -1
  39. package/dist/workflow/captureIntent.d.ts +7 -2
  40. package/dist/workflow/captureIntent.js +1 -25
  41. package/dist/workflow/captureIntent.js.map +1 -1
  42. package/dist/workflow/openMergeRequest.d.ts +1 -1
  43. package/dist/workflow/openMergeRequest.js +8 -7
  44. package/dist/workflow/openMergeRequest.js.map +1 -1
  45. package/dist/workflow/orchestrate.d.ts +1 -1
  46. package/dist/workflow/orchestrate.js +61 -39
  47. package/dist/workflow/orchestrate.js.map +1 -1
  48. package/dist/workflow/runPlan.d.ts +18 -0
  49. package/dist/workflow/runPlan.js +53 -0
  50. package/dist/workflow/runPlan.js.map +1 -0
  51. package/dist/workflow/syncTargetBranch.d.ts +37 -0
  52. package/dist/workflow/syncTargetBranch.js +83 -0
  53. package/dist/workflow/syncTargetBranch.js.map +1 -0
  54. package/dist/workflow/watchPipeline.js +61 -23
  55. package/dist/workflow/watchPipeline.js.map +1 -1
  56. package/package.json +1 -1
@@ -0,0 +1,89 @@
1
+ /** Shared human-readable formatting helpers for token/duration figures and output structure. */
2
+ import { styleText } from 'node:util';
3
+ /**
4
+ * Renders a token count the way the run header and session views show it:
5
+ * `949 tok`, `1.9k tok`, `41.2k tok`, `1.2M tok`. One decimal place above
6
+ * 1000, with a trailing `.0` trimmed so round figures read as `2k tok`, not
7
+ * `2.0k tok`.
8
+ */
9
+ export function formatTokens(tokens) {
10
+ if (!Number.isFinite(tokens) || tokens < 0)
11
+ return '? tok';
12
+ if (tokens < 1000)
13
+ return `${Math.round(tokens)} tok`;
14
+ const scaled = tokens < 1_000_000 ? { value: tokens / 1000, suffix: 'k' } : { value: tokens / 1_000_000, suffix: 'M' };
15
+ const text = scaled.value.toFixed(1).replace(/\.0$/, '');
16
+ return `${text}${scaled.suffix} tok`;
17
+ }
18
+ const BOX_WIDTH = 100;
19
+ function boxLine(content = '', width = BOX_WIDTH) {
20
+ if (!content)
21
+ return `│${' '.repeat(width - 2)}│`;
22
+ const padding = Math.max(0, width - content.length - 2);
23
+ return `│ ${content}${' '.repeat(padding)} │`;
24
+ }
25
+ export function boxTop() {
26
+ return `┌${`─`.repeat(BOX_WIDTH - 2)}┐`;
27
+ }
28
+ export function boxBottom() {
29
+ return `└${`─`.repeat(BOX_WIDTH - 2)}┘`;
30
+ }
31
+ export function boxHeader(text, emoji = '') {
32
+ const title = emoji ? `${emoji} ${text}` : text;
33
+ return [
34
+ boxTop(),
35
+ boxLine(styleText('bold', title)),
36
+ boxBottom(),
37
+ ];
38
+ }
39
+ export function boxBullet(label, value, indent = 0) {
40
+ const prefix = '• ';
41
+ const indentStr = ' '.repeat(indent);
42
+ const labelStr = label ? `${label.padEnd(12)}` : '';
43
+ return `${indentStr}${prefix}${labelStr}${value}`;
44
+ }
45
+ export function wrapText(text, maxWidth = BOX_WIDTH - 6, indent = 2) {
46
+ const lines = [];
47
+ const words = text.split(/\s+/);
48
+ let currentLine = '';
49
+ for (const word of words) {
50
+ const testLine = currentLine ? `${currentLine} ${word}` : word;
51
+ if (testLine.length <= maxWidth) {
52
+ currentLine = testLine;
53
+ }
54
+ else {
55
+ if (currentLine)
56
+ lines.push(currentLine);
57
+ currentLine = word.length > maxWidth ? word : word;
58
+ }
59
+ }
60
+ if (currentLine)
61
+ lines.push(currentLine);
62
+ return lines.map((line) => `${' '.repeat(indent)}${line}`);
63
+ }
64
+ /** Formats a multi-line block with wrapping for long text values. */
65
+ export function formatBulletBlock(items, indent = 2) {
66
+ const lines = [];
67
+ const maxLabelWidth = Math.max(...items.map((item) => item.label.length));
68
+ for (const item of items) {
69
+ const prefix = '• ';
70
+ const indentStr = ' '.repeat(indent);
71
+ const labelPad = item.label.padEnd(maxLabelWidth);
72
+ if (item.wrap && item.value.length > BOX_WIDTH - indent - prefix.length - maxLabelWidth - 5) {
73
+ // First line with label
74
+ lines.push(`${indentStr}${prefix}${labelPad} ${item.value.split('\n')[0]}`);
75
+ // Continuation lines
76
+ const continuationIndent = ' '.repeat(indent + prefix.length + maxLabelWidth + 2);
77
+ const wrapped = wrapText(item.value.substring(item.value.split('\n')[0].length), BOX_WIDTH - indent - 6, 0);
78
+ for (const line of wrapped) {
79
+ if (line.trim())
80
+ lines.push(`${continuationIndent}${line}`);
81
+ }
82
+ }
83
+ else {
84
+ lines.push(`${indentStr}${prefix}${labelPad} ${item.value}`);
85
+ }
86
+ }
87
+ return lines;
88
+ }
89
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/ui/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Rendering strategies for the run tree (ui/runTree.ts). Two implementations:
3
+ *
4
+ * - LineRenderer (here): append-only scrolled lines — used when stdout is not
5
+ * a TTY (CI logs, piped output) or when PIPELINE_WORKER_PLAIN_OUTPUT=true.
6
+ * Zero cursor movement; colors are applied via node:util's styleText, which
7
+ * already disables itself on non-color streams.
8
+ * - TreeRenderer (ui/treeRenderer.ts): the live TTY dashboard with a pinned
9
+ * bottom region.
10
+ *
11
+ * Renderers receive fine-grained TreeEvents from the facade (ui/steps.ts) and
12
+ * may ignore the granularity (TreeRenderer just repaints). log() is the one
13
+ * channel for freeform text — notes, agent output, warnings — so a renderer
14
+ * that owns the screen can route it above its pinned region.
15
+ */
16
+ import type { RunStatus, RunTree, StepNode, TreeEvent } from './runTree.js';
17
+ export interface Renderer {
18
+ onEvent(event: TreeEvent, tree: RunTree): void;
19
+ /** Freeform text outside the tree: notes, agent output, warnings. */
20
+ log(text: string): void;
21
+ /** Final paint for the run's terminal status; must leave the terminal usable. */
22
+ stop(status: RunStatus, detail: string | undefined, tree: RunTree): void;
23
+ }
24
+ export declare function formatElapsed(ms: number): string;
25
+ /** The parenthesized tail of a finished step: '(3.2s · 1.9k tok)', or '' when neither figure is known. */
26
+ export declare function formatStepFigures(node: StepNode): string;
27
+ /** 'attempt N/M' when both sides are known, else ''. */
28
+ export declare function formatAttempt(node: StepNode): string;
29
+ /**
30
+ * Append-only narration, one block per step: a bold start line with the
31
+ * detail beneath it, phase changes as indented arrows, and a colored
32
+ * ✓/✗/– settle line with duration and token figures. Mirrors the shape of
33
+ * the old numbered-stage output so non-TTY logs stay diffable and greppable.
34
+ */
35
+ export declare class LineRenderer implements Renderer {
36
+ private readonly out;
37
+ constructor(out?: (line: string) => void);
38
+ onEvent(event: TreeEvent): void;
39
+ log(text: string): void;
40
+ stop(status: RunStatus, detail: string | undefined, tree: RunTree): void;
41
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Rendering strategies for the run tree (ui/runTree.ts). Two implementations:
3
+ *
4
+ * - LineRenderer (here): append-only scrolled lines — used when stdout is not
5
+ * a TTY (CI logs, piped output) or when PIPELINE_WORKER_PLAIN_OUTPUT=true.
6
+ * Zero cursor movement; colors are applied via node:util's styleText, which
7
+ * already disables itself on non-color streams.
8
+ * - TreeRenderer (ui/treeRenderer.ts): the live TTY dashboard with a pinned
9
+ * bottom region.
10
+ *
11
+ * Renderers receive fine-grained TreeEvents from the facade (ui/steps.ts) and
12
+ * may ignore the granularity (TreeRenderer just repaints). log() is the one
13
+ * channel for freeform text — notes, agent output, warnings — so a renderer
14
+ * that owns the screen can route it above its pinned region.
15
+ */
16
+ import { styleText } from 'node:util';
17
+ import { formatTokens } from './format.js';
18
+ export function formatElapsed(ms) {
19
+ return `${(ms / 1000).toFixed(1)}s`;
20
+ }
21
+ /** The parenthesized tail of a finished step: '(3.2s · 1.9k tok)', or '' when neither figure is known. */
22
+ export function formatStepFigures(node) {
23
+ const parts = [];
24
+ if (node.durationMs !== undefined)
25
+ parts.push(formatElapsed(node.durationMs));
26
+ if (node.tokens !== undefined)
27
+ parts.push(formatTokens(node.tokens));
28
+ return parts.length > 0 ? ` (${parts.join(' · ')})` : '';
29
+ }
30
+ /** 'attempt N/M' when both sides are known, else ''. */
31
+ export function formatAttempt(node) {
32
+ return node.attempt !== undefined && node.maxAttempts !== undefined ? `attempt ${node.attempt}/${node.maxAttempts}` : '';
33
+ }
34
+ const FINISH_GLYPH = { done: '✓', failed: '✗', skipped: '–' };
35
+ const FINISH_COLOR = { done: 'green', failed: 'red', skipped: 'dim' };
36
+ const FINAL_LINE = {
37
+ done: '🎉 Done',
38
+ failed: '✗ Run failed',
39
+ escalated: '🚨 Stopped for human review',
40
+ interrupted: '⏹ Interrupted',
41
+ };
42
+ /**
43
+ * Append-only narration, one block per step: a bold start line with the
44
+ * detail beneath it, phase changes as indented arrows, and a colored
45
+ * ✓/✗/– settle line with duration and token figures. Mirrors the shape of
46
+ * the old numbered-stage output so non-TTY logs stay diffable and greppable.
47
+ */
48
+ export class LineRenderer {
49
+ out;
50
+ // The default defers the console.log lookup to call time (not construction),
51
+ // so a test — or the TreeRenderer's console interception — that swaps
52
+ // console.log after this renderer exists still receives the output.
53
+ constructor(out = (line) => console.log(line)) {
54
+ this.out = out;
55
+ }
56
+ onEvent(event) {
57
+ if (event.kind === 'start') {
58
+ const attempt = formatAttempt(event.node);
59
+ this.out('');
60
+ this.out(styleText(['bold', 'cyan'], `▶ ${event.node.label}${attempt ? ` — ${attempt}` : ''}`));
61
+ if (event.node.detail)
62
+ this.out(styleText('dim', ` ${event.node.detail}`));
63
+ return;
64
+ }
65
+ if (event.kind === 'update' && event.node.status === 'running' && event.node.detail) {
66
+ this.out(styleText('dim', ` → ${event.node.detail}`));
67
+ return;
68
+ }
69
+ if (event.kind === 'finish') {
70
+ const status = event.node.status;
71
+ const glyph = FINISH_GLYPH[status] ?? '?';
72
+ const skipTail = status === 'skipped' ? ' (skipped)' : '';
73
+ const detail = event.node.detail ? ` — ${event.node.detail}` : '';
74
+ this.out(styleText(FINISH_COLOR[status] ?? 'dim', `${glyph} ${event.node.label}${skipTail}${detail}${formatStepFigures(event.node)}`));
75
+ }
76
+ // 'add', 'tokens', and 'header' need no line of their own: tokens show on
77
+ // the finish line, and header changes only matter to the live dashboard.
78
+ }
79
+ log(text) {
80
+ this.out(text);
81
+ }
82
+ stop(status, detail, tree) {
83
+ if (status === 'running')
84
+ return;
85
+ const total = tree.totalTokens();
86
+ const tokensPart = total > 0 ? ` (${formatTokens(total)})` : '';
87
+ this.out('');
88
+ this.out(styleText('bold', `${FINAL_LINE[status]}${tokensPart}`));
89
+ if (detail)
90
+ this.out(styleText('dim', ` ${detail}`));
91
+ }
92
+ }
93
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/ui/renderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * The run's step tree: a pure in-memory data model of every workflow step,
3
+ * its status, timing, attempt counters, and best-effort token spend. This is
4
+ * what the renderers (ui/renderer.ts, ui/treeRenderer.ts) draw from — it
5
+ * contains no ANSI, no console access, and never throws: an unknown step id
6
+ * is auto-added as a top-level node rather than crashing the workflow (the
7
+ * UI must never kill a run — see CLAUDE.md's never-throw contracts).
8
+ *
9
+ * Step identity is a string id ('capture', 'ci-watch', 'ci-watch/fix-2').
10
+ * Ids replaced the old hard-coded stage numbers ([7/14]) because the watch
11
+ * loop grows children dynamically — fix attempts, rebases — and stable ids
12
+ * don't need renumbering when a step is inserted.
13
+ */
14
+ export type StepStatus = 'pending' | 'running' | 'done' | 'failed' | 'skipped';
15
+ /** The whole run's terminal status, shown in the header line. */
16
+ export type RunStatus = 'running' | 'done' | 'failed' | 'escalated' | 'interrupted';
17
+ export interface StepNode {
18
+ /** Unique within the tree; children conventionally use 'parent/child' ids. */
19
+ id: string;
20
+ /** Short name in the left column: 'capture', 'ci-watch', 'fix 2'. */
21
+ label: string;
22
+ /** Right-hand description; mutable while the step runs (phase updates). */
23
+ detail: string;
24
+ status: StepStatus;
25
+ /** Epoch ms when the step entered 'running'. */
26
+ startedAt?: number;
27
+ /** Set when the step finishes ('done'/'failed'). */
28
+ durationMs?: number;
29
+ /** Best-effort agent tokens attributed to this step; absent means unknown, never zero. */
30
+ tokens?: number;
31
+ /** Rendered as 'attempt N/M' when both are present. */
32
+ attempt?: number;
33
+ maxAttempts?: number;
34
+ children: StepNode[];
35
+ }
36
+ /** What a skeleton declares per step up front — everything else starts pending/empty. */
37
+ export interface StepSeed {
38
+ id: string;
39
+ label: string;
40
+ detail: string;
41
+ }
42
+ export interface RunHeader {
43
+ /** The run's name: initially generic, updated once intent names the branch. */
44
+ title: string;
45
+ /** Short worktree identifier (last hex chars of the temp-branch uuid). */
46
+ worktreeShortId?: string;
47
+ status: RunStatus;
48
+ }
49
+ export type TreeEvent = {
50
+ kind: 'add';
51
+ node: StepNode;
52
+ } | {
53
+ kind: 'start';
54
+ node: StepNode;
55
+ } | {
56
+ kind: 'finish';
57
+ node: StepNode;
58
+ } | {
59
+ kind: 'update';
60
+ node: StepNode;
61
+ } | {
62
+ kind: 'tokens';
63
+ node: StepNode;
64
+ } | {
65
+ kind: 'header';
66
+ };
67
+ /** One renderable row of the flattened tree: the node, its depth, and whether it is the last sibling at each ancestor level (for branch glyphs). */
68
+ export interface TreeRow {
69
+ node: StepNode;
70
+ depth: number;
71
+ /** isLast[d] — whether the chain through this row is the final sibling at depth d. Drives '├─' vs '└─' and '│' vs ' ' continuation. */
72
+ isLast: boolean[];
73
+ }
74
+ export declare class RunTree {
75
+ private readonly onChange;
76
+ readonly roots: StepNode[];
77
+ readonly header: RunHeader;
78
+ private readonly index;
79
+ /** Tokens spent before this tree existed (a resumed run's persisted total) — folded into totalTokens(). */
80
+ private seededTokens;
81
+ constructor(skeleton: StepSeed[], header: {
82
+ title: string;
83
+ worktreeShortId?: string;
84
+ }, onChange: (event: TreeEvent) => void);
85
+ private insert;
86
+ get(id: string): StepNode | undefined;
87
+ /**
88
+ * The never-throw guarantee: any operation on an id nobody declared falls
89
+ * back to materializing that id as a fresh top-level node, so the workflow
90
+ * keeps narrating instead of dying on a UI bookkeeping mismatch.
91
+ */
92
+ private getOrAdd;
93
+ /** Adds a child under parentId (or top-level when parentId is undefined). Adding an id that already exists is a no-op returning the existing node. */
94
+ add(parentId: string | undefined, seed: StepSeed, extras?: Partial<StepNode>): StepNode;
95
+ start(id: string, patch?: Partial<Pick<StepNode, 'detail' | 'attempt' | 'maxAttempts'>>): StepNode;
96
+ finish(id: string, status: 'done' | 'failed' | 'skipped', patch?: Partial<Pick<StepNode, 'detail'>>): StepNode;
97
+ update(id: string, patch: Partial<Pick<StepNode, 'detail' | 'attempt' | 'maxAttempts'>>): StepNode;
98
+ addTokens(id: string, tokens: number): void;
99
+ /** Registers tokens spent before this tree existed (a resumed run's persisted total). */
100
+ seedTokens(tokens: number): void;
101
+ setHeader(patch: Partial<RunHeader>): void;
102
+ /** The run's total spend: every node's tokens plus any seeded pre-resume total. */
103
+ totalTokens(): number;
104
+ /** Depth-first rows for rendering, with last-sibling flags per ancestor level for branch glyphs. */
105
+ flatten(): TreeRow[];
106
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * The run's step tree: a pure in-memory data model of every workflow step,
3
+ * its status, timing, attempt counters, and best-effort token spend. This is
4
+ * what the renderers (ui/renderer.ts, ui/treeRenderer.ts) draw from — it
5
+ * contains no ANSI, no console access, and never throws: an unknown step id
6
+ * is auto-added as a top-level node rather than crashing the workflow (the
7
+ * UI must never kill a run — see CLAUDE.md's never-throw contracts).
8
+ *
9
+ * Step identity is a string id ('capture', 'ci-watch', 'ci-watch/fix-2').
10
+ * Ids replaced the old hard-coded stage numbers ([7/14]) because the watch
11
+ * loop grows children dynamically — fix attempts, rebases — and stable ids
12
+ * don't need renumbering when a step is inserted.
13
+ */
14
+ export class RunTree {
15
+ onChange;
16
+ roots = [];
17
+ header;
18
+ index = new Map();
19
+ /** Tokens spent before this tree existed (a resumed run's persisted total) — folded into totalTokens(). */
20
+ seededTokens = 0;
21
+ constructor(skeleton, header, onChange) {
22
+ this.onChange = onChange;
23
+ this.header = { ...header, status: 'running' };
24
+ for (const seed of skeleton)
25
+ this.insert(undefined, seed);
26
+ }
27
+ insert(parent, seed, extras = {}) {
28
+ const node = { ...seed, status: 'pending', children: [], ...extras };
29
+ (parent ? parent.children : this.roots).push(node);
30
+ this.index.set(node.id, node);
31
+ return node;
32
+ }
33
+ get(id) {
34
+ return this.index.get(id);
35
+ }
36
+ /**
37
+ * The never-throw guarantee: any operation on an id nobody declared falls
38
+ * back to materializing that id as a fresh top-level node, so the workflow
39
+ * keeps narrating instead of dying on a UI bookkeeping mismatch.
40
+ */
41
+ getOrAdd(id) {
42
+ const existing = this.index.get(id);
43
+ if (existing)
44
+ return existing;
45
+ const node = this.insert(undefined, { id, label: id, detail: '' });
46
+ this.onChange({ kind: 'add', node });
47
+ return node;
48
+ }
49
+ /** Adds a child under parentId (or top-level when parentId is undefined). Adding an id that already exists is a no-op returning the existing node. */
50
+ add(parentId, seed, extras = {}) {
51
+ const existing = this.index.get(seed.id);
52
+ if (existing)
53
+ return existing;
54
+ const parent = parentId === undefined ? undefined : this.getOrAdd(parentId);
55
+ const node = this.insert(parent, seed, extras);
56
+ this.onChange({ kind: 'add', node });
57
+ return node;
58
+ }
59
+ start(id, patch = {}) {
60
+ const node = this.getOrAdd(id);
61
+ node.status = 'running';
62
+ node.startedAt = Date.now();
63
+ node.durationMs = undefined;
64
+ if (patch.detail !== undefined)
65
+ node.detail = patch.detail;
66
+ if (patch.attempt !== undefined)
67
+ node.attempt = patch.attempt;
68
+ if (patch.maxAttempts !== undefined)
69
+ node.maxAttempts = patch.maxAttempts;
70
+ this.onChange({ kind: 'start', node });
71
+ return node;
72
+ }
73
+ finish(id, status, patch = {}) {
74
+ const node = this.getOrAdd(id);
75
+ node.status = status;
76
+ if (node.startedAt !== undefined && status !== 'skipped')
77
+ node.durationMs = Date.now() - node.startedAt;
78
+ if (patch.detail !== undefined)
79
+ node.detail = patch.detail;
80
+ this.onChange({ kind: 'finish', node });
81
+ return node;
82
+ }
83
+ update(id, patch) {
84
+ const node = this.getOrAdd(id);
85
+ if (patch.detail !== undefined)
86
+ node.detail = patch.detail;
87
+ if (patch.attempt !== undefined)
88
+ node.attempt = patch.attempt;
89
+ if (patch.maxAttempts !== undefined)
90
+ node.maxAttempts = patch.maxAttempts;
91
+ this.onChange({ kind: 'update', node });
92
+ return node;
93
+ }
94
+ addTokens(id, tokens) {
95
+ if (!Number.isFinite(tokens) || tokens <= 0)
96
+ return;
97
+ const node = this.getOrAdd(id);
98
+ node.tokens = (node.tokens ?? 0) + tokens;
99
+ this.onChange({ kind: 'tokens', node });
100
+ }
101
+ /** Registers tokens spent before this tree existed (a resumed run's persisted total). */
102
+ seedTokens(tokens) {
103
+ if (!Number.isFinite(tokens) || tokens <= 0)
104
+ return;
105
+ this.seededTokens += tokens;
106
+ this.onChange({ kind: 'header' });
107
+ }
108
+ setHeader(patch) {
109
+ Object.assign(this.header, patch);
110
+ this.onChange({ kind: 'header' });
111
+ }
112
+ /** The run's total spend: every node's tokens plus any seeded pre-resume total. */
113
+ totalTokens() {
114
+ let total = this.seededTokens;
115
+ for (const node of this.index.values())
116
+ total += node.tokens ?? 0;
117
+ return total;
118
+ }
119
+ /** Depth-first rows for rendering, with last-sibling flags per ancestor level for branch glyphs. */
120
+ flatten() {
121
+ const rows = [];
122
+ const walk = (nodes, depth, ancestors) => {
123
+ nodes.forEach((node, i) => {
124
+ const isLast = [...ancestors, i === nodes.length - 1];
125
+ rows.push({ node, depth, isLast });
126
+ walk(node.children, depth + 1, isLast);
127
+ });
128
+ };
129
+ walk(this.roots, 0, []);
130
+ return rows;
131
+ }
132
+ }
133
+ //# sourceMappingURL=runTree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runTree.js","sourceRoot":"","sources":["../../src/ui/runTree.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@
4
4
  * narration style ui/steps.ts uses for a live run.
5
5
  */
6
6
  import { styleText } from 'node:util';
7
+ import { formatTokens } from './format.js';
7
8
  const PHASE_COLOR = {
8
9
  diff: 'dim',
9
10
  intent: 'dim',
@@ -25,12 +26,16 @@ function formatBranchColumn(branch) {
25
26
  function formatMrColumn(mrIid) {
26
27
  return mrIid !== undefined ? `#${mrIid}` : '-';
27
28
  }
29
+ /** '-' when the run's adapter never reported usage (pi/copilot, or a pre-token-accounting state file) — absence means unknown, never zero. */
30
+ function formatTokensColumn(totalTokens) {
31
+ return (totalTokens !== undefined ? formatTokens(totalTokens) : '-').padEnd(9);
32
+ }
28
33
  function formatSessionRow(session) {
29
34
  const { state } = session;
30
35
  const branch = formatBranchColumn(state.branch);
31
36
  const mr = formatMrColumn(state.mrIid);
32
37
  const attempts = `${String(state.ciFixAttempt).padEnd(6)} ${String(state.conflictAttempt).padEnd(8)}`;
33
- return `${branch} ${formatPhase(state.phase)} ${attempts} ${mr.padEnd(7)} ${formatTimestamp(state.updatedAt)}`;
38
+ return `${branch} ${formatPhase(state.phase)} ${attempts} ${mr.padEnd(7)} ${formatTokensColumn(state.totalTokens)} ${formatTimestamp(state.updatedAt)}`;
34
39
  }
35
40
  /** `pipeline-worker sessions` with no --branch: one line per persisted run, most recently updated first. */
36
41
  export function printSessionList(sessions) {
@@ -38,7 +43,7 @@ export function printSessionList(sessions) {
38
43
  console.log('pipeline-worker: no sessions found in this repo (.pipeline-worker/state/ is empty).');
39
44
  return;
40
45
  }
41
- console.log(styleText('bold', `${'BRANCH'.padEnd(40)} ${'PHASE'.padEnd(9)} CI-FIX CONFLICT MR/PR UPDATED`));
46
+ console.log(styleText('bold', `${'BRANCH'.padEnd(40)} ${'PHASE'.padEnd(9)} CI-FIX CONFLICT MR/PR ${'TOKENS'.padEnd(9)} UPDATED`));
42
47
  for (const session of sessions) {
43
48
  console.log(formatSessionRow(session));
44
49
  }
@@ -54,7 +59,8 @@ function formatOptionalMetaParts(state) {
54
59
  }
55
60
  function formatHistoryEntry(entry) {
56
61
  const message = entry.level === 'error' ? styleText('red', entry.message) : entry.message;
57
- return ` ${LEVEL_ICON[entry.level]} ${styleText('dim', formatTimestamp(entry.at))} ${styleText('dim', `[${entry.phase}]`)} ${message}`;
62
+ const tokensPart = entry.tokens !== undefined ? ` ${styleText('dim', ${formatTokens(entry.tokens)}`)}` : '';
63
+ return ` ${LEVEL_ICON[entry.level]} ${styleText('dim', formatTimestamp(entry.at))} ${styleText('dim', `[${entry.phase}]`)} ${message}${tokensPart}`;
58
64
  }
59
65
  /** `pipeline-worker sessions --branch <name>`: one run's metadata plus its full step-by-step history. */
60
66
  export function printSessionDetail(session) {
@@ -63,7 +69,8 @@ export function printSessionDetail(session) {
63
69
  console.log(styleText('bold', `Session: ${state.branch}`));
64
70
  console.log(styleText('dim', ` target: ${state.targetBranch}`));
65
71
  console.log(styleText('dim', ` worktree: ${state.worktreePath}`));
66
- console.log(styleText('dim', ` phase: ${state.phase} ci-fix: ${state.ciFixAttempt} conflict: ${state.conflictAttempt}${mrPart}${pipelinePart}`));
72
+ const tokensPart = state.totalTokens !== undefined ? ` tokens: ${formatTokens(state.totalTokens)}` : '';
73
+ console.log(styleText('dim', ` phase: ${state.phase} ci-fix: ${state.ciFixAttempt} conflict: ${state.conflictAttempt}${mrPart}${pipelinePart}${tokensPart}`));
67
74
  console.log(styleText('dim', ` started: ${formatTimestamp(state.startedAt)} updated: ${formatTimestamp(state.updatedAt)}`));
68
75
  const history = state.history ?? [];
69
76
  if (history.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/ui/sessions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/ui/sessions.ts"],"names":[],"mappings":"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"}