@orderful/droid 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +19 -1
- package/CHANGELOG.md +13 -0
- package/dist/bin/droid.js +8 -8
- package/dist/bin/droid.js.map +1 -1
- package/dist/commands/config.js +1 -1
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/install.js +3 -3
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +3 -3
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skills.js +4 -4
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/tui/components/Badge.d.ts +13 -0
- package/dist/commands/tui/components/Badge.d.ts.map +1 -0
- package/dist/commands/tui/components/Badge.js +29 -0
- package/dist/commands/tui/components/Badge.js.map +1 -0
- package/dist/commands/tui/components/Markdown.d.ts +5 -0
- package/dist/commands/tui/components/Markdown.d.ts.map +1 -0
- package/dist/commands/tui/components/Markdown.js +42 -0
- package/dist/commands/tui/components/Markdown.js.map +1 -0
- package/dist/commands/tui/components/SettingsDetails.d.ts +5 -0
- package/dist/commands/tui/components/SettingsDetails.d.ts.map +1 -0
- package/dist/commands/tui/components/SettingsDetails.js +11 -0
- package/dist/commands/tui/components/SettingsDetails.js.map +1 -0
- package/dist/commands/tui/components/TabBar.d.ts +10 -0
- package/dist/commands/tui/components/TabBar.d.ts.map +1 -0
- package/dist/commands/tui/components/TabBar.js +7 -0
- package/dist/commands/tui/components/TabBar.js.map +1 -0
- package/dist/commands/tui/components/ToolDetails.d.ts +8 -0
- package/dist/commands/tui/components/ToolDetails.d.ts.map +1 -0
- package/dist/commands/tui/components/ToolDetails.js +35 -0
- package/dist/commands/tui/components/ToolDetails.js.map +1 -0
- package/dist/commands/tui/components/ToolItem.d.ts +9 -0
- package/dist/commands/tui/components/ToolItem.d.ts.map +1 -0
- package/dist/commands/tui/components/ToolItem.js +11 -0
- package/dist/commands/tui/components/ToolItem.js.map +1 -0
- package/dist/commands/tui/constants.d.ts +16 -0
- package/dist/commands/tui/constants.d.ts.map +1 -0
- package/dist/commands/tui/constants.js +17 -0
- package/dist/commands/tui/constants.js.map +1 -0
- package/dist/commands/tui/hooks/useAppUpdate.d.ts +13 -0
- package/dist/commands/tui/hooks/useAppUpdate.d.ts.map +1 -0
- package/dist/commands/tui/hooks/useAppUpdate.js +52 -0
- package/dist/commands/tui/hooks/useAppUpdate.js.map +1 -0
- package/dist/commands/tui/hooks/useToolUpdates.d.ts +22 -0
- package/dist/commands/tui/hooks/useToolUpdates.d.ts.map +1 -0
- package/dist/commands/tui/hooks/useToolUpdates.js +77 -0
- package/dist/commands/tui/hooks/useToolUpdates.js.map +1 -0
- package/dist/commands/tui/types.d.ts +5 -0
- package/dist/commands/tui/types.d.ts.map +1 -0
- package/dist/commands/tui/types.js +2 -0
- package/dist/commands/tui/types.js.map +1 -0
- package/dist/commands/tui/views/ReadmeViewer.d.ts +7 -0
- package/dist/commands/tui/views/ReadmeViewer.d.ts.map +1 -0
- package/dist/commands/tui/views/ReadmeViewer.js +56 -0
- package/dist/commands/tui/views/ReadmeViewer.js.map +1 -0
- package/dist/commands/tui/views/SetupScreen.d.ts +8 -0
- package/dist/commands/tui/views/SetupScreen.d.ts.map +1 -0
- package/dist/commands/tui/views/SetupScreen.js +114 -0
- package/dist/commands/tui/views/SetupScreen.js.map +1 -0
- package/dist/commands/tui/views/SkillConfigScreen.d.ts +8 -0
- package/dist/commands/tui/views/SkillConfigScreen.d.ts.map +1 -0
- package/dist/commands/tui/views/SkillConfigScreen.js +148 -0
- package/dist/commands/tui/views/SkillConfigScreen.js.map +1 -0
- package/dist/commands/tui/views/ToolExplorer.d.ts +8 -0
- package/dist/commands/tui/views/ToolExplorer.d.ts.map +1 -0
- package/dist/commands/tui/views/ToolExplorer.js +86 -0
- package/dist/commands/tui/views/ToolExplorer.js.map +1 -0
- package/dist/commands/tui/views/ToolUpdatePrompt.d.ts +10 -0
- package/dist/commands/tui/views/ToolUpdatePrompt.d.ts.map +1 -0
- package/dist/commands/tui/views/ToolUpdatePrompt.js +38 -0
- package/dist/commands/tui/views/ToolUpdatePrompt.js.map +1 -0
- package/dist/commands/tui/views/WelcomeScreen.d.ts +11 -0
- package/dist/commands/tui/views/WelcomeScreen.d.ts.map +1 -0
- package/dist/commands/tui/views/WelcomeScreen.js +46 -0
- package/dist/commands/tui/views/WelcomeScreen.js.map +1 -0
- package/dist/commands/tui.d.ts.map +1 -1
- package/dist/commands/tui.js +54 -755
- package/dist/commands/tui.js.map +1 -1
- package/dist/commands/uninstall.js +2 -2
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +1 -1
- package/dist/commands/update.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/lib/agents.d.ts +1 -1
- package/dist/lib/agents.d.ts.map +1 -1
- package/dist/lib/agents.js +4 -4
- package/dist/lib/agents.js.map +1 -1
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/platforms.d.ts +1 -1
- package/dist/lib/platforms.d.ts.map +1 -1
- package/dist/lib/platforms.js +1 -1
- package/dist/lib/platforms.js.map +1 -1
- package/dist/lib/skill-config.d.ts +1 -1
- package/dist/lib/skill-config.d.ts.map +1 -1
- package/dist/lib/skill-config.js +2 -2
- package/dist/lib/skill-config.js.map +1 -1
- package/dist/lib/skills.d.ts +1 -1
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +5 -5
- package/dist/lib/skills.js.map +1 -1
- package/dist/lib/tools.d.ts +1 -1
- package/dist/lib/tools.d.ts.map +1 -1
- package/dist/lib/tools.js +3 -3
- package/dist/lib/tools.js.map +1 -1
- package/package.json +3 -3
- package/src/bin/droid.ts +8 -8
- package/src/commands/config.ts +1 -1
- package/src/commands/install.ts +3 -3
- package/src/commands/setup.test.ts +1 -1
- package/src/commands/setup.ts +3 -3
- package/src/commands/skills.ts +4 -4
- package/src/commands/tui/components/Badge.tsx +86 -0
- package/src/commands/tui/components/Markdown.tsx +48 -0
- package/src/commands/tui/components/SettingsDetails.tsx +70 -0
- package/src/commands/tui/components/TabBar.tsx +26 -0
- package/src/commands/tui/components/ToolDetails.tsx +117 -0
- package/src/commands/tui/components/ToolItem.tsx +39 -0
- package/src/commands/tui/constants.ts +17 -0
- package/src/commands/tui/hooks/useAppUpdate.ts +67 -0
- package/src/commands/tui/hooks/useToolUpdates.ts +110 -0
- package/src/commands/tui/types.ts +4 -0
- package/src/commands/tui/views/ReadmeViewer.tsx +93 -0
- package/src/commands/tui/views/SetupScreen.tsx +242 -0
- package/src/commands/tui/views/SkillConfigScreen.tsx +278 -0
- package/src/commands/tui/views/ToolExplorer.tsx +190 -0
- package/src/commands/tui/views/ToolUpdatePrompt.tsx +109 -0
- package/src/commands/tui/views/WelcomeScreen.tsx +149 -0
- package/src/commands/tui.tsx +65 -1587
- package/src/commands/uninstall.ts +2 -2
- package/src/commands/update.ts +1 -1
- package/src/index.ts +4 -4
- package/src/lib/agents.ts +4 -4
- package/src/lib/config.ts +1 -1
- package/src/lib/platforms.ts +1 -1
- package/src/lib/skill-config.ts +2 -2
- package/src/lib/skills.test.ts +2 -2
- package/src/lib/skills.ts +5 -5
- package/src/lib/tools.ts +3 -3
- package/src/lib/types.test.ts +1 -1
- package/src/lib/version.test.ts +1 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { useState, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
getBundledTools,
|
|
4
|
+
isToolInstalled,
|
|
5
|
+
getToolUpdateStatus,
|
|
6
|
+
getToolsWithUpdates,
|
|
7
|
+
type ToolUpdateInfo,
|
|
8
|
+
} from '../../../lib/tools';
|
|
9
|
+
import { installSkill, updateSkill } from '../../../lib/skills';
|
|
10
|
+
import { getAutoUpdateConfig, setAutoUpdateConfig } from '../../../lib/config';
|
|
11
|
+
import type { ToolManifest } from '../../../lib/types';
|
|
12
|
+
|
|
13
|
+
export interface UseToolUpdatesOptions {
|
|
14
|
+
onUpdateComplete: (result: { successCount: number; failCount: number; updatedNames: string[]; silent: boolean }) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface UseToolUpdatesResult {
|
|
18
|
+
toolUpdates: ToolUpdateInfo[];
|
|
19
|
+
isUpdatingTools: boolean;
|
|
20
|
+
autoUpdatedTools: string[];
|
|
21
|
+
checkForUpdates: () => { updates: ToolUpdateInfo[]; shouldAutoUpdate: boolean };
|
|
22
|
+
updateAllTools: (updates?: ToolUpdateInfo[], silent?: boolean) => void;
|
|
23
|
+
enableAutoUpdateAndUpdate: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function useToolUpdates({ onUpdateComplete }: UseToolUpdatesOptions): UseToolUpdatesResult {
|
|
27
|
+
const [toolUpdates, setToolUpdates] = useState<ToolUpdateInfo[]>([]);
|
|
28
|
+
const [isUpdatingTools, setIsUpdatingTools] = useState(false);
|
|
29
|
+
const [autoUpdatedTools, setAutoUpdatedTools] = useState<string[]>([]);
|
|
30
|
+
|
|
31
|
+
const tools = getBundledTools();
|
|
32
|
+
|
|
33
|
+
// Ensure system tools are installed/updated (bypasses auto-update settings)
|
|
34
|
+
const ensureSystemTools = useCallback(() => {
|
|
35
|
+
const systemTools = tools.filter(t => (t as ToolManifest & { system?: boolean }).system === true);
|
|
36
|
+
|
|
37
|
+
for (const systemTool of systemTools) {
|
|
38
|
+
const installed = isToolInstalled(systemTool.name);
|
|
39
|
+
const updateStatus = getToolUpdateStatus(systemTool.name);
|
|
40
|
+
|
|
41
|
+
if (!installed || updateStatus.hasUpdate) {
|
|
42
|
+
const primarySkill = systemTool.includes.skills.find(s => s.required)?.name || systemTool.name;
|
|
43
|
+
installSkill(primarySkill);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}, [tools]);
|
|
47
|
+
|
|
48
|
+
// Check for updates, returns info for caller to decide what to do
|
|
49
|
+
const checkForUpdates = useCallback(() => {
|
|
50
|
+
ensureSystemTools();
|
|
51
|
+
const updates = getToolsWithUpdates();
|
|
52
|
+
setToolUpdates(updates);
|
|
53
|
+
|
|
54
|
+
const autoUpdateConfig = getAutoUpdateConfig();
|
|
55
|
+
return {
|
|
56
|
+
updates,
|
|
57
|
+
shouldAutoUpdate: autoUpdateConfig.tools && updates.length > 0,
|
|
58
|
+
};
|
|
59
|
+
}, [ensureSystemTools]);
|
|
60
|
+
|
|
61
|
+
// Update all tools
|
|
62
|
+
const updateAllTools = useCallback((updates: ToolUpdateInfo[] = toolUpdates, silent = false) => {
|
|
63
|
+
if (!silent) {
|
|
64
|
+
setIsUpdatingTools(true);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
let successCount = 0;
|
|
69
|
+
let failCount = 0;
|
|
70
|
+
const updatedNames: string[] = [];
|
|
71
|
+
|
|
72
|
+
for (const tool of updates) {
|
|
73
|
+
const toolManifest = tools.find(t => t.name === tool.name);
|
|
74
|
+
if (toolManifest) {
|
|
75
|
+
const primarySkill = toolManifest.includes.skills.find(s => s.required)?.name || toolManifest.name;
|
|
76
|
+
const result = updateSkill(primarySkill);
|
|
77
|
+
if (result.success) {
|
|
78
|
+
successCount++;
|
|
79
|
+
updatedNames.push(tool.name);
|
|
80
|
+
} else {
|
|
81
|
+
failCount++;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setIsUpdatingTools(false);
|
|
87
|
+
|
|
88
|
+
if (silent && updatedNames.length > 0) {
|
|
89
|
+
setAutoUpdatedTools(updatedNames);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
onUpdateComplete({ successCount, failCount, updatedNames, silent });
|
|
93
|
+
}, 100);
|
|
94
|
+
}, [toolUpdates, tools, onUpdateComplete]);
|
|
95
|
+
|
|
96
|
+
// Enable auto-update and run updates
|
|
97
|
+
const enableAutoUpdateAndUpdate = useCallback(() => {
|
|
98
|
+
setAutoUpdateConfig({ tools: true });
|
|
99
|
+
updateAllTools();
|
|
100
|
+
}, [updateAllTools]);
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
toolUpdates,
|
|
104
|
+
isUpdatingTools,
|
|
105
|
+
autoUpdatedTools,
|
|
106
|
+
checkForUpdates,
|
|
107
|
+
updateAllTools,
|
|
108
|
+
enableAutoUpdateAndUpdate,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type Tab = 'tools' | 'settings';
|
|
2
|
+
export type View = 'welcome' | 'tool-updates' | 'setup' | 'menu' | 'detail' | 'configure' | 'readme' | 'explorer';
|
|
3
|
+
export type SetupStep = 'platform' | 'user_mention' | 'auto_update' | 'confirm';
|
|
4
|
+
export type ComponentType = 'skill' | 'command' | 'agent';
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Box, Text, useInput } from 'ink';
|
|
2
|
+
import { useState, useMemo } from 'react';
|
|
3
|
+
import { colors } from '../constants';
|
|
4
|
+
import { MarkdownLine } from '../components/Markdown';
|
|
5
|
+
|
|
6
|
+
export interface ReadmeViewerProps {
|
|
7
|
+
title: string;
|
|
8
|
+
content: string;
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ReadmeViewer({ title, content, onClose }: ReadmeViewerProps) {
|
|
13
|
+
const [scrollOffset, setScrollOffset] = useState(0);
|
|
14
|
+
const lines = useMemo(() => content.split('\n'), [content]);
|
|
15
|
+
const maxVisible = 20;
|
|
16
|
+
|
|
17
|
+
// Pre-compute code block state for each line
|
|
18
|
+
const lineStates = useMemo(() => {
|
|
19
|
+
const states: boolean[] = [];
|
|
20
|
+
let inCode = false;
|
|
21
|
+
for (const line of lines) {
|
|
22
|
+
if (line.startsWith('```')) {
|
|
23
|
+
states.push(false); // Delimiter itself is not "in" code block for styling
|
|
24
|
+
inCode = !inCode;
|
|
25
|
+
} else {
|
|
26
|
+
states.push(inCode);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return states;
|
|
30
|
+
}, [lines]);
|
|
31
|
+
|
|
32
|
+
// Max offset: when at end, we have top indicator + (maxVisible-1) content lines
|
|
33
|
+
// So max offset is lines.length - (maxVisible - 1) = lines.length - maxVisible + 1
|
|
34
|
+
const maxOffset = Math.max(0, lines.length - maxVisible + 1);
|
|
35
|
+
|
|
36
|
+
useInput((input, key) => {
|
|
37
|
+
if (key.escape) {
|
|
38
|
+
onClose();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (key.upArrow) {
|
|
42
|
+
setScrollOffset((prev) => Math.max(0, prev - 1));
|
|
43
|
+
}
|
|
44
|
+
if (key.downArrow) {
|
|
45
|
+
setScrollOffset((prev) => Math.min(maxOffset, prev + 1));
|
|
46
|
+
}
|
|
47
|
+
if (key.pageDown || input === ' ') {
|
|
48
|
+
setScrollOffset((prev) => Math.min(maxOffset, prev + maxVisible));
|
|
49
|
+
}
|
|
50
|
+
if (key.pageUp) {
|
|
51
|
+
setScrollOffset((prev) => Math.max(0, prev - maxVisible));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Adjust visible lines based on whether indicators are shown
|
|
56
|
+
const showTopIndicator = scrollOffset > 0;
|
|
57
|
+
// Reserve space for bottom indicator if not at end
|
|
58
|
+
const contentLines = maxVisible - (showTopIndicator ? 1 : 0);
|
|
59
|
+
const endIndex = Math.min(scrollOffset + contentLines, lines.length);
|
|
60
|
+
const showBottomIndicator = endIndex < lines.length;
|
|
61
|
+
const actualContentLines = contentLines - (showBottomIndicator ? 1 : 0);
|
|
62
|
+
const visibleLines = lines.slice(scrollOffset, scrollOffset + actualContentLines);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<Box flexDirection="column" padding={1}>
|
|
66
|
+
<Box marginBottom={1}>
|
|
67
|
+
<Text color={colors.text} bold>{title}</Text>
|
|
68
|
+
<Text color={colors.textDim}> · {lines.length} lines</Text>
|
|
69
|
+
</Box>
|
|
70
|
+
|
|
71
|
+
<Box
|
|
72
|
+
flexDirection="column"
|
|
73
|
+
borderStyle="single"
|
|
74
|
+
borderColor={colors.border}
|
|
75
|
+
paddingX={1}
|
|
76
|
+
>
|
|
77
|
+
{showTopIndicator && (
|
|
78
|
+
<Text color={colors.textDim}>↑ {scrollOffset} more lines</Text>
|
|
79
|
+
)}
|
|
80
|
+
{visibleLines.map((line, i) => (
|
|
81
|
+
<MarkdownLine key={scrollOffset + i} line={line} inCodeBlock={lineStates[scrollOffset + i]} />
|
|
82
|
+
))}
|
|
83
|
+
{showBottomIndicator && (
|
|
84
|
+
<Text color={colors.textDim}>↓ {lines.length - scrollOffset - actualContentLines} more lines</Text>
|
|
85
|
+
)}
|
|
86
|
+
</Box>
|
|
87
|
+
|
|
88
|
+
<Box marginTop={1}>
|
|
89
|
+
<Text color={colors.textDim}>↑↓ scroll · space/pgdn page · esc back</Text>
|
|
90
|
+
</Box>
|
|
91
|
+
</Box>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { Box, Text, useInput } from 'ink';
|
|
2
|
+
import TextInput from 'ink-text-input';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { colors } from '../constants';
|
|
5
|
+
import type { SetupStep } from '../types';
|
|
6
|
+
import { Platform, BuiltInOutput, type DroidConfig } from '../../../lib/types';
|
|
7
|
+
import { loadConfig, saveConfig, getAutoUpdateConfig, setAutoUpdateConfig } from '../../../lib/config';
|
|
8
|
+
import { configurePlatformPermissions } from '../../setup';
|
|
9
|
+
|
|
10
|
+
export interface SetupScreenProps {
|
|
11
|
+
onComplete: () => void;
|
|
12
|
+
onSkip: () => void;
|
|
13
|
+
initialConfig?: DroidConfig;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const platformOptions = [
|
|
17
|
+
{ label: 'Claude Code', value: Platform.ClaudeCode },
|
|
18
|
+
{ label: 'OpenCode', value: Platform.OpenCode },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export function SetupScreen({ onComplete, onSkip, initialConfig }: SetupScreenProps) {
|
|
22
|
+
const [step, setStep] = useState<SetupStep>('platform');
|
|
23
|
+
const [platform, setPlatform] = useState<Platform>(
|
|
24
|
+
initialConfig?.platform || Platform.ClaudeCode
|
|
25
|
+
);
|
|
26
|
+
const [userMention, setUserMention] = useState(initialConfig?.user_mention || '@user');
|
|
27
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
28
|
+
const [error, setError] = useState<string | null>(null);
|
|
29
|
+
|
|
30
|
+
// Auto-update state
|
|
31
|
+
const existingAutoUpdate = getAutoUpdateConfig();
|
|
32
|
+
const [autoUpdateTools, setAutoUpdateTools] = useState(existingAutoUpdate.tools);
|
|
33
|
+
const [autoUpdateApp, setAutoUpdateApp] = useState(existingAutoUpdate.app);
|
|
34
|
+
const [autoUpdateSelectedIndex, setAutoUpdateSelectedIndex] = useState(0);
|
|
35
|
+
|
|
36
|
+
const steps: SetupStep[] = ['platform', 'user_mention', 'auto_update', 'confirm'];
|
|
37
|
+
const stepIndex = steps.indexOf(step);
|
|
38
|
+
const totalSteps = steps.length - 1; // Don't count confirm as a step
|
|
39
|
+
|
|
40
|
+
const handleUserMentionSubmit = () => {
|
|
41
|
+
// Auto-add @ prefix if missing
|
|
42
|
+
const mention = userMention.startsWith('@') ? userMention : `@${userMention}`;
|
|
43
|
+
setUserMention(mention);
|
|
44
|
+
setError(null);
|
|
45
|
+
setStep('auto_update');
|
|
46
|
+
setAutoUpdateSelectedIndex(0);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Handle escape during text input (only intercept escape, nothing else)
|
|
50
|
+
useInput((input, key) => {
|
|
51
|
+
if (key.escape) {
|
|
52
|
+
setStep('platform');
|
|
53
|
+
setSelectedIndex(0);
|
|
54
|
+
}
|
|
55
|
+
}, { isActive: step === 'user_mention' });
|
|
56
|
+
|
|
57
|
+
// Handle all input for non-text-input steps
|
|
58
|
+
useInput((input, key) => {
|
|
59
|
+
if (key.escape) {
|
|
60
|
+
if (step === 'platform') {
|
|
61
|
+
onSkip();
|
|
62
|
+
} else if (step === 'auto_update') {
|
|
63
|
+
setStep('user_mention');
|
|
64
|
+
} else if (step === 'confirm') {
|
|
65
|
+
setStep('auto_update');
|
|
66
|
+
setAutoUpdateSelectedIndex(0);
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (step === 'platform') {
|
|
72
|
+
if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
73
|
+
if (key.downArrow) setSelectedIndex((prev) => Math.min(platformOptions.length - 1, prev + 1));
|
|
74
|
+
if (key.return) {
|
|
75
|
+
setPlatform(platformOptions[selectedIndex].value);
|
|
76
|
+
setStep('user_mention');
|
|
77
|
+
}
|
|
78
|
+
} else if (step === 'auto_update') {
|
|
79
|
+
// 0 = auto-update tools, 1 = auto-update app, 2 = next button
|
|
80
|
+
if (key.upArrow) setAutoUpdateSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
81
|
+
if (key.downArrow) setAutoUpdateSelectedIndex((prev) => Math.min(2, prev + 1));
|
|
82
|
+
if (key.return) {
|
|
83
|
+
if (autoUpdateSelectedIndex === 0) {
|
|
84
|
+
setAutoUpdateTools(!autoUpdateTools);
|
|
85
|
+
} else if (autoUpdateSelectedIndex === 1) {
|
|
86
|
+
setAutoUpdateApp(!autoUpdateApp);
|
|
87
|
+
} else {
|
|
88
|
+
setStep('confirm');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} else if (step === 'confirm') {
|
|
92
|
+
if (key.return) {
|
|
93
|
+
const existingConfig = loadConfig();
|
|
94
|
+
const config: DroidConfig = {
|
|
95
|
+
...existingConfig,
|
|
96
|
+
platform: platform,
|
|
97
|
+
user_mention: userMention,
|
|
98
|
+
output_preference: BuiltInOutput.Terminal, // Default to terminal
|
|
99
|
+
};
|
|
100
|
+
saveConfig(config);
|
|
101
|
+
setAutoUpdateConfig({ tools: autoUpdateTools, app: autoUpdateApp });
|
|
102
|
+
configurePlatformPermissions(platform);
|
|
103
|
+
onComplete();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}, { isActive: step !== 'user_mention' });
|
|
107
|
+
|
|
108
|
+
const renderHeader = () => (
|
|
109
|
+
<Box flexDirection="column" marginBottom={1}>
|
|
110
|
+
<Text>
|
|
111
|
+
<Text color={colors.textDim}>[</Text>
|
|
112
|
+
<Text color={colors.primary}>●</Text>
|
|
113
|
+
<Text color={colors.textDim}> </Text>
|
|
114
|
+
<Text color={colors.primary}>●</Text>
|
|
115
|
+
<Text color={colors.textDim}>] </Text>
|
|
116
|
+
<Text color={colors.text} bold>droid setup</Text>
|
|
117
|
+
<Text color={colors.textDim}> · Step {Math.min(stepIndex + 1, totalSteps)} of {totalSteps}</Text>
|
|
118
|
+
</Text>
|
|
119
|
+
</Box>
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
if (step === 'platform') {
|
|
123
|
+
return (
|
|
124
|
+
<Box flexDirection="column" padding={1}>
|
|
125
|
+
{renderHeader()}
|
|
126
|
+
<Text color={colors.text}>Which platform are you using?</Text>
|
|
127
|
+
<Box flexDirection="column" marginTop={1}>
|
|
128
|
+
{platformOptions.map((option, index) => (
|
|
129
|
+
<Text key={option.value}>
|
|
130
|
+
<Text color={colors.textDim}>{index === selectedIndex ? '>' : ' '} </Text>
|
|
131
|
+
<Text color={index === selectedIndex ? colors.text : colors.textMuted}>{option.label}</Text>
|
|
132
|
+
</Text>
|
|
133
|
+
))}
|
|
134
|
+
</Box>
|
|
135
|
+
<Box marginTop={1}>
|
|
136
|
+
<Text color={colors.textDim}>↑↓ select · enter next · esc skip</Text>
|
|
137
|
+
</Box>
|
|
138
|
+
</Box>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (step === 'user_mention') {
|
|
143
|
+
return (
|
|
144
|
+
<Box flexDirection="column" padding={1}>
|
|
145
|
+
{renderHeader()}
|
|
146
|
+
<Text color={colors.text}>What @mention should be used for you?</Text>
|
|
147
|
+
<Box marginTop={1}>
|
|
148
|
+
<Text color={colors.textDim}>{'> '}</Text>
|
|
149
|
+
<TextInput
|
|
150
|
+
value={userMention}
|
|
151
|
+
onChange={setUserMention}
|
|
152
|
+
onSubmit={handleUserMentionSubmit}
|
|
153
|
+
placeholder="@user"
|
|
154
|
+
/>
|
|
155
|
+
</Box>
|
|
156
|
+
{error && (
|
|
157
|
+
<Box marginTop={1}>
|
|
158
|
+
<Text color={colors.error}>{error}</Text>
|
|
159
|
+
</Box>
|
|
160
|
+
)}
|
|
161
|
+
<Box marginTop={1}>
|
|
162
|
+
<Text color={colors.textDim}>enter next · esc back</Text>
|
|
163
|
+
</Box>
|
|
164
|
+
</Box>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (step === 'auto_update') {
|
|
169
|
+
return (
|
|
170
|
+
<Box flexDirection="column" padding={1}>
|
|
171
|
+
{renderHeader()}
|
|
172
|
+
<Text color={colors.text}>Configure auto-update behaviour</Text>
|
|
173
|
+
<Box flexDirection="column" marginTop={1}>
|
|
174
|
+
<Box>
|
|
175
|
+
<Text>
|
|
176
|
+
<Text color={colors.textDim}>{autoUpdateSelectedIndex === 0 ? '>' : ' '} </Text>
|
|
177
|
+
<Text color={autoUpdateSelectedIndex === 0 ? colors.text : colors.textMuted}>
|
|
178
|
+
[{autoUpdateTools ? 'x' : ' '}] Auto-update tools
|
|
179
|
+
</Text>
|
|
180
|
+
</Text>
|
|
181
|
+
</Box>
|
|
182
|
+
<Text color={colors.textDim}> Update tools automatically when droid starts</Text>
|
|
183
|
+
<Box marginTop={1}>
|
|
184
|
+
<Text>
|
|
185
|
+
<Text color={colors.textDim}>{autoUpdateSelectedIndex === 1 ? '>' : ' '} </Text>
|
|
186
|
+
<Text color={autoUpdateSelectedIndex === 1 ? colors.text : colors.textMuted}>
|
|
187
|
+
[{autoUpdateApp ? 'x' : ' '}] Auto-update app
|
|
188
|
+
</Text>
|
|
189
|
+
</Text>
|
|
190
|
+
</Box>
|
|
191
|
+
<Text color={colors.textDim}> Update droid automatically when a new version is available</Text>
|
|
192
|
+
</Box>
|
|
193
|
+
<Box marginTop={2}>
|
|
194
|
+
<Text
|
|
195
|
+
backgroundColor={autoUpdateSelectedIndex === 2 ? colors.primary : colors.bgSelected}
|
|
196
|
+
color={autoUpdateSelectedIndex === 2 ? '#ffffff' : colors.textMuted}
|
|
197
|
+
bold={autoUpdateSelectedIndex === 2}
|
|
198
|
+
>
|
|
199
|
+
{' '}Next{' '}
|
|
200
|
+
</Text>
|
|
201
|
+
</Box>
|
|
202
|
+
<Box marginTop={1}>
|
|
203
|
+
<Text color={colors.textDim}>↑↓ select · enter toggle/next · esc back</Text>
|
|
204
|
+
</Box>
|
|
205
|
+
</Box>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Confirm step
|
|
210
|
+
return (
|
|
211
|
+
<Box flexDirection="column" padding={1}>
|
|
212
|
+
{renderHeader()}
|
|
213
|
+
<Text color={colors.text} bold>Review your settings</Text>
|
|
214
|
+
<Box flexDirection="column" marginTop={1}>
|
|
215
|
+
<Text>
|
|
216
|
+
<Text color={colors.textDim}>Platform: </Text>
|
|
217
|
+
<Text color={colors.text}>{platform === Platform.ClaudeCode ? 'Claude Code' : 'OpenCode'}</Text>
|
|
218
|
+
</Text>
|
|
219
|
+
<Text>
|
|
220
|
+
<Text color={colors.textDim}>Your @mention: </Text>
|
|
221
|
+
<Text color={colors.text}>{userMention}</Text>
|
|
222
|
+
</Text>
|
|
223
|
+
<Text>
|
|
224
|
+
<Text color={colors.textDim}>Auto-update tools: </Text>
|
|
225
|
+
<Text color={colors.text}>{autoUpdateTools ? 'enabled' : 'disabled'}</Text>
|
|
226
|
+
</Text>
|
|
227
|
+
<Text>
|
|
228
|
+
<Text color={colors.textDim}>Auto-update app: </Text>
|
|
229
|
+
<Text color={colors.text}>{autoUpdateApp ? 'enabled' : 'disabled'}</Text>
|
|
230
|
+
</Text>
|
|
231
|
+
</Box>
|
|
232
|
+
<Box marginTop={2}>
|
|
233
|
+
<Text backgroundColor={colors.primary} color="#ffffff" bold>
|
|
234
|
+
{' '}Save{' '}
|
|
235
|
+
</Text>
|
|
236
|
+
</Box>
|
|
237
|
+
<Box marginTop={1}>
|
|
238
|
+
<Text color={colors.textDim}>enter save · esc back</Text>
|
|
239
|
+
</Box>
|
|
240
|
+
</Box>
|
|
241
|
+
);
|
|
242
|
+
}
|