@orderful/droid 0.5.2 → 0.7.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/bun.lock +1 -1
  3. package/dist/commands/tui.d.ts.map +1 -1
  4. package/dist/commands/tui.js +54 -7
  5. package/dist/commands/tui.js.map +1 -1
  6. package/dist/lib/version.d.ts +17 -0
  7. package/dist/lib/version.d.ts.map +1 -1
  8. package/dist/lib/version.js +41 -0
  9. package/dist/lib/version.js.map +1 -1
  10. package/dist/skills/brain/SKILL.md +144 -0
  11. package/dist/skills/brain/SKILL.yaml +31 -0
  12. package/dist/skills/brain/commands/README.md +7 -0
  13. package/dist/skills/brain/commands/brain.md +45 -0
  14. package/dist/skills/brain/references/metadata.md +59 -0
  15. package/dist/skills/brain/references/naming.md +48 -0
  16. package/dist/skills/brain/references/templates.md +102 -0
  17. package/dist/skills/brain/references/workflows.md +188 -0
  18. package/dist/skills/brain-obsidian/SKILL.md +108 -0
  19. package/dist/skills/brain-obsidian/SKILL.yaml +45 -0
  20. package/dist/skills/brain-obsidian/references/templates.md +144 -0
  21. package/dist/skills/brain-obsidian/references/workflows.md +192 -0
  22. package/dist/skills/comments/SKILL.yaml +1 -1
  23. package/package.json +1 -1
  24. package/src/commands/tui.tsx +120 -15
  25. package/src/lib/version.ts +49 -0
  26. package/src/skills/brain/SKILL.md +144 -0
  27. package/src/skills/brain/SKILL.yaml +31 -0
  28. package/src/skills/brain/commands/README.md +7 -0
  29. package/src/skills/brain/commands/brain.md +45 -0
  30. package/src/skills/brain/references/metadata.md +59 -0
  31. package/src/skills/brain/references/naming.md +48 -0
  32. package/src/skills/brain/references/templates.md +102 -0
  33. package/src/skills/brain/references/workflows.md +188 -0
  34. package/src/skills/brain-obsidian/SKILL.md +108 -0
  35. package/src/skills/brain-obsidian/SKILL.yaml +45 -0
  36. package/src/skills/brain-obsidian/references/templates.md +144 -0
  37. package/src/skills/brain-obsidian/references/workflows.md +192 -0
  38. package/src/skills/comments/SKILL.yaml +1 -1
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: brain-obsidian
3
+ description: >-
4
+ Obsidian extension for brain skill. Adds YAML frontmatter, wikilinks, and folder
5
+ organization. Requires brain skill. Install this to use brain docs with your
6
+ Obsidian vault.
7
+ globs:
8
+ - "**/brain/**/*.md"
9
+ alwaysApply: false
10
+ ---
11
+
12
+ # Brain Obsidian Extension
13
+
14
+ Extends the brain skill with Obsidian-specific features. **This skill overrides brain's default templates and workflows.**
15
+
16
+ ## Requirements
17
+
18
+ - `brain` skill must be installed
19
+ - Set `brain_dir` to your Obsidian vault path in brain skill overrides
20
+
21
+ ## Configuration
22
+
23
+ **Required:** Set vault path in `~/.droid/skills/brain/overrides.yaml`:
24
+
25
+ ```yaml
26
+ brain_dir: ~/path/to/your/vault
27
+ ```
28
+
29
+ **Optional:** Configure folders in `~/.droid/skills/brain-obsidian/overrides.yaml`:
30
+
31
+ | Setting | Default | Description |
32
+ |--------------------|---------------|---------------------------------|
33
+ | `inbox_folder` | `0-Inbox` | Where new docs are created |
34
+ | `archive_folder` | `4-Archives` | Where stale/done docs go |
35
+ | `para_structure` | `false` | Enable full PARA organization |
36
+ | `projects_folder` | `1-Projects` | Active project docs (PARA only) |
37
+ | `areas_folder` | `1-Areas` | Area docs (PARA only) |
38
+ | `resources_folder` | `3-Resources` | Reference material (PARA only) |
39
+
40
+ ## What This Adds
41
+
42
+ | Feature | Description |
43
+ |---------------------|--------------------------------------------|
44
+ | YAML frontmatter | Type, status, dates, project links, tags |
45
+ | Wikilinks | `[[note-name]]` syntax for linking |
46
+ | Folder organization | Inbox + Archive always; full PARA optional |
47
+ | Project linking | Associate brain docs with project files |
48
+
49
+ ## Folder Organization
50
+
51
+ **Always available:**
52
+ - `inbox_folder` - New docs land here
53
+ - `archive_folder` - Stale/completed docs
54
+
55
+ **With `para_structure: true`:**
56
+ ```
57
+ vault/
58
+ ├── {inbox_folder}/ # New docs (default: 0-Inbox)
59
+ ├── {projects_folder}/ # Active project docs (default: 1-Projects)
60
+ ├── {areas_folder}/ # Area docs (default: 2-Areas)
61
+ ├── {resources_folder}/ # Reference material (default: 3-Resources)
62
+ └── {archive_folder}/ # Completed/stale (default: 4-Archives)
63
+ ```
64
+
65
+ ## Overridden Behavior
66
+
67
+ When this skill is installed, **ALL brain operations use Obsidian format**:
68
+
69
+ ### Templates
70
+
71
+ All docs get YAML frontmatter:
72
+
73
+ ```yaml
74
+ ---
75
+ type: plan | research | review | note
76
+ status: exploring | drafting | decided | done
77
+ created: YYYY-MM-DD
78
+ updated: YYYY-MM-DD
79
+ project: "[[project-name]]" # Optional
80
+ tags: [] # Optional
81
+ ---
82
+ ```
83
+
84
+ See `references/templates.md` for full templates.
85
+
86
+ ### File Location
87
+
88
+ Docs are created in your vault's inbox folder:
89
+ - `{brain_dir}/{inbox_folder}/{filename}.md`
90
+
91
+ ### Finalizing
92
+
93
+ When running `/brain done`:
94
+ 1. Updates status to `done` in frontmatter
95
+ 2. Suggests moving to archive (or projects/resources if PARA enabled)
96
+ 3. Confirms before moving
97
+
98
+ ## Commands
99
+
100
+ Same commands as brain skill, but with Obsidian output:
101
+
102
+ | Command | Obsidian Behavior |
103
+ |---------------------------|--------------------------------------------|
104
+ | `/brain plan {topic}` | Creates in inbox with frontmatter |
105
+ | `/brain research {topic}` | Creates in inbox with frontmatter |
106
+ | `/brain review {topic}` | Creates in inbox with frontmatter |
107
+ | `/brain note {text}` | Quick capture to inbox |
108
+ | `/brain done` | Updates status, suggests archive/PARA move |
@@ -0,0 +1,45 @@
1
+ name: brain-obsidian
2
+ description: >-
3
+ Obsidian extension for brain skill. Adds YAML frontmatter, wikilinks, and folder
4
+ organization. Requires brain skill. Install this to use brain docs with your
5
+ Obsidian vault.
6
+ version: 0.1.0
7
+ status: beta
8
+ dependencies:
9
+ - brain
10
+ # Optional: project skill enables linking features
11
+ provides_output: false
12
+ config_schema:
13
+ inbox_folder:
14
+ type: string
15
+ description: Folder for new brain docs
16
+ default: "0-Inbox"
17
+ archive_folder:
18
+ type: string
19
+ description: Folder for archived/stale docs
20
+ default: "4-Archives"
21
+ para_structure:
22
+ type: boolean
23
+ description: Enable full PARA folder organization
24
+ default: false
25
+ projects_folder:
26
+ type: string
27
+ description: Folder for active project docs (when para_structure is true)
28
+ default: "1-Projects"
29
+ areas_folder:
30
+ type: string
31
+ description: Folder for area docs (when para_structure is true)
32
+ default: "1-Areas"
33
+ resources_folder:
34
+ type: string
35
+ description: Folder for reference material (when para_structure is true)
36
+ default: "3-Resources"
37
+ examples:
38
+ - title: "Create planning doc in vault"
39
+ code: |
40
+ /brain plan auth refactor
41
+ # Creates in vault's 0-Inbox/ with YAML frontmatter
42
+ - title: "Link to project"
43
+ code: |
44
+ /brain plan feature-x
45
+ # Frontmatter includes project: "[[feature-x]]"
@@ -0,0 +1,144 @@
1
+ # Obsidian Brain Templates
2
+
3
+ Templates with YAML frontmatter and wikilink support.
4
+
5
+ ## Plan Template
6
+
7
+ ```markdown
8
+ ---
9
+ type: plan
10
+ status: exploring
11
+ created: {date}
12
+ updated: {date}
13
+ project: "[[{project}]]"
14
+ tags: []
15
+ ---
16
+
17
+ # {Topic}
18
+
19
+ Planning {brief description}.
20
+
21
+ ## Context
22
+
23
+ What we're solving and why.
24
+
25
+ ## Exploration
26
+
27
+ Options and approaches considered.
28
+
29
+ ## Decision
30
+
31
+ What we chose and why.
32
+
33
+ ## Next Steps
34
+
35
+ - [ ] Action items
36
+ ```
37
+
38
+ ## Research Template
39
+
40
+ ```markdown
41
+ ---
42
+ type: research
43
+ status: exploring
44
+ created: {date}
45
+ updated: {date}
46
+ project: "[[{project}]]"
47
+ tags: []
48
+ ---
49
+
50
+ # {Topic}
51
+
52
+ Researching {brief description}.
53
+
54
+ ## Questions
55
+
56
+ What we're trying to understand.
57
+
58
+ ## Findings
59
+
60
+ What we've learned.
61
+
62
+ ## Summary
63
+
64
+ Key takeaways.
65
+
66
+ ## Related
67
+
68
+ - [[related-note-1]]
69
+ - [[related-note-2]]
70
+ ```
71
+
72
+ ## Review Template
73
+
74
+ ```markdown
75
+ ---
76
+ type: review
77
+ status: exploring
78
+ created: {date}
79
+ updated: {date}
80
+ project: "[[{project}]]"
81
+ tags: []
82
+ ---
83
+
84
+ # {Topic}
85
+
86
+ Reviewing {brief description}.
87
+
88
+ ## Overview
89
+
90
+ What's being reviewed and scope.
91
+
92
+ ## Observations
93
+
94
+ Key findings and notes.
95
+
96
+ ## Recommendations
97
+
98
+ Suggested changes or actions.
99
+
100
+ ## Verdict
101
+
102
+ Overall assessment.
103
+ ```
104
+
105
+ ## Note Template
106
+
107
+ ```markdown
108
+ ---
109
+ type: note
110
+ created: {date}
111
+ tags: []
112
+ ---
113
+
114
+ # {Brief Title}
115
+
116
+ {content}
117
+ ```
118
+
119
+ ## Template Variables
120
+
121
+ | Variable | Description | Example |
122
+ |----------|-------------|---------|
123
+ | `{Topic}` | Doc title from user input | "Auth Refactor" |
124
+ | `{date}` | Current date (YYYY-MM-DD) | "2025-01-15" |
125
+ | `{brief description}` | Context from conversation | "refactoring the authentication system" |
126
+ | `{project}` | Active project name (if any) | "transaction-templates" |
127
+ | `{content}` | User-provided text | (for notes) |
128
+
129
+ ## Frontmatter Fields
130
+
131
+ | Field | Type | Description |
132
+ |-------|------|-------------|
133
+ | `type` | string | Doc type: `plan`, `research`, `review`, `note` |
134
+ | `status` | string | Lifecycle: `exploring`, `drafting`, `decided`, `done`, `stale` |
135
+ | `created` | date | Creation date (YYYY-MM-DD) |
136
+ | `updated` | date | Last modification date |
137
+ | `project` | wikilink | Link to related project: `"[[project-name]]"` |
138
+ | `tags` | list | Tags for filtering: `[tag1, tag2]` |
139
+
140
+ ## Wikilink Conventions
141
+
142
+ - Project links: `[[project-name]]` or `[[1-Projects/project-name/PROJECT]]`
143
+ - Related notes: `[[note-name]]`
144
+ - Use Obsidian's autocomplete to find existing notes
@@ -0,0 +1,192 @@
1
+ # Obsidian Brain Workflows
2
+
3
+ Obsidian-specific procedures that override brain defaults.
4
+
5
+ ## Creating Docs
6
+
7
+ **Overrides:** brain's Creating workflow
8
+
9
+ **Steps:**
10
+
11
+ 1. **Resolve paths from config:**
12
+ - `brain_dir` from brain skill (your vault path)
13
+ - `inbox_folder` from brain-obsidian (default: `0-Inbox`)
14
+
15
+ 2. **Target folder:** `{brain_dir}/{inbox_folder}/`
16
+
17
+ 3. **Generate filename** using brain's naming conventions:
18
+ - Format: `{type}-{topic-slug}.md`
19
+
20
+ 4. **Check for active project:**
21
+ - If `/project` was loaded this session, use its name for `project` field
22
+ - Otherwise, leave `project` field empty or ask user
23
+
24
+ 5. **Apply Obsidian template** from `references/templates.md`:
25
+ - Include YAML frontmatter with all fields
26
+ - Set `created` and `updated` to today
27
+ - Set `status: exploring`
28
+
29
+ 6. **Create the file** in vault
30
+
31
+ 7. **Set as active doc** (same as brain)
32
+
33
+ ## Opening Docs
34
+
35
+ **Overrides:** brain's Opening workflow
36
+
37
+ **Steps:**
38
+
39
+ 1. **Search in brain_dir** (your vault):
40
+ ```
41
+ Glob: {brain_dir}/**/*{topic}*.md
42
+ ```
43
+
44
+ 2. **Rest of workflow same as brain** (fuzzy match, select, read, set active)
45
+
46
+ ## Updating Frontmatter
47
+
48
+ When modifying any brain doc:
49
+
50
+ 1. **Update the `updated` field** to current date
51
+ 2. **Update `status`** if work has progressed
52
+ 3. **Add `project` link** if doc becomes associated with a project
53
+
54
+ ## Finalizing
55
+
56
+ **Overrides:** brain's Finalizing workflow
57
+
58
+ **Steps:**
59
+
60
+ 1. **Read active doc** and current location
61
+
62
+ 2. **Update frontmatter:**
63
+ - Set `status: done`
64
+ - Update `updated` date
65
+
66
+ 3. **Suggest destination based on content and config:**
67
+
68
+ **Without PARA (`para_structure: false`):**
69
+ | Condition | Suggested Destination |
70
+ |-----------|----------------------|
71
+ | Done/stale | `{archive_folder}/` |
72
+ | Still useful in inbox | Keep in place |
73
+
74
+ **With PARA (`para_structure: true`):**
75
+ | Condition | Suggested Destination |
76
+ |-----------|----------------------|
77
+ | Has active project link | `{projects_folder}/` |
78
+ | Ongoing area of responsibility | `{areas_folder}/` |
79
+ | Reference/learning value | `{resources_folder}/` |
80
+ | Stale or obsolete | `{archive_folder}/` |
81
+
82
+ 4. **Confirm move with user** before relocating
83
+
84
+ 5. **Move the file** if confirmed:
85
+ ```bash
86
+ mv "{brain_dir}/{inbox_folder}/{file}" "{brain_dir}/{destination}/{file}"
87
+ ```
88
+
89
+ 6. **Clear active doc** from session
90
+
91
+ ## Quick Notes
92
+
93
+ **Overrides:** brain's Notes workflow
94
+
95
+ **Steps:**
96
+
97
+ 1. **Create in inbox:** `{brain_dir}/{inbox_folder}/note-{date}-{slug}.md`
98
+
99
+ 2. **Use note template** with minimal frontmatter:
100
+ ```yaml
101
+ ---
102
+ type: note
103
+ created: {date}
104
+ tags: []
105
+ ---
106
+ ```
107
+
108
+ 3. **Fire-and-forget** (does not become active)
109
+
110
+ ## Project Integration (Optional)
111
+
112
+ **Requires:** `project` skill. If not installed, suggest:
113
+ > "Linking to projects requires the project skill. Install it with `droid` → Skills → project"
114
+
115
+ When a project is loaded via `/project {name}`:
116
+
117
+ 1. **Remember project name** for session
118
+ 2. **New brain docs** automatically get `project: "[[{name}]]"` in frontmatter
119
+ 3. **Suggest linking** existing brain docs to the project
120
+
121
+ ## Adding Brain Doc to Existing Project
122
+
123
+ **Trigger:** User says "add this to the project", "link this to project", or "capture in project"
124
+
125
+ **Requires:** `project` skill. If not installed, suggest:
126
+ > "Linking to projects requires the project skill. Install it with `droid` → Skills → project"
127
+
128
+ For linking a brain doc (research, notes, design) to an existing project.
129
+
130
+ **Steps:**
131
+
132
+ 1. **Check for active project:**
133
+ - If project loaded via `/project`, use that
134
+ - Otherwise, ask which project to link to
135
+
136
+ 2. **Update brain doc frontmatter:**
137
+ - Add `project: "[[{project-name}]]"`
138
+ - Update status if appropriate
139
+
140
+ 3. **Update project:**
141
+ - Add wikilink in Related section: `[[{brain-doc}]]`
142
+ - Or add to appropriate section (Key Decisions, Implementation, etc.)
143
+
144
+ 4. **Suggest moving brain doc:**
145
+ - With PARA: move to `{projects_folder}/` alongside project
146
+ - Without PARA: keep in place with project link
147
+
148
+ ## Promoting Brain Doc to New Project
149
+
150
+ **Trigger:** User says "promote to project", "make this a project", or "convert to project"
151
+
152
+ **Requires:** `project` skill. If not installed, suggest:
153
+ > "Promoting to project requires the project skill. Install it with `droid` → Skills → project"
154
+
155
+ For graduating a full tech design or plan into its own project.
156
+
157
+ **Steps:**
158
+
159
+ 1. **Confirm promotion:**
160
+ - "This will create a new project from this brain doc. Continue?"
161
+
162
+ 2. **Extract project info from brain doc:**
163
+ - Title → project name
164
+ - Context → project overview
165
+ - Decision/Next Steps → initial tasks
166
+ - Status → project status
167
+
168
+ 3. **Create new project** via project skill:
169
+ - Generate PROJECT.md from brain doc content
170
+ - Create CHANGELOG.md with initial entry
171
+ - Place in projects directory
172
+
173
+ 4. **Update original brain doc:**
174
+ - Add `project: "[[{new-project}]]"` to frontmatter
175
+ - Update status to `done`
176
+ - Add note: "Promoted to project: [[{new-project}]]"
177
+
178
+ 5. **Handle the brain doc:**
179
+ - Option A: Keep as historical reference in `{resources_folder}/`
180
+ - Option B: Archive to `{archive_folder}/`
181
+ - Option C: Delete (content now lives in project)
182
+
183
+ ## Listing Docs
184
+
185
+ **Overrides:** brain's Listing workflow
186
+
187
+ Search in vault:
188
+ ```
189
+ Glob: {brain_dir}/**/*.md
190
+ ```
191
+
192
+ Filter to brain doc types by checking frontmatter for `type: plan|research|review|note`.
@@ -3,7 +3,7 @@ description: >-
3
3
  Enable inline conversations using @droid/@user markers. Tag @droid to ask the AI,
4
4
  AI responds with @{your-name}. Use /comments check to address markers, /comments cleanup
5
5
  to remove resolved threads. Ideal for code review notes and async collaboration.
6
- version: 0.2.0
6
+ version: 0.2.1
7
7
  status: beta
8
8
  dependencies: []
9
9
  provides_output: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orderful/droid",
3
- "version": "0.5.2",
3
+ "version": "0.7.0",
4
4
  "description": "AI workflow toolkit for sharing skills, commands, and agents across the team",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,7 @@ import { getBundledAgents, getBundledAgentsDir, isAgentInstalled, installAgent,
21
21
  import { configExists, loadConfig, saveConfig, loadSkillOverrides, saveSkillOverrides } from '../lib/config.js';
22
22
  import { configureAIToolPermissions } from './setup.js';
23
23
  import { AITool, BuiltInOutput, ConfigOptionType, type DroidConfig, type OutputPreference, type SkillManifest, type ConfigOption, type SkillOverrides } from '../lib/types.js';
24
- import { getVersion } from '../lib/version.js';
24
+ import { getVersion, getUpdateInfo, runUpdate, type UpdateInfo } from '../lib/version.js';
25
25
 
26
26
  type Tab = 'skills' | 'commands' | 'agents' | 'settings';
27
27
  type View = 'welcome' | 'setup' | 'menu' | 'detail' | 'configure' | 'readme';
@@ -133,20 +133,49 @@ function getOutputOptions(): Array<{ label: string; value: OutputPreference }> {
133
133
  return options;
134
134
  }
135
135
 
136
- function WelcomeScreen({ onContinue }: { onContinue: () => void }) {
136
+ interface WelcomeScreenProps {
137
+ onContinue: () => void;
138
+ onUpdate: () => void;
139
+ updateInfo: UpdateInfo;
140
+ isUpdating: boolean;
141
+ }
142
+
143
+ function WelcomeScreen({ onContinue, onUpdate, updateInfo, isUpdating }: WelcomeScreenProps) {
144
+ const [selectedButton, setSelectedButton] = useState(0);
145
+
137
146
  useInput((input, key) => {
138
- if (key.return || input === 'q') {
139
- onContinue();
147
+ if (isUpdating) return;
148
+
149
+ if (updateInfo.hasUpdate) {
150
+ if (key.leftArrow || key.rightArrow) {
151
+ setSelectedButton((prev) => (prev === 0 ? 1 : 0));
152
+ }
153
+ if (key.return) {
154
+ if (selectedButton === 0) {
155
+ onUpdate();
156
+ } else {
157
+ onContinue();
158
+ }
159
+ }
160
+ if (input === 'q') {
161
+ onContinue();
162
+ }
163
+ } else {
164
+ if (key.return || input === 'q') {
165
+ onContinue();
166
+ }
140
167
  }
141
168
  });
142
169
 
170
+ const hasUpdate = updateInfo.hasUpdate && updateInfo.latestVersion;
171
+
143
172
  return (
144
- <Box flexDirection="column" alignItems="center" justifyContent="center" height={16}>
173
+ <Box flexDirection="column" alignItems="center" justifyContent="center" height={18}>
145
174
  <Box
146
175
  flexDirection="column"
147
176
  alignItems="center"
148
177
  borderStyle="single"
149
- borderColor={colors.border}
178
+ borderColor={hasUpdate ? '#eab308' : colors.border}
150
179
  paddingX={4}
151
180
  paddingY={1}
152
181
  >
@@ -154,13 +183,13 @@ function WelcomeScreen({ onContinue }: { onContinue: () => void }) {
154
183
  <Text>
155
184
  <Text color={colors.textDim}>╔═════╗ </Text>
156
185
  <Text color={colors.text}>droid</Text>
157
- <Text color={colors.textDim}> v{getVersion()}</Text>
186
+ <Text color={colors.textDim}> v{updateInfo.currentVersion}</Text>
158
187
  </Text>
159
188
  <Text>
160
189
  <Text color={colors.textDim}>║ </Text>
161
- <Text color={colors.primary}>●</Text>
190
+ <Text color={hasUpdate ? '#eab308' : colors.primary}>●</Text>
162
191
  <Text color={colors.textDim}> </Text>
163
- <Text color={colors.primary}>●</Text>
192
+ <Text color={hasUpdate ? '#eab308' : colors.primary}>●</Text>
164
193
  <Text color={colors.textDim}> ║ </Text>
165
194
  <Text color={colors.textMuted}>Teaching your droid new tricks</Text>
166
195
  </Text>
@@ -170,13 +199,60 @@ function WelcomeScreen({ onContinue }: { onContinue: () => void }) {
170
199
  </Text>
171
200
  </Box>
172
201
 
173
- <Box marginTop={2} marginBottom={1}>
174
- <Text backgroundColor={colors.primary} color="#ffffff" bold>
175
- {' '}I'm probably the droid you are looking for.{' '}
176
- </Text>
177
- </Box>
202
+ {hasUpdate ? (
203
+ <>
204
+ <Box marginTop={2} marginBottom={1} flexDirection="column" alignItems="center">
205
+ <Text color="#eab308" italic>
206
+ "The odds of functioning optimally without this
207
+ </Text>
208
+ <Text color="#eab308" italic>
209
+ update are approximately 3,720 to 1."
210
+ </Text>
211
+ </Box>
212
+
213
+ <Box marginBottom={1}>
214
+ <Text color={colors.textMuted}>
215
+ v{updateInfo.currentVersion} → v{updateInfo.latestVersion}
216
+ </Text>
217
+ </Box>
178
218
 
179
- <Text color={colors.textDim}>press enter</Text>
219
+ {isUpdating ? (
220
+ <Text color="#eab308">Updating...</Text>
221
+ ) : (
222
+ <Box flexDirection="row">
223
+ <Text
224
+ backgroundColor={selectedButton === 0 ? '#eab308' : colors.bgSelected}
225
+ color={selectedButton === 0 ? '#000000' : colors.textMuted}
226
+ bold={selectedButton === 0}
227
+ >
228
+ {' '}Update{' '}
229
+ </Text>
230
+ <Text> </Text>
231
+ <Text
232
+ backgroundColor={selectedButton === 1 ? colors.bgSelected : undefined}
233
+ color={selectedButton === 1 ? colors.text : colors.textMuted}
234
+ bold={selectedButton === 1}
235
+ >
236
+ {' '}Skip for now{' '}
237
+ </Text>
238
+ </Box>
239
+ )}
240
+
241
+ <Box marginTop={1}>
242
+ <Text color={colors.textDim}>←→ select · enter</Text>
243
+ </Box>
244
+ </>
245
+ ) : (
246
+ <>
247
+ <Box marginTop={2} marginBottom={1}>
248
+ <Text backgroundColor={colors.primary} color="#ffffff" bold>
249
+ {' '}I'm probably the droid you are looking for.{' '}
250
+ </Text>
251
+ </Box>
252
+
253
+ <Text color={colors.textDim}>press enter</Text>
254
+ </>
255
+ )}
180
256
  </Box>
181
257
  </Box>
182
258
  );
@@ -1183,6 +1259,31 @@ function App() {
1183
1259
  const [message, setMessage] = useState<{ text: string; type: 'success' | 'error' } | null>(null);
1184
1260
  const [isEditingSettings, setIsEditingSettings] = useState(false);
1185
1261
  const [readmeContent, setReadmeContent] = useState<{ title: string; content: string } | null>(null);
1262
+ const [isUpdating, setIsUpdating] = useState(false);
1263
+
1264
+ // Check for updates once on mount
1265
+ const updateInfo = useMemo(() => getUpdateInfo(), []);
1266
+
1267
+ const handleUpdate = () => {
1268
+ setIsUpdating(true);
1269
+ // Run update in next tick to allow UI to show "Updating..."
1270
+ setTimeout(() => {
1271
+ const result = runUpdate();
1272
+ if (result.success) {
1273
+ // Exit and let user restart with new version
1274
+ exit();
1275
+ } else {
1276
+ setIsUpdating(false);
1277
+ setMessage({ text: result.message, type: 'error' });
1278
+ // Continue to menu on failure
1279
+ if (!configExists()) {
1280
+ setView('setup');
1281
+ } else {
1282
+ setView('menu');
1283
+ }
1284
+ }
1285
+ }, 100);
1286
+ };
1186
1287
 
1187
1288
  const MAX_VISIBLE_ITEMS = 6;
1188
1289
 
@@ -1424,6 +1525,9 @@ function App() {
1424
1525
  if (view === 'welcome') {
1425
1526
  return (
1426
1527
  <WelcomeScreen
1528
+ updateInfo={updateInfo}
1529
+ isUpdating={isUpdating}
1530
+ onUpdate={handleUpdate}
1427
1531
  onContinue={() => {
1428
1532
  // If no config exists, show setup first
1429
1533
  if (!configExists()) {
@@ -1498,6 +1602,7 @@ function App() {
1498
1602
  <Text color={colors.primary}>●</Text>
1499
1603
  <Text color={colors.textDim}>] </Text>
1500
1604
  <Text color={colors.textMuted}>droid</Text>
1605
+ <Text color={colors.textDim}> v{getVersion()}</Text>
1501
1606
  </Text>
1502
1607
  </Box>
1503
1608