@aiderdesk/aiderdesk 0.61.0-dev → 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.
Files changed (196) hide show
  1. package/out/renderer/assets/__vite-browser-external-2447137e-DYxpcVy9.js +4 -0
  2. package/out/renderer/assets/{_baseUniq-Z8t1Ab1g.js → _baseUniq-BPF2Herp.js} +21 -197
  3. package/out/renderer/assets/{arc-CwESpVYE.js → arc-DfPLteHF.js} +1 -1
  4. package/out/renderer/assets/{architectureDiagram-2XIMDMQ5-C490EQr5.js → architectureDiagram-Q4EWVU46-Bw0u-sSH.js} +34 -20
  5. package/out/renderer/assets/{blockDiagram-WCTKOSBZ-DbHssxrQ.js → blockDiagram-DXYQGD6D-CkfB9if8.js} +21 -8
  6. package/out/renderer/assets/{c4Diagram-IC4MRINW-BxE3GUKu.js → c4Diagram-AHTNJAMY-DweK9Liz.js} +31 -35
  7. package/out/renderer/assets/{channel-C9hJq_Xr.js → channel-C5wwrRof.js} +1 -1
  8. package/out/renderer/assets/{chunk-4BX2VUAB-ChcKNpL6.js → chunk-4BX2VUAB-0KM14cFd.js} +1 -1
  9. package/out/renderer/assets/{chunk-WL4C6EOR-vhby2fZi.js → chunk-4TB4RGXK-CmVtCVL4.js} +121 -82
  10. package/out/renderer/assets/{chunk-55IACEB6-oLT9lXTt.js → chunk-55IACEB6-BzVYZvBM.js} +1 -1
  11. package/out/renderer/assets/{chunk-KX2RTZJC-D32tV7H-.js → chunk-EDXVE4YY-BryQl5Kv.js} +1 -1
  12. package/out/renderer/assets/{chunk-FMBD7UC4-B5k8rETe.js → chunk-FMBD7UC4-CRiLea_e.js} +1 -1
  13. package/out/renderer/assets/{chunk-NQ4KR5QH-Bmqo2FpL.js → chunk-OYMX7WX6-Cpi4N3NO.js} +32 -15
  14. package/out/renderer/assets/{chunk-QZHKN3VN-8BpGifjS.js → chunk-QZHKN3VN-BT8kABWC.js} +1 -1
  15. package/out/renderer/assets/{chunk-JSJVCQXG-DtjSx6Cj.js → chunk-YZCP3GAM-OLZV_Sef.js} +1 -1
  16. package/out/renderer/assets/{classDiagram-VBA2DB6C-BxRSSb9e.js → classDiagram-6PBFFD2Q-VdE6G90i.js} +6 -6
  17. package/out/renderer/assets/{classDiagram-v2-RAHNMMFH-BxRSSb9e.js → classDiagram-v2-HSJHXN6E-VdE6G90i.js} +6 -6
  18. package/out/renderer/assets/{clone-D9a-uIZa.js → clone-DwQZ86nS.js} +1 -1
  19. package/out/renderer/assets/{cose-bilkent-S5V4N54A-CUqqQ-6R.js → cose-bilkent-S5V4N54A-BEcAKM9H.js} +1 -1
  20. package/out/renderer/assets/{dagre-KLK3FWXG-ORIwMMhq.js → dagre-KV5264BT-BcFQYL1M.js} +6 -6
  21. package/out/renderer/assets/diagram-5BDNPKRD-GrUNdC1u.js +171 -0
  22. package/out/renderer/assets/{diagram-E7M64L7V-bS9HcoDQ.js → diagram-G4DWMVQ6-CG4S-ov5.js} +15 -13
  23. package/out/renderer/assets/{diagram-IFDJBPK2-BRlTIR0J.js → diagram-MMDJMWI5-9ogY3MRC.js} +5 -6
  24. package/out/renderer/assets/{diagram-P4PSJMXO-jsjGwH-p.js → diagram-TYMM5635-Ck7mI1bS.js} +5 -6
  25. package/out/renderer/assets/{erDiagram-INFDFZHY-DGlgjHOQ.js → erDiagram-SMLLAGMA-Dvf_c-7M.js} +81 -35
  26. package/out/renderer/assets/{flowDiagram-PKNHOUZH-CzLC87bM.js → flowDiagram-DWJPFMVM-CPDjOXYp.js} +27 -45
  27. package/out/renderer/assets/{ganttDiagram-A5KZAMGK-BbDv36wT.js → ganttDiagram-T4ZO3ILL-B4dJrK-3.js} +17 -8
  28. package/out/renderer/assets/{gitGraphDiagram-K3NZZRJ6-CBQnBjEi.js → gitGraphDiagram-UUTBAWPF-De2eCfMN.js} +244 -67
  29. package/out/renderer/assets/{graph-Dl5N6maZ.js → graph-BFn23kR_.js} +175 -3
  30. package/out/renderer/assets/{index-MDHavDF9.js → index-BL-57WPa.js} +15877 -20787
  31. package/out/renderer/assets/{index-CDCy_DhA.css → index-BkntVzTm.css} +114 -301
  32. package/out/renderer/assets/{infoDiagram-LFFYTUFH-GtEDBEmz.js → infoDiagram-42DDH7IO-BIt9B6mQ.js} +5 -6
  33. package/out/renderer/assets/{ishikawaDiagram-PHBUUO56-Uj90gr3I.js → ishikawaDiagram-UXIWVN3A-CXZs0KGV.js} +3 -3
  34. package/out/renderer/assets/{journeyDiagram-4ABVD52K-DekFuOwS.js → journeyDiagram-VCZTEJTY-B-EXuj5b.js} +14 -13
  35. package/out/renderer/assets/{kanban-definition-K7BYSVSG-Hfz2L6NS.js → kanban-definition-6JOO6SKY-ByvN0qaD.js} +5 -2
  36. package/out/renderer/assets/{layout-B9K2VT39.js → layout-BpybWUv6.js} +117 -4
  37. package/out/renderer/assets/min-DB8ixvoT.js +41 -0
  38. package/out/renderer/assets/{mindmap-definition-YRQLILUH-DDcS7_GH.js → mindmap-definition-QFDTVHPH-Do-I-At8.js} +69 -13
  39. package/out/renderer/assets/{pieDiagram-SKSYHLDU-DwjEcJ0Q.js → pieDiagram-DEJITSTG-Cnpf6Gt6.js} +20 -13
  40. package/out/renderer/assets/{quadrantDiagram-337W2JSQ-CpGqN7vo.js → quadrantDiagram-34T5L4WZ-VcOb1qLd.js} +1 -1
  41. package/out/renderer/assets/{requirementDiagram-Z7DCOOCP-qDRUf1ip.js → requirementDiagram-MS252O5E-VJs9Hpaw.js} +42 -11
  42. package/out/renderer/assets/{sankeyDiagram-WA2Y5GQK-DRKS8C1H.js → sankeyDiagram-XADWPNL6-BoXxgLvi.js} +1 -1
  43. package/out/renderer/assets/{sequenceDiagram-2WXFIKYE-DhVN2ug2.js → sequenceDiagram-FGHM5R23-b69hQjSp.js} +446 -220
  44. package/out/renderer/assets/{stateDiagram-RAJIS63D-BpP4eSqu.js → stateDiagram-FHFEXIEX-BK7E-REm.js} +10 -9
  45. package/out/renderer/assets/{stateDiagram-v2-FVOUBMTO-B_qQJqra.js → stateDiagram-v2-QKLJ7IA2-Cd2wfCQu.js} +4 -4
  46. package/out/renderer/assets/{timeline-definition-YZTLITO2-UoWXE_76.js → timeline-definition-GMOUNBTQ-Bl-MTfK5.js} +445 -71
  47. package/out/renderer/assets/{vennDiagram-LZ73GAT5-Dp1FZ609.js → vennDiagram-DHZGUBPP-DNmr1k2L.js} +1 -1
  48. package/out/renderer/assets/{treemap-KZPCXAKY-W2a2L6ff.js → wardley-RL74JXVD-DTbxPMj9.js} +1474 -977
  49. package/out/renderer/assets/wardleyDiagram-NUSXRM2D-BWw08wtD.js +901 -0
  50. package/out/renderer/assets/{xychartDiagram-JWTSCODW-CTzYHTbD.js → xychartDiagram-5P7HB3ND-EEYPnLDT.js} +20 -4
  51. package/out/renderer/index.html +3 -3
  52. package/out/renderer/progress.html +212 -62
  53. package/out/resources/mcp-server/aider-desk-mcp-server.js +642 -402
  54. package/out/resources/skills/extension-creator/SKILL.md +320 -0
  55. package/out/resources/skills/extension-creator/assets/templates/Component.jsx.template +76 -0
  56. package/out/resources/skills/extension-creator/assets/templates/ConfigComponent.jsx.template +38 -0
  57. package/out/resources/skills/extension-creator/assets/templates/folder-extension/config.ts.template +29 -0
  58. package/out/resources/skills/extension-creator/assets/templates/folder-extension/index.ts.template +42 -0
  59. package/out/resources/skills/extension-creator/assets/templates/folder-extension/package.json +12 -0
  60. package/out/resources/skills/extension-creator/assets/templates/folder-extension/tsconfig.json +23 -0
  61. package/out/resources/skills/extension-creator/assets/templates/folder-extension-with-config/index.ts.template +80 -0
  62. package/out/resources/skills/extension-creator/assets/templates/single-file.ts.template +30 -0
  63. package/out/resources/skills/extension-creator/assets/templates/ui-component-external.ts.template +91 -0
  64. package/out/resources/skills/extension-creator/assets/templates/ui-component.ts.template +79 -0
  65. package/out/resources/skills/extension-creator/references/command-definition.md +170 -0
  66. package/out/resources/skills/extension-creator/references/config-components.md +427 -0
  67. package/out/resources/skills/extension-creator/references/event-types.md +156 -0
  68. package/out/resources/skills/extension-creator/references/examples-gallery.md +583 -0
  69. package/out/resources/skills/extension-creator/references/extension-interface.md +240 -0
  70. package/out/resources/skills/extension-creator/references/extension-types.md +186 -0
  71. package/out/resources/skills/extension-creator/references/in-repo-flow.md +132 -0
  72. package/out/resources/skills/extension-creator/references/install-targets.md +96 -0
  73. package/out/resources/skills/extension-creator/references/project-global-flow.md +76 -0
  74. package/out/resources/skills/extension-creator/references/ui-components.md +663 -0
  75. package/out/runner.js +976 -386
  76. package/package.json +2 -3
  77. package/out/renderer/assets/_basePickBy-BWoXHZ8Z.js +0 -161
  78. package/out/renderer/assets/apl-fqmucPXA.js +0 -140
  79. package/out/renderer/assets/asciiarmor-DucZyvP0.js +0 -56
  80. package/out/renderer/assets/asn1-BnOEsgAm.js +0 -144
  81. package/out/renderer/assets/asterisk-QAlztEwS.js +0 -345
  82. package/out/renderer/assets/brainfuck-DZVCuF_t.js +0 -53
  83. package/out/renderer/assets/clike-xqXYL6ge.js +0 -805
  84. package/out/renderer/assets/clojure-BhXMqnxz.js +0 -849
  85. package/out/renderer/assets/cmake-BGaNd9E7.js +0 -71
  86. package/out/renderer/assets/cobol-4yqQntpt.js +0 -120
  87. package/out/renderer/assets/coffeescript-D2dXvhEc.js +0 -308
  88. package/out/renderer/assets/commonlisp-CF_VNHQR.js +0 -130
  89. package/out/renderer/assets/crystal-DyuLTqLs.js +0 -398
  90. package/out/renderer/assets/css-c-jst79C.js +0 -1783
  91. package/out/renderer/assets/cypher-Dlu_3r4V.js +0 -121
  92. package/out/renderer/assets/d-UURgV0Ux.js +0 -179
  93. package/out/renderer/assets/diff-B_Bi2Crb.js +0 -25
  94. package/out/renderer/assets/dockerfile-Bvk733Ga.js +0 -201
  95. package/out/renderer/assets/dtd-Dy74G54E.js +0 -114
  96. package/out/renderer/assets/dylan-TSb-Nfix.js +0 -314
  97. package/out/renderer/assets/ebnf-4fKAGW3a.js +0 -140
  98. package/out/renderer/assets/ecl-B59qGGVg.js +0 -178
  99. package/out/renderer/assets/eiffel-Dze7nlu3.js +0 -134
  100. package/out/renderer/assets/elm-DG7jkhNZ.js +0 -176
  101. package/out/renderer/assets/erlang-BO6gOnGA.js +0 -674
  102. package/out/renderer/assets/factor-CMxFHDqz.js +0 -65
  103. package/out/renderer/assets/fcl-CDDUNjTj.js +0 -141
  104. package/out/renderer/assets/forth-B9D2JCeE.js +0 -116
  105. package/out/renderer/assets/fortran-CAG2BFbe.js +0 -467
  106. package/out/renderer/assets/gas-d3KEcW3x.js +0 -294
  107. package/out/renderer/assets/gherkin-DhZlEZiy.js +0 -115
  108. package/out/renderer/assets/groovy-CpwJiBl7.js +0 -223
  109. package/out/renderer/assets/haskell-ySd-OUo8.js +0 -459
  110. package/out/renderer/assets/haxe-7MlzfeYV.js +0 -514
  111. package/out/renderer/assets/http-BqypyemW.js +0 -79
  112. package/out/renderer/assets/idl-4HIGJlDI.js +0 -985
  113. package/out/renderer/assets/index-6qedlt0q.js +0 -689
  114. package/out/renderer/assets/index-86jDpUJn.js +0 -385
  115. package/out/renderer/assets/index-BRjO8ber.js +0 -332
  116. package/out/renderer/assets/index-BVgw7j0d.js +0 -312
  117. package/out/renderer/assets/index-BhkyI1q3.js +0 -642
  118. package/out/renderer/assets/index-BqrmLPkg.js +0 -82
  119. package/out/renderer/assets/index-BuPbw4xM.js +0 -178
  120. package/out/renderer/assets/index-CTO-LPBg.js +0 -311
  121. package/out/renderer/assets/index-CTO4SzlI.js +0 -97
  122. package/out/renderer/assets/index-CZ9IQK_0.js +0 -2488
  123. package/out/renderer/assets/index-CZxsVxBZ.js +0 -1765
  124. package/out/renderer/assets/index-DIXV-3Xn.js +0 -406
  125. package/out/renderer/assets/index-DNzOtZX5.js +0 -61
  126. package/out/renderer/assets/index-DZtJe7oC.js +0 -1019
  127. package/out/renderer/assets/index-DaWjZz_g.js +0 -291
  128. package/out/renderer/assets/index-De056HHR.js +0 -151
  129. package/out/renderer/assets/index-Dk3wSDSN.js +0 -117
  130. package/out/renderer/assets/index-Dy4VRsnA.js +0 -1041
  131. package/out/renderer/assets/index-FnnayPBc.js +0 -82
  132. package/out/renderer/assets/index-MZb_zy6R.js +0 -704
  133. package/out/renderer/assets/index-chzQl8rJ.js +0 -157
  134. package/out/renderer/assets/index-s-Owx3Pm.js +0 -327
  135. package/out/renderer/assets/javascript-C_OHM9hj.js +0 -994
  136. package/out/renderer/assets/julia-Bs6JJhYG.js +0 -407
  137. package/out/renderer/assets/livescript-DmzgM3Yt.js +0 -296
  138. package/out/renderer/assets/lua-8cJgIlqe.js +0 -256
  139. package/out/renderer/assets/mathematica-DNLOL9PQ.js +0 -110
  140. package/out/renderer/assets/mbox-Ga7d4MMN.js +0 -117
  141. package/out/renderer/assets/mirc-Dma3B8rS.js +0 -107
  142. package/out/renderer/assets/mllike-DHn7xckP.js +0 -334
  143. package/out/renderer/assets/modelica-0d55jYY0.js +0 -147
  144. package/out/renderer/assets/mscgen-DdqZYINH.js +0 -135
  145. package/out/renderer/assets/mumps-Btr8VblO.js +0 -93
  146. package/out/renderer/assets/nginx-DTDtBDVN.js +0 -141
  147. package/out/renderer/assets/nsis-3zG7tgur.js +0 -62
  148. package/out/renderer/assets/ntriples-CvgOYMpL.js +0 -153
  149. package/out/renderer/assets/octave-DYBj3-tl.js +0 -200
  150. package/out/renderer/assets/oz-R_e8WMIi.js +0 -231
  151. package/out/renderer/assets/pascal-GD8iposT.js +0 -105
  152. package/out/renderer/assets/perl-DL9mHpoi.js +0 -1105
  153. package/out/renderer/assets/pig-C_4T4YIV.js +0 -101
  154. package/out/renderer/assets/powershell-B0suO7Vd.js +0 -328
  155. package/out/renderer/assets/properties-BR-vP1aU.js +0 -58
  156. package/out/renderer/assets/protobuf-BxgpyhoW.js +0 -77
  157. package/out/renderer/assets/pug-CTXt1f8z.js +0 -405
  158. package/out/renderer/assets/puppet-Bdao66PW.js +0 -137
  159. package/out/renderer/assets/python-CvWbmiX4.js +0 -427
  160. package/out/renderer/assets/q-CrbCVq4a.js +0 -131
  161. package/out/renderer/assets/r-V7nswm59.js +0 -170
  162. package/out/renderer/assets/rpm-C-DLY-If.js +0 -109
  163. package/out/renderer/assets/ruby-JDKLJNK0.js +0 -330
  164. package/out/renderer/assets/sas-D2UG-yhZ.js +0 -207
  165. package/out/renderer/assets/scheme-BKzrkGJD.js +0 -222
  166. package/out/renderer/assets/shell-BlsXDxCn.js +0 -222
  167. package/out/renderer/assets/sieve-CjwBwOY5.js +0 -135
  168. package/out/renderer/assets/simple-mode-DMneyfDu.js +0 -130
  169. package/out/renderer/assets/smalltalk-BOIGQuhN.js +0 -121
  170. package/out/renderer/assets/solr-CwD7U71z.js +0 -69
  171. package/out/renderer/assets/sparql-DYskk2vE.js +0 -249
  172. package/out/renderer/assets/spreadsheet-Bgtt3oLP.js +0 -87
  173. package/out/renderer/assets/sql-BSrOzCRI.js +0 -354
  174. package/out/renderer/assets/stex-B6LNC55o.js +0 -231
  175. package/out/renderer/assets/stylus-BkS-boTH.js +0 -565
  176. package/out/renderer/assets/swift-FRZi1uvB.js +0 -291
  177. package/out/renderer/assets/tcl-CUcaCdmq.js +0 -114
  178. package/out/renderer/assets/textile-BnFpjsrl.js +0 -414
  179. package/out/renderer/assets/tiddlywiki-CjprD-Qp.js +0 -218
  180. package/out/renderer/assets/tiki-DK9DOeWn.js +0 -268
  181. package/out/renderer/assets/toml-BOuWGMcf.js +0 -76
  182. package/out/renderer/assets/troff-E1bJ0PPL.js +0 -61
  183. package/out/renderer/assets/ttcn-cfg-Dc39-fIP.js +0 -133
  184. package/out/renderer/assets/ttcn-tKd4HLu4.js +0 -192
  185. package/out/renderer/assets/turtle-Dq7-1WAf.js +0 -124
  186. package/out/renderer/assets/vb-Dp90gtsv.js +0 -196
  187. package/out/renderer/assets/vbscript-CI6_mxxU.js +0 -479
  188. package/out/renderer/assets/velocity-BwIZK1TH.js +0 -149
  189. package/out/renderer/assets/verilog-DDCYnHN8.js +0 -430
  190. package/out/renderer/assets/vhdl-DCkMIyT9.js +0 -158
  191. package/out/renderer/assets/webidl-BTLTThCm.js +0 -204
  192. package/out/renderer/assets/xquery-BrBUuxMR.js +0 -525
  193. package/out/renderer/assets/yacas-b5lAVEIl.js +0 -130
  194. package/out/renderer/assets/z80-BZV19vqv.js +0 -93
  195. package/scripts/download-uv.mjs +0 -147
  196. /package/patches/{ai+5.0.161.patch → ai+5.0.167.patch} +0 -0
@@ -0,0 +1,427 @@
1
+ # Config Components Reference
2
+
3
+ Config components provide a **per-extension settings UI** that appears in the Extension Settings dialog when users click the gear icon on an extension card. Unlike placement-based UI components (which render inside task pages), config components render in a dedicated settings modal with Save/Cancel buttons.
4
+
5
+ ## Overview
6
+
7
+ ```
8
+ User clicks extension gear icon
9
+ → ExtensionSettingsDialog opens
10
+ → Calls api.getExtensionConfigComponent(extensionId)
11
+ → Extension.getConfigComponent(context) returns JSX string
12
+ → Calls api.getExtensionConfig(extensionId)
13
+ → Extension.getConfigData(context) returns current config data
14
+ → Renders JSX with { config, updateConfig } props
15
+ → User edits values, clicks Save
16
+ → Calls api.saveExtensionConfig(extensionId, config)
17
+ → Extension.saveConfigData(configData, context) persists data
18
+ ```
19
+
20
+ ## The Three Methods
21
+
22
+ ### `getConfigComponent(context)` — Return Settings JSX
23
+
24
+ Returns a JSX string for the settings UI. The component receives `{ config, updateConfig }` as props:
25
+
26
+ - **`config`** — The current config data loaded from `getConfigData()`
27
+ - **`updateConfig`** — Callback to mutate the in-memory config state
28
+
29
+ ```typescript
30
+ getConfigComponent(_context: ExtensionContext): string | undefined {
31
+ // Option A: Inline JSX string
32
+ return `({ config, updateConfig }) => { ... }`;
33
+
34
+ // Option B: Load from external .jsx file (recommended for > 20 lines)
35
+ return readFileSync(join(__dirname, './ConfigComponent.jsx'), 'utf-8');
36
+ }
37
+ ```
38
+
39
+ Return `undefined` if your extension has no settings UI.
40
+
41
+ ### `getConfigData(context)` — Load Current Config
42
+
43
+ Called when the settings dialog opens. Returns the persisted configuration data:
44
+
45
+ ```typescript
46
+ async getConfigData(_context: ExtensionContext): Promise<unknown> {
47
+ try {
48
+ if (existsSync(this.configPath)) {
49
+ const data = readFileSync(this.configPath, 'utf-8');
50
+ const parsed = JSON.parse(data);
51
+ return { ...DEFAULT_CONFIG, ...parsed };
52
+ }
53
+ } catch {
54
+ // Ignore errors, fall back to defaults
55
+ }
56
+ return { ...DEFAULT_CONFIG };
57
+ }
58
+ ```
59
+
60
+ ### `saveConfigData(configData, context)` — Persist Config
61
+
62
+ Called when user clicks **Save** in the dialog:
63
+
64
+ ```typescript
65
+ async saveConfigData(configData: unknown, _context: ExtensionContext): Promise<unknown> {
66
+ const merged = { ...DEFAULT_CONFIG, ...configData as Partial<MyConfig> };
67
+ writeFileSync(this.configPath, JSON.stringify(merged, null, 2), 'utf-8');
68
+ return merged;
69
+ }
70
+ ```
71
+
72
+ ## Prefer ui Components Over Raw HTML
73
+
74
+ Always use the `ui` prop components (`ui.Input`, `ui.TextArea`, `ui.Select`, `ui.Checkbox`, etc.) instead of raw HTML `<input>`, `<textarea>`, `<select>` elements. This ensures consistent styling, accessibility, and theming across the application.
75
+
76
+ **Do this:**
77
+ ```jsx
78
+ ({ config, updateConfig, ui }) => {
79
+ const { Input } = ui;
80
+
81
+ return (
82
+ <Input
83
+ label="My Setting"
84
+ value={config?.mySetting || ''}
85
+ onChange={(value) => updateConfig({ ...config, mySetting: value })}
86
+ />
87
+ );
88
+ };
89
+ ```
90
+
91
+ **Not this:**
92
+ ```jsx
93
+ // Avoid raw HTML — inconsistent styling, no theme support
94
+ <input
95
+ type="text"
96
+ value={config?.mySetting || ''}
97
+ onChange={(e) => updateConfig({ ...config, mySetting: e.target.value })}
98
+ className="w-full px-3 py-2 ..."
99
+ />
100
+ ```
101
+
102
+ The `ui` components handle their own labels, styling, focus states, and dark mode automatically.
103
+
104
+ ## When Inner State Is (and Isn't) Needed
105
+
106
+ Config components receive `config` that is kept in sync by the parent dialog. **You do NOT need local state for simple form fields.**
107
+
108
+ ### No inner state needed (most cases)
109
+
110
+ When your component just reads from `config` and calls `updateConfig` on change — use `config` directly:
111
+
112
+ ```jsx
113
+ ({ config, updateConfig, ui }) => {
114
+ const { Input } = ui;
115
+ return <Input label="Folders" value={config?.folders || ''} onChange={(v) => updateConfig({ ...config, folders: v })} />;
116
+ };
117
+ ```
118
+
119
+ This works because `updateConfig` triggers a re-render with the updated `config` prop, so the input always shows the current value.
120
+
121
+ ### Inner state IS needed
122
+
123
+ Only introduce local state when you need behavior that goes beyond simple read/write:
124
+
125
+ - **Derived/computed values**: Displaying a transformed version of config (e.g., splitting a comma string into tags)
126
+ - **Transient UI state**: Expand/collapse sections, active tabs, modal visibility
127
+ - **Debounced input**: Delaying updates until user stops typing
128
+ - **Validation state**: Showing per-field error messages
129
+
130
+ ```jsx
131
+ ({ config, updateConfig, ui }) => {
132
+ const { useState } = React;
133
+ const { Input } = ui;
134
+
135
+ // Only needed because we transform config into tag-like items for editing
136
+ const [tags, setTags] = useState((config?.folders || '').split(',').filter(Boolean));
137
+
138
+ // ...
139
+ };
140
+ ```
141
+
142
+ ## Config Component Props
143
+
144
+ The JSX component receives these props:
145
+
146
+ ```typescript
147
+ {
148
+ // Current config data from getConfigData()
149
+ config: unknown,
150
+
151
+ // Callback to update in-memory config (does NOT persist!)
152
+ updateConfig: (newConfig: unknown) => void,
153
+
154
+ // All standard extension props (from useExtensions())
155
+ ui: UIComponents,
156
+ icons: Record<string, unknown>,
157
+ models: Model[],
158
+ providers: ProviderProfile[],
159
+ projectDir?: string,
160
+ task?: TaskData,
161
+ agentProfile?: AgentProfile,
162
+ mode: string,
163
+ api: ApplicationAPI,
164
+ }
165
+ ```
166
+
167
+ **Important:** `updateConfig` only updates the local React state. Persistence happens only when the user clicks **Save**, which triggers `saveConfigData()`.
168
+
169
+ ## Config Component JSX Format
170
+
171
+ Config components follow the same format as all other extension JSX files:
172
+
173
+ - Pure arrow function with destructured props
174
+ - React hooks accessed via `React.useState`, `React.useEffect`, etc.
175
+ - No imports — everything is available via props or globals
176
+ - Use Tailwind CSS for styling
177
+
178
+ ### Example: Text Input (no inner state, using ui.Input)
179
+
180
+ ```jsx
181
+ ({ config, updateConfig, ui }) => {
182
+ const { Input } = ui;
183
+
184
+ return (
185
+ <div className="flex flex-col gap-4">
186
+ <Input
187
+ label="My Setting"
188
+ value={config?.mySetting || ''}
189
+ onChange={(value) => updateConfig({ ...config, mySetting: value })}
190
+ placeholder="Enter value..."
191
+ />
192
+ <p className="text-xs text-text-secondary -mt-2">
193
+ Description of what this setting does.
194
+ </p>
195
+ </div>
196
+ );
197
+ };
198
+ ```
199
+
200
+ ### Example: Checkbox Toggle (no inner state)
201
+
202
+ ```jsx
203
+ ({ config, updateConfig, ui }) => {
204
+ const { Checkbox } = ui;
205
+
206
+ return (
207
+ <Checkbox
208
+ label="Enable feature"
209
+ checked={config?.enabled ?? false}
210
+ onChange={(checked) => updateConfig({ ...config, enabled: checked })}
211
+ />
212
+ );
213
+ };
214
+ ```
215
+
216
+ ### Example: Multiple Fields (no inner state)
217
+
218
+ ```jsx
219
+ ({ config, updateConfig, ui }) => {
220
+ const { Input, Checkbox } = ui;
221
+
222
+ return (
223
+ <div className="flex flex-col gap-4">
224
+ <Input
225
+ label="Rule Folders"
226
+ value={config?.ruleFolders || ''}
227
+ onChange={(value) => updateConfig({ ...config, ruleFolders: value })}
228
+ placeholder=".custom-rules, .ai/rules"
229
+ />
230
+ <Input
231
+ label="Max Depth"
232
+ type="number"
233
+ value={String(config?.maxDepth ?? 3)}
234
+ onChange={(value) => updateConfig({ ...config, maxDepth: Number(value) })}
235
+ />
236
+ <Checkbox
237
+ label="Include hidden directories"
238
+ checked={config?.includeHidden ?? false}
239
+ onChange={(checked) => updateConfig({ ...config, includeHidden: checked })}
240
+ />
241
+ </div>
242
+ );
243
+ };
244
+ ```
245
+
246
+ ### Example: With Inner State (derived/transient UI only)
247
+
248
+ Only use local state when you need behavior beyond simple read/write — such as derived display values or transient UI state:
249
+
250
+ ```jsx
251
+ ({ config, updateConfig, ui }) => {
252
+ const { useState, useMemo } = React;
253
+ const { Input } = ui;
254
+
255
+ // Inner state needed: splitting comma string into editable tag-like items
256
+ const rawValue = config?.folders || '';
257
+ const tags = useMemo(() => rawValue.split(',').map(t => t.trim()).filter(Boolean), [rawValue]);
258
+ const [activeTag, setActiveTag] = useState(null);
259
+
260
+ return (
261
+ <div className="flex flex-col gap-4">
262
+ <Input
263
+ label="Folders (comma-separated)"
264
+ value={rawValue}
265
+ onChange={(value) => updateConfig({ ...config, folders: value })}
266
+ />
267
+ {/* Tag preview — derived from config, uses inner state for UI interaction */}
268
+ <div className="flex flex-wrap gap-1">
269
+ {tags.map((tag) => (
270
+ <span
271
+ key={tag}
272
+ onClick={() => setActiveTag(tag === activeTag ? null : tag)}
273
+ className={`px-2 py-0.5 rounded text-xs cursor-pointer ${
274
+ tag === activeTag ? 'bg-accent text-white' : 'bg-bg-secondary'
275
+ }`}
276
+ >
277
+ {tag}
278
+ </span>
279
+ ))}
280
+ </div>
281
+ </div>
282
+ );
283
+ };
284
+ ```
285
+
286
+ ## File Structure Pattern
287
+
288
+ Recommended structure for extensions with config components:
289
+
290
+ ```
291
+ my-extension/
292
+ ├── index.ts # Main extension (loads JSX, implements 3 methods)
293
+ ├── ConfigComponent.jsx # Settings UI (pure arrow function)
294
+ └── config.json # Default/persisted config file
295
+ ```
296
+
297
+ ### index.ts Pattern
298
+
299
+ ```typescript
300
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
301
+ import { join } from 'node:path';
302
+ import type { Extension, ExtensionContext } from '@aiderdesk/extensions';
303
+
304
+ // Load config JSX at module level (read once)
305
+ const configComponentJsx = readFileSync(join(__dirname, './ConfigComponent.jsx'), 'utf-8');
306
+
307
+ interface MyExtensionConfig {
308
+ ruleFolders: string;
309
+ enabled: boolean;
310
+ }
311
+
312
+ const DEFAULT_CONFIG: MyExtensionConfig = {
313
+ ruleFolders: '',
314
+ enabled: true,
315
+ };
316
+
317
+ export default class MyExtension implements Extension {
318
+ static metadata = {
319
+ name: 'My Extension',
320
+ version: '1.0.0',
321
+ description: 'Description here',
322
+ author: 'author-name',
323
+ capabilities: ['context'],
324
+ };
325
+
326
+ private configPath: string;
327
+
328
+ constructor() {
329
+ this.configPath = join(__dirname, 'config.json');
330
+ }
331
+
332
+ async onLoad(context: ExtensionContext): Promise<void> {
333
+ context.log('My Extension loaded', 'info');
334
+ }
335
+
336
+ getConfigComponent(_context: ExtensionContext): string {
337
+ return configComponentJsx;
338
+ }
339
+
340
+ async getConfigData(_context: ExtensionContext): Promise<MyExtensionConfig> {
341
+ try {
342
+ if (existsSync(this.configPath)) {
343
+ const data = readFileSync(this.configPath, 'utf-8');
344
+ return { ...DEFAULT_CONFIG, ...JSON.parse(data) };
345
+ }
346
+ } catch {
347
+ // Ignore errors
348
+ }
349
+ return { ...DEFAULT_CONFIG };
350
+ }
351
+
352
+ async saveConfigData(configData: unknown, _context: ExtensionContext): Promise<unknown> {
353
+ const merged: MyExtensionConfig = { ...DEFAULT_CONFIG, ...configData as Partial<MyExtensionConfig> };
354
+ writeFileSync(this.configPath, JSON.stringify(merged, null, 2), 'utf-8');
355
+ return merged;
356
+ }
357
+ }
358
+ ```
359
+
360
+ ### config.json (default)
361
+
362
+ ```json
363
+ {
364
+ "ruleFolders": "",
365
+ "enabled": true
366
+ }
367
+ ```
368
+
369
+ ## How hasConfig is Determined
370
+
371
+ The `InstalledExtension.metadata.hasConfig` flag is set by checking whether `instance.getConfigComponent` exists and returns a truthy (non-empty) JSX string. This means:
372
+
373
+ - If you implement `getConfigComponent` and return a non-empty string → `hasConfig: true` → gear icon appears on the extension card
374
+ - If you don't implement it, or return `undefined`/empty string → `hasConfig: false` → no settings entry point
375
+
376
+ ## Differences from Placement-Based UI Components
377
+
378
+ | Aspect | Config Components | Placement UI Components |
379
+ |--------|-------------------|------------------------|
380
+ | **Where they render** | ExtensionSettingsDialog modal | Task page placements |
381
+ | **Registration method** | `getConfigComponent()` | `getUIComponents()` |
382
+ | **Props received** | `{ config, updateConfig, ui, icons, ... }` | `{ data, task, ui, icons, ... }` |
383
+ | **Data loading** | `getConfigData()` always called | `getUIExtensionData()` only if `loadData: true` |
384
+ | **Persistence** | `saveConfigData()` on Save click | Via `executeExtensionAction()` |
385
+ | **Placement enum** | Not applicable | `UIComponentPlacement` enum |
386
+ | **One per extension** | Yes (single) | No (multiple allowed) |
387
+
388
+ ## Best Practices
389
+
390
+ ### Prefer ui.* components over raw HTML elements
391
+
392
+ Always use components from the `ui` prop (`Input`, `TextArea`, `Select`, `Checkbox`, etc.) instead of raw `<input>`, `<textarea>`, or `<select>` elements. The ui components handle labels, styling, focus states, dark mode, and accessibility automatically.
393
+
394
+ ### Avoid unnecessary inner state
395
+
396
+ For simple form fields, read directly from `config` and call `updateConfig` on change — no `useState`/`useEffect` needed. The parent re-renders with updated `config` after each `updateConfig` call. Only introduce local state for derived values, transient UI state (tabs, expand/collapse), debounced input, or validation.
397
+
398
+ ### Call updateConfig on every change
399
+
400
+ Don't wait for blur/submit — call `updateConfig` immediately so the Save button persists the latest value:
401
+
402
+ ```jsx
403
+ onChange={(e) => {
404
+ setValue(e.target.value);
405
+ updateConfig({ ...config, myValue: e.target.value });
406
+ }}
407
+ ```
408
+
409
+ ### Merge with defaults in both load and save
410
+
411
+ Always merge incoming data with defaults to handle missing fields gracefully:
412
+
413
+ ```typescript
414
+ // In getConfigData
415
+ return { ...DEFAULT_CONFIG, ...parsed };
416
+
417
+ // In saveConfigData
418
+ const merged = { ...DEFAULT_CONFIG, ...configData };
419
+ ```
420
+
421
+ ### Store config in the extension directory
422
+
423
+ Use `join(__dirname, 'config.json')` so config lives alongside the extension code. Never write outside the extension directory.
424
+
425
+ ### Keep config serializable
426
+
427
+ Only use primitive types (string, number, boolean, arrays, plain objects) that can be safely JSON-stringified.
@@ -0,0 +1,156 @@
1
+ # Event Types
2
+
3
+ All event types and their payloads for extension event handlers.
4
+
5
+ ## Event Modification Modes
6
+
7
+ | Mode | Events | Can Block | Can Modify |
8
+ |------|--------|-----------|------------|
9
+ | Read-Only | onTaskCreated, onTaskClosed, onFileAdded, etc. | No | No |
10
+ | Blocking | onToolApproval, onToolCalled, onPromptSubmitted, onHandleApproval, onSubagentStarted | Yes | Some |
11
+ | Modifying | onToolFinished, onResponseMessageProcessed, onAgentStarted | No | Yes |
12
+
13
+ ## Agent Events
14
+
15
+ ### AgentStartedEvent (Modifying)
16
+
17
+ ```typescript
18
+ interface AgentStartedEvent {
19
+ readonly mode: Mode;
20
+ prompt: string | null;
21
+ agentProfile: AgentProfile;
22
+ providerProfile: ProviderProfile;
23
+ model: string;
24
+ promptContext?: PromptContext;
25
+ systemPrompt: string | undefined;
26
+ contextMessages: ContextMessage[];
27
+ contextFiles: ContextFile[];
28
+ blocked?: boolean;
29
+ }
30
+ ```
31
+
32
+ ### AgentFinishedEvent
33
+
34
+ ```typescript
35
+ interface AgentFinishedEvent {
36
+ readonly mode: Mode;
37
+ readonly agentProfile: AgentProfile;
38
+ resultMessages: ContextMessage[];
39
+ }
40
+ ```
41
+
42
+ ### AgentStepFinishedEvent (Modifying)
43
+
44
+ ```typescript
45
+ interface AgentStepFinishedEvent {
46
+ readonly mode: Mode;
47
+ readonly agentProfile: AgentProfile;
48
+ readonly currentResponseId: string;
49
+ readonly stepResult: AgentStepResult;
50
+ finishReason: 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other' | 'unknown';
51
+ responseMessages: ContextMessage[];
52
+ }
53
+ ```
54
+
55
+ ## Tool Events
56
+
57
+ ### ToolCalledEvent (Blocking)
58
+
59
+ ```typescript
60
+ interface ToolCalledEvent {
61
+ readonly tool: string;
62
+ readonly toolInput: Record<string, unknown>;
63
+ readonly agentProfile: AgentProfile;
64
+ blocked?: boolean;
65
+ }
66
+ ```
67
+
68
+ ### ToolFinishedEvent (Modifying)
69
+
70
+ ```typescript
71
+ interface ToolFinishedEvent {
72
+ readonly tool: string;
73
+ readonly toolInput: Record<string, unknown>;
74
+ readonly agentProfile: AgentProfile;
75
+ toolResult: unknown;
76
+ metadata?: Record<string, unknown>;
77
+ }
78
+ ```
79
+
80
+ ## Prompt Events
81
+
82
+ ### PromptSubmittedEvent (Blocking/Modifying)
83
+
84
+ ```typescript
85
+ interface PromptSubmittedEvent {
86
+ prompt: string;
87
+ mode: Mode;
88
+ promptContext: PromptContext;
89
+ blocked?: boolean;
90
+ }
91
+ ```
92
+
93
+ ## File Events
94
+
95
+ ### FileAddedEvent
96
+
97
+ ```typescript
98
+ interface FileAddedEvent {
99
+ files: string[];
100
+ }
101
+ ```
102
+
103
+ ## Subagent Events
104
+
105
+ ### SubagentStartedEvent (Blocking/Modifying)
106
+
107
+ ```typescript
108
+ interface SubagentStartedEvent {
109
+ subagentProfile: AgentProfile;
110
+ prompt: string;
111
+ promptContext?: PromptContext;
112
+ contextMessages: ContextMessage[];
113
+ contextFiles: ContextFile[];
114
+ systemPrompt?: string;
115
+ blocked?: boolean;
116
+ }
117
+ ```
118
+
119
+ ## Common Patterns
120
+
121
+ ### Blocking Execution
122
+
123
+ ```typescript
124
+ async onToolCalled(event: ToolCalledEvent): Promise<Partial<ToolCalledEvent>> {
125
+ if (event.tool === 'power---bash' && isDangerous(event.toolInput)) {
126
+ return { blocked: true };
127
+ }
128
+ return {};
129
+ }
130
+ ```
131
+
132
+ ### Modifying Messages
133
+
134
+ ```typescript
135
+ async onAgentStarted(event: AgentStartedEvent): Promise<Partial<AgentStartedEvent>> {
136
+ return {
137
+ contextMessages: [
138
+ { id: 'custom', role: 'user', content: 'Custom instruction' },
139
+ ...event.contextMessages
140
+ ]
141
+ };
142
+ }
143
+ ```
144
+
145
+ ### Modifying Profile
146
+
147
+ ```typescript
148
+ async onAgentStarted(event: AgentStartedEvent): Promise<Partial<AgentStartedEvent>> {
149
+ return {
150
+ agentProfile: {
151
+ ...event.agentProfile,
152
+ includeRepoMap: false
153
+ }
154
+ };
155
+ }
156
+ ```