homebridge-roborock-vacuum 1.6.0 → 1.6.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.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/config.schema.json +1 -1
  3. package/dist/platform.js +48 -20
  4. package/dist/platform.js.map +1 -1
  5. package/homebridge-ui/public/index.html +15 -8
  6. package/homebridge-ui/public/index.js +59 -5
  7. package/homebridge-ui/public/styles.css +49 -0
  8. package/package.json +9 -3
  9. package/.gemini/commands/openspec/apply.toml +0 -21
  10. package/.gemini/commands/openspec/archive.toml +0 -25
  11. package/.gemini/commands/openspec/proposal.toml +0 -26
  12. package/.opencode/command/openspec-apply.md +0 -24
  13. package/.opencode/command/openspec-archive.md +0 -27
  14. package/.opencode/command/openspec-proposal.md +0 -29
  15. package/AGENTS.md +0 -170
  16. package/CLAUDE.md +0 -50
  17. package/Plan.md +0 -54
  18. package/homebridge-roborock-vacuum.code-workspace +0 -7
  19. package/openspec/AGENTS.md +0 -456
  20. package/openspec/changes/add-device-exclusion-config/proposal.md +0 -14
  21. package/openspec/changes/add-device-exclusion-config/specs/vacuum-model-support/spec.md +0 -19
  22. package/openspec/changes/add-device-exclusion-config/tasks.md +0 -14
  23. package/openspec/changes/add-dynamic-model-capabilities/design.md +0 -49
  24. package/openspec/changes/add-dynamic-model-capabilities/proposal.md +0 -44
  25. package/openspec/changes/add-dynamic-model-capabilities/specs/vacuum-model-support/spec.md +0 -62
  26. package/openspec/changes/add-dynamic-model-capabilities/tasks.md +0 -21
  27. package/openspec/changes/archive/2026-02-08-add-model-support-a95-a159-ss07/design.md +0 -35
  28. package/openspec/changes/archive/2026-02-08-add-model-support-a95-a159-ss07/proposal.md +0 -15
  29. package/openspec/changes/archive/2026-02-08-add-model-support-a95-a159-ss07/specs/vacuum-model-support/spec.md +0 -15
  30. package/openspec/changes/archive/2026-02-08-add-model-support-a95-a159-ss07/tasks.md +0 -13
  31. package/openspec/changes/archive/2026-02-08-add-your-feature-here/proposal.md +0 -15
  32. package/openspec/changes/archive/2026-02-08-add-your-feature-here/specs/vacuum-feature-controls/spec.md +0 -12
  33. package/openspec/changes/archive/2026-02-08-add-your-feature-here/tasks.md +0 -12
  34. package/openspec/changes/archive/2026-02-08-update-unknown-model-skip-errors/proposal.md +0 -15
  35. package/openspec/changes/archive/2026-02-08-update-unknown-model-skip-errors/specs/vacuum-model-support/spec.md +0 -26
  36. package/openspec/changes/archive/2026-02-08-update-unknown-model-skip-errors/tasks.md +0 -11
  37. package/openspec/changes/archive/2026-02-18-update-mqtt-missing-localkey-handling/proposal.md +0 -19
  38. package/openspec/changes/archive/2026-02-18-update-mqtt-missing-localkey-handling/specs/runtime-deprecation-hygiene/spec.md +0 -16
  39. package/openspec/changes/archive/2026-02-18-update-mqtt-missing-localkey-handling/specs/vacuum-mqtt-decoding/spec.md +0 -35
  40. package/openspec/changes/archive/2026-02-18-update-mqtt-missing-localkey-handling/tasks.md +0 -16
  41. package/openspec/project.md +0 -72
  42. package/openspec/specs/runtime-deprecation-hygiene/spec.md +0 -20
  43. package/openspec/specs/vacuum-feature-controls/spec.md +0 -16
  44. package/openspec/specs/vacuum-model-support/spec.md +0 -44
  45. package/openspec/specs/vacuum-mqtt-decoding/spec.md +0 -39
package/README.md CHANGED
@@ -69,6 +69,6 @@ Follow these steps to install the plugin:
69
69
 
70
70
  ## Configuration
71
71
 
72
- Use the Homebridge UI settings page to sign in and configure the plugin. To exclude vacuums from HomeKit, add their Roborock device IDs to **Skipped Device IDs**. Multiple IDs can be entered one per line or separated by commas.
72
+ Use the Homebridge UI settings page to sign in and configure the plugin. To exclude vacuums from HomeKit, add their Roborock device IDs to **Skipped Device IDs**.
73
73
 
74
74
  When Homebridge restarts, matching devices will be skipped during discovery. If a skipped device already exists in HomeKit as a cached accessory, the plugin will remove it from Homebridge.
@@ -28,7 +28,7 @@
28
28
  "skipDevices": {
29
29
  "title": "Skipped Device IDs",
30
30
  "type": "string",
31
- "description": "Roborock device IDs to exclude from HomeKit. Enter multiple IDs separated by commas or new lines."
31
+ "description": "Roborock device IDs to exclude from HomeKit."
32
32
  },
33
33
  "baseURL": {
34
34
  "type": "string",
package/dist/platform.js CHANGED
@@ -51,6 +51,7 @@ class RoborockPlatform {
51
51
  this.Characteristic = this.api.hap.Characteristic;
52
52
  // Used to track restored cached accessories
53
53
  this.accessories = [];
54
+ this.cachedAccessoriesToRemove = [];
54
55
  this.vacuums = [];
55
56
  this.platformConfig = config;
56
57
  this.skippedDeviceIds = new Set(this.parseDeviceIds(this.platformConfig.skipDevices));
@@ -92,6 +93,8 @@ class RoborockPlatform {
92
93
  });
93
94
  }
94
95
  async configurePlugin() {
96
+ this.removeSkippedCachedAccessories();
97
+ this.removeDeferredCachedAccessories();
95
98
  await this.loginAndDiscoverDevices();
96
99
  }
97
100
  async loginAndDiscoverDevices() {
@@ -125,11 +128,9 @@ class RoborockPlatform {
125
128
  configureAccessory(accessory) {
126
129
  this.log.info(`Loading accessory '${accessory.displayName}' from cache.`);
127
130
  if (this.isSkippedDeviceId(accessory.context)) {
128
- this.log.info(`Removing accessory '${accessory.displayName}' (${accessory.context}) ` +
129
- "because it is configured to be skipped.");
130
- this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [
131
- accessory,
132
- ]);
131
+ this.log.info(`Accessory '${accessory.displayName}' (${accessory.context}) is configured ` +
132
+ "to be skipped and will be removed after Homebridge finishes launching.");
133
+ this.accessories.push(accessory);
133
134
  return;
134
135
  }
135
136
  // Store restored accessory in the cached accessories list
@@ -137,10 +138,10 @@ class RoborockPlatform {
137
138
  try {
138
139
  const existingAccessory = this.accessories.find((a) => a.UUID === accessory.UUID);
139
140
  if (existingAccessory) {
140
- this.log.info(`Removing duplicate accessory '${existingAccessory.displayName}' from cache.`);
141
- this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [
142
- existingAccessory,
143
- ]);
141
+ this.log.info(`Accessory '${accessory.displayName}' is a duplicate and will be ` +
142
+ "removed after Homebridge finishes launching.");
143
+ this.cachedAccessoriesToRemove.push(accessory);
144
+ return;
144
145
  }
145
146
  }
146
147
  catch (e) {
@@ -167,6 +168,41 @@ class RoborockPlatform {
167
168
  }
168
169
  return this.skippedDeviceIds.has(`${deviceId}`.trim());
169
170
  }
171
+ removeSkippedCachedAccessories() {
172
+ for (const cachedAccessory of [...this.accessories]) {
173
+ if (this.isSkippedDeviceId(cachedAccessory.context)) {
174
+ this.unregisterCachedAccessory(cachedAccessory, "because it is configured to be skipped");
175
+ }
176
+ }
177
+ }
178
+ removeDeferredCachedAccessories() {
179
+ for (const cachedAccessory of [...this.cachedAccessoriesToRemove]) {
180
+ this.unregisterCachedAccessory(cachedAccessory, "because another cached accessory with the same UUID was already restored");
181
+ }
182
+ }
183
+ unregisterCachedAccessory(accessory, reason) {
184
+ this.log.info(`Removing accessory '${accessory.displayName}' (${accessory.context}) ${reason}.`);
185
+ try {
186
+ this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [
187
+ accessory,
188
+ ]);
189
+ this.removeTrackedAccessory(accessory);
190
+ }
191
+ catch (error) {
192
+ this.log.error(`Unable to remove accessory '${accessory.displayName}' (${accessory.context}): ${error}`);
193
+ this.log.debug(error);
194
+ }
195
+ }
196
+ removeTrackedAccessory(accessory) {
197
+ const accessoryIndex = this.accessories.indexOf(accessory);
198
+ if (accessoryIndex !== -1) {
199
+ this.accessories.splice(accessoryIndex, 1);
200
+ }
201
+ const deferredIndex = this.cachedAccessoriesToRemove.indexOf(accessory);
202
+ if (deferredIndex !== -1) {
203
+ this.cachedAccessoriesToRemove.splice(deferredIndex, 1);
204
+ }
205
+ }
170
206
  /**
171
207
  * Fetches all of the user's devices from Roborock App and sets up handlers.
172
208
  *
@@ -222,24 +258,16 @@ class RoborockPlatform {
222
258
  }
223
259
  // At this point, we set up all devices from Roborock App, but we did not unregister
224
260
  // cached devices that do not exist on the Roborock App account anymore.
225
- for (const cachedAccessory of this.accessories) {
261
+ for (const cachedAccessory of [...this.accessories]) {
226
262
  if (cachedAccessory.context) {
227
263
  if (this.isSkippedDeviceId(cachedAccessory.context)) {
228
- this.log.info(`Removing accessory '${cachedAccessory.displayName}' (${cachedAccessory.context}) ` +
229
- "because it is configured to be skipped.");
230
- this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [
231
- cachedAccessory,
232
- ]);
264
+ this.unregisterCachedAccessory(cachedAccessory, "because it is configured to be skipped");
233
265
  continue;
234
266
  }
235
267
  const vacuum = self.roborockAPI.getVacuumDeviceData(cachedAccessory.context);
236
268
  if (vacuum === undefined) {
237
269
  // This cached devices does not exist on the Roborock App account (anymore).
238
- this.log.info(`Removing accessory '${cachedAccessory.displayName}' (${cachedAccessory.context}) ` +
239
- "because it does not exist on the Roborock account anymore.");
240
- this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [
241
- cachedAccessory,
242
- ]);
270
+ this.unregisterCachedAccessory(cachedAccessory, "because it does not exist on the Roborock account anymore");
243
271
  }
244
272
  }
245
273
  }
@@ -1 +1 @@
1
- {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":";;;;;AAWA,0EAAyD;AAEzD,sDAA8C;AAE9C,yCAAwD;AAExD,qCAA0C;AAE1C,MAAM,YAAY,GAAG,SAAS,CAAC;AAC/B,IAAI,sBAAsB,GAAG,KAAK,CAAC;AAEnC,SAAS,+BAA+B;IACtC,IAAI,sBAAsB,EAAE,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,sBAAsB,GAAG,IAAI,CAAC;IAE9B,MAAM,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9D,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,OAAO,CAAC,WAAW,GAAG,CAAC,CACrB,OAAuB,EACvB,IAAa,EACb,IAAa,EACb,IAAe,EACT,EAAE;QACR,MAAM,WAAW,GACf,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,MAAM,IAAI,OAAO;YAClE,CAAC,CAAC,MAAM,CAAE,OAA6B,CAAC,IAAI,CAAC;YAC7C,CAAC,CAAC,IAAI,CAAC;QAEX,IAAI,WAAW,KAAK,YAAY,EAAE,CAAC;YACjC,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,aAAa,GAAG,IAAI,CAAC;gBACrB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,kFAAkF,CACnF,CAAC;YACJ,CAAC;YACD,OAAO;QACT,CAAC;QAEA,mBAAoD,CACnD,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,IAAI,CACL,CAAC;IACJ,CAAC,CAA+B,CAAC;AACnC,CAAC;AAED,+BAA+B,EAAE,CAAC;AAElC,MAAM,QAAQ,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC,QAAQ,CAAC;AAEhE;;;GAGG;AACH,MAAqB,gBAAgB;IAgBnC;;;;;;;OAOG;IACH,YACE,gBAAwB,EACxB,MAAsB,EACL,GAAQ;QAAR,QAAG,GAAH,GAAG,CAAK;QA1BX,YAAO,GAAmB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QAC/C,mBAAc,GAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QAE9B,4CAA4C;QAC3B,gBAAW,GAAgC,EAAE,CAAC;QAC9C,8BAAyB,GAAgC,EAAE,CAAC;QAC5D,YAAO,GAA8B,EAAE,CAAC;QAqBvD,IAAI,CAAC,cAAc,GAAG,MAAgC,CAAC;QACvD,IAAI,CAAC,gBAAgB,GAAG,IAAI,GAAG,CAC7B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CACrD,CAAC;QAEF,6BAA6B;QAC7B,IAAI,CAAC,GAAG,GAAG,IAAI,gBAAsB,CACnC,gBAAgB,EAChB,IAAI,CAAC,cAAc,CAAC,SAAS,CAC9B,CAAC;QACF,2CAA2C;QAE3C,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;QAEhD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAChD,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc;YACzD,CAAC,CAAC,IAAA,uBAAc,EAAC,IAAI,CAAC,cAAc,CAAC,cAAc,EAAE,WAAW,CAAC;YACjE,CAAC,CAAC,IAAI,CAAC;QAET,IAAI,CAAC,WAAW,GAAG,IAAI,QAAQ,CAAC;YAC9B,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,SAAS;YAChB,OAAO,EAAE,OAAO;YAChB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,WAAW;SACzB,CAAC,CAAC;QAEH;;;;;WAKG;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,2DAAgC,GAAG,EAAE;YAC9C,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACtE,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,qCAAoB,GAAG,EAAE;YAClC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAEnC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;YACjC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,IAAI,CAAC,8BAA8B,EAAE,CAAC;QACtC,IAAI,CAAC,+BAA+B,EAAE,CAAC;QACvC,MAAM,IAAI,CAAC,uBAAuB,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,uBAAuB;QAC3B,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;YAC/B,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,mDAAmD;gBACjD,qEAAqE,CACxE,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,cAAc,EAAE,CAAC;YACzE,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,sDAAsD;gBACpD,2DAA2D,CAC9D,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC;QAElB,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,UAAU,EAAE,EAAE,QAAQ;YACrD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,wBAAwB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YAExE,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClC,MAAM,CAAC,mBAAmB,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YACjC,mCAAmC;YACnC,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,kBAAkB,CAAC,SAAoC;QACrD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,sBAAsB,SAAS,CAAC,WAAW,eAAe,CAAC,CAAC;QAE1E,IAAI,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,cAAc,SAAS,CAAC,WAAW,MAAM,SAAS,CAAC,OAAO,kBAAkB;gBAC1E,wEAAwE,CAC3E,CAAC;YACF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,0DAA0D;QAC1D,gCAAgC;QAEhC,IAAI,CAAC;YACH,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAC7C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CACjC,CAAC;YACF,IAAI,iBAAiB,EAAE,CAAC;gBACtB,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,cAAc,SAAS,CAAC,WAAW,+BAA+B;oBAChE,8CAA8C,CACjD,CAAC;gBACF,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC/C,OAAO;YACT,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,sCAAsC,GAAG,CAAC,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAED,iBAAiB,CAAC,KAAa;QAC7B,2CAA2C;QAC3C,OAAO,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;IAC9C,CAAC;IAED,cAAc,CAAC,KAA4C;QACzD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAErE,OAAO,OAAO;aACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;aACjC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,iBAAiB,CAAC,QAAiB;QACjC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,YAAY,MAAM,CAAC,EAAE,CAAC;YAClE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAEO,8BAA8B;QACpC,KAAK,MAAM,eAAe,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YACpD,IAAI,IAAI,CAAC,iBAAiB,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpD,IAAI,CAAC,yBAAyB,CAC5B,eAAe,EACf,wCAAwC,CACzC,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAEO,+BAA+B;QACrC,KAAK,MAAM,eAAe,IAAI,CAAC,GAAG,IAAI,CAAC,yBAAyB,CAAC,EAAE,CAAC;YAClE,IAAI,CAAC,yBAAyB,CAC5B,eAAe,EACf,0EAA0E,CAC3E,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,yBAAyB,CAC/B,SAAoC,EACpC,MAAc;QAEd,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,uBAAuB,SAAS,CAAC,WAAW,MAAM,SAAS,CAAC,OAAO,KAAK,MAAM,GAAG,CAClF,CAAC;QAEF,IAAI,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,6BAA6B,CAAC,sBAAW,EAAE,wBAAa,EAAE;gBACjE,SAAS;aACV,CAAC,CAAC;YACH,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,+BAA+B,SAAS,CAAC,WAAW,MAAM,SAAS,CAAC,OAAO,MAAM,KAAK,EAAE,CACzF,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAEO,sBAAsB,CAAC,SAAoC;QACjE,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC3D,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACxE,IAAI,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,eAAe;QACnB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAE/C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC;YAElB,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAChC,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,OAAO,CAAC,UAAU,MAAM;oBACvD,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;oBACvB,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;oBACvB,IAAI,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;oBAEhE,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;wBACjC,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,oBAAoB,IAAI,MAAM,IAAI,2CAA2C,CAC9E,CAAC;wBAEF,OAAO;oBACT,CAAC;oBAED,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;wBACnC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,MAAM,IAAI,qBAAqB,CAAC,CAAC;wBAE9D,OAAO;oBACT,CAAC;oBAED,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBAErD,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAC7C,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CACvC,CAAC;oBAEF,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;wBACpC,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,wBAAwB,iBAAiB,CAAC,WAAW,IAAI;4BACvD,IAAI,IAAI,eAAe,CAC1B,CAAC;wBAEF,kEAAkE;wBAClE,wCAAwC;wBACxC,iBAAiB,CAAC,OAAO,GAAG,IAAI,CAAC;wBACjC,IAAI,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;wBAExD,0DAA0D;wBAE1D,IAAI,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC;oBAClD,CAAC;yBAAM,CAAC;wBACN,wDAAwD;wBAExD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,qBAAqB,IAAI,MAAM,IAAI,IAAI,CAAC,CAAC;wBACvD,4DAA4D;wBAC5D,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAC9C,IAAI,EACJ,IAAI,CACL,CAAC;wBAEF,yEAAyE;wBACzE,wEAAwE;wBACxE,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;wBAEzB,8DAA8D;wBAC9D,+CAA+C;wBAC/C,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC;wBAExC,sCAAsC;wBACtC,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC,sBAAW,EAAE,wBAAa,EAAE;4BAC/D,SAAS;yBACV,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;YAED,oFAAoF;YACpF,wEAAwE;YACxE,KAAK,MAAM,eAAe,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;gBACpD,IAAI,eAAe,CAAC,OAAO,EAAE,CAAC;oBAC5B,IAAI,IAAI,CAAC,iBAAiB,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;wBACpD,IAAI,CAAC,yBAAyB,CAC5B,eAAe,EACf,wCAAwC,CACzC,CAAC;wBACF,SAAS;oBACX,CAAC;oBAED,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,mBAAmB,CACjD,eAAe,CAAC,OAAO,CACxB,CAAC;oBAEF,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;wBACzB,4EAA4E;wBAC5E,IAAI,CAAC,yBAAyB,CAC5B,eAAe,EACf,2DAA2D,CAC5D,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,6CAA6C;gBAC3C,0CAA0C,CAC7C,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,uBAAuB,CAAC,SAAoC;QAC1D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,0BAAuB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAClE,CAAC;CACF;AAhWD,mCAgWC"}
@@ -36,14 +36,21 @@
36
36
  </option>
37
37
  </select>
38
38
  </label>
39
- <label>
40
- Skipped Device IDs
41
- <textarea
42
- id="skip-devices"
43
- rows="4"
44
- placeholder="One device ID per line, or comma-separated"
45
- ></textarea>
46
- </label>
39
+ <div class="field">
40
+ <div class="field-header">
41
+ <span>Skipped Device IDs</span>
42
+ <button
43
+ id="add-skip-device"
44
+ class="icon-button"
45
+ type="button"
46
+ title="Add skipped device"
47
+ aria-label="Add skipped device"
48
+ >
49
+ +
50
+ </button>
51
+ </div>
52
+ <div id="skip-devices" class="skip-device-list"></div>
53
+ </div>
47
54
  <p class="help">
48
55
  Matching devices will not be added to HomeKit and existing cached
49
56
  accessories will be removed on restart.
@@ -4,6 +4,7 @@ const elements = {
4
4
  passwordRow: document.getElementById("password-row"),
5
5
  baseUrl: document.getElementById("base-url"),
6
6
  skipDevices: document.getElementById("skip-devices"),
7
+ addSkipDevice: document.getElementById("add-skip-device"),
7
8
  debugMode: document.getElementById("debug-mode"),
8
9
  code: document.getElementById("two-factor-code"),
9
10
  login: document.getElementById("login"),
@@ -55,6 +56,7 @@ async function loadConfig() {
55
56
  (entry) => entry.platform === "RoborockVacuumPlatform"
56
57
  );
57
58
  if (!config) {
59
+ renderSkipDevices([]);
58
60
  return;
59
61
  }
60
62
 
@@ -64,9 +66,7 @@ async function loadConfig() {
64
66
  elements.baseUrl.value = normalizeBaseUrl(
65
67
  config.baseURL || "https://usiot.roborock.com"
66
68
  );
67
- if (config.skipDevices) {
68
- elements.skipDevices.value = parseDeviceIds(config.skipDevices).join("\n");
69
- }
69
+ renderSkipDevices(config.skipDevices);
70
70
  elements.debugMode.checked = Boolean(config.debugMode);
71
71
 
72
72
  setLoggedInState(Boolean(config.encryptedToken));
@@ -85,7 +85,10 @@ function getBaseUrl() {
85
85
  }
86
86
 
87
87
  function getSkipDevices() {
88
- return parseDeviceIds(elements.skipDevices.value).join(",");
88
+ return getSkipDeviceInputs()
89
+ .map((input) => input.value.trim())
90
+ .filter((entry) => entry)
91
+ .join(",");
89
92
  }
90
93
 
91
94
  function getDebugMode() {
@@ -105,6 +108,54 @@ function parseDeviceIds(value) {
105
108
  return entries.map((entry) => String(entry).trim()).filter((entry) => entry);
106
109
  }
107
110
 
111
+ function getSkipDeviceInputs() {
112
+ return Array.from(elements.skipDevices.querySelectorAll("input"));
113
+ }
114
+
115
+ function renderSkipDevices(value) {
116
+ elements.skipDevices.textContent = "";
117
+
118
+ const deviceIds = parseDeviceIds(value);
119
+ if (deviceIds.length === 0) {
120
+ addSkipDeviceRow("", false);
121
+ return;
122
+ }
123
+
124
+ deviceIds.forEach((deviceId) => addSkipDeviceRow(deviceId, false));
125
+ }
126
+
127
+ function addSkipDeviceRow(value = "", shouldFocus = true) {
128
+ const row = document.createElement("div");
129
+ row.className = "skip-device-row";
130
+
131
+ const input = document.createElement("input");
132
+ input.type = "text";
133
+ input.placeholder = "Device ID";
134
+ input.setAttribute("aria-label", "Skipped device ID");
135
+ input.value = value;
136
+ input.addEventListener("change", saveCredentials);
137
+
138
+ const remove = document.createElement("button");
139
+ remove.type = "button";
140
+ remove.className = "icon-button remove";
141
+ remove.title = "Remove skipped device";
142
+ remove.setAttribute("aria-label", "Remove skipped device");
143
+ remove.textContent = "-";
144
+ remove.addEventListener("click", () => {
145
+ row.remove();
146
+ if (getSkipDeviceInputs().length === 0) {
147
+ addSkipDeviceRow();
148
+ }
149
+ saveCredentials();
150
+ });
151
+
152
+ row.append(input, remove);
153
+ elements.skipDevices.appendChild(row);
154
+ if (shouldFocus) {
155
+ input.focus();
156
+ }
157
+ }
158
+
108
159
  async function saveCredentials() {
109
160
  const email = getEmail();
110
161
  const baseURL = getBaseUrl();
@@ -262,6 +313,7 @@ async function updatePluginConfig(patch) {
262
313
  }
263
314
 
264
315
  function init() {
316
+ renderSkipDevices([]);
265
317
  loadConfig().catch(() => {
266
318
  showToast("error", "Failed to load current config.");
267
319
  });
@@ -270,7 +322,9 @@ function init() {
270
322
  elements.verify2fa.addEventListener("click", verifyTwoFactorCode);
271
323
  elements.logout.addEventListener("click", logout);
272
324
  elements.baseUrl.addEventListener("change", saveCredentials);
273
- elements.skipDevices.addEventListener("change", saveCredentials);
325
+ elements.addSkipDevice.addEventListener("click", () => {
326
+ addSkipDeviceRow();
327
+ });
274
328
  elements.debugMode.addEventListener("change", saveCredentials);
275
329
  elements.email.addEventListener("change", saveCredentials);
276
330
  }
@@ -65,6 +65,19 @@ label {
65
65
  color: var(--muted);
66
66
  }
67
67
 
68
+ .field {
69
+ margin-top: 16px;
70
+ font-size: 0.95rem;
71
+ color: var(--muted);
72
+ }
73
+
74
+ .field-header {
75
+ display: flex;
76
+ align-items: center;
77
+ justify-content: space-between;
78
+ gap: 12px;
79
+ }
80
+
68
81
  select,
69
82
  input,
70
83
  textarea {
@@ -83,6 +96,23 @@ textarea {
83
96
  resize: vertical;
84
97
  }
85
98
 
99
+ .skip-device-list {
100
+ display: grid;
101
+ gap: 10px;
102
+ margin-top: 8px;
103
+ }
104
+
105
+ .skip-device-row {
106
+ display: grid;
107
+ grid-template-columns: minmax(0, 1fr) 44px;
108
+ gap: 8px;
109
+ align-items: center;
110
+ }
111
+
112
+ .skip-device-row input {
113
+ margin-top: 0;
114
+ }
115
+
86
116
  input::placeholder,
87
117
  textarea::placeholder {
88
118
  color: #64748b;
@@ -137,6 +167,25 @@ button:hover {
137
167
  box-shadow: 0 12px 24px rgba(56, 189, 248, 0.18);
138
168
  }
139
169
 
170
+ .icon-button {
171
+ width: 40px;
172
+ min-width: 40px;
173
+ height: 40px;
174
+ padding: 0;
175
+ display: inline-flex;
176
+ align-items: center;
177
+ justify-content: center;
178
+ font-size: 1.3rem;
179
+ line-height: 1;
180
+ background: var(--secondary);
181
+ color: var(--text);
182
+ border: 1px solid var(--border);
183
+ }
184
+
185
+ .icon-button.remove {
186
+ color: #fca5a5;
187
+ }
188
+
140
189
  .primary {
141
190
  background: var(--primary);
142
191
  color: #041826;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-roborock-vacuum",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "Roborock Vacuum Cleaner - plugin for Homebridge.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -18,6 +18,13 @@
18
18
  },
19
19
  "homepage": "https://github.com/tasict/homebridge-roborock-vacuum",
20
20
  "main": "dist/index.js",
21
+ "files": [
22
+ "CHANGELOG.md",
23
+ "config.schema.json",
24
+ "dist",
25
+ "homebridge-ui",
26
+ "roborockLib"
27
+ ],
21
28
  "engines": {
22
29
  "homebridge": "^1.6.0 || ^2.0.0-beta.0",
23
30
  "node": "^18.20.4 || ^20.15.1 || ^22 || ^24"
@@ -25,8 +32,7 @@
25
32
  "scripts": {
26
33
  "clean": "rimraf ./dist",
27
34
  "build": "rimraf ./dist && tsc",
28
- "prepare": "npm run build",
29
- "prepublishOnly": "npm run build",
35
+ "prepublishOnly": "npm install --include=dev && npm run build",
30
36
  "postpublish": "npm run clean",
31
37
  "lint": "prettier --check .",
32
38
  "lint:fix": "prettier --write .",
@@ -1,21 +0,0 @@
1
- description = "Implement an approved OpenSpec change and keep tasks in sync."
2
-
3
- prompt = """
4
- <!-- OPENSPEC:START -->
5
- **Guardrails**
6
- - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
7
- - Keep changes tightly scoped to the requested outcome.
8
- - Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
9
-
10
- **Steps**
11
- Track these steps as TODOs and complete them one by one.
12
- 1. Read `changes/<id>/proposal.md`, `design.md` (if present), and `tasks.md` to confirm scope and acceptance criteria.
13
- 2. Work through tasks sequentially, keeping edits minimal and focused on the requested change.
14
- 3. Confirm completion before updating statuses—make sure every item in `tasks.md` is finished.
15
- 4. Update the checklist after all work is done so each task is marked `- [x]` and reflects reality.
16
- 5. Reference `openspec list` or `openspec show <item>` when additional context is required.
17
-
18
- **Reference**
19
- - Use `openspec show <id> --json --deltas-only` if you need additional context from the proposal while implementing.
20
- <!-- OPENSPEC:END -->
21
- """
@@ -1,25 +0,0 @@
1
- description = "Archive a deployed OpenSpec change and update specs."
2
-
3
- prompt = """
4
- <!-- OPENSPEC:START -->
5
- **Guardrails**
6
- - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
7
- - Keep changes tightly scoped to the requested outcome.
8
- - Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
9
-
10
- **Steps**
11
- 1. Determine the change ID to archive:
12
- - If this prompt already includes a specific change ID (for example inside a `<ChangeId>` block populated by slash-command arguments), use that value after trimming whitespace.
13
- - If the conversation references a change loosely (for example by title or summary), run `openspec list` to surface likely IDs, share the relevant candidates, and confirm which one the user intends.
14
- - Otherwise, review the conversation, run `openspec list`, and ask the user which change to archive; wait for a confirmed change ID before proceeding.
15
- - If you still cannot identify a single change ID, stop and tell the user you cannot archive anything yet.
16
- 2. Validate the change ID by running `openspec list` (or `openspec show <id>`) and stop if the change is missing, already archived, or otherwise not ready to archive.
17
- 3. Run `openspec archive <id> --yes` so the CLI moves the change and applies spec updates without prompts (use `--skip-specs` only for tooling-only work).
18
- 4. Review the command output to confirm the target specs were updated and the change landed in `changes/archive/`.
19
- 5. Validate with `openspec validate --strict` and inspect with `openspec show <id>` if anything looks off.
20
-
21
- **Reference**
22
- - Use `openspec list` to confirm change IDs before archiving.
23
- - Inspect refreshed specs with `openspec list --specs` and address any validation issues before handing off.
24
- <!-- OPENSPEC:END -->
25
- """
@@ -1,26 +0,0 @@
1
- description = "Scaffold a new OpenSpec change and validate strictly."
2
-
3
- prompt = """
4
- <!-- OPENSPEC:START -->
5
- **Guardrails**
6
- - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
7
- - Keep changes tightly scoped to the requested outcome.
8
- - Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
9
- - Identify any vague or ambiguous details and ask the necessary follow-up questions before editing files.
10
- - Do not write any code during the proposal stage. Only create design documents (proposal.md, tasks.md, design.md, and spec deltas). Implementation happens in the apply stage after approval.
11
-
12
- **Steps**
13
- 1. Review `openspec/project.md`, run `openspec list` and `openspec list --specs`, and inspect related code or docs (e.g., via `rg`/`ls`) to ground the proposal in current behaviour; note any gaps that require clarification.
14
- 2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, and `design.md` (when needed) under `openspec/changes/<id>/`.
15
- 3. Map the change into concrete capabilities or requirements, breaking multi-scope efforts into distinct spec deltas with clear relationships and sequencing.
16
- 4. Capture architectural reasoning in `design.md` when the solution spans multiple systems, introduces new patterns, or demands trade-off discussion before committing to specs.
17
- 5. Draft spec deltas in `changes/<id>/specs/<capability>/spec.md` (one folder per capability) using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement and cross-reference related capabilities when relevant.
18
- 6. Draft `tasks.md` as an ordered list of small, verifiable work items that deliver user-visible progress, include validation (tests, tooling), and highlight dependencies or parallelizable work.
19
- 7. Validate with `openspec validate <id> --strict` and resolve every issue before sharing the proposal.
20
-
21
- **Reference**
22
- - Use `openspec show <id> --json --deltas-only` or `openspec show <spec> --type spec` to inspect details when validation fails.
23
- - Search existing requirements with `rg -n "Requirement:|Scenario:" openspec/specs` before writing new ones.
24
- - Explore the codebase with `rg <keyword>`, `ls`, or direct file reads so proposals align with current implementation realities.
25
- <!-- OPENSPEC:END -->
26
- """
@@ -1,24 +0,0 @@
1
- ---
2
- description: Implement an approved OpenSpec change and keep tasks in sync.
3
- ---
4
- The user has requested to implement the following change proposal. Find the change proposal and follow the instructions below. If you're not sure or if ambiguous, ask for clarification from the user.
5
- <UserRequest>
6
- $ARGUMENTS
7
- </UserRequest>
8
- <!-- OPENSPEC:START -->
9
- **Guardrails**
10
- - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
11
- - Keep changes tightly scoped to the requested outcome.
12
- - Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
13
-
14
- **Steps**
15
- Track these steps as TODOs and complete them one by one.
16
- 1. Read `changes/<id>/proposal.md`, `design.md` (if present), and `tasks.md` to confirm scope and acceptance criteria.
17
- 2. Work through tasks sequentially, keeping edits minimal and focused on the requested change.
18
- 3. Confirm completion before updating statuses—make sure every item in `tasks.md` is finished.
19
- 4. Update the checklist after all work is done so each task is marked `- [x]` and reflects reality.
20
- 5. Reference `openspec list` or `openspec show <item>` when additional context is required.
21
-
22
- **Reference**
23
- - Use `openspec show <id> --json --deltas-only` if you need additional context from the proposal while implementing.
24
- <!-- OPENSPEC:END -->
@@ -1,27 +0,0 @@
1
- ---
2
- description: Archive a deployed OpenSpec change and update specs.
3
- ---
4
- <ChangeId>
5
- $ARGUMENTS
6
- </ChangeId>
7
- <!-- OPENSPEC:START -->
8
- **Guardrails**
9
- - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
10
- - Keep changes tightly scoped to the requested outcome.
11
- - Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
12
-
13
- **Steps**
14
- 1. Determine the change ID to archive:
15
- - If this prompt already includes a specific change ID (for example inside a `<ChangeId>` block populated by slash-command arguments), use that value after trimming whitespace.
16
- - If the conversation references a change loosely (for example by title or summary), run `openspec list` to surface likely IDs, share the relevant candidates, and confirm which one the user intends.
17
- - Otherwise, review the conversation, run `openspec list`, and ask the user which change to archive; wait for a confirmed change ID before proceeding.
18
- - If you still cannot identify a single change ID, stop and tell the user you cannot archive anything yet.
19
- 2. Validate the change ID by running `openspec list` (or `openspec show <id>`) and stop if the change is missing, already archived, or otherwise not ready to archive.
20
- 3. Run `openspec archive <id> --yes` so the CLI moves the change and applies spec updates without prompts (use `--skip-specs` only for tooling-only work).
21
- 4. Review the command output to confirm the target specs were updated and the change landed in `changes/archive/`.
22
- 5. Validate with `openspec validate --strict` and inspect with `openspec show <id>` if anything looks off.
23
-
24
- **Reference**
25
- - Use `openspec list` to confirm change IDs before archiving.
26
- - Inspect refreshed specs with `openspec list --specs` and address any validation issues before handing off.
27
- <!-- OPENSPEC:END -->
@@ -1,29 +0,0 @@
1
- ---
2
- description: Scaffold a new OpenSpec change and validate strictly.
3
- ---
4
- The user has requested the following change proposal. Use the openspec instructions to create their change proposal.
5
- <UserRequest>
6
- $ARGUMENTS
7
- </UserRequest>
8
- <!-- OPENSPEC:START -->
9
- **Guardrails**
10
- - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
11
- - Keep changes tightly scoped to the requested outcome.
12
- - Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
13
- - Identify any vague or ambiguous details and ask the necessary follow-up questions before editing files.
14
- - Do not write any code during the proposal stage. Only create design documents (proposal.md, tasks.md, design.md, and spec deltas). Implementation happens in the apply stage after approval.
15
-
16
- **Steps**
17
- 1. Review `openspec/project.md`, run `openspec list` and `openspec list --specs`, and inspect related code or docs (e.g., via `rg`/`ls`) to ground the proposal in current behaviour; note any gaps that require clarification.
18
- 2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, and `design.md` (when needed) under `openspec/changes/<id>/`.
19
- 3. Map the change into concrete capabilities or requirements, breaking multi-scope efforts into distinct spec deltas with clear relationships and sequencing.
20
- 4. Capture architectural reasoning in `design.md` when the solution spans multiple systems, introduces new patterns, or demands trade-off discussion before committing to specs.
21
- 5. Draft spec deltas in `changes/<id>/specs/<capability>/spec.md` (one folder per capability) using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement and cross-reference related capabilities when relevant.
22
- 6. Draft `tasks.md` as an ordered list of small, verifiable work items that deliver user-visible progress, include validation (tests, tooling), and highlight dependencies or parallelizable work.
23
- 7. Validate with `openspec validate <id> --strict` and resolve every issue before sharing the proposal.
24
-
25
- **Reference**
26
- - Use `openspec show <id> --json --deltas-only` or `openspec show <spec> --type spec` to inspect details when validation fails.
27
- - Search existing requirements with `rg -n "Requirement:|Scenario:" openspec/specs` before writing new ones.
28
- - Explore the codebase with `rg <keyword>`, `ls`, or direct file reads so proposals align with current implementation realities.
29
- <!-- OPENSPEC:END -->