@aiderdesk/aiderdesk 0.61.0 → 0.61.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/resources/skills/extension-creator/SKILL.md +320 -0
- package/out/resources/skills/extension-creator/assets/templates/Component.jsx.template +76 -0
- package/out/resources/skills/extension-creator/assets/templates/ConfigComponent.jsx.template +38 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension/config.ts.template +29 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension/index.ts.template +42 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension/package.json +12 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension/tsconfig.json +23 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension-with-config/index.ts.template +80 -0
- package/out/resources/skills/extension-creator/assets/templates/single-file.ts.template +30 -0
- package/out/resources/skills/extension-creator/assets/templates/ui-component-external.ts.template +91 -0
- package/out/resources/skills/extension-creator/assets/templates/ui-component.ts.template +79 -0
- package/out/resources/skills/extension-creator/references/command-definition.md +170 -0
- package/out/resources/skills/extension-creator/references/config-components.md +427 -0
- package/out/resources/skills/extension-creator/references/event-types.md +156 -0
- package/out/resources/skills/extension-creator/references/examples-gallery.md +583 -0
- package/out/resources/skills/extension-creator/references/extension-interface.md +240 -0
- package/out/resources/skills/extension-creator/references/extension-types.md +186 -0
- package/out/resources/skills/extension-creator/references/in-repo-flow.md +132 -0
- package/out/resources/skills/extension-creator/references/install-targets.md +96 -0
- package/out/resources/skills/extension-creator/references/project-global-flow.md +76 -0
- package/out/resources/skills/extension-creator/references/ui-components.md +663 -0
- package/package.json +1 -1
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Extension Interface
|
|
2
|
+
|
|
3
|
+
Full TypeScript interface for AiderDesk extensions.
|
|
4
|
+
|
|
5
|
+
## Extension Interface
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
interface Extension {
|
|
9
|
+
// Lifecycle
|
|
10
|
+
onLoad?(context: ExtensionContext): Promise<void> | void;
|
|
11
|
+
onUnload?(context: ExtensionContext): Promise<void> | void;
|
|
12
|
+
|
|
13
|
+
// Registration
|
|
14
|
+
getCommands?(context: ExtensionContext): CommandDefinition[];
|
|
15
|
+
getTools?(context: ExtensionContext, mode: string, agentProfile: AgentProfile): ToolDefinition[];
|
|
16
|
+
getAgents?(context: ExtensionContext): AgentProfile[];
|
|
17
|
+
getModes?(context: ExtensionContext): ModeDefinition[];
|
|
18
|
+
getUIComponents?(context: ExtensionContext): UIComponentDefinition[];
|
|
19
|
+
|
|
20
|
+
// UI Component support
|
|
21
|
+
getUIExtensionData?(componentId: string, context: ExtensionContext): Promise<unknown>;
|
|
22
|
+
executeUIExtensionAction?(componentId: string, action: string, args: unknown[], context: ExtensionContext): Promise<unknown>;
|
|
23
|
+
|
|
24
|
+
// Settings configuration (per-extension settings UI)
|
|
25
|
+
getConfigComponent?(context: ExtensionContext): string | undefined;
|
|
26
|
+
getConfigData?(context: ExtensionContext): Promise<unknown>;
|
|
27
|
+
saveConfigData?(configData: unknown, context: ExtensionContext): Promise<unknown>;
|
|
28
|
+
|
|
29
|
+
// Task Events
|
|
30
|
+
onTaskCreated?(event: TaskCreatedEvent, context: ExtensionContext): Promise<void | Partial<TaskCreatedEvent>>;
|
|
31
|
+
onTaskInitialized?(event: TaskInitializedEvent, context: ExtensionContext): Promise<void>;
|
|
32
|
+
onTaskClosed?(event: TaskClosedEvent, context: ExtensionContext): Promise<void>;
|
|
33
|
+
|
|
34
|
+
// Agent Events
|
|
35
|
+
onAgentStarted?(event: AgentStartedEvent, context: ExtensionContext): Promise<void | Partial<AgentStartedEvent>>;
|
|
36
|
+
onAgentFinished?(event: AgentFinishedEvent, context: ExtensionContext): Promise<void | Partial<AgentFinishedEvent>>;
|
|
37
|
+
onAgentStepFinished?(event: AgentStepFinishedEvent, context: ExtensionContext): Promise<void | Partial<AgentStepFinishedEvent>>;
|
|
38
|
+
onAgentProfileUpdated?(context: ExtensionContext, agentId: string, updatedProfile: AgentProfile): Promise<AgentProfile>;
|
|
39
|
+
|
|
40
|
+
// Tool Events
|
|
41
|
+
onToolApproval?(event: ToolApprovalEvent, context: ExtensionContext): Promise<void | Partial<ToolApprovalEvent>>;
|
|
42
|
+
onToolCalled?(event: ToolCalledEvent, context: ExtensionContext): Promise<void | Partial<ToolCalledEvent>>;
|
|
43
|
+
onToolFinished?(event: ToolFinishedEvent, context: ExtensionContext): Promise<void | Partial<ToolFinishedEvent>>;
|
|
44
|
+
|
|
45
|
+
// File Events
|
|
46
|
+
onFileAdded?(event: FileAddedEvent, context: ExtensionContext): Promise<void>;
|
|
47
|
+
onFileDropped?(event: FileDroppedEvent, context: ExtensionContext): Promise<void>;
|
|
48
|
+
|
|
49
|
+
// Prompt Events
|
|
50
|
+
onPromptSubmitted?(event: PromptSubmittedEvent, context: ExtensionContext): Promise<void | Partial<PromptSubmittedEvent>>;
|
|
51
|
+
onPromptStarted?(event: PromptStartedEvent, context: ExtensionContext): Promise<void>;
|
|
52
|
+
onPromptFinished?(event: PromptFinishedEvent, context: ExtensionContext): Promise<void>;
|
|
53
|
+
|
|
54
|
+
// Message Events
|
|
55
|
+
onResponseMessageProcessed?(event: ResponseMessageProcessedEvent, context: ExtensionContext): Promise<void | Partial<ResponseMessageProcessedEvent>>;
|
|
56
|
+
|
|
57
|
+
// Other Events
|
|
58
|
+
onProjectOpen?(context: ExtensionContext): Promise<void>;
|
|
59
|
+
onRuleFilesRetrieved?(context: ExtensionContext, ruleFiles: string[]): Promise<string[]>;
|
|
60
|
+
onSubagentStarted?(event: SubagentStartedEvent, context: ExtensionContext): Promise<void | Partial<SubagentStartedEvent>>;
|
|
61
|
+
onSubagentFinished?(event: SubagentFinishedEvent, context: ExtensionContext): Promise<void>;
|
|
62
|
+
onQuestionAsked?(event: QuestionAskedEvent, context: ExtensionContext): Promise<void>;
|
|
63
|
+
onQuestionAnswered?(event: QuestionAnsweredEvent, context: ExtensionContext): Promise<void>;
|
|
64
|
+
onCommandExecuted?(event: CommandExecutedEvent, context: ExtensionContext): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## ExtensionContext
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
interface ExtensionContext {
|
|
72
|
+
// Logging (backend/dev console only — NOT visible to users in chat UI)
|
|
73
|
+
log(message: string, type: 'info' | 'error' | 'warn' | 'debug'): void;
|
|
74
|
+
|
|
75
|
+
// Project access
|
|
76
|
+
getProjectDir(): string;
|
|
77
|
+
getTaskContext(): TaskContext | null;
|
|
78
|
+
getProjectContext(): ProjectContext;
|
|
79
|
+
|
|
80
|
+
// Settings
|
|
81
|
+
getSetting(key: string): Promise<unknown>;
|
|
82
|
+
updateSettings(updates: Record<string, unknown>): Promise<void>;
|
|
83
|
+
|
|
84
|
+
// Models
|
|
85
|
+
getModelConfigs(): Promise<Model[]>;
|
|
86
|
+
|
|
87
|
+
// UI updates
|
|
88
|
+
triggerUIDataRefresh(componentId?: string, taskId?: string): void;
|
|
89
|
+
triggerUIComponentsReload(): void;
|
|
90
|
+
|
|
91
|
+
// Navigation
|
|
92
|
+
openUrl(url: string, target?: 'external' | 'window' | 'modal-overlay'): Promise<void>;
|
|
93
|
+
openPath(path: string): Promise<boolean>;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## TaskContext
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
interface TaskContext {
|
|
101
|
+
// Logging to chat (visible to users in the task's chat UI)
|
|
102
|
+
addLogMessage(level: 'info' | 'error' | 'warning', message?: string): void;
|
|
103
|
+
addLoadingMessage(message?: string, finished?: boolean): void;
|
|
104
|
+
|
|
105
|
+
// Task operations
|
|
106
|
+
updateTask(updates: Partial<TaskData>): Promise<TaskData>;
|
|
107
|
+
runPrompt(prompt: string, mode?: string): Promise<void>;
|
|
108
|
+
runCustomCommand(name: string, args?: string[], mode?: string): Promise<void>;
|
|
109
|
+
runSubagent(agentProfile: AgentProfile, prompt: string): Promise<void>;
|
|
110
|
+
interruptResponse(): Promise<void>;
|
|
111
|
+
|
|
112
|
+
// File operations
|
|
113
|
+
getRepoMap(): string;
|
|
114
|
+
getContextFiles(): ContextFile[];
|
|
115
|
+
addContextFiles(files: ContextFile[]): Promise<void>;
|
|
116
|
+
|
|
117
|
+
// Questions
|
|
118
|
+
askQuestion(text: string, options?: QuestionOptions): Promise<string>;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## UIComponentDefinition
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
interface UIComponentDefinition {
|
|
126
|
+
/** Unique component identifier */
|
|
127
|
+
id: string;
|
|
128
|
+
|
|
129
|
+
/** Where in UI to render this component */
|
|
130
|
+
placement: UIComponentPlacement;
|
|
131
|
+
|
|
132
|
+
/** JSX/TSX component as string to be parsed */
|
|
133
|
+
jsx: string;
|
|
134
|
+
|
|
135
|
+
/** Optional flag to load data from extension (default: false) */
|
|
136
|
+
loadData?: boolean;
|
|
137
|
+
|
|
138
|
+
/** Optional flag to disable data caching (default: false) */
|
|
139
|
+
noDataCache?: boolean;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
type UIComponentPlacement =
|
|
143
|
+
| 'task-status-bar-left'
|
|
144
|
+
| 'task-status-bar-right'
|
|
145
|
+
| 'task-usage-info-bottom'
|
|
146
|
+
| 'task-messages-top'
|
|
147
|
+
| 'task-messages-bottom'
|
|
148
|
+
| 'task-input-above'
|
|
149
|
+
| 'task-input-toolbar-left'
|
|
150
|
+
| 'task-input-toolbar-right'
|
|
151
|
+
| 'tasks-sidebar-header'
|
|
152
|
+
| 'tasks-sidebar-bottom'
|
|
153
|
+
| 'task-message-above'
|
|
154
|
+
| 'task-message-below'
|
|
155
|
+
| 'task-message-bar'
|
|
156
|
+
| 'task-top-bar-left'
|
|
157
|
+
| 'task-top-bar-right'
|
|
158
|
+
| 'task-state-actions'
|
|
159
|
+
| 'task-state-actions-all'
|
|
160
|
+
| 'header-left'
|
|
161
|
+
| 'header-right'
|
|
162
|
+
| 'welcome-page';
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## UIComponentProps
|
|
166
|
+
|
|
167
|
+
Props available to UI components via the `data` prop (React is globally available, not a prop):
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
interface UIComponentProps {
|
|
171
|
+
// Context data
|
|
172
|
+
projectDir?: string;
|
|
173
|
+
task?: TaskData;
|
|
174
|
+
agentProfile?: AgentProfile;
|
|
175
|
+
models: Model[];
|
|
176
|
+
providers: ProviderProfile[];
|
|
177
|
+
|
|
178
|
+
// UI library
|
|
179
|
+
ui: UIComponents;
|
|
180
|
+
|
|
181
|
+
// Icons library (organized by icon set)
|
|
182
|
+
icons: Record<string, Record<string, IconComponent>>;
|
|
183
|
+
|
|
184
|
+
// Extension actions
|
|
185
|
+
executeExtensionAction: (action: string, ...args: unknown[]) => Promise<unknown>;
|
|
186
|
+
|
|
187
|
+
// Data from getUIExtensionData() (if loadData: true)
|
|
188
|
+
data?: unknown;
|
|
189
|
+
|
|
190
|
+
// Message-specific (for message placements)
|
|
191
|
+
message?: MessageData;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
interface UIComponents {
|
|
195
|
+
Button: Component;
|
|
196
|
+
Checkbox: Component;
|
|
197
|
+
Input: Component;
|
|
198
|
+
Select: Component;
|
|
199
|
+
TextArea: Component;
|
|
200
|
+
IconButton: Component;
|
|
201
|
+
RadioButton: Component;
|
|
202
|
+
MultiSelect: Component;
|
|
203
|
+
Slider: Component;
|
|
204
|
+
DatePicker: Component;
|
|
205
|
+
Chip: Component;
|
|
206
|
+
ModelSelector: Component;
|
|
207
|
+
Tooltip: Component;
|
|
208
|
+
LoadingOverlay: Component;
|
|
209
|
+
ConfirmDialog: Component;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Metadata
|
|
214
|
+
|
|
215
|
+
Metadata is defined as a **static property** on the extension class:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
export default class MyExtension implements Extension {
|
|
219
|
+
static metadata = {
|
|
220
|
+
name: 'My Extension',
|
|
221
|
+
version: '1.0.0',
|
|
222
|
+
description: 'What this extension does',
|
|
223
|
+
author: 'Author Name',
|
|
224
|
+
capabilities: ['events', 'commands'],
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Important:** Metadata must be a `static` property on the class. Do NOT use a separate `export const metadata = { ... }` — the extension loader reads it from `ExtensionClass.metadata`.
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
interface ExtensionMetadata {
|
|
233
|
+
name: string;
|
|
234
|
+
version: string;
|
|
235
|
+
description?: string;
|
|
236
|
+
author?: string;
|
|
237
|
+
capabilities?: string[];
|
|
238
|
+
iconUrl?: string;
|
|
239
|
+
}
|
|
240
|
+
```
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Extension Types
|
|
2
|
+
|
|
3
|
+
AiderDesk supports two types of extensions: single-file and folder extensions.
|
|
4
|
+
|
|
5
|
+
## Single-File Extensions
|
|
6
|
+
|
|
7
|
+
**When to use:** Simple extensions with no npm dependencies
|
|
8
|
+
|
|
9
|
+
**Location:** `packages/extensions/extensions/my-extension.ts`
|
|
10
|
+
|
|
11
|
+
**Structure:**
|
|
12
|
+
```typescript
|
|
13
|
+
import type { Extension, ExtensionContext } from '@aiderdesk/extensions';
|
|
14
|
+
|
|
15
|
+
export default class MyExtension implements Extension {
|
|
16
|
+
static metadata = {
|
|
17
|
+
name: 'My Extension',
|
|
18
|
+
version: '1.0.0',
|
|
19
|
+
description: 'What this extension does',
|
|
20
|
+
author: 'Author Name',
|
|
21
|
+
capabilities: ['events', 'commands'],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
async onLoad(context: ExtensionContext): Promise<void> {
|
|
25
|
+
context.log('Extension loaded', 'info');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Advantages:**
|
|
31
|
+
- Simple structure
|
|
32
|
+
- Easy to maintain
|
|
33
|
+
- No build step required
|
|
34
|
+
|
|
35
|
+
**Limitations:**
|
|
36
|
+
- Cannot use npm dependencies
|
|
37
|
+
- All code in one file
|
|
38
|
+
- No separate config or logger files
|
|
39
|
+
|
|
40
|
+
## Folder Extensions
|
|
41
|
+
|
|
42
|
+
**When to use:** Complex extensions with npm dependencies or multiple files
|
|
43
|
+
|
|
44
|
+
**Location:** `packages/extensions/extensions/my-extension/`
|
|
45
|
+
|
|
46
|
+
**Structure:**
|
|
47
|
+
```
|
|
48
|
+
packages/extensions/extensions/my-extension/
|
|
49
|
+
├── index.ts # Main extension file (implements Extension)
|
|
50
|
+
├── package.json # npm dependencies
|
|
51
|
+
├── tsconfig.json # TypeScript config (module: ES2020+)
|
|
52
|
+
├── README.md # Documentation
|
|
53
|
+
├── config.ts # Optional: persistent config storage
|
|
54
|
+
├── logger.ts # Optional: local logger
|
|
55
|
+
├── constants.ts # Optional: extension constants
|
|
56
|
+
└── resources/ # Optional: WASM, queries, assets
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**package.json:**
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"name": "my-extension",
|
|
63
|
+
"version": "1.0.0",
|
|
64
|
+
"main": "index.ts",
|
|
65
|
+
"dependencies": {
|
|
66
|
+
// Required packages
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**tsconfig.json:**
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"compilerOptions": {
|
|
75
|
+
"target": "ES2020",
|
|
76
|
+
"module": "ES2020",
|
|
77
|
+
"moduleResolution": "node",
|
|
78
|
+
"esModuleInterop": true,
|
|
79
|
+
"strict": true
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Advantages:**
|
|
85
|
+
- Can use npm dependencies
|
|
86
|
+
- Modular structure
|
|
87
|
+
- Separate config and logger files
|
|
88
|
+
- Can include resources (WASM, queries, assets)
|
|
89
|
+
|
|
90
|
+
**Requirements:**
|
|
91
|
+
- Must have package.json
|
|
92
|
+
- Must have tsconfig.json with ES2020+ module
|
|
93
|
+
- Must set `hasDependencies: true` in extensions.json
|
|
94
|
+
|
|
95
|
+
## Choosing Extension Type
|
|
96
|
+
|
|
97
|
+
**When:** Extension needs npm packages
|
|
98
|
+
|
|
99
|
+
**Then:** Use folder extension
|
|
100
|
+
|
|
101
|
+
**When:** Extension is simple with no dependencies
|
|
102
|
+
|
|
103
|
+
**Then:** Use single-file extension
|
|
104
|
+
|
|
105
|
+
**When:** Extension needs multiple files
|
|
106
|
+
|
|
107
|
+
**Then:** Use folder extension
|
|
108
|
+
|
|
109
|
+
**When:** Extension needs resources (WASM, queries)
|
|
110
|
+
|
|
111
|
+
**Then:** Use folder extension
|
|
112
|
+
|
|
113
|
+
## Common Patterns by Type
|
|
114
|
+
|
|
115
|
+
### Single-File: Simple Event Handler
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import type { Extension, ExtensionContext, AgentStartedEvent } from '@aiderdesk/extensions';
|
|
119
|
+
|
|
120
|
+
export default class SimpleExtension implements Extension {
|
|
121
|
+
static metadata = {
|
|
122
|
+
name: 'Simple Extension',
|
|
123
|
+
version: '1.0.0',
|
|
124
|
+
description: 'Simple event handler',
|
|
125
|
+
author: 'Author Name',
|
|
126
|
+
capabilities: ['events'],
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
async onLoad(context: ExtensionContext): Promise<void> {
|
|
130
|
+
context.log('Simple extension loaded', 'info');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async onAgentStarted(
|
|
134
|
+
event: AgentStartedEvent,
|
|
135
|
+
context: ExtensionContext
|
|
136
|
+
): Promise<void | Partial<AgentStartedEvent>> {
|
|
137
|
+
context.log('Agent started', 'info');
|
|
138
|
+
return { contextMessages: [...event.contextMessages] };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Folder: Extension with Config and Dependencies
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
tree-sitter-repo-map/
|
|
147
|
+
├── index.ts # Main extension with getTools()
|
|
148
|
+
├── package.json # tree-sitter dependencies
|
|
149
|
+
├── tsconfig.json # ES2020 module
|
|
150
|
+
├── config.ts # Config storage
|
|
151
|
+
├── logger.ts # Extension logger
|
|
152
|
+
├── constants.ts # Extension constants
|
|
153
|
+
└── resources/
|
|
154
|
+
└── queries/ # Language queries
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Updating extensions.json
|
|
158
|
+
|
|
159
|
+
### Single-File Entry
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"id": "my-extension",
|
|
164
|
+
"name": "My Extension",
|
|
165
|
+
"description": "Description of what it does",
|
|
166
|
+
"file": "extensions/my-extension.ts",
|
|
167
|
+
"type": "single",
|
|
168
|
+
"capabilities": ["onLoad", "onAgentStarted"]
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Folder Entry
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"id": "my-extension",
|
|
177
|
+
"name": "My Extension",
|
|
178
|
+
"description": "Description",
|
|
179
|
+
"folder": "extensions/my-extension",
|
|
180
|
+
"type": "folder",
|
|
181
|
+
"hasDependencies": true,
|
|
182
|
+
"capabilities": ["onLoad", "getCommands", "onAgentStarted"]
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Note:** Always set `hasDependencies: true` for folder extensions, even if they don't have dependencies yet. This ensures proper loading.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# In-Repo Installation Flow
|
|
2
|
+
|
|
3
|
+
This flow covers developing extensions **inside the AiderDesk codebase** at `packages/extensions/extensions/`. These extensions ship with the application and are available to all users by default.
|
|
4
|
+
|
|
5
|
+
## When to Use This Flow
|
|
6
|
+
|
|
7
|
+
Only when:
|
|
8
|
+
1. The current working project **is** the AiderDesk repository itself
|
|
9
|
+
2. The user explicitly chooses "In-Repo" as the installation target
|
|
10
|
+
3. The extension is meant to be a built-in feature, not a personal or project-specific tool
|
|
11
|
+
|
|
12
|
+
## Process
|
|
13
|
+
|
|
14
|
+
1. **Determine extension type** — single-file or folder
|
|
15
|
+
2. **Create extension file(s)** in `packages/extensions/extensions/`
|
|
16
|
+
3. **Implement Extension interface methods**
|
|
17
|
+
4. **Export metadata and default class**
|
|
18
|
+
5. **Update `packages/extensions/extensions.json`** — register the extension
|
|
19
|
+
6. **Update `docs-site/docs/extensions/examples.md`** — document it
|
|
20
|
+
7. **Verify with type checking and code-checker**
|
|
21
|
+
|
|
22
|
+
## Directory Structure
|
|
23
|
+
|
|
24
|
+
### Single-File In-Repo Extension
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
packages/extensions/extensions/
|
|
28
|
+
└── my-extension.ts # Everything in one file
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Folder In-Repo Extension
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
packages/extensions/extensions/
|
|
35
|
+
└── my-extension/
|
|
36
|
+
├── index.ts # Main extension file
|
|
37
|
+
├── package.json # npm dependencies (must run npm install)
|
|
38
|
+
├── tsconfig.json # TypeScript config (module: ES2020+)
|
|
39
|
+
├── README.md # Documentation
|
|
40
|
+
├── config.ts # Optional: persistent config storage
|
|
41
|
+
├── logger.ts # Optional: local logger
|
|
42
|
+
├── constants.ts # Optional: extension constants
|
|
43
|
+
└── resources/ # Optional: WASM, queries, assets
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Step-by-Step
|
|
47
|
+
|
|
48
|
+
### Step 1: Determine type
|
|
49
|
+
|
|
50
|
+
- **Single-file**: No npm dependencies, simple logic
|
|
51
|
+
- **Folder**: Needs npm packages, multiple files, resources
|
|
52
|
+
|
|
53
|
+
### Step 2: Create the extension
|
|
54
|
+
|
|
55
|
+
Use the templates:
|
|
56
|
+
- [single-file.ts.template](../assets/templates/single-file.ts.template)
|
|
57
|
+
- [folder-extension/](../assets/templates/folder-extension/)
|
|
58
|
+
- [folder-extension-with-config/index.ts.template](../assets/templates/folder-extension-with-config/index.ts.template)
|
|
59
|
+
|
|
60
|
+
Create files in `packages/extensions/extensions/{name}/` or `packages/extensions/extensions/{name}.ts`.
|
|
61
|
+
|
|
62
|
+
### Step 3: Implement interface
|
|
63
|
+
|
|
64
|
+
Same as any extension — implement required methods, export metadata and class.
|
|
65
|
+
|
|
66
|
+
Reference: [extension-interface.md](extension-interface.md)
|
|
67
|
+
|
|
68
|
+
### Step 4: Register in extensions.json
|
|
69
|
+
|
|
70
|
+
**This step is unique to In-Repo extensions.**
|
|
71
|
+
|
|
72
|
+
Add an entry to `packages/extensions/extensions.json`:
|
|
73
|
+
|
|
74
|
+
**Single-file entry:**
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"id": "my-extension",
|
|
78
|
+
"name": "My Extension",
|
|
79
|
+
"description": "Description of what it does",
|
|
80
|
+
"file": "extensions/my-extension.ts",
|
|
81
|
+
"type": "single",
|
|
82
|
+
"capabilities": ["onLoad", "onAgentStarted"]
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Folder entry:**
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"id": "my-extension",
|
|
90
|
+
"name": "My Extension",
|
|
91
|
+
"description": "Description",
|
|
92
|
+
"folder": "extensions/my-extension",
|
|
93
|
+
"type": "folder",
|
|
94
|
+
"hasDependencies": true,
|
|
95
|
+
"capabilities": ["onLoad", "getCommands", "onAgentStarted"]
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Important:** Always set `hasDependencies: true` for folder extensions, even if they don't have dependencies yet.
|
|
100
|
+
|
|
101
|
+
### Step 5: Document in examples.md
|
|
102
|
+
|
|
103
|
+
Add an entry to the table in `docs-site/docs/extensions/examples.md`:
|
|
104
|
+
|
|
105
|
+
| Extension | Description | Capabilities | Type |
|
|
106
|
+
|-----------|-------------|-------------|------|
|
|
107
|
+
| My Extension | What it does | events, commands | folder |
|
|
108
|
+
|
|
109
|
+
Include extension name, description, capabilities, and type.
|
|
110
|
+
|
|
111
|
+
### Step 6: Install dependencies (folder extensions only)
|
|
112
|
+
|
|
113
|
+
If this is a folder extension with npm dependencies:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
cd packages/extensions
|
|
117
|
+
npm install
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Step 7: Verify
|
|
121
|
+
|
|
122
|
+
- Run type checking: `npm run typecheck`
|
|
123
|
+
- Run tests if applicable: `npm run test`
|
|
124
|
+
- Verify extension loads without errors
|
|
125
|
+
- Check that extension appears in extensions list
|
|
126
|
+
|
|
127
|
+
## What NOT to do (In-Repo)
|
|
128
|
+
|
|
129
|
+
- Do NOT use `@/` imports in extension files — use relative imports or `@aiderdesk/extensions` package imports only
|
|
130
|
+
- Do NOT forget to update `extensions.json` — the extension won't load without registration
|
|
131
|
+
- Do NOT forget to update `examples.md` — users won't know about the extension
|
|
132
|
+
- Do NOT place files outside `packages/extensions/extensions/` unless there's a specific reason (e.g., shared utilities should go in `packages/extensions/src/`)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Installation Targets
|
|
2
|
+
|
|
3
|
+
AiderDesk extensions can be installed in three locations, each with different purposes and workflows.
|
|
4
|
+
|
|
5
|
+
## Target Options
|
|
6
|
+
|
|
7
|
+
### 1. Current Project (`.aider-desk/extensions/`)
|
|
8
|
+
|
|
9
|
+
**Use when:** The extension is specific to this project and should travel with the codebase.
|
|
10
|
+
|
|
11
|
+
**Location:** `{projectDir}/.aider-desk/extensions/`
|
|
12
|
+
|
|
13
|
+
**Characteristics:**
|
|
14
|
+
- Project-scoped: only available when working in this project
|
|
15
|
+
- Committed to version control alongside the project
|
|
16
|
+
- Shared with team members via git
|
|
17
|
+
- No need to update any registry or manifest files
|
|
18
|
+
- Simple drop-in: just create the file/folder in the directory
|
|
19
|
+
|
|
20
|
+
**Best for:** Project-specific tools, domain-specific rules, team conventions, repo-specific integrations.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
### 2. Global (`~/.aider-desk/extensions/`)
|
|
25
|
+
|
|
26
|
+
**Use when:** The extension is a personal utility you want available across all projects.
|
|
27
|
+
|
|
28
|
+
**Location:** `~/.aider-desk/extensions/`
|
|
29
|
+
|
|
30
|
+
**Characteristics:**
|
|
31
|
+
- User-scoped: available in every project you work on
|
|
32
|
+
- Not committed to any repository (lives in home directory)
|
|
33
|
+
- Private to your environment
|
|
34
|
+
- No need to update any registry or manifest files
|
|
35
|
+
- Simple drop-in: just create the file/folder in the directory
|
|
36
|
+
|
|
37
|
+
**Best for:** Personal productivity tools, custom commands, cross-project utilities, personal preferences.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### 3. In-Repo (`packages/extensions/`) — **Only when working inside the AiderDesk project**
|
|
42
|
+
|
|
43
|
+
**Use when:** You are developing an extension that ships *with* AiderDesk itself, as part of the application.
|
|
44
|
+
|
|
45
|
+
**Location:** `packages/extensions/extensions/{name}/` or `packages/extensions/extensions/{name}.ts`
|
|
46
|
+
|
|
47
|
+
**Characteristics:**
|
|
48
|
+
- Ships with the AiderDesk application as a built-in extension
|
|
49
|
+
- Available to all users by default
|
|
50
|
+
- Requires updating `packages/extensions/extensions.json` (the extension registry)
|
|
51
|
+
- Requires updating documentation in `docs-site/docs/extensions/examples.md`
|
|
52
|
+
- Must follow monorepo conventions (no `@/` imports, proper tsconfig/package.json)
|
|
53
|
+
- Subject to the full AiderDesk development workflow (type checking, testing, etc.)
|
|
54
|
+
|
|
55
|
+
**Best for:** Core features, official integrations, extensions that should be available out-of-the-box.
|
|
56
|
+
|
|
57
|
+
## How to Choose
|
|
58
|
+
|
|
59
|
+
Ask the user at the start of every extension creation session:
|
|
60
|
+
|
|
61
|
+
> "Where should this extension be installed? **Current project** (project-scoped, shared with team), **Global** (personal, available everywhere), or **In-Repo** (ships with AiderDesk, only available when working in the aider-desk project)?"
|
|
62
|
+
|
|
63
|
+
**Decision tree:**
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
Is the current project the AiderDesk codebase itself?
|
|
67
|
+
├── YES → Offer all 3 options (Project, Global, In-Repo)
|
|
68
|
+
│ In-Repo means: packages/extensions/ + update extensions.json + update docs
|
|
69
|
+
│
|
|
70
|
+
└── NO → Offer only 2 options (Project, Global)
|
|
71
|
+
Project = .aider-desk/extensions/ in current project
|
|
72
|
+
Global = ~/.aider-desk/extensions/
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Key Differences Summary
|
|
76
|
+
|
|
77
|
+
| Aspect | Project | Global | In-Repo |
|
|
78
|
+
|--------|---------|--------|---------|
|
|
79
|
+
| Location | `.aider-desk/extensions/` | `~/.aider-desk/extensions/` | `packages/extensions/extensions/` |
|
|
80
|
+
| Scope | This project only | All projects | All users (ships with app) |
|
|
81
|
+
| Version controlled | Yes (with project) | No | Yes (with AiderDesk) |
|
|
82
|
+
| Update extensions.json | No | No | **Yes** |
|
|
83
|
+
| Update examples.md docs | No | No | **Yes** |
|
|
84
|
+
| npm install needed | No | No | **Yes** (if folder extension) |
|
|
85
|
+
| Available immediately | Yes | Yes | After build/restart |
|
|
86
|
+
|
|
87
|
+
## Shared Rules (All Targets)
|
|
88
|
+
|
|
89
|
+
Regardless of target, these rules always apply:
|
|
90
|
+
|
|
91
|
+
- Implement the `Extension` interface correctly
|
|
92
|
+
- Export `metadata` object with name, version, description, author, capabilities
|
|
93
|
+
- Export class as `default`
|
|
94
|
+
- Never use `@/` imports in extension files
|
|
95
|
+
- Store config files inside the extension directory
|
|
96
|
+
- Use proper TypeScript (ES2020+ modules for folder extensions)
|