@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.
- package/LICENSE +47 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +117 -0
- package/dist/bin.js.map +1 -0
- package/dist/src/docs/browser.md +105 -0
- package/dist/src/docs/python.md +618 -0
- package/dist/src/docs/typescript.md +584 -0
- package/dist/src/docs/vercel-ai-sdk.md +304 -0
- package/dist/src/lib/agent-interface.d.ts +46 -0
- package/dist/src/lib/agent-interface.js +292 -0
- package/dist/src/lib/agent-interface.js.map +1 -0
- package/dist/src/lib/agent-prompts.d.ts +10 -0
- package/dist/src/lib/agent-prompts.js +49 -0
- package/dist/src/lib/agent-prompts.js.map +1 -0
- package/dist/src/lib/config.d.ts +39 -0
- package/dist/src/lib/config.js +549 -0
- package/dist/src/lib/config.js.map +1 -0
- package/dist/src/lib/constants.d.ts +27 -0
- package/dist/src/lib/constants.js +165 -0
- package/dist/src/lib/constants.js.map +1 -0
- package/dist/src/lib/handlers.d.ts +68 -0
- package/dist/src/lib/handlers.js +420 -0
- package/dist/src/lib/handlers.js.map +1 -0
- package/dist/src/lib/integration-testing.d.ts +44 -0
- package/dist/src/lib/integration-testing.js +123 -0
- package/dist/src/lib/integration-testing.js.map +1 -0
- package/dist/src/lib/mcp.d.ts +14 -0
- package/dist/src/lib/mcp.js +134 -0
- package/dist/src/lib/mcp.js.map +1 -0
- package/dist/src/lib/sdk-messages.d.ts +17 -0
- package/dist/src/lib/sdk-messages.js +278 -0
- package/dist/src/lib/sdk-messages.js.map +1 -0
- package/dist/src/lib/wizard.d.ts +6 -0
- package/dist/src/lib/wizard.js +131 -0
- package/dist/src/lib/wizard.js.map +1 -0
- package/dist/src/run.d.ts +8 -0
- package/dist/src/run.js +53 -0
- package/dist/src/run.js.map +1 -0
- package/dist/src/ui/App.d.ts +15 -0
- package/dist/src/ui/App.js +27 -0
- package/dist/src/ui/App.js.map +1 -0
- package/dist/src/ui/cancellation.d.ts +14 -0
- package/dist/src/ui/cancellation.js +17 -0
- package/dist/src/ui/cancellation.js.map +1 -0
- package/dist/src/ui/components/ClarifyingQuestionsPrompt.d.ts +17 -0
- package/dist/src/ui/components/ClarifyingQuestionsPrompt.js +359 -0
- package/dist/src/ui/components/ClarifyingQuestionsPrompt.js.map +1 -0
- package/dist/src/ui/components/ContinuePrompt.d.ts +14 -0
- package/dist/src/ui/components/ContinuePrompt.js +23 -0
- package/dist/src/ui/components/ContinuePrompt.js.map +1 -0
- package/dist/src/ui/components/DiffDisplay.d.ts +18 -0
- package/dist/src/ui/components/DiffDisplay.js +110 -0
- package/dist/src/ui/components/DiffDisplay.js.map +1 -0
- package/dist/src/ui/components/FeedbackSelectPrompt.d.ts +20 -0
- package/dist/src/ui/components/FeedbackSelectPrompt.js +132 -0
- package/dist/src/ui/components/FeedbackSelectPrompt.js.map +1 -0
- package/dist/src/ui/components/HistoryItemDisplay.d.ts +14 -0
- package/dist/src/ui/components/HistoryItemDisplay.js +140 -0
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -0
- package/dist/src/ui/components/Logo.d.ts +10 -0
- package/dist/src/ui/components/Logo.js +47 -0
- package/dist/src/ui/components/Logo.js.map +1 -0
- package/dist/src/ui/components/OrgInfoBox.d.ts +11 -0
- package/dist/src/ui/components/OrgInfoBox.js +16 -0
- package/dist/src/ui/components/OrgInfoBox.js.map +1 -0
- package/dist/src/ui/components/PendingPrompt.d.ts +18 -0
- package/dist/src/ui/components/PendingPrompt.js +57 -0
- package/dist/src/ui/components/PendingPrompt.js.map +1 -0
- package/dist/src/ui/components/PersistentTextInput.d.ts +21 -0
- package/dist/src/ui/components/PersistentTextInput.js +117 -0
- package/dist/src/ui/components/PersistentTextInput.js.map +1 -0
- package/dist/src/ui/components/PlanApprovalPrompt.d.ts +19 -0
- package/dist/src/ui/components/PlanApprovalPrompt.js +62 -0
- package/dist/src/ui/components/PlanApprovalPrompt.js.map +1 -0
- package/dist/src/ui/components/PromptContainer.d.ts +14 -0
- package/dist/src/ui/components/PromptContainer.js +18 -0
- package/dist/src/ui/components/PromptContainer.js.map +1 -0
- package/dist/src/ui/components/SelectPrompt.d.ts +14 -0
- package/dist/src/ui/components/SelectPrompt.js +62 -0
- package/dist/src/ui/components/SelectPrompt.js.map +1 -0
- package/dist/src/ui/components/SpinnerDisplay.d.ts +13 -0
- package/dist/src/ui/components/SpinnerDisplay.js +11 -0
- package/dist/src/ui/components/SpinnerDisplay.js.map +1 -0
- package/dist/src/ui/components/ToolApprovalPrompt.d.ts +14 -0
- package/dist/src/ui/components/ToolApprovalPrompt.js +142 -0
- package/dist/src/ui/components/ToolApprovalPrompt.js.map +1 -0
- package/dist/src/ui/components/ToolCallDisplay.d.ts +14 -0
- package/dist/src/ui/components/ToolCallDisplay.js +83 -0
- package/dist/src/ui/components/ToolCallDisplay.js.map +1 -0
- package/dist/src/ui/components/WriteKeyDisplay.d.ts +15 -0
- package/dist/src/ui/components/WriteKeyDisplay.js +13 -0
- package/dist/src/ui/components/WriteKeyDisplay.js.map +1 -0
- package/dist/src/ui/contexts/WizardContext.d.ts +210 -0
- package/dist/src/ui/contexts/WizardContext.js +362 -0
- package/dist/src/ui/contexts/WizardContext.js.map +1 -0
- package/dist/src/ui/hooks/useCancellation.d.ts +15 -0
- package/dist/src/ui/hooks/useCancellation.js +25 -0
- package/dist/src/ui/hooks/useCancellation.js.map +1 -0
- package/dist/src/ui/render.d.ts +34 -0
- package/dist/src/ui/render.js +94 -0
- package/dist/src/ui/render.js.map +1 -0
- package/dist/src/ui/types.d.ts +184 -0
- package/dist/src/ui/types.js +6 -0
- package/dist/src/ui/types.js.map +1 -0
- package/dist/src/utils/clack-utils.d.ts +13 -0
- package/dist/src/utils/clack-utils.js +131 -0
- package/dist/src/utils/clack-utils.js.map +1 -0
- package/dist/src/utils/debug.d.ts +13 -0
- package/dist/src/utils/debug.js +47 -0
- package/dist/src/utils/debug.js.map +1 -0
- package/dist/src/utils/environment.d.ts +5 -0
- package/dist/src/utils/environment.js +131 -0
- package/dist/src/utils/environment.js.map +1 -0
- package/dist/src/utils/logging.d.ts +9 -0
- package/dist/src/utils/logging.js +38 -0
- package/dist/src/utils/logging.js.map +1 -0
- package/dist/src/utils/oauth.d.ts +12 -0
- package/dist/src/utils/oauth.js +497 -0
- package/dist/src/utils/oauth.js.map +1 -0
- package/dist/src/utils/package-json-types.d.ts +44 -0
- package/dist/src/utils/package-json-types.js +6 -0
- package/dist/src/utils/package-json-types.js.map +1 -0
- package/dist/src/utils/package-json.d.ts +19 -0
- package/dist/src/utils/package-json.js +22 -0
- package/dist/src/utils/package-json.js.map +1 -0
- package/dist/src/utils/session.d.ts +2 -0
- package/dist/src/utils/session.js +87 -0
- package/dist/src/utils/session.js.map +1 -0
- package/dist/src/utils/types.d.ts +61 -0
- package/dist/src/utils/types.js +2 -0
- package/dist/src/utils/types.js.map +1 -0
- package/dist/src/utils/ui.d.ts +120 -0
- package/dist/src/utils/ui.js +164 -0
- package/dist/src/utils/ui.js.map +1 -0
- 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":";AAAA;;;;;;;;GAQG;AAEH,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAOnD;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAClC,KAAK,GAC6B;IAClC,MAAM,EACJ,WAAW,EACX,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,OAAO,GACR,GAAG,KAAK,CAAC;IAEV,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,0BAA0B,EAAE,GAC3D,gBAAgB,EAAE,CAAC;IACrB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IACvD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEtD,2BAA2B;IAC3B,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,gBAAgB;QAChB,IAAI,GAAG,CAAC,IAAI,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAC9B,uDAAuD;YACvD,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;gBACjB,QAAQ,CAAC,EAAE,CAAC,CAAC;gBACb,0BAA0B,CAAC,EAAE,CAAC,CAAC;gBAC/B,cAAc,CAAC,IAAI,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;YAED,gDAAgD;YAChD,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,OAAO,EAAE,CAAC;oBACZ,+BAA+B;oBAC/B,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,IAAI,WAAW,EAAE,CAAC;oBACvB,6CAA6C;oBAC7C,WAAW,EAAE,CAAC;gBAChB,CAAC;qBAAM,CAAC;oBACN,6DAA6D;oBAC7D,OAAO,CAAC;wBACN,IAAI,EAAE,aAAa;wBACnB,IAAI,EAAE,OAAO,IAAI,EAAE;wBACnB,KAAK,EAAE,aAAa;qBACrB,CAAC,CAAC;oBACH,cAAc,CAAC,aAAa,CAAC,CAAC;gBAChC,CAAC;gBACD,OAAO;YACT,CAAC;YAED,oDAAoD;YACpD,cAAc,CAAC,IAAI,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,gBAAgB;QAChB,IAAI,GAAG,CAAC,MAAM,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;YACnC,IAAI,WAAW,EAAE,CAAC;gBAChB,kCAAkC;gBAClC,WAAW,EAAE,CAAC;YAChB,CAAC;iBAAM,CAAC;gBACN,6DAA6D;gBAC7D,OAAO,CAAC;oBACN,IAAI,EAAE,aAAa;oBACnB,IAAI,EAAE,OAAO,IAAI,EAAE;oBACnB,KAAK,EAAE,aAAa;iBACrB,CAAC,CAAC;gBACH,cAAc,CAAC,aAAa,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,oBAAoB;IACpB,MAAM,YAAY,GAAG,CAAC,cAAsB,EAAE,EAAE;QAC9C,iCAAiC;QACjC,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,eAAe,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;YACjD,IAAI,eAAe,EAAE,CAAC;gBACpB,QAAQ,CAAC,eAAe,CAAC,CAAC;gBAC1B,OAAO;YACT,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,+BAA+B;YAC/B,IAAI,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC1B,KAAK,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;gBACtD,QAAQ,CAAC,EAAE,CAAC,CAAC;gBACb,+BAA+B;gBAC/B,0BAA0B,CAAC,EAAE,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,uDAAuD;YACvD,cAAc,CAAC,cAAc,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,eAAe,eAEb,OAAO,IAAI,KAAC,IAAI,cAAE,OAAO,GAAQ,EAGlC,MAAC,GAAG,IAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAC7B,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,wBAAU,EAC5B,KAAC,SAAS,IACR,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE;4BACrB,QAAQ,CAAC,QAAQ,CAAC,CAAC;4BACnB,2FAA2F;4BAC3F,0BAA0B,CAAC,QAAQ,CAAC,CAAC;4BACrC,IAAI,KAAK;gCAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;4BAC1B,2CAA2C;4BAC3C,IAAI,WAAW;gCAAE,cAAc,CAAC,KAAK,CAAC,CAAC;wBACzC,CAAC,EACD,WAAW,EAAE,WAAW,IAAI,uCAAuC,EACnE,QAAQ,EAAE,YAAY,GACtB,IACE,EAGL,KAAK,IAAI,CACR,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,YAAE,KAAK,GAAQ,GAC5B,CACP,IACe,CACnB,CAAC;AACJ,CAAC;AAED,eAAe,mBAAmB,CAAC","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":"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","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;
|