wiggum-cli 0.16.0 → 0.17.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.
Files changed (97) hide show
  1. package/bin/ralph.js +0 -0
  2. package/dist/agent/memory/ingest.d.ts +14 -0
  3. package/dist/agent/memory/ingest.js +77 -0
  4. package/dist/agent/memory/store.d.ts +15 -0
  5. package/dist/agent/memory/store.js +98 -0
  6. package/dist/agent/memory/types.d.ts +16 -0
  7. package/dist/agent/memory/types.js +14 -0
  8. package/dist/agent/orchestrator.d.ts +7 -0
  9. package/dist/agent/orchestrator.js +266 -0
  10. package/dist/agent/resolve-config.d.ts +26 -0
  11. package/dist/agent/resolve-config.js +43 -0
  12. package/dist/agent/tools/backlog.d.ts +27 -0
  13. package/dist/agent/tools/backlog.js +51 -0
  14. package/dist/agent/tools/dry-run.d.ts +106 -0
  15. package/dist/agent/tools/dry-run.js +119 -0
  16. package/dist/agent/tools/execution.d.ts +51 -0
  17. package/dist/agent/tools/execution.js +256 -0
  18. package/dist/agent/tools/feature-state.d.ts +43 -0
  19. package/dist/agent/tools/feature-state.js +184 -0
  20. package/dist/agent/tools/introspection.d.ts +23 -0
  21. package/dist/agent/tools/introspection.js +40 -0
  22. package/dist/agent/tools/memory.d.ts +44 -0
  23. package/dist/agent/tools/memory.js +99 -0
  24. package/dist/agent/tools/preflight.d.ts +7 -0
  25. package/dist/agent/tools/preflight.js +137 -0
  26. package/dist/agent/tools/reporting.d.ts +58 -0
  27. package/dist/agent/tools/reporting.js +119 -0
  28. package/dist/agent/tools/schemas.d.ts +2 -0
  29. package/dist/agent/tools/schemas.js +3 -0
  30. package/dist/agent/types.d.ts +45 -0
  31. package/dist/agent/types.js +1 -0
  32. package/dist/ai/conversation/conversation-manager.js +8 -0
  33. package/dist/ai/conversation/url-fetcher.js +27 -0
  34. package/dist/ai/providers.js +5 -5
  35. package/dist/commands/agent.d.ts +17 -0
  36. package/dist/commands/agent.js +114 -0
  37. package/dist/commands/monitor.js +50 -183
  38. package/dist/commands/new-auto.d.ts +15 -0
  39. package/dist/commands/new-auto.js +237 -0
  40. package/dist/commands/run.js +20 -10
  41. package/dist/commands/sync.d.ts +15 -0
  42. package/dist/commands/sync.js +68 -0
  43. package/dist/generator/config.d.ts +1 -41
  44. package/dist/generator/config.js +7 -0
  45. package/dist/generator/index.d.ts +2 -2
  46. package/dist/generator/templates.d.ts +2 -0
  47. package/dist/generator/templates.js +9 -1
  48. package/dist/index.d.ts +1 -1
  49. package/dist/index.js +115 -4
  50. package/dist/repl/command-parser.d.ts +5 -0
  51. package/dist/repl/command-parser.js +5 -0
  52. package/dist/templates/prompts/PROMPT.md.tmpl +13 -10
  53. package/dist/templates/prompts/PROMPT_e2e.md.tmpl +13 -7
  54. package/dist/templates/prompts/PROMPT_feature.md.tmpl +16 -3
  55. package/dist/templates/prompts/PROMPT_review_auto.md.tmpl +32 -12
  56. package/dist/templates/prompts/PROMPT_review_manual.md.tmpl +4 -1
  57. package/dist/templates/prompts/PROMPT_review_merge.md.tmpl +39 -14
  58. package/dist/templates/prompts/PROMPT_verify.md.tmpl +5 -2
  59. package/dist/templates/scripts/feature-loop.sh.tmpl +441 -69
  60. package/dist/tui/app.d.ts +19 -2
  61. package/dist/tui/app.js +22 -4
  62. package/dist/tui/components/IssuePicker.d.ts +27 -0
  63. package/dist/tui/components/IssuePicker.js +64 -0
  64. package/dist/tui/components/RunCompletionSummary.js +6 -3
  65. package/dist/tui/hooks/useAgentOrchestrator.d.ts +29 -0
  66. package/dist/tui/hooks/useAgentOrchestrator.js +453 -0
  67. package/dist/tui/orchestration/interview-orchestrator.d.ts +5 -1
  68. package/dist/tui/orchestration/interview-orchestrator.js +27 -6
  69. package/dist/tui/screens/AgentScreen.d.ts +21 -0
  70. package/dist/tui/screens/AgentScreen.js +159 -0
  71. package/dist/tui/screens/InitScreen.js +4 -0
  72. package/dist/tui/screens/InterviewScreen.d.ts +3 -1
  73. package/dist/tui/screens/InterviewScreen.js +146 -10
  74. package/dist/tui/screens/MainShell.d.ts +1 -1
  75. package/dist/tui/screens/MainShell.js +36 -1
  76. package/dist/tui/screens/RunScreen.js +38 -6
  77. package/dist/tui/utils/build-run-summary.d.ts +1 -1
  78. package/dist/tui/utils/build-run-summary.js +40 -84
  79. package/dist/tui/utils/clear-screen.d.ts +14 -0
  80. package/dist/tui/utils/clear-screen.js +16 -0
  81. package/dist/tui/utils/loop-status.d.ts +41 -1
  82. package/dist/tui/utils/loop-status.js +243 -35
  83. package/dist/tui/utils/pr-summary.d.ts +3 -2
  84. package/dist/tui/utils/pr-summary.js +41 -6
  85. package/dist/utils/config.d.ts +8 -0
  86. package/dist/utils/config.js +8 -0
  87. package/dist/utils/github.d.ts +32 -0
  88. package/dist/utils/github.js +106 -0
  89. package/package.json +4 -1
  90. package/src/templates/prompts/PROMPT.md.tmpl +13 -10
  91. package/src/templates/prompts/PROMPT_e2e.md.tmpl +13 -7
  92. package/src/templates/prompts/PROMPT_feature.md.tmpl +16 -3
  93. package/src/templates/prompts/PROMPT_review_auto.md.tmpl +32 -12
  94. package/src/templates/prompts/PROMPT_review_manual.md.tmpl +4 -1
  95. package/src/templates/prompts/PROMPT_review_merge.md.tmpl +39 -14
  96. package/src/templates/prompts/PROMPT_verify.md.tmpl +5 -2
  97. package/src/templates/scripts/feature-loop.sh.tmpl +441 -69
package/dist/tui/app.d.ts CHANGED
@@ -16,7 +16,7 @@ import type { SessionState } from '../repl/session-state.js';
16
16
  /**
17
17
  * Available screen types for the App component
18
18
  */
19
- export type AppScreen = 'shell' | 'interview' | 'init' | 'run';
19
+ export type AppScreen = 'shell' | 'interview' | 'init' | 'run' | 'agent';
20
20
  /**
21
21
  * Props for the interview screen
22
22
  */
@@ -31,6 +31,19 @@ export interface InterviewAppProps {
31
31
  model: string;
32
32
  /** Optional scan result with detected tech stack */
33
33
  scanResult?: ScanResult;
34
+ /** References to auto-add during context phase (from CLI --issue/--context flags) */
35
+ initialReferences?: string[];
36
+ }
37
+ /**
38
+ * Props for the agent screen when launched directly from CLI
39
+ */
40
+ export interface AgentAppProps {
41
+ modelOverride?: string;
42
+ maxItems?: number;
43
+ maxSteps?: number;
44
+ labels?: string[];
45
+ reviewMode?: 'manual' | 'auto' | 'merge';
46
+ dryRun?: boolean;
34
47
  }
35
48
  /**
36
49
  * Props for the run/monitor screen when launched directly from CLI
@@ -57,6 +70,8 @@ export interface AppProps {
57
70
  interviewProps?: InterviewAppProps;
58
71
  /** Props for the run/monitor screen (required when screen is 'run') */
59
72
  runProps?: RunAppProps;
73
+ /** Props for the agent screen (required when screen is 'agent') */
74
+ agentProps?: AgentAppProps;
60
75
  /** Called when the screen completes successfully */
61
76
  onComplete?: (result: string) => void;
62
77
  /** Called when the user exits/cancels */
@@ -69,7 +84,7 @@ export interface AppProps {
69
84
  * and receives a shared headerElement prop.
70
85
  */
71
86
  export declare function App({ screen: initialScreen, initialSessionState, version, // Fallback if package.json read fails (keep in sync with index.ts)
72
- interviewProps, runProps, onComplete, onExit, }: AppProps): React.ReactElement | null;
87
+ interviewProps, runProps, agentProps, onComplete, onExit, }: AppProps): React.ReactElement | null;
73
88
  /**
74
89
  * Render options for renderApp
75
90
  */
@@ -84,6 +99,8 @@ export interface RenderAppOptions {
84
99
  interviewProps?: InterviewAppProps;
85
100
  /** Props for run/monitor screen (if starting directly on run screen) */
86
101
  runProps?: RunAppProps;
102
+ /** Props for agent screen (if starting directly on agent screen) */
103
+ agentProps?: AgentAppProps;
87
104
  /** Called when spec generation completes */
88
105
  onComplete?: (result: string) => void;
89
106
  /** Called when user exits */
package/dist/tui/app.js CHANGED
@@ -19,6 +19,7 @@ import { logger } from '../utils/logger.js';
19
19
  import { InterviewScreen } from './screens/InterviewScreen.js';
20
20
  import { InitScreen } from './screens/InitScreen.js';
21
21
  import { RunScreen } from './screens/RunScreen.js';
22
+ import { AgentScreen } from './screens/AgentScreen.js';
22
23
  import { MainShell } from './screens/MainShell.js';
23
24
  import { HeaderContent } from './components/HeaderContent.js';
24
25
  import { useBackgroundRuns } from './hooks/useBackgroundRuns.js';
@@ -29,7 +30,7 @@ import { useBackgroundRuns } from './hooks/useBackgroundRuns.js';
29
30
  * and receives a shared headerElement prop.
30
31
  */
31
32
  export function App({ screen: initialScreen, initialSessionState, version = '0.12.1', // Fallback if package.json read fails (keep in sync with index.ts)
32
- interviewProps, runProps, onComplete, onExit, }) {
33
+ interviewProps, runProps, agentProps, onComplete, onExit, }) {
33
34
  const [currentScreen, setCurrentScreen] = useState(initialScreen);
34
35
  const [screenProps, setScreenProps] = useState(() => {
35
36
  if (initialScreen === 'run' && runProps) {
@@ -184,7 +185,7 @@ interviewProps, runProps, onComplete, onExit, }) {
184
185
  navigate('shell', { message: 'Feature name is required for the run screen.' });
185
186
  }
186
187
  }
187
- else if (currentScreen !== 'shell' && currentScreen !== 'init') {
188
+ else if (currentScreen !== 'shell' && currentScreen !== 'init' && currentScreen !== 'agent') {
188
189
  // Unknown screen — redirect to shell on next tick
189
190
  navigate('shell', { message: `Internal error: unknown screen "${currentScreen}". Returned to shell.` });
190
191
  }
@@ -198,7 +199,7 @@ interviewProps, runProps, onComplete, onExit, }) {
198
199
  if (!featureName || typeof featureName !== 'string' || !sessionState.provider) {
199
200
  return null; // useEffect will redirect to shell
200
201
  }
201
- return (_jsx(InterviewScreen, { header: headerElement, featureName: featureName, projectRoot: sessionState.projectRoot, provider: sessionState.provider, model: sessionState.model, scanResult: sessionState.scanResult, specsPath: sessionState.config?.paths.specs, onComplete: handleInterviewComplete, onCancel: handleInterviewCancel }));
202
+ return (_jsx(InterviewScreen, { header: headerElement, featureName: featureName, projectRoot: sessionState.projectRoot, provider: sessionState.provider, model: sessionState.model, scanResult: sessionState.scanResult, specsPath: sessionState.config?.paths.specs, initialReferences: interviewProps?.initialReferences, onComplete: handleInterviewComplete, onCancel: handleInterviewCancel }));
202
203
  }
203
204
  case 'init':
204
205
  return (_jsx(InitScreen, { header: headerElement, projectRoot: sessionState.projectRoot, sessionState: sessionState, onComplete: handleInitComplete, onCancel: () => navigate('shell') }));
@@ -211,6 +212,23 @@ interviewProps, runProps, onComplete, onExit, }) {
211
212
  const reviewMode = screenProps?.reviewMode;
212
213
  return (_jsx(RunScreen, { header: headerElement, featureName: featureName, projectRoot: sessionState.projectRoot, sessionState: sessionState, monitorOnly: monitorOnly, reviewMode: reviewMode, onComplete: handleRunComplete, onBackground: handleRunBackground, onCancel: () => navigate('shell') }));
213
214
  }
215
+ case 'agent': {
216
+ // Merge CLI-provided agentProps with navigation screenProps (from /agent command)
217
+ const resolvedAgentOptions = {
218
+ ...agentProps,
219
+ ...(screenProps?.dryRun != null ? { dryRun: screenProps.dryRun } : {}),
220
+ ...(screenProps?.maxItems != null ? { maxItems: screenProps.maxItems } : {}),
221
+ ...(screenProps?.reviewMode != null ? { reviewMode: screenProps.reviewMode } : {}),
222
+ };
223
+ return (_jsx(AgentScreen, { header: headerElement, projectRoot: sessionState.projectRoot, agentOptions: resolvedAgentOptions, onExit: () => {
224
+ if (initialScreen === 'agent') {
225
+ onExit?.();
226
+ }
227
+ else {
228
+ navigate('shell');
229
+ }
230
+ } }));
231
+ }
214
232
  default: {
215
233
  // Return fallback UI instead of calling navigate() during render (which would be setState during render).
216
234
  // The useEffect guard above will redirect to shell on next tick.
@@ -224,5 +242,5 @@ interviewProps, runProps, onComplete, onExit, }) {
224
242
  * Render the App component to the terminal
225
243
  */
226
244
  export function renderApp(options) {
227
- return render(_jsx(App, { screen: options.screen, initialSessionState: options.initialSessionState, version: options.version, interviewProps: options.interviewProps, runProps: options.runProps, onComplete: options.onComplete, onExit: options.onExit }));
245
+ return render(_jsx(App, { screen: options.screen, initialSessionState: options.initialSessionState, version: options.version, interviewProps: options.interviewProps, runProps: options.runProps, agentProps: options.agentProps, onComplete: options.onComplete, onExit: options.onExit }));
228
246
  }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * IssuePicker - GitHub issue selection dropdown
3
+ *
4
+ * Displays a bordered list of GitHub issues for the user to navigate
5
+ * and select from. Follows the visual style of CommandDropdown.
6
+ * Supports arrow keys and j/k for navigation, Enter to select, Esc to cancel.
7
+ */
8
+ import React from 'react';
9
+ import type { GitHubIssueListItem } from '../../utils/github.js';
10
+ /**
11
+ * Props for the IssuePicker component
12
+ */
13
+ export interface IssuePickerProps {
14
+ /** List of issues to display */
15
+ issues: GitHubIssueListItem[];
16
+ /** Repository slug (e.g. "owner/repo") shown in header */
17
+ repoSlug: string;
18
+ /** Called when an issue is selected */
19
+ onSelect: (issue: GitHubIssueListItem) => void;
20
+ /** Called when the picker is dismissed (Escape) */
21
+ onCancel: () => void;
22
+ /** Whether issues are currently loading */
23
+ isLoading: boolean;
24
+ /** Optional error message to display */
25
+ error?: string;
26
+ }
27
+ export declare function IssuePicker({ issues, repoSlug, onSelect, onCancel, isLoading, error, }: IssuePickerProps): React.ReactElement;
@@ -0,0 +1,64 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * IssuePicker - GitHub issue selection dropdown
4
+ *
5
+ * Displays a bordered list of GitHub issues for the user to navigate
6
+ * and select from. Follows the visual style of CommandDropdown.
7
+ * Supports arrow keys and j/k for navigation, Enter to select, Esc to cancel.
8
+ */
9
+ import React, { useState } from 'react';
10
+ import { Box, Text, useInput, useStdout } from 'ink';
11
+ import Spinner from 'ink-spinner';
12
+ import { colors, box } from '../theme.js';
13
+ const MAX_LABELS = 2;
14
+ function truncate(text, maxLen) {
15
+ if (text.length <= maxLen)
16
+ return text;
17
+ return text.slice(0, maxLen - 1) + '\u2026';
18
+ }
19
+ export function IssuePicker({ issues, repoSlug, onSelect, onCancel, isLoading, error, }) {
20
+ const [selectedIndex, setSelectedIndex] = useState(0);
21
+ const { stdout } = useStdout();
22
+ const columns = stdout?.columns ?? 80;
23
+ React.useEffect(() => {
24
+ setSelectedIndex(0);
25
+ }, [issues]);
26
+ // Handle keyboard input
27
+ useInput((input, key) => {
28
+ if (key.escape) {
29
+ onCancel();
30
+ return;
31
+ }
32
+ if (key.return && issues.length > 0) {
33
+ onSelect(issues[selectedIndex]);
34
+ return;
35
+ }
36
+ if (key.upArrow || input === 'k') {
37
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
38
+ return;
39
+ }
40
+ if (key.downArrow || input === 'j') {
41
+ setSelectedIndex((prev) => Math.min(issues.length - 1, prev + 1));
42
+ return;
43
+ }
44
+ });
45
+ // Build border strings
46
+ const countSuffix = !isLoading && !error ? ` (${issues.length})` : '';
47
+ const headerLabel = ` GitHub Issues ${box.horizontal} ${repoSlug}${countSuffix} `;
48
+ const contentWidth = Math.min(Math.max(60, headerLabel.length + 10), columns - 6);
49
+ const topBorderFill = contentWidth - headerLabel.length - 1;
50
+ const topBorder = box.topLeft + box.horizontal + headerLabel + box.horizontal.repeat(Math.max(0, topBorderFill)) + box.topRight;
51
+ const bottomBorder = box.bottomLeft + box.horizontal.repeat(contentWidth) + box.bottomRight;
52
+ // Space budget for title: total width minus number, labels, borders, padding
53
+ const numberWidth = 6; // " #999 " — enough for 3-digit issues
54
+ const labelBudget = 24; // space for up to 2 labels
55
+ const chrome = 4; // borders + padding
56
+ const titleMaxLen = Math.max(20, contentWidth - numberWidth - labelBudget - chrome);
57
+ return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: topBorder }), isLoading && (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { dimColor: true, children: box.vertical }), _jsx(Text, { children: " " }), _jsx(Spinner, { type: "dots" }), _jsx(Text, { color: colors.yellow, children: " Searching..." }), _jsx(Text, { children: ' '.repeat(Math.max(0, contentWidth - 16)) }), _jsx(Text, { dimColor: true, children: box.vertical })] })), !isLoading && error && (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { dimColor: true, children: box.vertical }), _jsxs(Text, { color: colors.pink, children: [" ", error] }), _jsx(Text, { children: ' '.repeat(Math.max(0, contentWidth - error.length - 1)) }), _jsx(Text, { dimColor: true, children: box.vertical })] })), !isLoading && !error && issues.length === 0 && (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { dimColor: true, children: box.vertical }), _jsx(Text, { dimColor: true, children: " No open issues found" }), _jsx(Text, { children: ' '.repeat(Math.max(0, contentWidth - 21)) }), _jsx(Text, { dimColor: true, children: box.vertical })] })), !isLoading && !error && issues.map((issue, index) => {
58
+ const isSelected = index === selectedIndex;
59
+ const numberText = `#${issue.number}`;
60
+ const title = truncate(issue.title, titleMaxLen);
61
+ const labelTags = issue.labels.slice(0, MAX_LABELS).join(' ');
62
+ return (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { dimColor: true, children: box.vertical }), _jsxs(Text, { backgroundColor: isSelected ? colors.yellow : undefined, color: isSelected ? colors.brown : colors.yellow, children: [' ', numberText] }), _jsxs(Text, { backgroundColor: isSelected ? colors.yellow : undefined, color: isSelected ? colors.brown : undefined, children: [' ', title] }), labelTags && (_jsxs(Text, { backgroundColor: isSelected ? colors.yellow : undefined, color: isSelected ? colors.brown : colors.gray, children: [' ', labelTags] })), _jsxs(Text, { dimColor: true, children: [' '.repeat(1), box.vertical] })] }, issue.number));
63
+ }), _jsx(Text, { dimColor: true, children: bottomBorder }), _jsx(Box, { marginLeft: 1, children: _jsxs(Text, { color: colors.gray, children: ['(', '\u2191\u2193 navigate, Enter select, Esc cancel', ')'] }) })] }));
64
+ }
@@ -116,10 +116,12 @@ export function RunCompletionSummary({ summary, }) {
116
116
  return (_jsxs(SummaryBox, { minWidth: 60, children: [_jsx(Text, { bold: true, children: summary.feature }), _jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsxs(Text, { bold: true, color: exitStatus.color, children: [statusIcon, " ", exitStatus.label] }), _jsx(Text, { dimColor: true, children: "\u00B7" }), _jsx(Text, { dimColor: true, children: subtitleParts.join(' · ') })] }), _jsxs(SummaryBoxSection, { children: [_jsx(Text, { bold: true, children: "Phases" }), summary.phases && summary.phases.length > 0 ? (summary.phases.map((phaseInfo) => {
117
117
  const phaseIcon = phaseInfo.status === 'success' ? phase.complete :
118
118
  phaseInfo.status === 'failed' ? phase.error :
119
- phase.pending;
119
+ phaseInfo.status === 'started' ? phase.active :
120
+ phase.pending;
120
121
  const phaseColor = phaseInfo.status === 'success' ? colors.green :
121
122
  phaseInfo.status === 'failed' ? colors.pink :
122
- colors.gray;
123
+ phaseInfo.status === 'started' ? colors.yellow :
124
+ colors.gray;
123
125
  const durationText = phaseInfo.durationMs !== undefined
124
126
  ? formatDurationMs(phaseInfo.durationMs)
125
127
  : 'Not available';
@@ -127,7 +129,8 @@ export function RunCompletionSummary({ summary, }) {
127
129
  ? ` (${phaseInfo.iterations} iterations)`
128
130
  : '';
129
131
  const statusText = phaseInfo.status === 'skipped' ? ' skipped' :
130
- phaseInfo.status === 'failed' ? ' failed' : '';
132
+ phaseInfo.status === 'failed' ? ' failed' :
133
+ phaseInfo.status === 'started' ? ' in progress' : '';
131
134
  return (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: phaseColor, children: [phaseIcon, " "] }), _jsxs(Text, { children: [phaseInfo.label, " ", durationText, iterationsText, statusText] })] }, phaseInfo.id));
132
135
  })) : (_jsx(Text, { children: "No phase information available" }))] }), _jsxs(SummaryBoxSection, { children: [_jsx(Text, { bold: true, children: "Changes" }), !summary.changes || !summary.changes.available ? (_jsx(Text, { children: "Changes: Not available" })) : summary.changes.totalFilesChanged === 0 || (summary.changes.files && summary.changes.files.length === 0) ? (_jsx(Text, { children: "No changes" })) : summary.changes.totalFilesChanged !== undefined ? (_jsxs(Text, { children: [summary.changes.totalFilesChanged, " file", summary.changes.totalFilesChanged !== 1 ? 's' : '', " changed"] })) : !summary.changes.files ? (_jsx(Text, { children: "Changes: Could not compute diff" })) : null, (() => {
133
136
  const files = summary.changes?.available ? summary.changes.files : undefined;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * useAgentOrchestrator — React hook that bridges the agent orchestrator
3
+ * lifecycle to TUI state via callbacks.
4
+ *
5
+ * Creates the orchestrator, runs it via stream(), and interprets tool
6
+ * calls into structured state (active issue, queue, completed, log).
7
+ * Exposes an abort() function for clean shutdown on q/Esc.
8
+ */
9
+ import type { AgentIssueState, AgentLogEntry, ReviewMode } from '../../agent/types.js';
10
+ export type AgentStatus = 'idle' | 'running' | 'complete' | 'error';
11
+ export interface UseAgentOrchestratorOptions {
12
+ projectRoot: string;
13
+ modelOverride?: string;
14
+ maxItems?: number;
15
+ maxSteps?: number;
16
+ labels?: string[];
17
+ reviewMode?: ReviewMode;
18
+ dryRun?: boolean;
19
+ }
20
+ export interface UseAgentOrchestratorResult {
21
+ status: AgentStatus;
22
+ activeIssue: AgentIssueState | null;
23
+ queue: AgentIssueState[];
24
+ completed: AgentIssueState[];
25
+ logEntries: AgentLogEntry[];
26
+ error: string | null;
27
+ abort: () => void;
28
+ }
29
+ export declare function useAgentOrchestrator(options: UseAgentOrchestratorOptions): UseAgentOrchestratorResult;