@raindrop-ai/wizard 0.0.1

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 (135) hide show
  1. package/LICENSE +47 -0
  2. package/dist/bin.d.ts +2 -0
  3. package/dist/bin.js +117 -0
  4. package/dist/bin.js.map +1 -0
  5. package/dist/src/docs/browser.md +105 -0
  6. package/dist/src/docs/python.md +618 -0
  7. package/dist/src/docs/typescript.md +584 -0
  8. package/dist/src/docs/vercel-ai-sdk.md +304 -0
  9. package/dist/src/lib/agent-interface.d.ts +46 -0
  10. package/dist/src/lib/agent-interface.js +292 -0
  11. package/dist/src/lib/agent-interface.js.map +1 -0
  12. package/dist/src/lib/agent-prompts.d.ts +10 -0
  13. package/dist/src/lib/agent-prompts.js +49 -0
  14. package/dist/src/lib/agent-prompts.js.map +1 -0
  15. package/dist/src/lib/config.d.ts +39 -0
  16. package/dist/src/lib/config.js +549 -0
  17. package/dist/src/lib/config.js.map +1 -0
  18. package/dist/src/lib/constants.d.ts +27 -0
  19. package/dist/src/lib/constants.js +165 -0
  20. package/dist/src/lib/constants.js.map +1 -0
  21. package/dist/src/lib/handlers.d.ts +68 -0
  22. package/dist/src/lib/handlers.js +420 -0
  23. package/dist/src/lib/handlers.js.map +1 -0
  24. package/dist/src/lib/integration-testing.d.ts +44 -0
  25. package/dist/src/lib/integration-testing.js +123 -0
  26. package/dist/src/lib/integration-testing.js.map +1 -0
  27. package/dist/src/lib/mcp.d.ts +14 -0
  28. package/dist/src/lib/mcp.js +134 -0
  29. package/dist/src/lib/mcp.js.map +1 -0
  30. package/dist/src/lib/sdk-messages.d.ts +17 -0
  31. package/dist/src/lib/sdk-messages.js +278 -0
  32. package/dist/src/lib/sdk-messages.js.map +1 -0
  33. package/dist/src/lib/wizard.d.ts +6 -0
  34. package/dist/src/lib/wizard.js +131 -0
  35. package/dist/src/lib/wizard.js.map +1 -0
  36. package/dist/src/run.d.ts +8 -0
  37. package/dist/src/run.js +53 -0
  38. package/dist/src/run.js.map +1 -0
  39. package/dist/src/ui/App.d.ts +15 -0
  40. package/dist/src/ui/App.js +27 -0
  41. package/dist/src/ui/App.js.map +1 -0
  42. package/dist/src/ui/cancellation.d.ts +14 -0
  43. package/dist/src/ui/cancellation.js +17 -0
  44. package/dist/src/ui/cancellation.js.map +1 -0
  45. package/dist/src/ui/components/ClarifyingQuestionsPrompt.d.ts +17 -0
  46. package/dist/src/ui/components/ClarifyingQuestionsPrompt.js +359 -0
  47. package/dist/src/ui/components/ClarifyingQuestionsPrompt.js.map +1 -0
  48. package/dist/src/ui/components/ContinuePrompt.d.ts +14 -0
  49. package/dist/src/ui/components/ContinuePrompt.js +23 -0
  50. package/dist/src/ui/components/ContinuePrompt.js.map +1 -0
  51. package/dist/src/ui/components/DiffDisplay.d.ts +18 -0
  52. package/dist/src/ui/components/DiffDisplay.js +110 -0
  53. package/dist/src/ui/components/DiffDisplay.js.map +1 -0
  54. package/dist/src/ui/components/FeedbackSelectPrompt.d.ts +20 -0
  55. package/dist/src/ui/components/FeedbackSelectPrompt.js +132 -0
  56. package/dist/src/ui/components/FeedbackSelectPrompt.js.map +1 -0
  57. package/dist/src/ui/components/HistoryItemDisplay.d.ts +14 -0
  58. package/dist/src/ui/components/HistoryItemDisplay.js +140 -0
  59. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -0
  60. package/dist/src/ui/components/Logo.d.ts +10 -0
  61. package/dist/src/ui/components/Logo.js +47 -0
  62. package/dist/src/ui/components/Logo.js.map +1 -0
  63. package/dist/src/ui/components/OrgInfoBox.d.ts +11 -0
  64. package/dist/src/ui/components/OrgInfoBox.js +16 -0
  65. package/dist/src/ui/components/OrgInfoBox.js.map +1 -0
  66. package/dist/src/ui/components/PendingPrompt.d.ts +18 -0
  67. package/dist/src/ui/components/PendingPrompt.js +57 -0
  68. package/dist/src/ui/components/PendingPrompt.js.map +1 -0
  69. package/dist/src/ui/components/PersistentTextInput.d.ts +21 -0
  70. package/dist/src/ui/components/PersistentTextInput.js +117 -0
  71. package/dist/src/ui/components/PersistentTextInput.js.map +1 -0
  72. package/dist/src/ui/components/PlanApprovalPrompt.d.ts +19 -0
  73. package/dist/src/ui/components/PlanApprovalPrompt.js +62 -0
  74. package/dist/src/ui/components/PlanApprovalPrompt.js.map +1 -0
  75. package/dist/src/ui/components/PromptContainer.d.ts +14 -0
  76. package/dist/src/ui/components/PromptContainer.js +18 -0
  77. package/dist/src/ui/components/PromptContainer.js.map +1 -0
  78. package/dist/src/ui/components/SelectPrompt.d.ts +14 -0
  79. package/dist/src/ui/components/SelectPrompt.js +62 -0
  80. package/dist/src/ui/components/SelectPrompt.js.map +1 -0
  81. package/dist/src/ui/components/SpinnerDisplay.d.ts +13 -0
  82. package/dist/src/ui/components/SpinnerDisplay.js +11 -0
  83. package/dist/src/ui/components/SpinnerDisplay.js.map +1 -0
  84. package/dist/src/ui/components/ToolApprovalPrompt.d.ts +14 -0
  85. package/dist/src/ui/components/ToolApprovalPrompt.js +142 -0
  86. package/dist/src/ui/components/ToolApprovalPrompt.js.map +1 -0
  87. package/dist/src/ui/components/ToolCallDisplay.d.ts +14 -0
  88. package/dist/src/ui/components/ToolCallDisplay.js +83 -0
  89. package/dist/src/ui/components/ToolCallDisplay.js.map +1 -0
  90. package/dist/src/ui/components/WriteKeyDisplay.d.ts +15 -0
  91. package/dist/src/ui/components/WriteKeyDisplay.js +13 -0
  92. package/dist/src/ui/components/WriteKeyDisplay.js.map +1 -0
  93. package/dist/src/ui/contexts/WizardContext.d.ts +210 -0
  94. package/dist/src/ui/contexts/WizardContext.js +362 -0
  95. package/dist/src/ui/contexts/WizardContext.js.map +1 -0
  96. package/dist/src/ui/hooks/useCancellation.d.ts +15 -0
  97. package/dist/src/ui/hooks/useCancellation.js +25 -0
  98. package/dist/src/ui/hooks/useCancellation.js.map +1 -0
  99. package/dist/src/ui/render.d.ts +34 -0
  100. package/dist/src/ui/render.js +94 -0
  101. package/dist/src/ui/render.js.map +1 -0
  102. package/dist/src/ui/types.d.ts +184 -0
  103. package/dist/src/ui/types.js +6 -0
  104. package/dist/src/ui/types.js.map +1 -0
  105. package/dist/src/utils/clack-utils.d.ts +13 -0
  106. package/dist/src/utils/clack-utils.js +131 -0
  107. package/dist/src/utils/clack-utils.js.map +1 -0
  108. package/dist/src/utils/debug.d.ts +13 -0
  109. package/dist/src/utils/debug.js +47 -0
  110. package/dist/src/utils/debug.js.map +1 -0
  111. package/dist/src/utils/environment.d.ts +5 -0
  112. package/dist/src/utils/environment.js +131 -0
  113. package/dist/src/utils/environment.js.map +1 -0
  114. package/dist/src/utils/logging.d.ts +9 -0
  115. package/dist/src/utils/logging.js +38 -0
  116. package/dist/src/utils/logging.js.map +1 -0
  117. package/dist/src/utils/oauth.d.ts +12 -0
  118. package/dist/src/utils/oauth.js +497 -0
  119. package/dist/src/utils/oauth.js.map +1 -0
  120. package/dist/src/utils/package-json-types.d.ts +44 -0
  121. package/dist/src/utils/package-json-types.js +6 -0
  122. package/dist/src/utils/package-json-types.js.map +1 -0
  123. package/dist/src/utils/package-json.d.ts +19 -0
  124. package/dist/src/utils/package-json.js +22 -0
  125. package/dist/src/utils/package-json.js.map +1 -0
  126. package/dist/src/utils/session.d.ts +2 -0
  127. package/dist/src/utils/session.js +87 -0
  128. package/dist/src/utils/session.js.map +1 -0
  129. package/dist/src/utils/types.d.ts +61 -0
  130. package/dist/src/utils/types.js +2 -0
  131. package/dist/src/utils/types.js.map +1 -0
  132. package/dist/src/utils/ui.d.ts +120 -0
  133. package/dist/src/utils/ui.js +164 -0
  134. package/dist/src/utils/ui.js.map +1 -0
  135. package/package.json +140 -0
@@ -0,0 +1,117 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Unified text input component for the wizard.
4
+ *
5
+ * Two modes:
6
+ * 1. Callback mode: Uses onSubmit/onInterrupt callbacks (for persistent input during agent execution)
7
+ * 2. Context mode: Uses resolvePending from WizardContext (for standalone text prompts)
8
+ *
9
+ * Note: Spinner is managed separately via ui.spinner() - this component is just the input.
10
+ */
11
+ import { useState } from 'react';
12
+ import { Box, Text, useInput } from 'ink';
13
+ import TextInput from 'ink-text-input';
14
+ import { PromptContainer } from './PromptContainer.js';
15
+ import { useWizardActions } from '../contexts/WizardContext.js';
16
+ import { CANCEL_SYMBOL } from '../cancellation.js';
17
+ /**
18
+ * Unified text input component.
19
+ * - With callbacks (onSubmit/onInterrupt): Uses callbacks for submit/interrupt
20
+ * - Without callbacks: Uses resolvePending from context (text prompt mode)
21
+ */
22
+ export function PersistentTextInput({ props, }) {
23
+ const { placeholder, message, defaultValue, validate, onSubmit, onInterrupt, onCtrlC, } = props;
24
+ const { resolvePending, addItem, updatePersistentInputValue } = useWizardActions();
25
+ const [value, setValue] = useState(defaultValue || '');
26
+ const [error, setError] = useState(null);
27
+ const [exitPending, setExitPending] = useState(false);
28
+ // Handle Escape and Ctrl+C
29
+ useInput((input, key) => {
30
+ // Handle Ctrl+C
31
+ if (key.ctrl && input === 'c') {
32
+ // If there's text, clear it first and set exit pending
33
+ if (value.trim()) {
34
+ setValue('');
35
+ updatePersistentInputValue('');
36
+ setExitPending(true);
37
+ return;
38
+ }
39
+ // If no text and exit is pending, actually exit
40
+ if (exitPending) {
41
+ if (onCtrlC) {
42
+ // Has Ctrl+C callback - use it
43
+ onCtrlC();
44
+ }
45
+ else if (onInterrupt) {
46
+ // No Ctrl+C callback, fall back to interrupt
47
+ onInterrupt();
48
+ }
49
+ else {
50
+ // No callback - cancel via resolvePending (text prompt mode)
51
+ addItem({
52
+ type: 'text-result',
53
+ text: message || '',
54
+ label: '(cancelled)',
55
+ });
56
+ resolvePending(CANCEL_SYMBOL);
57
+ }
58
+ return;
59
+ }
60
+ // If no text and not exit pending, set exit pending
61
+ setExitPending(true);
62
+ return;
63
+ }
64
+ // Handle Escape
65
+ if (key.escape || input === '\x1b') {
66
+ if (onInterrupt) {
67
+ // Has interrupt callback - use it
68
+ onInterrupt();
69
+ }
70
+ else {
71
+ // No callback - cancel via resolvePending (text prompt mode)
72
+ addItem({
73
+ type: 'text-result',
74
+ text: message || '',
75
+ label: '(cancelled)',
76
+ });
77
+ resolvePending(CANCEL_SYMBOL);
78
+ }
79
+ }
80
+ });
81
+ // Handle submission
82
+ const handleSubmit = (submittedValue) => {
83
+ // Validate if validator provided
84
+ if (validate) {
85
+ const validationError = validate(submittedValue);
86
+ if (validationError) {
87
+ setError(validationError);
88
+ return;
89
+ }
90
+ }
91
+ if (onSubmit) {
92
+ // Has submit callback - use it
93
+ if (submittedValue.trim()) {
94
+ void Promise.resolve(onSubmit(submittedValue.trim()));
95
+ setValue('');
96
+ // Clear saved value in context
97
+ updatePersistentInputValue('');
98
+ }
99
+ }
100
+ else {
101
+ // No callback - resolve via context (text prompt mode)
102
+ resolvePending(submittedValue);
103
+ }
104
+ };
105
+ return (_jsxs(PromptContainer, { children: [message && _jsx(Text, { children: message }), _jsxs(Box, { marginTop: message ? 1 : 0, children: [_jsx(Text, { color: "cyan", children: "\u203A " }), _jsx(TextInput, { value: value, onChange: (newValue) => {
106
+ setValue(newValue);
107
+ // Preserve value in context so it survives unmount/remount (e.g., during approval prompts)
108
+ updatePersistentInputValue(newValue);
109
+ if (error)
110
+ setError(null);
111
+ // Reset exit pending state when user types
112
+ if (exitPending)
113
+ setExitPending(false);
114
+ }, placeholder: placeholder || 'Type a message or Esc to interrupt...', onSubmit: handleSubmit })] }), error && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "red", children: error }) }))] }));
115
+ }
116
+ export default PersistentTextInput;
117
+ //# sourceMappingURL=PersistentTextInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PersistentTextInput.js","sourceRoot":"","sources":["../../../../src/ui/components/PersistentTextInput.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified text input component for the wizard.\n *\n * Two modes:\n * 1. Callback mode: Uses onSubmit/onInterrupt callbacks (for persistent input during agent execution)\n * 2. Context mode: Uses resolvePending from WizardContext (for standalone text prompts)\n *\n * Note: Spinner is managed separately via ui.spinner() - this component is just the input.\n */\n\nimport React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport TextInput from 'ink-text-input';\nimport { PromptContainer } from './PromptContainer.js';\nimport { useWizardActions } from '../contexts/WizardContext.js';\nimport { CANCEL_SYMBOL } from '../cancellation.js';\nimport type { PersistentInputProps } from '../types.js';\n\ninterface PersistentTextInputComponentProps {\n props: PersistentInputProps;\n}\n\n/**\n * Unified text input component.\n * - With callbacks (onSubmit/onInterrupt): Uses callbacks for submit/interrupt\n * - Without callbacks: Uses resolvePending from context (text prompt mode)\n */\nexport function PersistentTextInput({\n props,\n}: PersistentTextInputComponentProps): React.ReactElement {\n const {\n placeholder,\n message,\n defaultValue,\n validate,\n onSubmit,\n onInterrupt,\n onCtrlC,\n } = props;\n\n const { resolvePending, addItem, updatePersistentInputValue } =\n useWizardActions();\n const [value, setValue] = useState(defaultValue || '');\n const [error, setError] = useState<string | null>(null);\n const [exitPending, setExitPending] = useState(false);\n\n // Handle Escape and Ctrl+C\n useInput((input, key) => {\n // Handle Ctrl+C\n if (key.ctrl && input === 'c') {\n // If there's text, clear it first and set exit pending\n if (value.trim()) {\n setValue('');\n updatePersistentInputValue('');\n setExitPending(true);\n return;\n }\n\n // If no text and exit is pending, actually exit\n if (exitPending) {\n if (onCtrlC) {\n // Has Ctrl+C callback - use it\n onCtrlC();\n } else if (onInterrupt) {\n // No Ctrl+C callback, fall back to interrupt\n onInterrupt();\n } else {\n // No callback - cancel via resolvePending (text prompt mode)\n addItem({\n type: 'text-result',\n text: message || '',\n label: '(cancelled)',\n });\n resolvePending(CANCEL_SYMBOL);\n }\n return;\n }\n\n // If no text and not exit pending, set exit pending\n setExitPending(true);\n return;\n }\n\n // Handle Escape\n if (key.escape || input === '\\x1b') {\n if (onInterrupt) {\n // Has interrupt callback - use it\n onInterrupt();\n } else {\n // No callback - cancel via resolvePending (text prompt mode)\n addItem({\n type: 'text-result',\n text: message || '',\n label: '(cancelled)',\n });\n resolvePending(CANCEL_SYMBOL);\n }\n }\n });\n\n // Handle submission\n const handleSubmit = (submittedValue: string) => {\n // Validate if validator provided\n if (validate) {\n const validationError = validate(submittedValue);\n if (validationError) {\n setError(validationError);\n return;\n }\n }\n\n if (onSubmit) {\n // Has submit callback - use it\n if (submittedValue.trim()) {\n void Promise.resolve(onSubmit(submittedValue.trim()));\n setValue('');\n // Clear saved value in context\n updatePersistentInputValue('');\n }\n } else {\n // No callback - resolve via context (text prompt mode)\n resolvePending(submittedValue);\n }\n };\n\n return (\n <PromptContainer>\n {/* Message */}\n {message && <Text>{message}</Text>}\n\n {/* Text input */}\n <Box marginTop={message ? 1 : 0}>\n <Text color=\"cyan\">› </Text>\n <TextInput\n value={value}\n onChange={(newValue) => {\n setValue(newValue);\n // Preserve value in context so it survives unmount/remount (e.g., during approval prompts)\n updatePersistentInputValue(newValue);\n if (error) setError(null);\n // Reset exit pending state when user types\n if (exitPending) setExitPending(false);\n }}\n placeholder={placeholder || 'Type a message or Esc to interrupt...'}\n onSubmit={handleSubmit}\n />\n </Box>\n\n {/* Validation error */}\n {error && (\n <Box marginTop={1}>\n <Text color=\"red\">{error}</Text>\n </Box>\n )}\n </PromptContainer>\n );\n}\n\nexport default PersistentTextInput;\n"]}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Plan approval prompt component.
3
+ * Note: The plan content is shown in history (static) before this prompt.
4
+ * This component only renders the selection UI to prevent re-rendering the plan.
5
+ * Uses the shared FeedbackSelectPrompt for the options/input interaction.
6
+ */
7
+ import React from 'react';
8
+ import type { PlanApprovalProps } from '../types.js';
9
+ interface PlanApprovalPromptComponentProps {
10
+ props: PlanApprovalProps;
11
+ }
12
+ /**
13
+ * Plan approval prompt for the ExitPlanMode tool.
14
+ * Note: The plan content is displayed in history before this prompt appears.
15
+ * This component only shows the approval selection UI to avoid re-rendering
16
+ * the plan on every keystroke.
17
+ */
18
+ export declare function PlanApprovalPrompt({ props, }: PlanApprovalPromptComponentProps): React.ReactElement;
19
+ export default PlanApprovalPrompt;
@@ -0,0 +1,62 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Plan approval prompt component.
4
+ * Note: The plan content is shown in history (static) before this prompt.
5
+ * This component only renders the selection UI to prevent re-rendering the plan.
6
+ * Uses the shared FeedbackSelectPrompt for the options/input interaction.
7
+ */
8
+ import { useCallback } from 'react';
9
+ import { useWizard } from '../contexts/WizardContext.js';
10
+ import { FeedbackSelectPrompt } from './FeedbackSelectPrompt.js';
11
+ /**
12
+ * Plan approval prompt for the ExitPlanMode tool.
13
+ * Note: The plan content is displayed in history before this prompt appears.
14
+ * This component only shows the approval selection UI to avoid re-rendering
15
+ * the plan on every keystroke.
16
+ */
17
+ export function PlanApprovalPrompt({ props, }) {
18
+ const { planContent } = props;
19
+ const { actions } = useWizard();
20
+ const { resolvePending, addItem } = actions;
21
+ // Handle result from FeedbackSelectPrompt
22
+ const handleResult = useCallback((result) => {
23
+ if (result.type === 'option') {
24
+ // User approved the plan
25
+ addItem({
26
+ type: 'plan-approved',
27
+ text: 'User approved plan',
28
+ planContent,
29
+ });
30
+ const approvalResult = {
31
+ approved: true,
32
+ };
33
+ resolvePending(approvalResult);
34
+ }
35
+ else {
36
+ // User provided feedback (rejected) or interrupted
37
+ const isInterrupted = result.value === 'interrupted';
38
+ const displayLabel = isInterrupted ? '(interrupted)' : result.value;
39
+ addItem({
40
+ type: 'plan-rejected',
41
+ text: isInterrupted ? 'User interrupted plan approval' : 'User rejected plan',
42
+ label: displayLabel,
43
+ planContent,
44
+ });
45
+ const approvalResult = {
46
+ approved: false,
47
+ feedback: isInterrupted ? undefined : result.value,
48
+ };
49
+ resolvePending(approvalResult);
50
+ }
51
+ }, [planContent, resolvePending, addItem]);
52
+ const feedbackSelectOptions = {
53
+ message: 'Would you like to proceed?',
54
+ options: [
55
+ { value: 'accept', label: 'Yes, accept plan' },
56
+ { value: 'feedback', label: 'Type something', allowTextInput: true },
57
+ ],
58
+ };
59
+ return (_jsx(_Fragment, { children: _jsx(FeedbackSelectPrompt, { options: feedbackSelectOptions, onResult: handleResult, standalone: false }) }));
60
+ }
61
+ export default PlanApprovalPrompt;
62
+ //# sourceMappingURL=PlanApprovalPrompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlanApprovalPrompt.js","sourceRoot":"","sources":["../../../../src/ui/components/PlanApprovalPrompt.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AAEH,OAAc,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAWjE;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,KAAK,GAC4B;IACjC,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;IAC9B,MAAM,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,CAAC;IAChC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAE5C,0CAA0C;IAC1C,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,MAAsC,EAAE,EAAE;QACzC,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,yBAAyB;YACzB,OAAO,CAAC;gBACN,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,oBAAoB;gBAC1B,WAAW;aACZ,CAAC,CAAC;YAEH,MAAM,cAAc,GAAuB;gBACzC,QAAQ,EAAE,IAAI;aACf,CAAC;YACF,cAAc,CAAC,cAAc,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,KAAK,aAAa,CAAC;YACrD,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAEpE,OAAO,CAAC;gBACN,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,oBAAoB;gBAC7E,KAAK,EAAE,YAAY;gBACnB,WAAW;aACZ,CAAC,CAAC;YAEH,MAAM,cAAc,GAAuB;gBACzC,QAAQ,EAAE,KAAK;gBACf,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK;aACnD,CAAC;YACF,cAAc,CAAC,cAAc,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,EACD,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC,CACvC,CAAC;IAEF,MAAM,qBAAqB,GAAG;QAC5B,OAAO,EAAE,4BAA4B;QACrC,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,QAAiB,EAAE,KAAK,EAAE,kBAAkB,EAAE;YACvD,EAAE,KAAK,EAAE,UAAmB,EAAE,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,IAAI,EAAE;SAC9E;KACF,CAAC;IAEF,OAAO,CACL,4BAIE,KAAC,oBAAoB,IACnB,OAAO,EAAE,qBAAqB,EAC9B,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,KAAK,GACjB,GACD,CACJ,CAAC;AACJ,CAAC;AAED,eAAe,kBAAkB,CAAC","sourcesContent":["/**\n * Plan approval prompt component.\n * Note: The plan content is shown in history (static) before this prompt.\n * This component only renders the selection UI to prevent re-rendering the plan.\n * Uses the shared FeedbackSelectPrompt for the options/input interaction.\n */\n\nimport React, { useCallback } from 'react';\nimport { useWizard } from '../contexts/WizardContext.js';\nimport { FeedbackSelectPrompt } from './FeedbackSelectPrompt.js';\nimport type {\n PlanApprovalProps,\n PlanApprovalResult,\n FeedbackSelectResult,\n} from '../types.js';\n\ninterface PlanApprovalPromptComponentProps {\n props: PlanApprovalProps;\n}\n\n/**\n * Plan approval prompt for the ExitPlanMode tool.\n * Note: The plan content is displayed in history before this prompt appears.\n * This component only shows the approval selection UI to avoid re-rendering\n * the plan on every keystroke.\n */\nexport function PlanApprovalPrompt({\n props,\n}: PlanApprovalPromptComponentProps): React.ReactElement {\n const { planContent } = props;\n const { actions } = useWizard();\n const { resolvePending, addItem } = actions;\n\n // Handle result from FeedbackSelectPrompt\n const handleResult = useCallback(\n (result: FeedbackSelectResult<'accept'>) => {\n if (result.type === 'option') {\n // User approved the plan\n addItem({\n type: 'plan-approved',\n text: 'User approved plan',\n planContent,\n });\n\n const approvalResult: PlanApprovalResult = {\n approved: true,\n };\n resolvePending(approvalResult);\n } else {\n // User provided feedback (rejected) or interrupted\n const isInterrupted = result.value === 'interrupted';\n const displayLabel = isInterrupted ? '(interrupted)' : result.value;\n\n addItem({\n type: 'plan-rejected',\n text: isInterrupted ? 'User interrupted plan approval' : 'User rejected plan',\n label: displayLabel,\n planContent,\n });\n\n const approvalResult: PlanApprovalResult = {\n approved: false,\n feedback: isInterrupted ? undefined : result.value,\n };\n resolvePending(approvalResult);\n }\n },\n [planContent, resolvePending, addItem],\n );\n\n const feedbackSelectOptions = {\n message: 'Would you like to proceed?',\n options: [\n { value: 'accept' as const, label: 'Yes, accept plan' },\n { value: 'feedback' as const, label: 'Type something', allowTextInput: true },\n ],\n };\n\n return (\n <>\n {/* Note: Plan content is already displayed in history as a static item */}\n {/* Only show the selection prompt here to avoid re-rendering the plan on every keystroke */}\n {/* FeedbackSelectPrompt already has PromptContainer with lines, no need to wrap again */}\n <FeedbackSelectPrompt\n options={feedbackSelectOptions}\n onResult={handleResult}\n standalone={false}\n />\n </>\n );\n}\n\nexport default PlanApprovalPrompt;\n"]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Reusable container for prompt components.
3
+ * Provides consistent styling with dim horizontal lines above and below.
4
+ */
5
+ import React, { type ReactNode } from 'react';
6
+ interface PromptContainerProps {
7
+ children: ReactNode;
8
+ }
9
+ /**
10
+ * Container that wraps prompt content with dim horizontal lines.
11
+ * Ensures consistent styling across all input components.
12
+ */
13
+ export declare function PromptContainer({ children, }: PromptContainerProps): React.ReactElement;
14
+ export default PromptContainer;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Reusable container for prompt components.
4
+ * Provides consistent styling with dim horizontal lines above and below.
5
+ */
6
+ import React from 'react';
7
+ import { Box, Text, useStdout } from 'ink';
8
+ /**
9
+ * Container that wraps prompt content with dim horizontal lines.
10
+ * Ensures consistent styling across all input components.
11
+ */
12
+ export function PromptContainer({ children, }) {
13
+ const { stdout } = useStdout();
14
+ const terminalWidth = React.useMemo(() => stdout?.columns || 80, [stdout?.columns]);
15
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "gray", children: '─'.repeat(terminalWidth) }), children, _jsx(Text, { color: "gray", children: '─'.repeat(terminalWidth) })] }));
16
+ }
17
+ export default PromptContainer;
18
+ //# sourceMappingURL=PromptContainer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromptContainer.js","sourceRoot":"","sources":["../../../../src/ui/components/PromptContainer.tsx"],"names":[],"mappings":";AAAA;;;GAGG;AAEH,OAAO,KAAyB,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAM3C;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,GACa;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CACjC,GAAG,EAAE,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,EAC3B,CAAC,MAAM,EAAE,OAAO,CAAC,CAClB,CAAC;IAEF,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAQ,EACpD,QAAQ,EACT,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAQ,IACjD,CACP,CAAC;AACJ,CAAC;AAED,eAAe,eAAe,CAAC","sourcesContent":["/**\n * Reusable container for prompt components.\n * Provides consistent styling with dim horizontal lines above and below.\n */\n\nimport React, { type ReactNode } from 'react';\nimport { Box, Text, useStdout } from 'ink';\n\ninterface PromptContainerProps {\n children: ReactNode;\n}\n\n/**\n * Container that wraps prompt content with dim horizontal lines.\n * Ensures consistent styling across all input components.\n */\nexport function PromptContainer({\n children,\n}: PromptContainerProps): React.ReactElement {\n const { stdout } = useStdout();\n const terminalWidth = React.useMemo(\n () => stdout?.columns || 80,\n [stdout?.columns],\n );\n\n return (\n <Box flexDirection=\"column\">\n <Text color=\"gray\">{'─'.repeat(terminalWidth)}</Text>\n {children}\n <Text color=\"gray\">{'─'.repeat(terminalWidth)}</Text>\n </Box>\n );\n}\n\nexport default PromptContainer;\n"]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Select prompt component for the unified Ink app.
3
+ * Uses ink-select-input and dispatches results through WizardContext.
4
+ */
5
+ import React from 'react';
6
+ import type { SelectOptions } from '../types.js';
7
+ interface SelectPromptProps {
8
+ options: SelectOptions<unknown>;
9
+ }
10
+ /**
11
+ * Select prompt that integrates with the wizard context
12
+ */
13
+ export declare function SelectPrompt({ options }: SelectPromptProps): React.ReactElement;
14
+ export default SelectPrompt;
@@ -0,0 +1,62 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Select prompt component for the unified Ink app.
4
+ * Uses ink-select-input and dispatches results through WizardContext.
5
+ */
6
+ import { useMemo } from 'react';
7
+ import { Box, Text, useInput } from 'ink';
8
+ import SelectInput from 'ink-select-input';
9
+ import { useWizardActions } from '../contexts/WizardContext.js';
10
+ import { CANCEL_SYMBOL } from '../cancellation.js';
11
+ import { PromptContainer } from './PromptContainer.js';
12
+ /**
13
+ * Select prompt that integrates with the wizard context
14
+ */
15
+ export function SelectPrompt({ options }) {
16
+ const { resolvePending, addItem } = useWizardActions();
17
+ // Handle Ctrl+C cancellation
18
+ useInput((input, key) => {
19
+ if (key.ctrl && input === 'c') {
20
+ addItem({
21
+ type: 'select-result',
22
+ text: options.message,
23
+ label: '(cancelled)',
24
+ });
25
+ resolvePending(CANCEL_SYMBOL);
26
+ }
27
+ });
28
+ // Format items for ink-select-input
29
+ const items = useMemo(() => options.options.map((opt, index) => {
30
+ const number = `${index + 1}.`;
31
+ const label = `${number} ${opt.label}`;
32
+ return {
33
+ label,
34
+ value: opt.value,
35
+ originalLabel: opt.label,
36
+ hint: opt.hint,
37
+ };
38
+ }), [options.options]);
39
+ // Find initial index
40
+ const initialIndex = useMemo(() => {
41
+ if (options.initialValue === undefined)
42
+ return 0;
43
+ const idx = options.options.findIndex((opt) => opt.value === options.initialValue);
44
+ return idx >= 0 ? idx : 0;
45
+ }, [options.options, options.initialValue]);
46
+ // Handle selection
47
+ const handleSelect = (item) => {
48
+ addItem({
49
+ type: 'select-result',
50
+ text: options.message,
51
+ label: item.originalLabel || String(item.value),
52
+ });
53
+ resolvePending(item.value);
54
+ };
55
+ // Custom indicator component
56
+ const indicatorComponent = ({ isSelected }) => (_jsx(Text, { color: "cyan", children: isSelected ? '›' : ' ' }));
57
+ // Custom item component
58
+ const itemComponent = ({ isSelected, label, hint, }) => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: isSelected ? 'cyan' : undefined, children: label }), hint && (_jsxs(Text, { dimColor: true, children: [" ", hint] }))] }));
59
+ return (_jsxs(PromptContainer, { children: [_jsx(Text, { children: options.message }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: items, initialIndex: initialIndex, indicatorComponent: indicatorComponent, itemComponent: itemComponent, onSelect: handleSelect }) })] }));
60
+ }
61
+ export default SelectPrompt;
62
+ //# sourceMappingURL=SelectPrompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectPrompt.js","sourceRoot":"","sources":["../../../../src/ui/components/SelectPrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * Select prompt component for the unified Ink app.\n * Uses ink-select-input and dispatches results through WizardContext.\n */\n\nimport React, { useMemo } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport SelectInput from 'ink-select-input';\nimport { useWizardActions } from '../contexts/WizardContext.js';\nimport { CANCEL_SYMBOL } from '../cancellation.js';\nimport { PromptContainer } from './PromptContainer.js';\nimport type { SelectOptions } from '../types.js';\n\ninterface SelectPromptProps {\n options: SelectOptions<unknown>;\n}\n\n/**\n * Select prompt that integrates with the wizard context\n */\nexport function SelectPrompt({ options }: SelectPromptProps): React.ReactElement {\n const { resolvePending, addItem } = useWizardActions();\n\n // Handle Ctrl+C cancellation\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n addItem({\n type: 'select-result',\n text: options.message,\n label: '(cancelled)',\n });\n resolvePending(CANCEL_SYMBOL);\n }\n });\n\n // Format items for ink-select-input\n const items = useMemo(\n () =>\n options.options.map((opt, index) => {\n const number = `${index + 1}.`;\n const label = `${number} ${opt.label}`;\n\n return {\n label,\n value: opt.value,\n originalLabel: opt.label,\n hint: opt.hint,\n };\n }),\n [options.options],\n );\n\n // Find initial index\n const initialIndex = useMemo(() => {\n if (options.initialValue === undefined) return 0;\n const idx = options.options.findIndex(\n (opt) => opt.value === options.initialValue,\n );\n return idx >= 0 ? idx : 0;\n }, [options.options, options.initialValue]);\n\n // Handle selection\n const handleSelect = (item: { value: unknown; originalLabel?: string }) => {\n addItem({\n type: 'select-result',\n text: options.message,\n label: item.originalLabel || String(item.value),\n });\n resolvePending(item.value);\n };\n\n // Custom indicator component\n const indicatorComponent = ({ isSelected }: { isSelected: boolean }) => (\n <Text color=\"cyan\">{isSelected ? '›' : ' '}</Text>\n );\n\n // Custom item component\n const itemComponent = ({\n isSelected,\n label,\n hint,\n }: {\n isSelected: boolean;\n label: string;\n hint?: string;\n }) => (\n <Box flexDirection=\"column\">\n <Text color={isSelected ? 'cyan' : undefined}>{label}</Text>\n {hint && (\n <Text dimColor> {hint}</Text>\n )}\n </Box>\n );\n\n return (\n <PromptContainer>\n <Text>{options.message}</Text>\n <Box marginTop={1}>\n <SelectInput\n items={items}\n initialIndex={initialIndex}\n indicatorComponent={indicatorComponent}\n itemComponent={itemComponent}\n onSelect={handleSelect}\n />\n </Box>\n </PromptContainer>\n );\n}\n\nexport default SelectPrompt;\n"]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Spinner display component for the unified Ink app.
3
+ * Uses ink-spinner and updates via WizardContext.
4
+ */
5
+ import React from 'react';
6
+ interface SpinnerDisplayProps {
7
+ message: string;
8
+ }
9
+ /**
10
+ * Spinner display that integrates with the wizard context
11
+ */
12
+ export declare function SpinnerDisplay({ message }: SpinnerDisplayProps): React.ReactElement;
13
+ export default SpinnerDisplay;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ import InkSpinner from 'ink-spinner';
4
+ /**
5
+ * Spinner display that integrates with the wizard context
6
+ */
7
+ export function SpinnerDisplay({ message }) {
8
+ return (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: _jsx(InkSpinner, { type: "toggle9" }) }), _jsxs(Text, { children: [" ", message] })] }));
9
+ }
10
+ export default SpinnerDisplay;
11
+ //# sourceMappingURL=SpinnerDisplay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpinnerDisplay.js","sourceRoot":"","sources":["../../../../src/ui/components/SpinnerDisplay.tsx"],"names":[],"mappings":";AAMA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,UAAU,MAAM,aAAa,CAAC;AAMrC;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,OAAO,EAAuB;IAC7D,OAAO,CACL,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAChB,KAAC,UAAU,IAAC,IAAI,EAAC,SAAS,GAAG,GACxB,EACP,MAAC,IAAI,oBAAG,OAAO,IAAQ,IACnB,CACP,CAAC;AACJ,CAAC;AAED,eAAe,cAAc,CAAC","sourcesContent":["/**\n * Spinner display component for the unified Ink app.\n * Uses ink-spinner and updates via WizardContext.\n */\n\nimport React from 'react';\nimport { Box, Text } from 'ink';\nimport InkSpinner from 'ink-spinner';\n\ninterface SpinnerDisplayProps {\n message: string;\n}\n\n/**\n * Spinner display that integrates with the wizard context\n */\nexport function SpinnerDisplay({ message }: SpinnerDisplayProps): React.ReactElement {\n return (\n <Box>\n <Text color=\"cyan\">\n <InkSpinner type=\"toggle9\" />\n </Text>\n <Text> {message}</Text>\n </Box>\n );\n}\n\nexport default SpinnerDisplay;\n"]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Tool approval prompt component.
3
+ * Displays tool details and allows user to approve or deny execution.
4
+ */
5
+ import React from 'react';
6
+ import type { ToolApprovalProps } from '../types.js';
7
+ interface ToolApprovalPromptComponentProps {
8
+ props: ToolApprovalProps;
9
+ }
10
+ /**
11
+ * Tool approval prompt that shows tool details and approval options.
12
+ */
13
+ export declare function ToolApprovalPrompt({ props, }: ToolApprovalPromptComponentProps): React.ReactElement;
14
+ export default ToolApprovalPrompt;
@@ -0,0 +1,142 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Tool approval prompt component.
4
+ * Displays tool details and allows user to approve or deny execution.
5
+ */
6
+ import { useMemo } from 'react';
7
+ import { Box, Text, useInput, useStdout } from 'ink';
8
+ import SelectInput from 'ink-select-input';
9
+ import { useWizardActions } from '../contexts/WizardContext.js';
10
+ import { DiffDisplay } from './DiffDisplay.js';
11
+ import { PromptContainer } from './PromptContainer.js';
12
+ /**
13
+ * Extract the command pattern from a bash command for session approval.
14
+ * Returns the base command with the first argument(s) to match similar commands.
15
+ * Examples:
16
+ * "npm install axios" -> "npm install"
17
+ * "npm run build" -> "npm run"
18
+ * "pip install requests" -> "pip install"
19
+ */
20
+ function extractCommandPattern(command) {
21
+ const trimmed = command.trim();
22
+ const parts = trimmed.split(/\s+/);
23
+ // For package managers with subcommands, include the subcommand
24
+ if (parts.length >= 2) {
25
+ const [cmd, subcmd] = parts;
26
+ // Common package managers
27
+ if (['npm', 'yarn', 'bun', 'pip', 'pip3', 'poetry', 'cargo', 'go'].includes(cmd)) {
28
+ return `${cmd} ${subcmd}`;
29
+ }
30
+ }
31
+ // For other commands, just return the first part
32
+ return parts[0] || trimmed;
33
+ }
34
+ /**
35
+ * Tool approval prompt that shows tool details and approval options.
36
+ */
37
+ export function ToolApprovalPrompt({ props, }) {
38
+ const { toolName, input, diffContent, fileName, description } = props;
39
+ const { resolvePending } = useWizardActions();
40
+ const { stdout } = useStdout();
41
+ const terminalWidth = useMemo(() => stdout?.columns || 80, [stdout?.columns]);
42
+ // Handle Escape and Ctrl+C to cancel (deny the tool)
43
+ useInput((inputKey, key) => {
44
+ if (key.escape || (key.ctrl && inputKey === 'c')) {
45
+ handleSelection({ value: 'deny', label: '' });
46
+ }
47
+ });
48
+ // Get filename without path for the question
49
+ const fileNameOnly = useMemo(() => {
50
+ if (!fileName)
51
+ return '';
52
+ return fileName.split('/').pop() || fileName;
53
+ }, [fileName]);
54
+ // Get command pattern for Bash commands
55
+ const commandPattern = useMemo(() => {
56
+ if (toolName === 'Bash' && typeof input.command === 'string') {
57
+ return extractCommandPattern(input.command);
58
+ }
59
+ return undefined;
60
+ }, [toolName, input.command]);
61
+ // Approval options
62
+ const items = useMemo(() => {
63
+ // For file edits, show file-specific "allow all" option
64
+ if ((toolName === 'Edit' || toolName === 'Write') && fileNameOnly) {
65
+ return [
66
+ { label: 'Yes', value: 'allow' },
67
+ { label: `Yes, allow all edits to ${fileNameOnly} during this session`, value: 'allow-all-session' },
68
+ { label: 'No', value: 'deny' },
69
+ ];
70
+ }
71
+ // For Bash commands, show command-specific "allow all" option
72
+ if (toolName === 'Bash' && commandPattern) {
73
+ return [
74
+ { label: 'Yes', value: 'allow' },
75
+ { label: `Yes, allow all ${commandPattern} commands this session`, value: 'allow-all-command' },
76
+ { label: 'No', value: 'deny' },
77
+ ];
78
+ }
79
+ // Default options
80
+ return [
81
+ { label: 'Yes', value: 'allow' },
82
+ { label: 'No', value: 'deny' },
83
+ ];
84
+ }, [toolName, fileNameOnly, commandPattern]);
85
+ // Handle selection
86
+ const handleSelection = (item) => {
87
+ let result;
88
+ if (item.value === 'allow') {
89
+ result = { behavior: 'allow', updatedInput: input };
90
+ }
91
+ else if (item.value === 'allow-all-session') {
92
+ result = {
93
+ behavior: 'allow',
94
+ updatedInput: input,
95
+ allowAllForFile: fileName
96
+ };
97
+ }
98
+ else if (item.value === 'allow-all-command') {
99
+ result = {
100
+ behavior: 'allow',
101
+ updatedInput: input,
102
+ allowAllForCommandPattern: commandPattern
103
+ };
104
+ }
105
+ else {
106
+ result = { behavior: 'deny', message: 'User denied this action' };
107
+ }
108
+ resolvePending(result);
109
+ };
110
+ // Custom indicator component
111
+ const indicatorComponent = ({ isSelected }) => (_jsx(Text, { color: "cyan", children: isSelected ? '›' : ' ' }));
112
+ // Custom item component with numbers and bold command
113
+ const itemComponent = ({ isSelected, label, }) => {
114
+ const index = items.findIndex((item) => item.label === label);
115
+ const color = isSelected ? 'cyan' : undefined;
116
+ // Check if this label contains the command pattern to bold it
117
+ if (commandPattern && label.includes(commandPattern)) {
118
+ const parts = label.split(commandPattern);
119
+ return (_jsxs(Text, { color: color, children: [index + 1, ". ", parts[0], _jsx(Text, { bold: true, children: commandPattern }), parts[1]] }));
120
+ }
121
+ return (_jsxs(Text, { color: color, children: [index + 1, ". ", label] }));
122
+ };
123
+ // Render tool-specific details
124
+ const renderToolDetails = () => {
125
+ // For file modifications with diff content, show the diff
126
+ if (diffContent && fileName) {
127
+ const action = toolName === 'Write' ? 'Write file' : 'Edit file';
128
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { bold: true, children: [action, " "] }), _jsx(Text, { color: "cyan", children: fileName })] }), _jsx(Box, { marginTop: 1, children: _jsx(DiffDisplay, { diffContent: diffContent, maxHeight: 20 }) })] }));
129
+ }
130
+ // For Bash commands, show the command
131
+ if (toolName === 'Bash' && input.command) {
132
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Command:" }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { bold: true, children: String(input.command) }) })] }));
133
+ }
134
+ // For other tools, show input as JSON
135
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Input:" }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { dimColor: true, children: JSON.stringify(input, null, 2) }) })] }));
136
+ };
137
+ return (_jsxs(PromptContainer, { children: [_jsx(Box, { marginBottom: 1, flexDirection: "column", children: renderToolDetails() }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: '─'.repeat(terminalWidth) }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: toolName === 'Bash'
138
+ ? 'Do you want to proceed?'
139
+ : `Do you want to make this ${toolName.toLowerCase()} to ${fileNameOnly || 'this file'}?` }) }), _jsx(Box, { children: _jsx(SelectInput, { items: items, indicatorComponent: indicatorComponent, itemComponent: itemComponent, onSelect: handleSelection }) })] }));
140
+ }
141
+ export default ToolApprovalPrompt;
142
+ //# sourceMappingURL=ToolApprovalPrompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolApprovalPrompt.js","sourceRoot":"","sources":["../../../../src/ui/components/ToolApprovalPrompt.tsx"],"names":[],"mappings":";AAAA;;;GAGG;AAEH,OAAc,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,WAAW,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAcvD;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAC,OAAe;IAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAEnC,gEAAgE;IAChE,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;QAC5B,0BAA0B;QAC1B,IACE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAC5E,CAAC;YACD,OAAO,GAAG,GAAG,IAAI,MAAM,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,KAAK,GAC4B;IACjC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;IACtE,MAAM,EAAE,cAAc,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAE9E,qDAAqD;IACrD,QAAQ,CAAC,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE;QACzB,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,QAAQ,KAAK,GAAG,CAAC,EAAE,CAAC;YACjD,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,6CAA6C;IAC7C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,EAAE;QAChC,IAAI,CAAC,QAAQ;YAAE,OAAO,EAAE,CAAC;QACzB,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC;IAC/C,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,wCAAwC;IACxC,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,EAAE;QAClC,IAAI,QAAQ,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC7D,OAAO,qBAAqB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAE9B,mBAAmB;IACnB,MAAM,KAAK,GAAiB,OAAO,CAAC,GAAG,EAAE;QACvC,wDAAwD;QACxD,IAAI,CAAC,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,OAAO,CAAC,IAAI,YAAY,EAAE,CAAC;YAClE,OAAO;gBACL,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE;gBAChC,EAAE,KAAK,EAAE,2BAA2B,YAAY,sBAAsB,EAAE,KAAK,EAAE,mBAAmB,EAAE;gBACpG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;aAC/B,CAAC;QACJ,CAAC;QAED,8DAA8D;QAC9D,IAAI,QAAQ,KAAK,MAAM,IAAI,cAAc,EAAE,CAAC;YAC1C,OAAO;gBACL,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE;gBAChC,EAAE,KAAK,EAAE,kBAAkB,cAAc,wBAAwB,EAAE,KAAK,EAAE,mBAAmB,EAAE;gBAC/F,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;aAC/B,CAAC;QACJ,CAAC;QAED,kBAAkB;QAClB,OAAO;YACL,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE;YAChC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;SAC/B,CAAC;IACJ,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;IAE7C,mBAAmB;IACnB,MAAM,eAAe,GAAG,CAAC,IAA8C,EAAE,EAAE;QACzE,IAAI,MAA0B,CAAC;QAE/B,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YAC3B,MAAM,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QACtD,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,KAAK,mBAAmB,EAAE,CAAC;YAC9C,MAAM,GAAG;gBACP,QAAQ,EAAE,OAAO;gBACjB,YAAY,EAAE,KAAK;gBACnB,eAAe,EAAE,QAAQ;aAC1B,CAAC;QACJ,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,KAAK,mBAAmB,EAAE,CAAC;YAC9C,MAAM,GAAG;gBACP,QAAQ,EAAE,OAAO;gBACjB,YAAY,EAAE,KAAK;gBACnB,yBAAyB,EAAE,cAAc;aAC1C,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC;QACpE,CAAC;QAED,cAAc,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC,CAAC;IAEF,6BAA6B;IAC7B,MAAM,kBAAkB,GAAG,CAAC,EAAE,UAAU,EAA2B,EAAE,EAAE,CAAC,CACtE,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAQ,CACnD,CAAC;IAEF,sDAAsD;IACtD,MAAM,aAAa,GAAG,CAAC,EACrB,UAAU,EACV,KAAK,GAIN,EAAE,EAAE;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QAE9C,8DAA8D;QAC9D,IAAI,cAAc,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YAC1C,OAAO,CACL,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,aACf,KAAK,GAAG,CAAC,QAAI,KAAK,CAAC,CAAC,CAAC,EACtB,KAAC,IAAI,IAAC,IAAI,kBAAE,cAAc,GAAQ,EACjC,KAAK,CAAC,CAAC,CAAC,IACJ,CACR,CAAC;QACJ,CAAC;QAED,OAAO,CACL,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,aACf,KAAK,GAAG,CAAC,QAAI,KAAK,IACd,CACR,CAAC;IACJ,CAAC,CAAC;IAEF,+BAA+B;IAC/B,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC7B,0DAA0D;QAC1D,IAAI,WAAW,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC;YACjE,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,IAAI,mBAAE,MAAM,SAAS,EAC3B,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,QAAQ,GAAQ,IAChC,EACN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,WAAW,IAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,GAAI,GACpD,IACF,CACP,CAAC;QACJ,CAAC;QAED,sCAAsC;QACtC,IAAI,QAAQ,KAAK,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACzC,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,IAAI,2BAAgB,EACrB,KAAC,GAAG,IAAC,UAAU,EAAE,CAAC,YAChB,KAAC,IAAI,IAAC,IAAI,kBAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAQ,GACrC,IACF,CACP,CAAC;QACJ,CAAC;QAED,sCAAsC;QACtC,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,IAAI,IAAC,IAAI,6BAAc,EACxB,KAAC,GAAG,IAAC,UAAU,EAAE,CAAC,YAChB,KAAC,IAAI,IAAC,QAAQ,kBAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAQ,GAClD,IACF,CACP,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,eAAe,eAEd,KAAC,GAAG,IAAC,YAAY,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,YACzC,iBAAiB,EAAE,GAChB,EAGN,KAAC,GAAG,cACF,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAQ,GAC7C,EAGN,KAAC,GAAG,IAAC,YAAY,EAAE,CAAC,YAClB,KAAC,IAAI,cACF,QAAQ,KAAK,MAAM;wBAClB,CAAC,CAAC,yBAAyB;wBAC3B,CAAC,CAAC,4BAA4B,QAAQ,CAAC,WAAW,EAAE,OAAO,YAAY,IAAI,WAAW,GAAG,GACtF,GACH,EAGN,KAAC,GAAG,cACF,KAAC,WAAW,IACV,KAAK,EAAE,KAAK,EACZ,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,eAAe,GACzB,GACE,IACU,CACnB,CAAC;AACJ,CAAC;AAED,eAAe,kBAAkB,CAAC","sourcesContent":["/**\n * Tool approval prompt component.\n * Displays tool details and allows user to approve or deny execution.\n */\n\nimport React, { useMemo } from 'react';\nimport { Box, Text, useInput, useStdout } from 'ink';\nimport SelectInput from 'ink-select-input';\nimport { useWizardActions } from '../contexts/WizardContext.js';\nimport { DiffDisplay } from './DiffDisplay.js';\nimport { PromptContainer } from './PromptContainer.js';\nimport type { ToolApprovalProps, ToolApprovalResult } from '../types.js';\n\ninterface ToolApprovalPromptComponentProps {\n props: ToolApprovalProps;\n}\n\ntype ApprovalOption = 'allow' | 'allow-all-session' | 'allow-all-command' | 'deny';\n\ninterface SelectItem {\n label: string;\n value: ApprovalOption;\n}\n\n/**\n * Extract the command pattern from a bash command for session approval.\n * Returns the base command with the first argument(s) to match similar commands.\n * Examples:\n * \"npm install axios\" -> \"npm install\"\n * \"npm run build\" -> \"npm run\"\n * \"pip install requests\" -> \"pip install\"\n */\nfunction extractCommandPattern(command: string): string {\n const trimmed = command.trim();\n const parts = trimmed.split(/\\s+/);\n\n // For package managers with subcommands, include the subcommand\n if (parts.length >= 2) {\n const [cmd, subcmd] = parts;\n // Common package managers\n if (\n ['npm', 'yarn', 'bun', 'pip', 'pip3', 'poetry', 'cargo', 'go'].includes(cmd)\n ) {\n return `${cmd} ${subcmd}`;\n }\n }\n\n // For other commands, just return the first part\n return parts[0] || trimmed;\n}\n\n/**\n * Tool approval prompt that shows tool details and approval options.\n */\nexport function ToolApprovalPrompt({\n props,\n}: ToolApprovalPromptComponentProps): React.ReactElement {\n const { toolName, input, diffContent, fileName, description } = props;\n const { resolvePending } = useWizardActions();\n const { stdout } = useStdout();\n const terminalWidth = useMemo(() => stdout?.columns || 80, [stdout?.columns]);\n\n // Handle Escape and Ctrl+C to cancel (deny the tool)\n useInput((inputKey, key) => {\n if (key.escape || (key.ctrl && inputKey === 'c')) {\n handleSelection({ value: 'deny', label: '' });\n }\n });\n\n // Get filename without path for the question\n const fileNameOnly = useMemo(() => {\n if (!fileName) return '';\n return fileName.split('/').pop() || fileName;\n }, [fileName]);\n\n // Get command pattern for Bash commands\n const commandPattern = useMemo(() => {\n if (toolName === 'Bash' && typeof input.command === 'string') {\n return extractCommandPattern(input.command);\n }\n return undefined;\n }, [toolName, input.command]);\n\n // Approval options\n const items: SelectItem[] = useMemo(() => {\n // For file edits, show file-specific \"allow all\" option\n if ((toolName === 'Edit' || toolName === 'Write') && fileNameOnly) {\n return [\n { label: 'Yes', value: 'allow' },\n { label: `Yes, allow all edits to ${fileNameOnly} during this session`, value: 'allow-all-session' },\n { label: 'No', value: 'deny' },\n ];\n }\n\n // For Bash commands, show command-specific \"allow all\" option\n if (toolName === 'Bash' && commandPattern) {\n return [\n { label: 'Yes', value: 'allow' },\n { label: `Yes, allow all ${commandPattern} commands this session`, value: 'allow-all-command' },\n { label: 'No', value: 'deny' },\n ];\n }\n\n // Default options\n return [\n { label: 'Yes', value: 'allow' },\n { label: 'No', value: 'deny' },\n ];\n }, [toolName, fileNameOnly, commandPattern]);\n\n // Handle selection\n const handleSelection = (item: { value: ApprovalOption; label: string }) => {\n let result: ToolApprovalResult;\n\n if (item.value === 'allow') {\n result = { behavior: 'allow', updatedInput: input };\n } else if (item.value === 'allow-all-session') {\n result = {\n behavior: 'allow',\n updatedInput: input,\n allowAllForFile: fileName\n };\n } else if (item.value === 'allow-all-command') {\n result = {\n behavior: 'allow',\n updatedInput: input,\n allowAllForCommandPattern: commandPattern\n };\n } else {\n result = { behavior: 'deny', message: 'User denied this action' };\n }\n\n resolvePending(result);\n };\n\n // Custom indicator component\n const indicatorComponent = ({ isSelected }: { isSelected: boolean }) => (\n <Text color=\"cyan\">{isSelected ? '›' : ' '}</Text>\n );\n\n // Custom item component with numbers and bold command\n const itemComponent = ({\n isSelected,\n label,\n }: {\n isSelected: boolean;\n label: string;\n }) => {\n const index = items.findIndex((item) => item.label === label);\n const color = isSelected ? 'cyan' : undefined;\n\n // Check if this label contains the command pattern to bold it\n if (commandPattern && label.includes(commandPattern)) {\n const parts = label.split(commandPattern);\n return (\n <Text color={color}>\n {index + 1}. {parts[0]}\n <Text bold>{commandPattern}</Text>\n {parts[1]}\n </Text>\n );\n }\n\n return (\n <Text color={color}>\n {index + 1}. {label}\n </Text>\n );\n };\n\n // Render tool-specific details\n const renderToolDetails = () => {\n // For file modifications with diff content, show the diff\n if (diffContent && fileName) {\n const action = toolName === 'Write' ? 'Write file' : 'Edit file';\n return (\n <Box flexDirection=\"column\">\n <Box>\n <Text bold>{action} </Text>\n <Text color=\"cyan\">{fileName}</Text>\n </Box>\n <Box marginTop={1}>\n <DiffDisplay diffContent={diffContent} maxHeight={20} />\n </Box>\n </Box>\n );\n }\n\n // For Bash commands, show the command\n if (toolName === 'Bash' && input.command) {\n return (\n <Box flexDirection=\"column\">\n <Text>Command:</Text>\n <Box marginLeft={2}>\n <Text bold>{String(input.command)}</Text>\n </Box>\n </Box>\n );\n }\n\n // For other tools, show input as JSON\n return (\n <Box flexDirection=\"column\">\n <Text bold>Input:</Text>\n <Box marginLeft={2}>\n <Text dimColor>{JSON.stringify(input, null, 2)}</Text>\n </Box>\n </Box>\n );\n };\n\n return (\n <PromptContainer>\n {/* Tool details (Edit file path and diff) */}\n <Box marginBottom={1} flexDirection=\"column\">\n {renderToolDetails()}\n </Box>\n\n {/* Horizontal separator */}\n <Box>\n <Text dimColor>{'─'.repeat(terminalWidth)}</Text>\n </Box>\n\n {/* Question */}\n <Box marginBottom={1}>\n <Text>\n {toolName === 'Bash'\n ? 'Do you want to proceed?'\n : `Do you want to make this ${toolName.toLowerCase()} to ${fileNameOnly || 'this file'}?`}\n </Text>\n </Box>\n\n {/* Selection options */}\n <Box>\n <SelectInput\n items={items}\n indicatorComponent={indicatorComponent}\n itemComponent={itemComponent}\n onSelect={handleSelection}\n />\n </Box>\n </PromptContainer>\n );\n}\n\nexport default ToolApprovalPrompt;\n"]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Tool call display component for history items.
3
+ * Shows tool execution status, name, and optional details.
4
+ */
5
+ import React from 'react';
6
+ import type { ToolCallInfo } from '../types.js';
7
+ interface ToolCallDisplayProps {
8
+ toolCall: ToolCallInfo;
9
+ }
10
+ /**
11
+ * Display a tool call in the history
12
+ */
13
+ export declare function ToolCallDisplay({ toolCall, }: ToolCallDisplayProps): React.ReactElement;
14
+ export default ToolCallDisplay;