mb-run 0.0.3-dev-20260705-2f3e02d → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -3
- package/dist/upgrade.js +7 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/vendor/.agents/matterbridge.md +319 -0
- package/vendor/.agents/testing.md +56 -0
- package/vendor/.claude/rules/matterbridge/matterbridge.instructions.md +6 -6
- package/vendor/.claude/settings.json +1 -0
- package/vendor/.github-plugin/instructions/matterbridge/matterbridge.instructions.md +6 -6
- package/vendor/.vscode/settings.native.json +20 -11
- package/vendor/AGENTS.md +13 -6
- package/vendor/Branch protection.json +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -21,12 +21,12 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
21
21
|
|
|
22
22
|
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/assets/bmc-button.svg" alt="Buy me a coffee" width="120"></a>
|
|
23
23
|
|
|
24
|
-
## [0.0.3] -
|
|
24
|
+
## [0.0.3] - 2026-07-06
|
|
25
25
|
|
|
26
26
|
### Added
|
|
27
27
|
|
|
28
|
-
- [copilot]: Update VS Code settings to version 1.0.
|
|
29
|
-
- [claude]: Update Claude settings to version 1.0.
|
|
28
|
+
- [copilot]: Update VS Code settings to version 1.0.7 and add terminal auto-approve configurations.
|
|
29
|
+
- [claude]: Update Claude settings to version 1.0.4 and add terminal auto-approve configurations.
|
|
30
30
|
- [package]: Apply style.
|
|
31
31
|
|
|
32
32
|
### Changed
|
package/dist/upgrade.js
CHANGED
|
@@ -116,7 +116,11 @@ export async function runPackageJsonUpgrade(opts, pkgPath, pkgJson, isMonorepo =
|
|
|
116
116
|
removeDirSafe(path.join(dstDir, '.claude', 'rules', 'matterbridge'));
|
|
117
117
|
}
|
|
118
118
|
if (!isWorkspace) {
|
|
119
|
+
copyRecursive('.agents', '.agents');
|
|
119
120
|
copyRecursive('.codex', '.codex');
|
|
121
|
+
copyRecursive('AGENTS.md', 'AGENTS.md');
|
|
122
|
+
if (!isPlugin)
|
|
123
|
+
unlinkSafe(path.join(dstDir, '.agents', 'matterbridge.md'));
|
|
120
124
|
if (!isPlugin)
|
|
121
125
|
removeDirSafe(path.join(dstDir, '.codex', 'rules', 'matterbridge'));
|
|
122
126
|
}
|
|
@@ -339,6 +343,8 @@ export async function runPackageJsonUpgrade(opts, pkgPath, pkgJson, isMonorepo =
|
|
|
339
343
|
fileReplace('CHANGELOG.md', '(https://github.com/prettier/prettier)', '(https://prettier.io/)');
|
|
340
344
|
fileReplace('CHANGELOG.md', '(https://github.com/eslint/eslint)', '(https://eslint.org/)');
|
|
341
345
|
fileReplace('CHANGELOG.md', '(https://nodejs.org/api/esm.html)', '(https://nodejs.org/)');
|
|
346
|
+
if (isMonorepo)
|
|
347
|
+
return;
|
|
342
348
|
const scripts = pkgJson.scripts;
|
|
343
349
|
const startScript = scripts?.start ?? `node ${pkgJson.main ?? 'dist/module.js'}`;
|
|
344
350
|
log(magenta(`Start script: ${cyan(startScript)}`));
|
|
@@ -482,7 +488,7 @@ export async function runPackageJsonUpgrade(opts, pkgPath, pkgJson, isMonorepo =
|
|
|
482
488
|
log(green('Installing devDependencies...'));
|
|
483
489
|
const commands = [
|
|
484
490
|
`npm pkg delete overrides`,
|
|
485
|
-
`npm install --no-fund --no-audit --save-dev --save-exact typescript @types/node @typescript/native-preview oxlint oxlint-tsgolint oxfmt`,
|
|
491
|
+
`npm install --no-fund --no-audit --save-dev --save-exact typescript ${opts.useNode ? '@types/node' : ''} ${opts.useBun ? '@types/bun' : ''} @typescript/native-preview oxlint oxlint-tsgolint oxfmt`,
|
|
486
492
|
opts.enableJest ? `npm install --no-fund --no-audit --save-dev --save-exact jest ts-jest @types/jest @jest/globals cross-env` : null,
|
|
487
493
|
opts.enableVitest ? `npm install --no-fund --no-audit --save-dev --save-exact vitest @vitest/coverage-v8` : null,
|
|
488
494
|
opts.enableBundle ? 'npm install --no-fund --no-audit --save-dev --save-exact esbuild' : null,
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mb-run",
|
|
3
|
-
"version": "0.0.3
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "mb-run",
|
|
9
|
-
"version": "0.0.3
|
|
9
|
+
"version": "0.0.3",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"cross-spawn": "7.0.6",
|
package/package.json
CHANGED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# Matterbridge Endpoint Guide
|
|
2
|
+
|
|
3
|
+
Use this guide when writing Matterbridge code in this repository or when authoring a plugin that consumes Matterbridge.
|
|
4
|
+
|
|
5
|
+
## Public imports
|
|
6
|
+
|
|
7
|
+
- Import core classes, endpoint helpers, and device type definitions from `matterbridge`.
|
|
8
|
+
- Import single-class devices from `matterbridge/devices`.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import {
|
|
12
|
+
MatterbridgeAccessoryPlatform,
|
|
13
|
+
MatterbridgeDynamicPlatform,
|
|
14
|
+
MatterbridgeEndpoint,
|
|
15
|
+
addFixedLabel,
|
|
16
|
+
addUserLabel,
|
|
17
|
+
contactSensor,
|
|
18
|
+
getAttribute,
|
|
19
|
+
onOffLight,
|
|
20
|
+
powerSource,
|
|
21
|
+
setAttribute,
|
|
22
|
+
subscribeAttribute,
|
|
23
|
+
updateAttribute,
|
|
24
|
+
} from 'matterbridge';
|
|
25
|
+
|
|
26
|
+
import { LaundryWasher, RoboticVacuumCleaner } from 'matterbridge/devices';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Create a MatterbridgeEndpoint
|
|
30
|
+
|
|
31
|
+
`MatterbridgeEndpoint` is the low-level building block for custom Matterbridge devices.
|
|
32
|
+
|
|
33
|
+
Constructor:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
new MatterbridgeEndpoint(
|
|
37
|
+
definition: DeviceTypeDefinition | AtLeastOne<DeviceTypeDefinition>,
|
|
38
|
+
options: MatterbridgeEndpointOptions = {},
|
|
39
|
+
debug = false,
|
|
40
|
+
)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Recommended pattern:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
const device = new MatterbridgeEndpoint([contactSensor, powerSource], { id: 'EntryDoor' })
|
|
47
|
+
.createDefaultIdentifyClusterServer()
|
|
48
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('Entry Door', 'ENTRY-DOOR-001', 0xfff1, 'Matterbridge', 'Entry Door Sensor')
|
|
49
|
+
.createDefaultBooleanStateClusterServer(false)
|
|
50
|
+
.createDefaultPowerSourceReplaceableBatteryClusterServer(75)
|
|
51
|
+
.addRequiredClusters();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Rules that matter:
|
|
55
|
+
|
|
56
|
+
- `definition` can be a single device type or an array of device types.
|
|
57
|
+
- Use multiple device types when the endpoint needs more than one role, for example `[contactSensor, powerSource]`.
|
|
58
|
+
- Call one of the Basic Information helpers before `registerDevice()`. Without `deviceName`, `serialNumber`, and `uniqueId`, registration fails.
|
|
59
|
+
- Call `addRequiredClusters()` at the end of the chain so any required clusters (server or client) that you did not explicitly create are added automatically.
|
|
60
|
+
- Use `addOptionalClusterServers()` only when you really want the optional clusters defined by the selected device type(s).
|
|
61
|
+
|
|
62
|
+
## MatterbridgeEndpointOptions
|
|
63
|
+
|
|
64
|
+
`MatterbridgeEndpointOptions` supports:
|
|
65
|
+
|
|
66
|
+
- `id`: stable storage key for the endpoint.
|
|
67
|
+
- `number`: explicit endpoint number when you need one.
|
|
68
|
+
- `tagList`: semantic tags used for disambiguation, especially for composed devices or `mode: 'matter'` endpoints.
|
|
69
|
+
- `mode`: `undefined`, `'server'`, or `'matter'`.
|
|
70
|
+
|
|
71
|
+
Mode selection:
|
|
72
|
+
|
|
73
|
+
- `undefined`: normal bridged endpoint. This is the default for most DynamicPlatform devices.
|
|
74
|
+
- `'server'`: create an independent Matter device with its own server node.
|
|
75
|
+
- `'matter'`: add the endpoint directly to the Matterbridge server node alongside the aggregator.
|
|
76
|
+
|
|
77
|
+
Practical guidance:
|
|
78
|
+
|
|
79
|
+
- Use `mode: undefined` for normal bridged devices shown as children of the bridge.
|
|
80
|
+
- Use `mode: 'server'` when the device must be paired independently.
|
|
81
|
+
- Use `mode: 'matter'` when the device should be a native Matter endpoint on the server node.
|
|
82
|
+
- When using `mode: 'matter'`, respect Matter disambiguation rules and supply a `tagList` when sibling endpoints could be ambiguous.
|
|
83
|
+
|
|
84
|
+
Implementation details worth remembering:
|
|
85
|
+
|
|
86
|
+
- Spaces and `.` are removed from the internal endpoint id. The original value is retained as `originalId`.
|
|
87
|
+
- Non-Latin ids are normalized to a generated unique id.
|
|
88
|
+
- `id` should remain stable across restarts.
|
|
89
|
+
|
|
90
|
+
## Choose the right Basic Information helper
|
|
91
|
+
|
|
92
|
+
Use the helper that matches how the endpoint is exposed:
|
|
93
|
+
|
|
94
|
+
- `createDefaultBasicInformationClusterServer(...)`
|
|
95
|
+
Use for `mode: 'server'`, `mode: 'matter'`, and AccessoryPlatform devices.
|
|
96
|
+
- `createDefaultBridgedDeviceBasicInformationClusterServer(...)`
|
|
97
|
+
Use for bridged DynamicPlatform endpoints.
|
|
98
|
+
|
|
99
|
+
Important behavior:
|
|
100
|
+
|
|
101
|
+
- `createDefaultBasicInformationClusterServer(...)` sets the metadata on the endpoint.
|
|
102
|
+
- For bridged endpoints, `registerDevice()` can add the `BridgedDeviceBasicInformation` cluster automatically when the device is running as a bridged endpoint in bridge mode, or in childbridge mode on a `DynamicPlatform`.
|
|
103
|
+
- Explicitly calling `createDefaultBridgedDeviceBasicInformationClusterServer(...)` is clearer for bridged devices and matches the repo examples.
|
|
104
|
+
|
|
105
|
+
## Register the endpoint from a plugin
|
|
106
|
+
|
|
107
|
+
In plugin code, call `this.registerDevice(device)`.
|
|
108
|
+
|
|
109
|
+
DynamicPlatform bridged device:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { MatterbridgeDynamicPlatform, MatterbridgeEndpoint, onOffLight } from 'matterbridge';
|
|
113
|
+
|
|
114
|
+
export default function initializePlugin(matterbridge, log, config) {
|
|
115
|
+
return new ExamplePlatform(matterbridge, log, config);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
class ExamplePlatform extends MatterbridgeDynamicPlatform {
|
|
119
|
+
async onStart(reason) {
|
|
120
|
+
await this.ready;
|
|
121
|
+
|
|
122
|
+
const device = new MatterbridgeEndpoint(onOffLight, { id: 'OnOffLightPlugin' })
|
|
123
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('Kitchen Light', 'LIGHT-001', 0xfff1, 'Matterbridge', 'Matterbridge OnOffLight')
|
|
124
|
+
.addRequiredClusters();
|
|
125
|
+
|
|
126
|
+
await this.registerDevice(device);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
AccessoryPlatform device:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { MatterbridgeAccessoryPlatform, MatterbridgeEndpoint, temperatureSensor } from 'matterbridge';
|
|
135
|
+
|
|
136
|
+
export default function initializePlugin(matterbridge, log, config) {
|
|
137
|
+
return new ExamplePlatform(matterbridge, log, config);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
class ExamplePlatform extends MatterbridgeAccessoryPlatform {
|
|
141
|
+
async onStart(reason) {
|
|
142
|
+
await this.ready;
|
|
143
|
+
|
|
144
|
+
const device = new MatterbridgeEndpoint(temperatureSensor, { id: 'TemperatureSensorPlugin' })
|
|
145
|
+
.createDefaultBasicInformationClusterServer('Temperature Sensor', 'TEMP-001', 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Temperature Sensor')
|
|
146
|
+
.addRequiredClusters();
|
|
147
|
+
|
|
148
|
+
await this.registerDevice(device);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Standalone Matter device from a plugin:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
const device = new MatterbridgeEndpoint(pressureSensor, { id: 'ServerNodeDevice', mode: 'server' })
|
|
157
|
+
.createDefaultBasicInformationClusterServer('Server Node Device', 'SERVER-001', 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Server Node Device')
|
|
158
|
+
.addRequiredClusters();
|
|
159
|
+
|
|
160
|
+
await this.registerDevice(device);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Native Matter endpoint on the server node:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
const device = new MatterbridgeEndpoint(pressureSensor, { id: 'MatterNodeDevice', mode: 'matter' })
|
|
167
|
+
.createDefaultBasicInformationClusterServer('Matter Node Device', 'MATTER-001', 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Matter Node Device')
|
|
168
|
+
.addRequiredClusters();
|
|
169
|
+
|
|
170
|
+
await this.registerDevice(device);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Plugin rules:
|
|
174
|
+
|
|
175
|
+
- Use `await this.ready` before creating or registering devices.
|
|
176
|
+
- Always call `this.registerDevice(device)` from the platform.
|
|
177
|
+
- Use `this.unregisterDevice(device)` or `this.unregisterAllDevices()` during shutdown or development resets.
|
|
178
|
+
- AccessoryPlatform plugins can only expose one normal accessory device. If you need multiple bridged devices, use `MatterbridgeDynamicPlatform`.
|
|
179
|
+
- Use stable names and serial numbers so the derived `uniqueId` stays stable.
|
|
180
|
+
|
|
181
|
+
## Useful MatterbridgeEndpoint helpers
|
|
182
|
+
|
|
183
|
+
Common helpers on the endpoint instance:
|
|
184
|
+
|
|
185
|
+
- `hasClusterServer(cluster)`
|
|
186
|
+
- `hasAttributeServer(cluster, attribute)`
|
|
187
|
+
- `getAttribute(cluster, attribute)`
|
|
188
|
+
- `setAttribute(cluster, attribute, value)`
|
|
189
|
+
- `updateAttribute(cluster, attribute, value)`
|
|
190
|
+
- `subscribeAttribute(cluster, attribute, listener)`
|
|
191
|
+
- `addRequiredClusterServers()`
|
|
192
|
+
- `addOptionalClusterServers()`
|
|
193
|
+
- `addRequiredClusters()`
|
|
194
|
+
|
|
195
|
+
Example:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
await device.updateAttribute('OnOff', 'onOff', true);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Cluster references can be passed in several ways:
|
|
202
|
+
|
|
203
|
+
- behavior type
|
|
204
|
+
- cluster type
|
|
205
|
+
- cluster id
|
|
206
|
+
- cluster name string such as `'OnOff'`
|
|
207
|
+
|
|
208
|
+
Behavior type and cluster type are preferred because they are type-safe and avoid typos.
|
|
209
|
+
|
|
210
|
+
Using the cluster name string is useful in plugins because it avoids importing every cluster type.
|
|
211
|
+
|
|
212
|
+
## When to use a raw endpoint vs a single-class device
|
|
213
|
+
|
|
214
|
+
Use a raw `MatterbridgeEndpoint` when:
|
|
215
|
+
|
|
216
|
+
- you are building a custom combination of device types and clusters
|
|
217
|
+
- you want full control over which default cluster servers are created
|
|
218
|
+
- you are implementing a plugin-specific device model
|
|
219
|
+
|
|
220
|
+
Use a single-class device when:
|
|
221
|
+
|
|
222
|
+
- Matterbridge already ships a class for the device category you need
|
|
223
|
+
- you want a working device with sensible default clusters and behaviors
|
|
224
|
+
- you prefer a higher-level constructor over manual endpoint assembly
|
|
225
|
+
|
|
226
|
+
## Single-class devices
|
|
227
|
+
|
|
228
|
+
Single-class devices are exported from `matterbridge/devices`.
|
|
229
|
+
|
|
230
|
+
These classes already extend `MatterbridgeEndpoint` and usually do all of the following internally:
|
|
231
|
+
|
|
232
|
+
- create the correct device type combination
|
|
233
|
+
- create Basic Information
|
|
234
|
+
- create Power Source when needed
|
|
235
|
+
- create the default cluster servers and behavior wiring required by the device
|
|
236
|
+
|
|
237
|
+
Current exported single-class devices:
|
|
238
|
+
|
|
239
|
+
- Media: `BasicVideoPlayer`, `CastingVideoPlayer`, `Speaker`
|
|
240
|
+
- Matter 1.5 additions: `Closure`, `ClosurePanel`, `IrrigationSystem`, `SoilSensor`
|
|
241
|
+
- Robotic: `RoboticVacuumCleaner`
|
|
242
|
+
- Appliances: `AirConditioner`, `Cooktop`, `Dishwasher`, `ExtractorHood`, `LaundryDryer`, `LaundryWasher`, `MicrowaveOven`, `Oven`, `Refrigerator`
|
|
243
|
+
- Energy: `BatteryStorage`, `Evse`, `HeatPump`, `SolarPower`, `WaterHeater`
|
|
244
|
+
|
|
245
|
+
### Basic single-class example
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import { LaundryWasher } from 'matterbridge/devices';
|
|
249
|
+
|
|
250
|
+
const washer = new LaundryWasher('Laundry Washer', 'LW-001');
|
|
251
|
+
await this.registerDevice(washer);
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
This is enough because the class constructor already creates the required device types, basic information, power source, and default cluster servers.
|
|
255
|
+
|
|
256
|
+
### Single-class example with explicit mode
|
|
257
|
+
|
|
258
|
+
Some single-class devices expose `mode` directly in their constructor. For example:
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
import { RoboticVacuumCleaner } from 'matterbridge/devices';
|
|
262
|
+
|
|
263
|
+
const robot = new RoboticVacuumCleaner('Robot Vacuum', 'RVC-001', 'server');
|
|
264
|
+
await this.registerDevice(robot);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Use this when the class supports it and you want a standalone or native Matter device instead of a bridged endpoint.
|
|
268
|
+
|
|
269
|
+
### Composed single-class devices
|
|
270
|
+
|
|
271
|
+
Some single-class devices are composed devices and need child endpoints added after construction:
|
|
272
|
+
|
|
273
|
+
- `Oven`: create the oven, then call `addCabinet(...)`
|
|
274
|
+
- `Cooktop`: create the cooktop, then call `addSurface(...)`
|
|
275
|
+
- `Refrigerator`: create the refrigerator, then call `addCabinet(...)`
|
|
276
|
+
|
|
277
|
+
Example:
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
import { PositionTag } from '@matter/node';
|
|
281
|
+
import { Cooktop } from 'matterbridge/devices';
|
|
282
|
+
|
|
283
|
+
const cooktop = new Cooktop('Cooktop', 'CT-001');
|
|
284
|
+
cooktop.addSurface('Surface Top Left', [
|
|
285
|
+
{ mfgCode: null, namespaceId: PositionTag.Top.namespaceId, tag: PositionTag.Top.tag, label: PositionTag.Top.label },
|
|
286
|
+
{ mfgCode: null, namespaceId: PositionTag.Left.namespaceId, tag: PositionTag.Left.tag, label: PositionTag.Left.label },
|
|
287
|
+
]);
|
|
288
|
+
|
|
289
|
+
await this.registerDevice(cooktop);
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
For composed devices and for `mode: 'matter'`, use semantic tags carefully. `tagList` exists to satisfy Matter endpoint disambiguation rules.
|
|
293
|
+
|
|
294
|
+
## Recommended plugin workflow
|
|
295
|
+
|
|
296
|
+
For most plugins, follow this order:
|
|
297
|
+
|
|
298
|
+
1. Wait for `this.ready`.
|
|
299
|
+
2. Create the endpoint or single-class device.
|
|
300
|
+
3. Set device identity with one of the Basic Information helpers if you are using a raw `MatterbridgeEndpoint`.
|
|
301
|
+
4. Add explicit cluster servers you need.
|
|
302
|
+
5. Call `addRequiredClusterServers()` last.
|
|
303
|
+
6. Register the device with `await this.registerDevice(device)`.
|
|
304
|
+
7. Optionally add UI metadata with `setSelectDevice()` and `setSelectEntity()`.
|
|
305
|
+
|
|
306
|
+
## Avoid these mistakes
|
|
307
|
+
|
|
308
|
+
- Do not register a raw `MatterbridgeEndpoint` before assigning basic identity metadata.
|
|
309
|
+
- Do not use `MatterbridgeAccessoryPlatform` for multiple normal bridged accessories.
|
|
310
|
+
- Do not forget that some bridged endpoints need semantic tags for disambiguation.
|
|
311
|
+
- Do not assume single-class devices all share the same constructor shape. Check the device class when you need custom defaults or a mode argument.
|
|
312
|
+
- Do not call Matterbridge internals directly from plugin code when `registerDevice()` already handles validation and mode-specific setup.
|
|
313
|
+
|
|
314
|
+
## Short decision guide
|
|
315
|
+
|
|
316
|
+
- Need a custom sensor, switch, or actuator with a few clusters: use `MatterbridgeEndpoint`.
|
|
317
|
+
- Need a supported appliance, robotic, media, energy, closure, irrigation, or soil device: start with `matterbridge/devices`.
|
|
318
|
+
- Need one standalone accessory with its own server node: use `mode: 'server'` or a single-class device that exposes it.
|
|
319
|
+
- Need multiple bridged devices in a plugin: use `MatterbridgeDynamicPlatform`.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Testing Standards for Unit Tests
|
|
2
|
+
|
|
3
|
+
## 1. Test Framework
|
|
4
|
+
|
|
5
|
+
- Jest is available in the repository when the file `jest.config.js` exists.
|
|
6
|
+
- Vitest is available in the repository when the file `vite.config.ts` exists.
|
|
7
|
+
- Bun test is available in the repository when the file `bunfig.toml` exists.
|
|
8
|
+
- Jest tests live in `test` folders. Follow the existing convention in the repository for test file placement.
|
|
9
|
+
- Vitest tests live in `vitest` folders. Follow the existing convention in the repository for test file placement.
|
|
10
|
+
- Bun test tests live in `buntest` folders. Follow the existing convention in the repository for test file placement.
|
|
11
|
+
- Ensure that tests are written in TypeScript and follow the ESM module format.
|
|
12
|
+
|
|
13
|
+
## 2. Test Structure
|
|
14
|
+
|
|
15
|
+
- Organize tests in file name `*.test.ts` in the `test`, `vitest`, or `buntest` folders.
|
|
16
|
+
- Use `describe` blocks to group related tests and `test` blocks for individual test cases.
|
|
17
|
+
|
|
18
|
+
## 3. Test Naming
|
|
19
|
+
|
|
20
|
+
- Use descriptive test names that clearly indicate the behavior being tested.
|
|
21
|
+
- Follow the format: `should [expected behavior] when [condition]`.
|
|
22
|
+
|
|
23
|
+
## 4. Test Data
|
|
24
|
+
|
|
25
|
+
- Use small, deterministic test data to ensure tests are reliable and easy to understand.
|
|
26
|
+
|
|
27
|
+
## 5. Test Coverage
|
|
28
|
+
|
|
29
|
+
- Aim for high test coverage, but prioritize meaningful tests over achieving 100% coverage.
|
|
30
|
+
|
|
31
|
+
## 6. Mocking with Jest
|
|
32
|
+
|
|
33
|
+
- If using Jest, use `jest.unstable_mockModule` for mocking dependencies in ESM modules.
|
|
34
|
+
- If using Jest, avoid using `jest.mock` as it is not compatible with ESM modules.
|
|
35
|
+
|
|
36
|
+
## 7. Running Tests
|
|
37
|
+
|
|
38
|
+
- Run the relevant full test unit from start to finish rather than assuming isolated single-test execution is reliable.
|
|
39
|
+
- If only one test framework is installed, use `npm run test -- yourTest.test.ts` or `npm run test:coverage -- yourTest.test.ts` when the touched area can be validated by running the full relevant test file.
|
|
40
|
+
- When both Jest and Vitest are installed, use `npm run test -- yourTest.test.ts` for Jest or `npm run test:vitest -- yourTest.test.ts` for Vitest.
|
|
41
|
+
- When Bun test is installed, use `bun test yourTest.test.ts`.
|
|
42
|
+
- Use the existing `tasks.json` test tasks for areas that require grouped test files, custom coverage targets, or custom ignore-pattern handling.
|
|
43
|
+
- Avoid running all tests unnecessarily to save time and tokens.
|
|
44
|
+
|
|
45
|
+
## 8. Test Assertions
|
|
46
|
+
|
|
47
|
+
- Use appropriate Jest, Vitest, or Bun test matchers for assertions (e.g., `toBe`, `toEqual`, `toThrow`).
|
|
48
|
+
- Ensure that assertions are clear and directly related to the behavior being tested.
|
|
49
|
+
|
|
50
|
+
## 9. Performance
|
|
51
|
+
|
|
52
|
+
- Avoid optimization in tests; focus on correctness and clarity.
|
|
53
|
+
- Use simple loops and structures in tests to maintain readability and performance.
|
|
54
|
+
- Avoid complex setups that may slow down test execution unless necessary for the behavior being tested.
|
|
55
|
+
- Prefer simple test cases that are easy to understand and maintain over complex ones that may be difficult to debug.
|
|
56
|
+
- Some tests in this repo are intentionally structured as multi-step flows, where state persists across successive steps within a single test unit. Run those test units in full, and keep each test unit isolated from other test units.
|
|
@@ -114,7 +114,7 @@ Important behavior:
|
|
|
114
114
|
|
|
115
115
|
## Register the endpoint from a plugin
|
|
116
116
|
|
|
117
|
-
In plugin code,
|
|
117
|
+
In plugin code, call `this.registerDevice(device)`.
|
|
118
118
|
|
|
119
119
|
DynamicPlatform bridged device:
|
|
120
120
|
|
|
@@ -137,7 +137,7 @@ class ExamplePlatform extends MatterbridgeDynamicPlatform {
|
|
|
137
137
|
'Matterbridge',
|
|
138
138
|
'Matterbridge OnOffLight',
|
|
139
139
|
)
|
|
140
|
-
.
|
|
140
|
+
.addRequiredClusters();
|
|
141
141
|
|
|
142
142
|
await this.registerDevice(device);
|
|
143
143
|
}
|
|
@@ -166,7 +166,7 @@ class ExamplePlatform extends MatterbridgeAccessoryPlatform {
|
|
|
166
166
|
0x8000,
|
|
167
167
|
'Matterbridge Temperature Sensor',
|
|
168
168
|
)
|
|
169
|
-
.
|
|
169
|
+
.addRequiredClusters();
|
|
170
170
|
|
|
171
171
|
await this.registerDevice(device);
|
|
172
172
|
}
|
|
@@ -185,7 +185,7 @@ const device = new MatterbridgeEndpoint(pressureSensor, { id: 'ServerNodeDevice'
|
|
|
185
185
|
0x8000,
|
|
186
186
|
'Matterbridge Server Node Device',
|
|
187
187
|
)
|
|
188
|
-
.
|
|
188
|
+
.addRequiredClusters();
|
|
189
189
|
|
|
190
190
|
await this.registerDevice(device);
|
|
191
191
|
```
|
|
@@ -202,14 +202,14 @@ const device = new MatterbridgeEndpoint(pressureSensor, { id: 'MatterNodeDevice'
|
|
|
202
202
|
0x8000,
|
|
203
203
|
'Matterbridge Matter Node Device',
|
|
204
204
|
)
|
|
205
|
-
.
|
|
205
|
+
.addRequiredClusters();
|
|
206
206
|
|
|
207
207
|
await this.registerDevice(device);
|
|
208
208
|
```
|
|
209
209
|
|
|
210
210
|
Plugin rules:
|
|
211
211
|
|
|
212
|
-
- `await this.ready` before creating or registering devices.
|
|
212
|
+
- Use `await this.ready` before creating or registering devices.
|
|
213
213
|
- Always call `this.registerDevice(device)` from the platform.
|
|
214
214
|
- Use `this.unregisterDevice(device)` or `this.unregisterAllDevices()` during shutdown or development resets.
|
|
215
215
|
- AccessoryPlatform plugins can only expose one normal accessory device. If you need multiple bridged devices, use `MatterbridgeDynamicPlatform`.
|
|
@@ -115,7 +115,7 @@ Important behavior:
|
|
|
115
115
|
|
|
116
116
|
## Register the endpoint from a plugin
|
|
117
117
|
|
|
118
|
-
In plugin code,
|
|
118
|
+
In plugin code, call `this.registerDevice(device)`.
|
|
119
119
|
|
|
120
120
|
DynamicPlatform bridged device:
|
|
121
121
|
|
|
@@ -138,7 +138,7 @@ class ExamplePlatform extends MatterbridgeDynamicPlatform {
|
|
|
138
138
|
'Matterbridge',
|
|
139
139
|
'Matterbridge OnOffLight',
|
|
140
140
|
)
|
|
141
|
-
.
|
|
141
|
+
.addRequiredClusters();
|
|
142
142
|
|
|
143
143
|
await this.registerDevice(device);
|
|
144
144
|
}
|
|
@@ -167,7 +167,7 @@ class ExamplePlatform extends MatterbridgeAccessoryPlatform {
|
|
|
167
167
|
0x8000,
|
|
168
168
|
'Matterbridge Temperature Sensor',
|
|
169
169
|
)
|
|
170
|
-
.
|
|
170
|
+
.addRequiredClusters();
|
|
171
171
|
|
|
172
172
|
await this.registerDevice(device);
|
|
173
173
|
}
|
|
@@ -186,7 +186,7 @@ const device = new MatterbridgeEndpoint(pressureSensor, { id: 'ServerNodeDevice'
|
|
|
186
186
|
0x8000,
|
|
187
187
|
'Matterbridge Server Node Device',
|
|
188
188
|
)
|
|
189
|
-
.
|
|
189
|
+
.addRequiredClusters();
|
|
190
190
|
|
|
191
191
|
await this.registerDevice(device);
|
|
192
192
|
```
|
|
@@ -203,14 +203,14 @@ const device = new MatterbridgeEndpoint(pressureSensor, { id: 'MatterNodeDevice'
|
|
|
203
203
|
0x8000,
|
|
204
204
|
'Matterbridge Matter Node Device',
|
|
205
205
|
)
|
|
206
|
-
.
|
|
206
|
+
.addRequiredClusters();
|
|
207
207
|
|
|
208
208
|
await this.registerDevice(device);
|
|
209
209
|
```
|
|
210
210
|
|
|
211
211
|
Plugin rules:
|
|
212
212
|
|
|
213
|
-
- `await this.ready` before creating or registering devices.
|
|
213
|
+
- Use `await this.ready` before creating or registering devices.
|
|
214
214
|
- Always call `this.registerDevice(device)` from the platform.
|
|
215
215
|
- Use `this.unregisterDevice(device)` or `this.unregisterAllDevices()` during shutdown or development resets.
|
|
216
216
|
- AccessoryPlatform plugins can only expose one normal accessory device. If you need multiple bridged devices, use `MatterbridgeDynamicPlatform`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// VS Code settings native v. 1.0.
|
|
1
|
+
// VS Code settings native v. 1.0.7
|
|
2
2
|
{
|
|
3
3
|
"npm.packageManager": "npm",
|
|
4
4
|
"eslint.enable": false,
|
|
@@ -44,20 +44,29 @@
|
|
|
44
44
|
"git.autofetch": true,
|
|
45
45
|
"git.autoRepositoryDetection": false,
|
|
46
46
|
// VS Code's Copilot Chat extension settings
|
|
47
|
-
"chat.useCustomizationsInParentRepositories": true,
|
|
48
|
-
"chat.useAgentsMdFile": true,
|
|
49
|
-
"chat.useClaudeMdFile": true,
|
|
50
|
-
"chat.instructionsFilesLocations": {
|
|
51
|
-
".github/instructions": true,
|
|
52
|
-
".claude/rules": true,
|
|
53
|
-
"~/.copilot/instructions": true,
|
|
54
|
-
"~/.claude/rules": true
|
|
55
|
-
},
|
|
47
|
+
"chat.useCustomizationsInParentRepositories": true, // Default false.
|
|
56
48
|
"chat.tools.terminal.autoApprove": {
|
|
57
49
|
"npx tsc": true,
|
|
58
50
|
"npx tsgo": true,
|
|
59
51
|
"npx oxlint": true,
|
|
60
52
|
"npx oxfmt": true,
|
|
61
|
-
"npx vitest": true
|
|
53
|
+
"npx vitest": true,
|
|
54
|
+
"npm run build": true,
|
|
55
|
+
"npm run typecheck": true,
|
|
56
|
+
"npm run lint": true,
|
|
57
|
+
"npm run format:check": true,
|
|
58
|
+
"npm run test": true,
|
|
59
|
+
"npm run test:coverage": true,
|
|
60
|
+
"npm run update-htmls": true,
|
|
61
|
+
"git status": true,
|
|
62
|
+
"git diff": true,
|
|
63
|
+
"git diff --check": true,
|
|
64
|
+
"git diff --stat": true,
|
|
65
|
+
"git log": true,
|
|
66
|
+
"git show": true,
|
|
67
|
+
"git branch -vv": true,
|
|
68
|
+
"git ls-files": true,
|
|
69
|
+
"git --no-pager diff --stat": true,
|
|
70
|
+
"git --no-pager diff --check": true
|
|
62
71
|
}
|
|
63
72
|
}
|
package/vendor/AGENTS.md
CHANGED
|
@@ -3,24 +3,24 @@
|
|
|
3
3
|
## Style And Formatting
|
|
4
4
|
|
|
5
5
|
- Follow [STYLEGUIDE.md](./STYLEGUIDE.md) for code style, naming, JSDoc, validation, logging, and formatting expectations.
|
|
6
|
-
- JSDoc requirements are enforced by
|
|
7
|
-
- Import and export ordering are enforced by
|
|
8
|
-
-
|
|
6
|
+
- JSDoc requirements are enforced by the linter. Treat missing or incomplete JSDoc on required APIs as a real lint issue, not optional documentation.
|
|
7
|
+
- Import and export ordering are enforced by the linter or by theformater. Preserve the existing grouped and sorted order unless a change requires updating it.
|
|
8
|
+
- Follow the existing formatting and do not fight the formatter.
|
|
9
9
|
|
|
10
10
|
## Scope And Safety
|
|
11
11
|
|
|
12
12
|
- Keep changes minimal and scoped to the request. Avoid unrelated refactors or broad cleanup.
|
|
13
13
|
- Do not modify production code only to make a test pass. If a failing test points to a likely source issue, explain the issue and change behavior only when required by the task.
|
|
14
14
|
- Preserve cross-platform behavior. Changes must work on Windows, macOS, and Linux, especially for paths, shell commands, environment variables, and networking behavior.
|
|
15
|
-
- Maintain compatibility with the supported Node.js versions in this repository: 20, 22, 24 and 26.
|
|
15
|
+
- Maintain compatibility with the supported Node.js versions in this repository: 20.19, 22.13, 24.0 and 26.0.
|
|
16
16
|
|
|
17
17
|
## Project Architecture
|
|
18
18
|
|
|
19
|
-
- This repository is a TypeScript ESM
|
|
19
|
+
- This repository is a TypeScript ESM repo. Follow existing project patterns for imports, exports, build configuration, and test setup.
|
|
20
20
|
|
|
21
21
|
## Testing And Validation
|
|
22
22
|
|
|
23
|
-
- Prefer the existing npm scripts in [package.json](./package.json) and the
|
|
23
|
+
- Prefer the existing npm scripts in [package.json](./package.json) and the VS Code tasks in [tasks.json](./.vscode/tasks.json) when validating changes.
|
|
24
24
|
- Keep tests deterministic and simple. Prefer small data sets and straightforward setup.
|
|
25
25
|
- Some tests are intentionally multi-step flows. State may persist across successive steps within a single test flow, but each test unit must remain isolated from other tests.
|
|
26
26
|
- For validation, run the relevant full test file or the matching suite/task for the touched area rather than assuming arbitrary isolated single-test execution is reliable.
|
|
@@ -28,3 +28,10 @@
|
|
|
28
28
|
## Documentation
|
|
29
29
|
|
|
30
30
|
- When behavior changes, update the relevant tests and documentation.
|
|
31
|
+
|
|
32
|
+
## Additional Agent Guidance
|
|
33
|
+
|
|
34
|
+
For task-specific guidance, read relevant files in `.agents/`:
|
|
35
|
+
|
|
36
|
+
- `.agents/testing.md` for testing and validation expectations
|
|
37
|
+
- `.agents/matterbridge.md` for instruction about using matterbridge in a plugin
|