@orderful/droid 0.14.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 +31 -9
- package/CHANGELOG.md +35 -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 -756
- 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 +7 -7
- package/dist/lib/agents.d.ts.map +1 -1
- package/dist/lib/agents.js +63 -41
- 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 +2 -1
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +45 -12
- 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/dist/lib/types.d.ts +4 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/tools/README.md +79 -50
- package/dist/tools/brain/TOOL.yaml +1 -1
- package/dist/tools/brain/skills/brain/SKILL.md +1 -0
- package/dist/tools/brain/skills/brain-obsidian/SKILL.md +1 -0
- package/dist/tools/coach/TOOL.yaml +1 -1
- package/dist/tools/coach/skills/coach/SKILL.md +1 -0
- package/{src/tools/code-review/agents/edi-standards-reviewer/AGENT.md → dist/tools/code-review/agents/edi-standards-reviewer.md} +10 -0
- package/dist/tools/code-review/agents/{error-handling-reviewer/AGENT.md → error-handling-reviewer.md} +10 -0
- package/{src/tools/code-review/agents/test-coverage-analyzer/AGENT.md → dist/tools/code-review/agents/test-coverage-analyzer.md} +11 -0
- package/dist/tools/code-review/agents/{type-reviewer/AGENT.md → type-reviewer.md} +10 -0
- package/dist/tools/code-review/skills/code-review/SKILL.md +1 -0
- package/dist/tools/comments/TOOL.yaml +2 -2
- package/dist/tools/comments/skills/comments/SKILL.md +1 -0
- package/dist/tools/droid/skills/droid/SKILL.md +1 -0
- package/dist/tools/project/skills/project/SKILL.md +1 -0
- 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 -1588
- 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 +68 -45
- 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 +28 -33
- package/src/lib/skills.ts +49 -12
- package/src/lib/tools.ts +3 -3
- package/src/lib/types.test.ts +1 -1
- package/src/lib/types.ts +5 -0
- package/src/lib/version.test.ts +1 -1
- package/src/tools/README.md +79 -50
- package/src/tools/brain/TOOL.yaml +1 -1
- package/src/tools/brain/skills/brain/SKILL.md +1 -0
- package/src/tools/brain/skills/brain-obsidian/SKILL.md +1 -0
- package/src/tools/coach/TOOL.yaml +1 -1
- package/src/tools/coach/skills/coach/SKILL.md +1 -0
- package/{dist/tools/code-review/agents/edi-standards-reviewer/AGENT.md → src/tools/code-review/agents/edi-standards-reviewer.md} +10 -0
- package/src/tools/code-review/agents/{error-handling-reviewer/AGENT.md → error-handling-reviewer.md} +10 -0
- package/{dist/tools/code-review/agents/test-coverage-analyzer/AGENT.md → src/tools/code-review/agents/test-coverage-analyzer.md} +11 -0
- package/src/tools/code-review/agents/{type-reviewer/AGENT.md → type-reviewer.md} +10 -0
- package/src/tools/code-review/skills/code-review/SKILL.md +1 -0
- package/src/tools/comments/TOOL.yaml +2 -2
- package/src/tools/comments/skills/comments/SKILL.md +1 -0
- package/src/tools/droid/skills/droid/SKILL.md +1 -0
- package/src/tools/project/skills/project/SKILL.md +1 -0
- package/dist/tools/brain/skills/brain/SKILL.yaml +0 -29
- package/dist/tools/brain/skills/brain-obsidian/SKILL.yaml +0 -42
- package/dist/tools/coach/skills/coach/SKILL.yaml +0 -25
- package/dist/tools/code-review/agents/edi-standards-reviewer/AGENT.yaml +0 -14
- package/dist/tools/code-review/agents/error-handling-reviewer/AGENT.yaml +0 -14
- package/dist/tools/code-review/agents/test-coverage-analyzer/AGENT.yaml +0 -14
- package/dist/tools/code-review/agents/type-reviewer/AGENT.yaml +0 -13
- package/dist/tools/code-review/skills/code-review/SKILL.yaml +0 -19
- package/dist/tools/comments/skills/comments/SKILL.yaml +0 -50
- package/dist/tools/droid/skills/droid/SKILL.yaml +0 -7
- package/dist/tools/project/skills/project/SKILL.yaml +0 -30
- package/src/tools/brain/skills/brain/SKILL.yaml +0 -29
- package/src/tools/brain/skills/brain-obsidian/SKILL.yaml +0 -42
- package/src/tools/coach/skills/coach/SKILL.yaml +0 -25
- package/src/tools/code-review/agents/edi-standards-reviewer/AGENT.yaml +0 -14
- package/src/tools/code-review/agents/error-handling-reviewer/AGENT.yaml +0 -14
- package/src/tools/code-review/agents/test-coverage-analyzer/AGENT.yaml +0 -14
- package/src/tools/code-review/agents/type-reviewer/AGENT.yaml +0 -13
- package/src/tools/code-review/skills/code-review/SKILL.yaml +0 -19
- package/src/tools/comments/skills/comments/SKILL.yaml +0 -50
- package/src/tools/droid/skills/droid/SKILL.yaml +0 -7
- package/src/tools/project/skills/project/SKILL.yaml +0 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orderful/droid",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "AI workflow toolkit for sharing skills, commands, and agents across the team",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
},
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "tsc && cp -r src/tools dist/",
|
|
11
|
+
"build": "eslint src --ext .ts,.tsx && tsc && cp -r src/tools dist/",
|
|
12
12
|
"dev": "tsc --watch",
|
|
13
13
|
"start": "bun dist/bin/droid.js",
|
|
14
14
|
"test": "bun test src/",
|
|
15
15
|
"test:watch": "bun test src/ --watch",
|
|
16
|
-
"lint": "eslint src --ext .ts",
|
|
16
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
17
17
|
"format": "prettier --write 'src/**/*.ts'",
|
|
18
18
|
"changeset": "changeset",
|
|
19
19
|
"version": "changeset version",
|
package/src/bin/droid.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { program } from 'commander';
|
|
4
|
-
import { setupCommand } from '../commands/setup
|
|
5
|
-
import { configCommand } from '../commands/config
|
|
6
|
-
import { skillsCommand } from '../commands/skills
|
|
7
|
-
import { installCommand } from '../commands/install
|
|
8
|
-
import { uninstallCommand } from '../commands/uninstall
|
|
9
|
-
import { updateCommand } from '../commands/update
|
|
10
|
-
import { tuiCommand } from '../commands/tui
|
|
11
|
-
import { getVersion } from '../lib/version
|
|
4
|
+
import { setupCommand } from '../commands/setup';
|
|
5
|
+
import { configCommand } from '../commands/config';
|
|
6
|
+
import { skillsCommand } from '../commands/skills';
|
|
7
|
+
import { installCommand } from '../commands/install';
|
|
8
|
+
import { uninstallCommand } from '../commands/uninstall';
|
|
9
|
+
import { updateCommand } from '../commands/update';
|
|
10
|
+
import { tuiCommand } from '../commands/tui';
|
|
11
|
+
import { getVersion } from '../lib/version';
|
|
12
12
|
|
|
13
13
|
const version = getVersion();
|
|
14
14
|
|
package/src/commands/config.ts
CHANGED
package/src/commands/install.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { installSkill } from '../lib/skills
|
|
3
|
-
import { getBundledTools, isToolInstalled } from '../lib/tools
|
|
4
|
-
import { promptForSkillConfig } from '../lib/skill-config
|
|
2
|
+
import { installSkill } from '../lib/skills';
|
|
3
|
+
import { getBundledTools, isToolInstalled } from '../lib/tools';
|
|
4
|
+
import { promptForSkillConfig } from '../lib/skill-config';
|
|
5
5
|
|
|
6
6
|
export async function installCommand(toolName: string): Promise<void> {
|
|
7
7
|
// Check if tool exists
|
|
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach, mock, spyOn } from 'bun:te
|
|
|
2
2
|
import { existsSync, mkdirSync, rmSync, readFileSync, writeFileSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { tmpdir } from 'os';
|
|
5
|
-
import { Platform } from '../lib/types
|
|
5
|
+
import { Platform } from '../lib/types';
|
|
6
6
|
|
|
7
7
|
// We need to mock homedir() before importing the module
|
|
8
8
|
// Create a test directory that will act as our fake home
|
package/src/commands/setup.ts
CHANGED
|
@@ -4,9 +4,9 @@ import { execSync } from 'child_process';
|
|
|
4
4
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
5
5
|
import { join } from 'path';
|
|
6
6
|
import { homedir } from 'os';
|
|
7
|
-
import { loadConfig, saveConfig, configExists } from '../lib/config
|
|
8
|
-
import { getBundledSkills } from '../lib/skills
|
|
9
|
-
import { Platform, BuiltInOutput, type DroidConfig, type OutputPreference } from '../lib/types
|
|
7
|
+
import { loadConfig, saveConfig, configExists } from '../lib/config';
|
|
8
|
+
import { getBundledSkills } from '../lib/skills';
|
|
9
|
+
import { Platform, BuiltInOutput, type DroidConfig, type OutputPreference } from '../lib/types';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Permissions droid needs to operate without constant prompts
|
package/src/commands/skills.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import { installSkill, uninstallSkill } from '../lib/skills
|
|
4
|
-
import { getBundledTools, isToolInstalled, getInstalledToolVersion } from '../lib/tools
|
|
5
|
-
import { promptForSkillConfig } from '../lib/skill-config
|
|
6
|
-
import { SkillStatus, type ToolManifest } from '../lib/types
|
|
3
|
+
import { installSkill, uninstallSkill } from '../lib/skills';
|
|
4
|
+
import { getBundledTools, isToolInstalled, getInstalledToolVersion } from '../lib/tools';
|
|
5
|
+
import { promptForSkillConfig } from '../lib/skill-config';
|
|
6
|
+
import { SkillStatus, type ToolManifest } from '../lib/types';
|
|
7
7
|
|
|
8
8
|
function formatToolChoice(tool: ToolManifest): string {
|
|
9
9
|
const installed = isToolInstalled(tool.name);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Box, Text } from 'ink';
|
|
2
|
+
import type { ComponentType } from '../types';
|
|
3
|
+
import { colors } from '../constants';
|
|
4
|
+
import type { ToolManifest } from '../../../lib/types';
|
|
5
|
+
|
|
6
|
+
export function Badge({
|
|
7
|
+
type,
|
|
8
|
+
label,
|
|
9
|
+
isSelected = false,
|
|
10
|
+
dimmed = false,
|
|
11
|
+
}: {
|
|
12
|
+
type: ComponentType;
|
|
13
|
+
label?: string;
|
|
14
|
+
isSelected?: boolean;
|
|
15
|
+
dimmed?: boolean;
|
|
16
|
+
}) {
|
|
17
|
+
const color = colors[type];
|
|
18
|
+
const displayLabel = label || type.charAt(0).toUpperCase() + type.slice(1);
|
|
19
|
+
|
|
20
|
+
if (dimmed) {
|
|
21
|
+
return (
|
|
22
|
+
<Text color={colors.textDim}>{displayLabel}</Text>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Text
|
|
28
|
+
backgroundColor={isSelected ? color : undefined}
|
|
29
|
+
color={isSelected ? '#000000' : color}
|
|
30
|
+
bold={isSelected}
|
|
31
|
+
>
|
|
32
|
+
{isSelected ? ` ${displayLabel} ` : displayLabel}
|
|
33
|
+
</Text>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function ComponentBadges({ tool, compact = false }: { tool: ToolManifest; compact?: boolean }) {
|
|
38
|
+
const hasSkills = tool.includes.skills.length > 0;
|
|
39
|
+
const hasCommands = tool.includes.commands.length > 0;
|
|
40
|
+
const hasAgents = tool.includes.agents.length > 0;
|
|
41
|
+
|
|
42
|
+
if (compact) {
|
|
43
|
+
// Show colored squares for list view (single char with spacing)
|
|
44
|
+
const parts: string[] = [];
|
|
45
|
+
if (hasSkills) parts.push('skill');
|
|
46
|
+
if (hasCommands) parts.push('command');
|
|
47
|
+
if (hasAgents) parts.push('agent');
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Box flexDirection="row">
|
|
51
|
+
{parts.map((type, i) => (
|
|
52
|
+
<Text key={type}>
|
|
53
|
+
<Text backgroundColor={colors[type as ComponentType]}> </Text>
|
|
54
|
+
{i < parts.length - 1 && ' '}
|
|
55
|
+
</Text>
|
|
56
|
+
))}
|
|
57
|
+
</Box>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Box flexDirection="row">
|
|
63
|
+
{hasSkills && (
|
|
64
|
+
<Box marginRight={1}>
|
|
65
|
+
<Text backgroundColor={colors.skill} color="#000000" bold>
|
|
66
|
+
{` ${tool.includes.skills.length} skill${tool.includes.skills.length > 1 ? 's' : ''} `}
|
|
67
|
+
</Text>
|
|
68
|
+
</Box>
|
|
69
|
+
)}
|
|
70
|
+
{hasCommands && (
|
|
71
|
+
<Box marginRight={1}>
|
|
72
|
+
<Text backgroundColor={colors.command} color="#000000" bold>
|
|
73
|
+
{` ${tool.includes.commands.length} cmd${tool.includes.commands.length > 1 ? 's' : ''} `}
|
|
74
|
+
</Text>
|
|
75
|
+
</Box>
|
|
76
|
+
)}
|
|
77
|
+
{hasAgents && (
|
|
78
|
+
<Box marginRight={1}>
|
|
79
|
+
<Text backgroundColor={colors.agent} color="#000000" bold>
|
|
80
|
+
{` ${tool.includes.agents.length} agent${tool.includes.agents.length > 1 ? 's' : ''} `}
|
|
81
|
+
</Text>
|
|
82
|
+
</Box>
|
|
83
|
+
)}
|
|
84
|
+
</Box>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Text } from 'ink';
|
|
2
|
+
import { colors } from '../constants';
|
|
3
|
+
|
|
4
|
+
export function MarkdownLine({ line, inCodeBlock }: { line: string; inCodeBlock: boolean }) {
|
|
5
|
+
// Code block content
|
|
6
|
+
if (inCodeBlock) {
|
|
7
|
+
return <Text color="#a5d6ff">{line || ' '}</Text>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Code block delimiter
|
|
11
|
+
if (line.startsWith('```')) {
|
|
12
|
+
return <Text color={colors.textDim}>{line}</Text>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Headers
|
|
16
|
+
if (line.startsWith('# ')) {
|
|
17
|
+
return <Text color={colors.text} bold>{line.slice(2)}</Text>;
|
|
18
|
+
}
|
|
19
|
+
if (line.startsWith('## ')) {
|
|
20
|
+
return <Text color={colors.text} bold>{line.slice(3)}</Text>;
|
|
21
|
+
}
|
|
22
|
+
if (line.startsWith('### ')) {
|
|
23
|
+
return <Text color="#c9d1d9" bold>{line.slice(4)}</Text>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// YAML frontmatter delimiter
|
|
27
|
+
if (line === '---') {
|
|
28
|
+
return <Text color={colors.textDim}>{line}</Text>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// List items
|
|
32
|
+
if (line.match(/^[\s]*[-*]\s/)) {
|
|
33
|
+
return <Text color={colors.textMuted}>{line}</Text>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Blockquotes
|
|
37
|
+
if (line.startsWith('>')) {
|
|
38
|
+
return <Text color="#8b949e" italic>{line}</Text>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Table rows
|
|
42
|
+
if (line.includes('|')) {
|
|
43
|
+
return <Text color={colors.textMuted}>{line}</Text>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Default
|
|
47
|
+
return <Text color={colors.textMuted}>{line || ' '}</Text>;
|
|
48
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Box, Text } from 'ink';
|
|
2
|
+
import { loadConfig, getAutoUpdateConfig } from '../../../lib/config';
|
|
3
|
+
import { Platform } from '../../../lib/types';
|
|
4
|
+
import { colors } from '../constants';
|
|
5
|
+
|
|
6
|
+
export interface SettingsDetailsProps {
|
|
7
|
+
isFocused: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function SettingsDetails({
|
|
11
|
+
isFocused,
|
|
12
|
+
}: SettingsDetailsProps) {
|
|
13
|
+
const config = loadConfig();
|
|
14
|
+
const autoUpdateConfig = getAutoUpdateConfig();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Box flexDirection="column" paddingLeft={2} flexGrow={1}>
|
|
18
|
+
<Text color={colors.text} bold>Settings</Text>
|
|
19
|
+
|
|
20
|
+
<Box flexDirection="column" marginTop={1}>
|
|
21
|
+
<Text>
|
|
22
|
+
<Text color={colors.textDim}>Platform: </Text>
|
|
23
|
+
<Text color={colors.text}>
|
|
24
|
+
{config.platform === Platform.ClaudeCode ? 'Claude Code' : 'OpenCode'}
|
|
25
|
+
</Text>
|
|
26
|
+
</Text>
|
|
27
|
+
<Text>
|
|
28
|
+
<Text color={colors.textDim}>Your @mention: </Text>
|
|
29
|
+
<Text color={colors.text}>{config.user_mention}</Text>
|
|
30
|
+
</Text>
|
|
31
|
+
<Text>
|
|
32
|
+
<Text color={colors.textDim}>Auto-update tools: </Text>
|
|
33
|
+
<Text color={colors.text}>{autoUpdateConfig.tools ? 'enabled' : 'disabled'}</Text>
|
|
34
|
+
</Text>
|
|
35
|
+
<Text>
|
|
36
|
+
<Text color={colors.textDim}>Auto-update app: </Text>
|
|
37
|
+
<Text color={colors.text}>{autoUpdateConfig.app ? 'enabled' : 'disabled'}</Text>
|
|
38
|
+
</Text>
|
|
39
|
+
</Box>
|
|
40
|
+
|
|
41
|
+
<Box marginTop={2}>
|
|
42
|
+
<Text color={colors.textDim}>Config: ~/.droid/config.yaml</Text>
|
|
43
|
+
</Box>
|
|
44
|
+
|
|
45
|
+
{isFocused && (
|
|
46
|
+
<Box marginTop={2}>
|
|
47
|
+
<Text
|
|
48
|
+
backgroundColor={colors.primary}
|
|
49
|
+
color="#ffffff"
|
|
50
|
+
bold
|
|
51
|
+
>
|
|
52
|
+
{' '}Edit{' '}
|
|
53
|
+
</Text>
|
|
54
|
+
</Box>
|
|
55
|
+
)}
|
|
56
|
+
|
|
57
|
+
{isFocused && (
|
|
58
|
+
<Box marginTop={1}>
|
|
59
|
+
<Text color={colors.textDim}>enter edit · esc back</Text>
|
|
60
|
+
</Box>
|
|
61
|
+
)}
|
|
62
|
+
|
|
63
|
+
{!isFocused && (
|
|
64
|
+
<Box marginTop={2}>
|
|
65
|
+
<Text color={colors.textDim}>press enter to edit</Text>
|
|
66
|
+
</Box>
|
|
67
|
+
)}
|
|
68
|
+
</Box>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Box, Text } from 'ink';
|
|
2
|
+
import type { Tab } from '../types';
|
|
3
|
+
import { colors } from '../constants';
|
|
4
|
+
|
|
5
|
+
export interface TabBarProps {
|
|
6
|
+
tabs: { id: Tab; label: string }[];
|
|
7
|
+
activeTab: Tab;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function TabBar({ tabs, activeTab }: TabBarProps) {
|
|
11
|
+
return (
|
|
12
|
+
<Box flexDirection="row" flexWrap="wrap">
|
|
13
|
+
{tabs.map((tab) => (
|
|
14
|
+
<Text
|
|
15
|
+
key={tab.id}
|
|
16
|
+
backgroundColor={tab.id === activeTab ? colors.primary : undefined}
|
|
17
|
+
color={tab.id === activeTab ? '#ffffff' : colors.textMuted}
|
|
18
|
+
bold={tab.id === activeTab}
|
|
19
|
+
wrap="truncate"
|
|
20
|
+
>
|
|
21
|
+
{' '}{tab.label}{' '}
|
|
22
|
+
</Text>
|
|
23
|
+
))}
|
|
24
|
+
</Box>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Box, Text } from 'ink';
|
|
2
|
+
import { isToolInstalled, getInstalledToolVersion, getToolUpdateStatus } from '../../../lib/tools';
|
|
3
|
+
import type { ToolManifest } from '../../../lib/types';
|
|
4
|
+
import { colors } from '../constants';
|
|
5
|
+
import { ComponentBadges } from './Badge';
|
|
6
|
+
|
|
7
|
+
export interface ToolDetailsProps {
|
|
8
|
+
tool: ToolManifest | null;
|
|
9
|
+
isFocused: boolean;
|
|
10
|
+
selectedAction: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function ToolDetails({
|
|
14
|
+
tool,
|
|
15
|
+
isFocused,
|
|
16
|
+
selectedAction,
|
|
17
|
+
}: ToolDetailsProps) {
|
|
18
|
+
if (!tool) {
|
|
19
|
+
return (
|
|
20
|
+
<Box paddingLeft={2} flexGrow={1}>
|
|
21
|
+
<Text color={colors.textDim}>Select a tool</Text>
|
|
22
|
+
</Box>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const installed = isToolInstalled(tool.name);
|
|
27
|
+
const installedVersion = getInstalledToolVersion(tool.name);
|
|
28
|
+
const updateStatus = getToolUpdateStatus(tool.name);
|
|
29
|
+
const isSystemTool = (tool as ToolManifest & { system?: boolean }).system === true;
|
|
30
|
+
|
|
31
|
+
const actions = installed
|
|
32
|
+
? [
|
|
33
|
+
{ id: 'explore', label: 'Explore', variant: 'default' },
|
|
34
|
+
...(updateStatus.hasUpdate
|
|
35
|
+
? [{ id: 'update', label: `Update (${updateStatus.bundledVersion})`, variant: 'primary' }]
|
|
36
|
+
: []),
|
|
37
|
+
{ id: 'configure', label: 'Configure', variant: 'default' },
|
|
38
|
+
// System tools can't be uninstalled
|
|
39
|
+
...(!isSystemTool ? [{ id: 'uninstall', label: 'Uninstall', variant: 'danger' }] : []),
|
|
40
|
+
]
|
|
41
|
+
: [
|
|
42
|
+
{ id: 'explore', label: 'Explore', variant: 'default' },
|
|
43
|
+
// System tools auto-install, but show Install for manual trigger if needed
|
|
44
|
+
{ id: 'install', label: 'Install', variant: 'primary' },
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Box flexDirection="column" paddingLeft={2} flexGrow={1}>
|
|
49
|
+
<Text color={colors.text} bold>{tool.name}</Text>
|
|
50
|
+
|
|
51
|
+
<Box marginTop={1}>
|
|
52
|
+
<Text color={colors.textDim}>
|
|
53
|
+
{tool.version}
|
|
54
|
+
{tool.status && ` · ${tool.status}`}
|
|
55
|
+
{installed && <Text color={colors.success}> · installed</Text>}
|
|
56
|
+
{updateStatus.hasUpdate && (
|
|
57
|
+
<Text color={colors.primary}> · update ({installedVersion} → {updateStatus.bundledVersion})</Text>
|
|
58
|
+
)}
|
|
59
|
+
</Text>
|
|
60
|
+
</Box>
|
|
61
|
+
|
|
62
|
+
<Box marginTop={1}>
|
|
63
|
+
<Text color={colors.textMuted}>{tool.description}</Text>
|
|
64
|
+
</Box>
|
|
65
|
+
|
|
66
|
+
{/* Colored component badges */}
|
|
67
|
+
<Box flexDirection="column" marginTop={1}>
|
|
68
|
+
<Text color={colors.textDim}>Includes:</Text>
|
|
69
|
+
<Box marginTop={1}>
|
|
70
|
+
<ComponentBadges tool={tool} />
|
|
71
|
+
</Box>
|
|
72
|
+
{/* Show names below badges */}
|
|
73
|
+
<Box flexDirection="column" marginTop={1} marginLeft={1}>
|
|
74
|
+
{tool.includes.skills.length > 0 && (
|
|
75
|
+
<Text>
|
|
76
|
+
<Text color={colors.skill}>Skills: </Text>
|
|
77
|
+
<Text color={colors.textMuted}>{tool.includes.skills.map(s => s.name).join(', ')}</Text>
|
|
78
|
+
</Text>
|
|
79
|
+
)}
|
|
80
|
+
{tool.includes.commands.length > 0 && (
|
|
81
|
+
<Text>
|
|
82
|
+
<Text color={colors.command}>Commands: </Text>
|
|
83
|
+
<Text color={colors.textMuted}>{tool.includes.commands.map(c => `/${c}`).join(', ')}</Text>
|
|
84
|
+
</Text>
|
|
85
|
+
)}
|
|
86
|
+
{tool.includes.agents.length > 0 && (
|
|
87
|
+
<Text>
|
|
88
|
+
<Text color={colors.agent}>Agents: </Text>
|
|
89
|
+
<Text color={colors.textMuted}>{tool.includes.agents.join(', ')}</Text>
|
|
90
|
+
</Text>
|
|
91
|
+
)}
|
|
92
|
+
</Box>
|
|
93
|
+
</Box>
|
|
94
|
+
|
|
95
|
+
{isFocused && (
|
|
96
|
+
<Box flexDirection="row" marginTop={1}>
|
|
97
|
+
{actions.map((action, index) => (
|
|
98
|
+
<Text
|
|
99
|
+
key={action.id}
|
|
100
|
+
backgroundColor={
|
|
101
|
+
selectedAction === index
|
|
102
|
+
? action.variant === 'danger'
|
|
103
|
+
? colors.error
|
|
104
|
+
: colors.primary
|
|
105
|
+
: colors.bgSelected
|
|
106
|
+
}
|
|
107
|
+
color={selectedAction === index ? '#ffffff' : colors.textMuted}
|
|
108
|
+
bold={selectedAction === index}
|
|
109
|
+
>
|
|
110
|
+
{' '}{action.label}{' '}
|
|
111
|
+
</Text>
|
|
112
|
+
))}
|
|
113
|
+
</Box>
|
|
114
|
+
)}
|
|
115
|
+
</Box>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Box, Text } from 'ink';
|
|
2
|
+
import { isToolInstalled, getInstalledToolVersion, getToolUpdateStatus } from '../../../lib/tools';
|
|
3
|
+
import type { ToolManifest } from '../../../lib/types';
|
|
4
|
+
import { colors } from '../constants';
|
|
5
|
+
|
|
6
|
+
export interface ToolItemProps {
|
|
7
|
+
tool: ToolManifest;
|
|
8
|
+
isSelected: boolean;
|
|
9
|
+
isActive: boolean;
|
|
10
|
+
wasAutoUpdated?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function ToolItem({
|
|
14
|
+
tool,
|
|
15
|
+
isSelected,
|
|
16
|
+
isActive,
|
|
17
|
+
wasAutoUpdated,
|
|
18
|
+
}: ToolItemProps) {
|
|
19
|
+
const installed = isToolInstalled(tool.name);
|
|
20
|
+
const installedVersion = getInstalledToolVersion(tool.name);
|
|
21
|
+
const updateStatus = getToolUpdateStatus(tool.name);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Box paddingX={1} backgroundColor={isActive ? colors.bgSelected : undefined}>
|
|
25
|
+
<Text wrap="truncate">
|
|
26
|
+
<Text color={colors.textDim}>{isSelected ? '>' : ' '} </Text>
|
|
27
|
+
<Text color={isSelected || isActive ? colors.text : colors.textMuted}>{tool.name}</Text>
|
|
28
|
+
{installed && installedVersion && <Text color={colors.textDim}> v{installedVersion}</Text>}
|
|
29
|
+
{installed && <Text color={colors.success}> ✓</Text>}
|
|
30
|
+
{wasAutoUpdated && <Text color={colors.success}> ↑</Text>}
|
|
31
|
+
{updateStatus.hasUpdate && !wasAutoUpdated && <Text color={colors.primary}> ↑</Text>}
|
|
32
|
+
<Text> </Text>
|
|
33
|
+
{tool.includes.skills.length > 0 && <Text color={colors.skill}>● </Text>}
|
|
34
|
+
{tool.includes.commands.length > 0 && <Text color={colors.command}>● </Text>}
|
|
35
|
+
{tool.includes.agents.length > 0 && <Text color={colors.agent}>●</Text>}
|
|
36
|
+
</Text>
|
|
37
|
+
</Box>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const colors = {
|
|
2
|
+
primary: '#6366f1',
|
|
3
|
+
bgSelected: '#2d2d2d',
|
|
4
|
+
border: '#3a3a3a',
|
|
5
|
+
text: '#e8e8e8',
|
|
6
|
+
textMuted: '#999999',
|
|
7
|
+
textDim: '#6a6a6a',
|
|
8
|
+
success: '#4ade80',
|
|
9
|
+
error: '#f87171',
|
|
10
|
+
// Component type badges
|
|
11
|
+
skill: '#ec4899', // pink/magenta
|
|
12
|
+
command: '#22d3ee', // cyan
|
|
13
|
+
agent: '#fbbf24', // yellow/amber
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
export const MAX_VISIBLE_ITEMS = 6;
|
|
17
|
+
export const MAX_VISIBLE_CONFIG_ITEMS = 4; // Each config item takes ~3 lines
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useState, useMemo } from 'react';
|
|
2
|
+
import { useApp } from 'ink';
|
|
3
|
+
import { getUpdateInfo, runUpdate, type UpdateInfo } from '../../../lib/version';
|
|
4
|
+
import { setAutoUpdateConfig } from '../../../lib/config';
|
|
5
|
+
|
|
6
|
+
export interface UseAppUpdateOptions {
|
|
7
|
+
onUpdateSuccess: (message: string) => void;
|
|
8
|
+
onUpdateFailure: (error: string) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface UseAppUpdateResult {
|
|
12
|
+
updateInfo: UpdateInfo;
|
|
13
|
+
isUpdating: boolean;
|
|
14
|
+
handleUpdate: () => void;
|
|
15
|
+
handleAlwaysUpdate: () => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function useAppUpdate({ onUpdateSuccess, onUpdateFailure }: UseAppUpdateOptions): UseAppUpdateResult {
|
|
19
|
+
const { exit } = useApp();
|
|
20
|
+
const [isUpdating, setIsUpdating] = useState(false);
|
|
21
|
+
|
|
22
|
+
const updateInfo = useMemo(() => getUpdateInfo(), []);
|
|
23
|
+
|
|
24
|
+
const handleUpdate = () => {
|
|
25
|
+
setIsUpdating(true);
|
|
26
|
+
// Run update in next tick to allow UI to show "Updating..."
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
const result = runUpdate();
|
|
29
|
+
if (result.success) {
|
|
30
|
+
// Build exit message with ANSI colors
|
|
31
|
+
const blue = '\x1b[38;2;99;102;241m'; // #6366f1
|
|
32
|
+
const dim = '\x1b[38;2;106;106;106m';
|
|
33
|
+
const reset = '\x1b[0m';
|
|
34
|
+
const message = `
|
|
35
|
+
${dim}────────────────────────────────────────────────────────${reset}
|
|
36
|
+
|
|
37
|
+
${dim}╔═════╗${reset}
|
|
38
|
+
${dim}║${reset} ${blue}●${reset} ${blue}●${reset} ${dim}║${reset} ${blue}"It's quite possible this system${reset}
|
|
39
|
+
${dim}╚═╦═╦═╝${reset} ${blue}is now fully operational."${reset}
|
|
40
|
+
|
|
41
|
+
Run ${blue}droid${reset} to start the new version.
|
|
42
|
+
|
|
43
|
+
${dim}────────────────────────────────────────────────────────${reset}
|
|
44
|
+
`;
|
|
45
|
+
onUpdateSuccess(message);
|
|
46
|
+
exit();
|
|
47
|
+
} else {
|
|
48
|
+
setIsUpdating(false);
|
|
49
|
+
onUpdateFailure(result.message);
|
|
50
|
+
}
|
|
51
|
+
}, 100);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handleAlwaysUpdate = () => {
|
|
55
|
+
// Enable auto-update for app in config
|
|
56
|
+
setAutoUpdateConfig({ app: true });
|
|
57
|
+
// Then run the update
|
|
58
|
+
handleUpdate();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
updateInfo,
|
|
63
|
+
isUpdating,
|
|
64
|
+
handleUpdate,
|
|
65
|
+
handleAlwaysUpdate,
|
|
66
|
+
};
|
|
67
|
+
}
|