@orderful/droid 0.10.0 → 0.10.2
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/CHANGELOG.md +23 -0
- package/README.md +2 -2
- package/dist/bin/droid.js +1 -1
- package/dist/bin/droid.js.map +1 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +3 -1
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +3 -1
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/tui.d.ts.map +1 -1
- package/dist/commands/tui.js +40 -14
- package/dist/commands/tui.js.map +1 -1
- package/dist/lib/quotes.d.ts +11 -0
- package/dist/lib/quotes.d.ts.map +1 -0
- package/dist/lib/quotes.js +24 -0
- package/dist/lib/quotes.js.map +1 -0
- package/dist/skills/brain/SKILL.md +39 -17
- package/dist/skills/brain/commands/brain.md +1 -0
- package/dist/skills/brain/commands/scratchpad.md +1 -0
- package/dist/skills/brain/references/metadata.md +14 -13
- package/dist/skills/brain/references/naming.md +12 -10
- package/dist/skills/brain/references/templates.md +5 -5
- package/dist/skills/brain/references/workflows.md +16 -6
- package/dist/skills/comments/SKILL.md +2 -2
- package/dist/skills/comments/SKILL.yaml +1 -1
- package/package.json +1 -1
- package/src/bin/droid.ts +1 -1
- package/src/commands/install.ts +5 -1
- package/src/commands/skills.ts +5 -1
- package/src/commands/tui.tsx +42 -14
- package/src/lib/quotes.ts +24 -0
- package/src/skills/brain/SKILL.md +39 -17
- package/src/skills/brain/commands/brain.md +1 -0
- package/src/skills/brain/commands/scratchpad.md +1 -0
- package/src/skills/brain/references/metadata.md +14 -13
- package/src/skills/brain/references/naming.md +12 -10
- package/src/skills/brain/references/templates.md +5 -5
- package/src/skills/brain/references/workflows.md +16 -6
- package/src/skills/comments/SKILL.md +2 -2
- package/src/skills/comments/SKILL.yaml +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Star Wars themed quotes for the TUI welcome screen.
|
|
3
|
+
* Some hint at specific skills available in droid.
|
|
4
|
+
*/
|
|
5
|
+
export const quotes = [
|
|
6
|
+
"I'm probably the droid you are looking for.",
|
|
7
|
+
"These are the skills you're looking for.",
|
|
8
|
+
"I have a bad feeling about this, we might be too efficient.",
|
|
9
|
+
"May the source be with you.",
|
|
10
|
+
"The Force is strong with this one.",
|
|
11
|
+
"This is the way.",
|
|
12
|
+
"I'm fluent in over six million forms of communication. - `/comments`",
|
|
13
|
+
"Much to learn, you still have. - `/coach`",
|
|
14
|
+
"If into the archives you go, only knowledge will you find. - `/project`",
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Get a random quote from the list.
|
|
18
|
+
* Uses a simple random selection - each launch gets a fresh quote.
|
|
19
|
+
*/
|
|
20
|
+
export function getRandomQuote() {
|
|
21
|
+
const index = Math.floor(Math.random() * quotes.length);
|
|
22
|
+
return quotes[index];
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=quotes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quotes.js","sourceRoot":"","sources":["../../src/lib/quotes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,6CAA6C;IAC7C,0CAA0C;IAC1C,6DAA6D;IAC7D,6BAA6B;IAC7B,oCAAoC;IACpC,kBAAkB;IAClB,sEAAsE;IACtE,2CAA2C;IAC3C,yEAAyE;CAC1E,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -38,12 +38,13 @@ Ideas develop through iteration, not single prompts.
|
|
|
38
38
|
|
|
39
39
|
**IMPORTANT:** Before using any default paths, ALWAYS read `~/.droid/skills/brain/overrides.yaml` first. If `brain_dir` is configured there, use that path. Only fall back to defaults if the file doesn't exist or lacks a `brain_dir` setting.
|
|
40
40
|
|
|
41
|
-
| Setting
|
|
42
|
-
|
|
43
|
-
| `brain_dir`
|
|
44
|
-
| `inbox_folder` | (empty)
|
|
41
|
+
| Setting | Default | Description |
|
|
42
|
+
| -------------- | ----------- | --------------------------------------------------------- |
|
|
43
|
+
| `brain_dir` | (see below) | Where docs are stored |
|
|
44
|
+
| `inbox_folder` | (empty) | Optional subfolder for new docs (omit for flat structure) |
|
|
45
45
|
|
|
46
46
|
Default `brain_dir` by AI tool (only if not configured):
|
|
47
|
+
|
|
47
48
|
- **claude-code**: `~/.claude/brain`
|
|
48
49
|
- **opencode**: `~/.config/opencode/brain`
|
|
49
50
|
|
|
@@ -52,28 +53,42 @@ Default `brain_dir` by AI tool (only if not configured):
|
|
|
52
53
|
**Active doc:** Opening or creating a brain doc makes it "active" for the session. Subsequent `/brain add` commands append to it without specifying a path.
|
|
53
54
|
|
|
54
55
|
**Doc types:**
|
|
56
|
+
|
|
55
57
|
- `plan` - Structured: Context → Exploration → Decision → Next Steps
|
|
56
58
|
- `research` - Open-ended exploration of a topic
|
|
57
59
|
- `review` - Code review, document review, or any evaluation task
|
|
58
60
|
- `note` - Quick capture (fire-and-forget, doesn't become active)
|
|
59
61
|
|
|
60
|
-
**Comment conventions:**
|
|
62
|
+
**Comment conventions:** In markdown files, ALWAYS use blockquote `>` prefix for @mention comments:
|
|
63
|
+
|
|
64
|
+
- `> @droid` - User leaves comment for AI to address
|
|
65
|
+
- `> @{user}` - AI leaves comment for user to address
|
|
66
|
+
|
|
67
|
+
Example conversation:
|
|
68
|
+
|
|
69
|
+
```markdown
|
|
70
|
+
> @droid Should we add caching here?
|
|
71
|
+
|
|
72
|
+
> @fry Yes, Redis would work well for this use case.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Read user's configured mention from `~/.droid/config.yaml` → `user_mention` (e.g., `@fry`). If droid's `comments` skill is installed, use `/comments check` for full support.
|
|
61
76
|
|
|
62
77
|
**Status lifecycle:** `exploring` → `drafting` → `decided` → `done`
|
|
63
78
|
|
|
64
79
|
## Commands
|
|
65
80
|
|
|
66
|
-
| Command
|
|
67
|
-
|
|
68
|
-
| `/brain`
|
|
69
|
-
| `/brain {topic}`
|
|
70
|
-
| `/brain plan {topic}`
|
|
71
|
-
| `/brain research {topic}` | Create research doc (requires `research` keyword)
|
|
72
|
-
| `/brain review {topic}`
|
|
73
|
-
| `/brain note {text}`
|
|
74
|
-
| `/brain add {text}`
|
|
75
|
-
| `/brain check`
|
|
76
|
-
| `/brain done`
|
|
81
|
+
| Command | Action |
|
|
82
|
+
| ------------------------- | ---------------------------------------------------------- |
|
|
83
|
+
| `/brain` | List recent docs or create new |
|
|
84
|
+
| `/brain {topic}` | **Search** for existing doc (fuzzy match) → becomes active |
|
|
85
|
+
| `/brain plan {topic}` | Create planning doc (requires `plan` keyword) |
|
|
86
|
+
| `/brain research {topic}` | Create research doc (requires `research` keyword) |
|
|
87
|
+
| `/brain review {topic}` | Create review doc (requires `review` keyword) |
|
|
88
|
+
| `/brain note {text}` | Quick capture (standalone, doesn't become active) |
|
|
89
|
+
| `/brain add {text}` | Append to active doc |
|
|
90
|
+
| `/brain check` | Address @droid comments in active doc |
|
|
91
|
+
| `/brain done` | Finalize active doc, update status |
|
|
77
92
|
|
|
78
93
|
**IMPORTANT:** The default action for `/brain {topic}` is to **SEARCH** for existing docs, NOT create. Only use `/brain plan {topic}` or `/brain research {topic}` when the user explicitly wants to create a new doc.
|
|
79
94
|
|
|
@@ -115,7 +130,7 @@ Full procedure: `references/workflows.md` § Adding
|
|
|
115
130
|
|
|
116
131
|
**Trigger:** `/brain check`
|
|
117
132
|
|
|
118
|
-
**TLDR:** Find `> @droid` comments in active doc, address each one.
|
|
133
|
+
**TLDR:** Find `> @droid` comments in active doc, address each one with `> @{user_mention}` response (always use blockquote `>`).
|
|
119
134
|
|
|
120
135
|
Full procedure: `references/workflows.md` § Checking
|
|
121
136
|
|
|
@@ -132,11 +147,18 @@ Full procedure: `references/workflows.md` § Finalizing
|
|
|
132
147
|
Before creating or modifying brain docs, check if any `brain-*` extension skills are installed:
|
|
133
148
|
|
|
134
149
|
```
|
|
150
|
+
# Claude Code
|
|
135
151
|
~/.claude/skills/brain-*/SKILL.md
|
|
152
|
+
|
|
153
|
+
# OpenCode
|
|
154
|
+
~/.config/opencode/skills/brain-*/SKILL.md
|
|
155
|
+
|
|
156
|
+
# Shared (droid config)
|
|
136
157
|
~/.droid/skills/brain-*/SKILL.md
|
|
137
158
|
```
|
|
138
159
|
|
|
139
160
|
If found (e.g., `brain-obsidian`), **ALWAYS** use the extension's templates, workflows, and configuration instead of this skill's defaults. Extensions may provide:
|
|
161
|
+
|
|
140
162
|
- Alternative template formats (YAML frontmatter, wikilinks)
|
|
141
163
|
- Folder organization (PARA structure)
|
|
142
164
|
- Additional commands or integrations
|
|
@@ -20,12 +20,12 @@ Simple and portable. Works anywhere markdown is supported.
|
|
|
20
20
|
|
|
21
21
|
## Fields
|
|
22
22
|
|
|
23
|
-
| Field
|
|
24
|
-
|
|
25
|
-
| `Type`
|
|
26
|
-
| `Status`
|
|
27
|
-
| `Created` | Yes
|
|
28
|
-
| `Updated` | No
|
|
23
|
+
| Field | Required | Description |
|
|
24
|
+
| --------- | ------------------ | ------------------------------------------------- |
|
|
25
|
+
| `Type` | Yes | Doc type: `plan`, `research`, `review`, or `note` |
|
|
26
|
+
| `Status` | Yes (except notes) | Current lifecycle stage |
|
|
27
|
+
| `Created` | Yes | Creation date |
|
|
28
|
+
| `Updated` | No | Last modification date (add when doc changes) |
|
|
29
29
|
|
|
30
30
|
## Status Lifecycle
|
|
31
31
|
|
|
@@ -37,13 +37,13 @@ exploring → drafting → decided → done
|
|
|
37
37
|
|
|
38
38
|
### Status Definitions
|
|
39
39
|
|
|
40
|
-
| Status
|
|
41
|
-
|
|
42
|
-
| `exploring` | Initial discovery, gathering information | Research, ask questions, explore options
|
|
43
|
-
| `drafting`
|
|
44
|
-
| `decided`
|
|
45
|
-
| `done`
|
|
46
|
-
| `stale`
|
|
40
|
+
| Status | Meaning | Typical Actions |
|
|
41
|
+
| ----------- | ---------------------------------------- | ------------------------------------------------ |
|
|
42
|
+
| `exploring` | Initial discovery, gathering information | Research, ask questions, explore options |
|
|
43
|
+
| `drafting` | Forming opinions, narrowing options | Document trade-offs, propose approaches |
|
|
44
|
+
| `decided` | Decision made, ready to act | Document decision rationale, plan implementation |
|
|
45
|
+
| `done` | Work complete, doc is reference material | Archive or link from project |
|
|
46
|
+
| `stale` | Abandoned or outdated | Review for archival or deletion |
|
|
47
47
|
|
|
48
48
|
### Transitions
|
|
49
49
|
|
|
@@ -55,5 +55,6 @@ exploring → drafting → decided → done
|
|
|
55
55
|
## Updating Metadata
|
|
56
56
|
|
|
57
57
|
When modifying a doc:
|
|
58
|
+
|
|
58
59
|
1. Add or update the `Updated` field to current date
|
|
59
60
|
2. Update `Status` if the work has progressed
|
|
@@ -10,10 +10,10 @@ Conventions for naming brain docs.
|
|
|
10
10
|
|
|
11
11
|
## Components
|
|
12
12
|
|
|
13
|
-
| Component
|
|
14
|
-
|
|
15
|
-
| `{type}`
|
|
16
|
-
| `{topic-slug}` | Lowercase, hyphen-separated topic
|
|
13
|
+
| Component | Description | Examples |
|
|
14
|
+
| -------------- | ------------------------------------ | ------------------------------------- |
|
|
15
|
+
| `{type}` | Doc type: `plan`, `research`, `note` | `plan`, `research`, `note` |
|
|
16
|
+
| `{topic-slug}` | Lowercase, hyphen-separated topic | `auth-refactor`, `caching-strategies` |
|
|
17
17
|
|
|
18
18
|
## Slug Rules
|
|
19
19
|
|
|
@@ -25,16 +25,17 @@ Conventions for naming brain docs.
|
|
|
25
25
|
|
|
26
26
|
## Examples
|
|
27
27
|
|
|
28
|
-
| Input
|
|
29
|
-
|
|
30
|
-
| `/brain plan Auth Refactor`
|
|
31
|
-
| `/brain research Caching Strategies`
|
|
32
|
-
| `/brain plan Transaction Template Rendering` | `plan-transaction-template-rendering.md`
|
|
33
|
-
| `/brain note Remember to check rate limits`
|
|
28
|
+
| Input | Filename |
|
|
29
|
+
| -------------------------------------------- | ----------------------------------------- |
|
|
30
|
+
| `/brain plan Auth Refactor` | `plan-auth-refactor.md` |
|
|
31
|
+
| `/brain research Caching Strategies` | `research-caching-strategies.md` |
|
|
32
|
+
| `/brain plan Transaction Template Rendering` | `plan-transaction-template-rendering.md` |
|
|
33
|
+
| `/brain note Remember to check rate limits` | `note-20250115-remember-to-check-rate.md` |
|
|
34
34
|
|
|
35
35
|
## Notes
|
|
36
36
|
|
|
37
37
|
For notes, include the date in the filename:
|
|
38
|
+
|
|
38
39
|
```
|
|
39
40
|
note-{YYYYMMDD}-{slug}.md
|
|
40
41
|
```
|
|
@@ -44,5 +45,6 @@ This prevents collisions and allows chronological sorting.
|
|
|
44
45
|
## Uniqueness
|
|
45
46
|
|
|
46
47
|
If a file with the generated name already exists:
|
|
48
|
+
|
|
47
49
|
1. Check if user wants to open existing doc
|
|
48
50
|
2. Or append a numeric suffix: `plan-auth-refactor-2.md`
|
|
@@ -94,9 +94,9 @@ Overall assessment.
|
|
|
94
94
|
|
|
95
95
|
## Template Variables
|
|
96
96
|
|
|
97
|
-
| Variable
|
|
98
|
-
|
|
99
|
-
| `{Topic}`
|
|
100
|
-
| `{date}`
|
|
97
|
+
| Variable | Description | Example |
|
|
98
|
+
| --------------------- | ------------------------- | --------------------------------------- |
|
|
99
|
+
| `{Topic}` | Doc title from user input | "Auth Refactor" |
|
|
100
|
+
| `{date}` | Current date (YYYY-MM-DD) | "2025-01-15" |
|
|
101
101
|
| `{brief description}` | Context from conversation | "refactoring the authentication system" |
|
|
102
|
-
| `{content}`
|
|
102
|
+
| `{content}` | User-provided text | (for notes) |
|
|
@@ -13,9 +13,11 @@ Detailed procedures for each brain operation.
|
|
|
13
13
|
- Use `brain_dir` if configured, otherwise use default for current AI tool
|
|
14
14
|
|
|
15
15
|
2. **Search for matches**
|
|
16
|
+
|
|
16
17
|
```
|
|
17
18
|
Glob: {brain_dir}/**/*{topic}*.md
|
|
18
19
|
```
|
|
20
|
+
|
|
19
21
|
Fuzzy match the topic against doc filenames
|
|
20
22
|
|
|
21
23
|
3. **Handle results:**
|
|
@@ -59,11 +61,16 @@ Detailed procedures for each brain operation.
|
|
|
59
61
|
- Any constraints or requirements mentioned?
|
|
60
62
|
- Related work or prior decisions?
|
|
61
63
|
|
|
62
|
-
7. **
|
|
64
|
+
7. **Add placeholder comments** for sections needing user input:
|
|
65
|
+
- Read user's mention from `~/.droid/config.yaml` → `user_mention`
|
|
66
|
+
- Use `> @{user_mention}` for placeholders (e.g., `> @fry - Please provide requirements`)
|
|
67
|
+
- Do NOT use `> @droid` - that's for user-to-AI comments
|
|
63
68
|
|
|
64
|
-
8. **
|
|
69
|
+
8. **Write the doc** with template structure and initial context
|
|
65
70
|
|
|
66
|
-
9. **
|
|
71
|
+
9. **Set as active doc**
|
|
72
|
+
|
|
73
|
+
10. **Confirm creation** and summarize what was captured
|
|
67
74
|
|
|
68
75
|
## Notes
|
|
69
76
|
|
|
@@ -105,8 +112,8 @@ Detailed procedures for each brain operation.
|
|
|
105
112
|
2. **Read current content** of active doc
|
|
106
113
|
|
|
107
114
|
3. **Append new section:**
|
|
108
|
-
```markdown
|
|
109
115
|
|
|
116
|
+
```markdown
|
|
110
117
|
---
|
|
111
118
|
|
|
112
119
|
## Update ({date})
|
|
@@ -139,8 +146,9 @@ Detailed procedures for each brain operation.
|
|
|
139
146
|
4. **For each comment:**
|
|
140
147
|
- Show the comment and surrounding context
|
|
141
148
|
- Address the question/request
|
|
142
|
-
- Add response as `> @{user_mention}`
|
|
143
|
-
-
|
|
149
|
+
- Add response as blockquote with user's mention: `> @{user_mention} Your response here`
|
|
150
|
+
- Example: `> @fry Yes, the index covers that query pattern.`
|
|
151
|
+
- IMPORTANT: Always include the `>` prefix to maintain blockquote formatting
|
|
144
152
|
|
|
145
153
|
5. **Update the doc** with responses
|
|
146
154
|
|
|
@@ -182,9 +190,11 @@ Detailed procedures for each brain operation.
|
|
|
182
190
|
- Use `brain_dir` if configured, otherwise use default for current AI tool
|
|
183
191
|
|
|
184
192
|
2. **Find recent docs:**
|
|
193
|
+
|
|
185
194
|
```
|
|
186
195
|
Glob: {brain_dir}/**/*.md
|
|
187
196
|
```
|
|
197
|
+
|
|
188
198
|
Sort by modification time, limit to 10-15
|
|
189
199
|
|
|
190
200
|
3. **Present list** with:
|
|
@@ -98,8 +98,8 @@ user_mention: "@fry"
|
|
|
98
98
|
# Additional AI mentions to recognize (e.g., if you're used to @claude)
|
|
99
99
|
ai_mentions: "@claude"
|
|
100
100
|
|
|
101
|
-
# Keep comments after addressing them (default:
|
|
102
|
-
preserve_comments:
|
|
101
|
+
# Keep comments after addressing them (default: true)
|
|
102
|
+
preserve_comments: true
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
## File Type Support
|
package/package.json
CHANGED
package/src/bin/droid.ts
CHANGED
package/src/commands/install.ts
CHANGED
|
@@ -34,7 +34,11 @@ export async function installCommand(skillName: string): Promise<void> {
|
|
|
34
34
|
// Check if skill has configurable options
|
|
35
35
|
const manifest = loadSkillManifest(join(getBundledSkillsDir(), skillName));
|
|
36
36
|
if (manifest?.config_schema && Object.keys(manifest.config_schema).length > 0) {
|
|
37
|
-
|
|
37
|
+
// If any config option lacks a default, go straight to config (it's required)
|
|
38
|
+
const hasRequiredConfig = Object.values(manifest.config_schema).some(
|
|
39
|
+
(option) => option.default === undefined
|
|
40
|
+
);
|
|
41
|
+
await promptForSkillConfig(skillName, manifest.config_schema, !hasRequiredConfig);
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
// Show next steps
|
package/src/commands/skills.ts
CHANGED
|
@@ -127,7 +127,11 @@ export async function skillsCommand(): Promise<void> {
|
|
|
127
127
|
// Prompt for config if skill has options
|
|
128
128
|
const manifest = loadSkillManifest(join(getBundledSkillsDir(), skill.name));
|
|
129
129
|
if (manifest?.config_schema && Object.keys(manifest.config_schema).length > 0) {
|
|
130
|
-
|
|
130
|
+
// If any config option lacks a default, go straight to config (it's required)
|
|
131
|
+
const hasRequiredConfig = Object.values(manifest.config_schema).some(
|
|
132
|
+
(option) => option.default === undefined
|
|
133
|
+
);
|
|
134
|
+
await promptForSkillConfig(skill.name, manifest.config_schema, !hasRequiredConfig);
|
|
131
135
|
}
|
|
132
136
|
} else {
|
|
133
137
|
console.log(chalk.red(`\n✗ ${result.message}`));
|
package/src/commands/tui.tsx
CHANGED
|
@@ -19,6 +19,7 @@ import { configExists, loadConfig, saveConfig, loadSkillOverrides, saveSkillOver
|
|
|
19
19
|
import { configureAIToolPermissions } from './setup.js';
|
|
20
20
|
import { AITool, BuiltInOutput, ConfigOptionType, type DroidConfig, type OutputPreference, type SkillManifest, type ConfigOption, type SkillOverrides } from '../lib/types.js';
|
|
21
21
|
import { getVersion, getUpdateInfo, runUpdate, type UpdateInfo } from '../lib/version.js';
|
|
22
|
+
import { getRandomQuote } from '../lib/quotes.js';
|
|
22
23
|
|
|
23
24
|
type Tab = 'skills' | 'commands' | 'agents' | 'settings';
|
|
24
25
|
type View = 'welcome' | 'setup' | 'menu' | 'detail' | 'configure' | 'readme';
|
|
@@ -100,20 +101,28 @@ function getCommandsFromSkills(): Command[] {
|
|
|
100
101
|
return commands;
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
function
|
|
104
|
+
function detectInstalledAITools(): Set<AITool> {
|
|
105
|
+
const installed = new Set<AITool>();
|
|
104
106
|
try {
|
|
105
107
|
execSync('claude --version', { stdio: 'ignore' });
|
|
106
|
-
|
|
108
|
+
installed.add(AITool.ClaudeCode);
|
|
107
109
|
} catch {
|
|
108
110
|
// Claude Code not found
|
|
109
111
|
}
|
|
110
112
|
try {
|
|
111
113
|
execSync('opencode --version', { stdio: 'ignore' });
|
|
112
|
-
|
|
114
|
+
installed.add(AITool.OpenCode);
|
|
113
115
|
} catch {
|
|
114
116
|
// OpenCode not found
|
|
115
117
|
}
|
|
116
|
-
return
|
|
118
|
+
return installed;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getDefaultAITool(): AITool {
|
|
122
|
+
const installed = detectInstalledAITools();
|
|
123
|
+
if (installed.has(AITool.ClaudeCode)) return AITool.ClaudeCode;
|
|
124
|
+
if (installed.has(AITool.OpenCode)) return AITool.OpenCode;
|
|
125
|
+
return AITool.ClaudeCode;
|
|
117
126
|
}
|
|
118
127
|
|
|
119
128
|
function getOutputOptions(): Array<{ label: string; value: OutputPreference }> {
|
|
@@ -183,12 +192,14 @@ function findAgentSourcePath(agentName: string): string | null {
|
|
|
183
192
|
interface WelcomeScreenProps {
|
|
184
193
|
onContinue: () => void;
|
|
185
194
|
onUpdate: () => void;
|
|
195
|
+
onExit: () => void;
|
|
186
196
|
updateInfo: UpdateInfo;
|
|
187
197
|
isUpdating: boolean;
|
|
188
198
|
}
|
|
189
199
|
|
|
190
|
-
function WelcomeScreen({ onContinue, onUpdate, updateInfo, isUpdating }: WelcomeScreenProps) {
|
|
200
|
+
function WelcomeScreen({ onContinue, onUpdate, onExit, updateInfo, isUpdating }: WelcomeScreenProps) {
|
|
191
201
|
const [selectedButton, setSelectedButton] = useState(0);
|
|
202
|
+
const welcomeQuote = useMemo(() => getRandomQuote(), []);
|
|
192
203
|
|
|
193
204
|
useInput((input, key) => {
|
|
194
205
|
if (isUpdating) return;
|
|
@@ -205,12 +216,15 @@ function WelcomeScreen({ onContinue, onUpdate, updateInfo, isUpdating }: Welcome
|
|
|
205
216
|
}
|
|
206
217
|
}
|
|
207
218
|
if (input === 'q') {
|
|
208
|
-
|
|
219
|
+
onExit();
|
|
209
220
|
}
|
|
210
221
|
} else {
|
|
211
|
-
if (key.return
|
|
222
|
+
if (key.return) {
|
|
212
223
|
onContinue();
|
|
213
224
|
}
|
|
225
|
+
if (input === 'q') {
|
|
226
|
+
onExit();
|
|
227
|
+
}
|
|
214
228
|
}
|
|
215
229
|
});
|
|
216
230
|
|
|
@@ -238,7 +252,7 @@ function WelcomeScreen({ onContinue, onUpdate, updateInfo, isUpdating }: Welcome
|
|
|
238
252
|
<Text color={colors.textDim}> </Text>
|
|
239
253
|
<Text color={hasUpdate ? '#eab308' : colors.primary}>●</Text>
|
|
240
254
|
<Text color={colors.textDim}> ║ </Text>
|
|
241
|
-
<Text color={colors.textMuted}>
|
|
255
|
+
<Text color={colors.textMuted}>Droid, teaching your AI new tricks</Text>
|
|
242
256
|
</Text>
|
|
243
257
|
<Text>
|
|
244
258
|
<Text color={colors.textDim}>╚═╦═╦═╝ </Text>
|
|
@@ -293,7 +307,7 @@ function WelcomeScreen({ onContinue, onUpdate, updateInfo, isUpdating }: Welcome
|
|
|
293
307
|
<>
|
|
294
308
|
<Box marginTop={2} marginBottom={1}>
|
|
295
309
|
<Text backgroundColor={colors.primary} color="#ffffff" bold>
|
|
296
|
-
{
|
|
310
|
+
{` ${welcomeQuote} `}
|
|
297
311
|
</Text>
|
|
298
312
|
</Box>
|
|
299
313
|
|
|
@@ -314,7 +328,7 @@ interface SetupScreenProps {
|
|
|
314
328
|
function SetupScreen({ onComplete, onSkip, initialConfig }: SetupScreenProps) {
|
|
315
329
|
const [step, setStep] = useState<SetupStep>('ai_tool');
|
|
316
330
|
const [aiTool, setAITool] = useState<AITool>(
|
|
317
|
-
initialConfig?.ai_tool ||
|
|
331
|
+
initialConfig?.ai_tool || getDefaultAITool()
|
|
318
332
|
);
|
|
319
333
|
const [userMention, setUserMention] = useState(initialConfig?.user_mention || '@user');
|
|
320
334
|
const [outputPreference, setOutputPreference] = useState<OutputPreference>(
|
|
@@ -323,6 +337,8 @@ function SetupScreen({ onComplete, onSkip, initialConfig }: SetupScreenProps) {
|
|
|
323
337
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
324
338
|
const [error, setError] = useState<string | null>(null);
|
|
325
339
|
|
|
340
|
+
// Cache detection results once on mount (avoids re-running execSync on every render)
|
|
341
|
+
const installedTools = useMemo(() => detectInstalledAITools(), []);
|
|
326
342
|
const aiToolOptions = useMemo(() => [
|
|
327
343
|
{ label: 'Claude Code', value: AITool.ClaudeCode },
|
|
328
344
|
{ label: 'OpenCode', value: AITool.OpenCode },
|
|
@@ -418,7 +434,7 @@ function SetupScreen({ onComplete, onSkip, initialConfig }: SetupScreenProps) {
|
|
|
418
434
|
<Text key={option.value}>
|
|
419
435
|
<Text color={colors.textDim}>{index === selectedIndex ? '>' : ' '} </Text>
|
|
420
436
|
<Text color={index === selectedIndex ? colors.text : colors.textMuted}>{option.label}</Text>
|
|
421
|
-
{option.value
|
|
437
|
+
{installedTools.has(option.value) && <Text color={colors.success}> (detected)</Text>}
|
|
422
438
|
</Text>
|
|
423
439
|
))}
|
|
424
440
|
</Box>
|
|
@@ -1358,7 +1374,8 @@ function App() {
|
|
|
1358
1374
|
setTimeout(() => {
|
|
1359
1375
|
const result = runUpdate();
|
|
1360
1376
|
if (result.success) {
|
|
1361
|
-
//
|
|
1377
|
+
// Print success message before exiting
|
|
1378
|
+
console.log('\n✅ Update complete! Run `droid` to start the new version.\n');
|
|
1362
1379
|
exit();
|
|
1363
1380
|
} else {
|
|
1364
1381
|
setIsUpdating(false);
|
|
@@ -1521,8 +1538,18 @@ function App() {
|
|
|
1521
1538
|
type: result.success ? 'success' : 'error',
|
|
1522
1539
|
});
|
|
1523
1540
|
if (result.success) {
|
|
1524
|
-
|
|
1525
|
-
|
|
1541
|
+
// Check if skill has required config (options without defaults)
|
|
1542
|
+
const configSchema = skill.config_schema || {};
|
|
1543
|
+
const hasRequiredConfig = Object.values(configSchema).some(
|
|
1544
|
+
(option) => (option as ConfigOption).default === undefined
|
|
1545
|
+
);
|
|
1546
|
+
if (hasRequiredConfig) {
|
|
1547
|
+
// Go to configure view for required setup
|
|
1548
|
+
setView('configure');
|
|
1549
|
+
} else {
|
|
1550
|
+
setView('menu');
|
|
1551
|
+
setSelectedAction(0);
|
|
1552
|
+
}
|
|
1526
1553
|
}
|
|
1527
1554
|
}
|
|
1528
1555
|
}
|
|
@@ -1595,6 +1622,7 @@ function App() {
|
|
|
1595
1622
|
updateInfo={updateInfo}
|
|
1596
1623
|
isUpdating={isUpdating}
|
|
1597
1624
|
onUpdate={handleUpdate}
|
|
1625
|
+
onExit={exit}
|
|
1598
1626
|
onContinue={() => {
|
|
1599
1627
|
// If no config exists, show setup first
|
|
1600
1628
|
if (!configExists()) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Star Wars themed quotes for the TUI welcome screen.
|
|
3
|
+
* Some hint at specific skills available in droid.
|
|
4
|
+
*/
|
|
5
|
+
export const quotes = [
|
|
6
|
+
"I'm probably the droid you are looking for.",
|
|
7
|
+
"These are the skills you're looking for.",
|
|
8
|
+
"I have a bad feeling about this, we might be too efficient.",
|
|
9
|
+
"May the source be with you.",
|
|
10
|
+
"The Force is strong with this one.",
|
|
11
|
+
"This is the way.",
|
|
12
|
+
"I'm fluent in over six million forms of communication. - `/comments`",
|
|
13
|
+
"Much to learn, you still have. - `/coach`",
|
|
14
|
+
"If into the archives you go, only knowledge will you find. - `/project`",
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get a random quote from the list.
|
|
19
|
+
* Uses a simple random selection - each launch gets a fresh quote.
|
|
20
|
+
*/
|
|
21
|
+
export function getRandomQuote(): string {
|
|
22
|
+
const index = Math.floor(Math.random() * quotes.length);
|
|
23
|
+
return quotes[index];
|
|
24
|
+
}
|