@agentdeck/bridge 1.0.3 → 1.0.4

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.
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Optional Python runtime used by the terminal-managed BLE device clients.
3
+ *
4
+ * The npm package owns the Python scripts, while the writable virtual
5
+ * environment lives under ~/.agentdeck so a global npm upgrade cannot erase it.
6
+ * Explicit BLE CLI commands may prepare the environment; daemon startup only
7
+ * inspects it and never performs network installation on its own.
8
+ */
9
+ import { type SpawnSyncOptions } from 'child_process';
10
+ export interface BleRuntimePaths {
11
+ packageRoot: string;
12
+ dataDir: string;
13
+ runtimeDir: string;
14
+ venvDir: string;
15
+ venvPython: string;
16
+ legacyPython: string;
17
+ requirements: string;
18
+ readyMarker: string;
19
+ scripts: {
20
+ idotmatrixScan: string;
21
+ idotmatrixBrightness: string;
22
+ idotmatrixSync: string;
23
+ timeboxScan: string;
24
+ timeboxSync: string;
25
+ sharedSync: string;
26
+ };
27
+ }
28
+ export interface BleRuntimeOptions {
29
+ packageRoot?: string;
30
+ dataDir?: string;
31
+ platform?: NodeJS.Platform;
32
+ env?: NodeJS.ProcessEnv;
33
+ log?: (message: string) => void;
34
+ run?: BleCommandRunner;
35
+ }
36
+ export interface BleRuntimeStatus {
37
+ ready: boolean;
38
+ python?: string;
39
+ paths: BleRuntimePaths;
40
+ reason?: string;
41
+ }
42
+ interface CommandResult {
43
+ status: number | null;
44
+ error?: Error;
45
+ }
46
+ type BleCommandRunner = (command: string, args: string[], options?: SpawnSyncOptions) => CommandResult;
47
+ export declare function resolveBleRuntimePaths(options?: BleRuntimeOptions): BleRuntimePaths;
48
+ /**
49
+ * Read-only daemon probe. It deliberately does not run Python or install
50
+ * packages, so daemon startup remains deterministic and offline-safe.
51
+ */
52
+ export declare function getBleRuntimeStatus(options?: BleRuntimeOptions): BleRuntimeStatus;
53
+ /**
54
+ * Ensure the optional BLE dependencies exist. This is called only from an
55
+ * explicit BLE command (`ble setup`, scan, brightness, test, or sync).
56
+ */
57
+ export declare function ensureBleRuntime(options?: BleRuntimeOptions): BleRuntimeStatus & {
58
+ ready: true;
59
+ python: string;
60
+ };
61
+ export {};
62
+ //# sourceMappingURL=python-ble-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"python-ble-runtime.d.ts","sourceRoot":"","sources":["../src/python-ble-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAOjE,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QACP,cAAc,EAAE,MAAM,CAAC;QACvB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,GAAG,CAAC,EAAE,gBAAgB,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,KAAK,gBAAgB,GAAG,CACtB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,gBAAgB,KACvB,aAAa,CAAC;AAcnB,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,iBAAsB,GAAG,eAAe,CA4BvF;AAoBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAkCrF;AAsDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAgFpH"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Optional Python runtime used by the terminal-managed BLE device clients.
3
+ *
4
+ * The npm package owns the Python scripts, while the writable virtual
5
+ * environment lives under ~/.agentdeck so a global npm upgrade cannot erase it.
6
+ * Explicit BLE CLI commands may prepare the environment; daemon startup only
7
+ * inspects it and never performs network installation on its own.
8
+ */
9
+ import { spawnSync } from 'child_process';
10
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
11
+ import { homedir } from 'os';
12
+ import { dirname, join } from 'path';
13
+ import { fileURLToPath } from 'url';
14
+ import { createHash } from 'crypto';
15
+ function defaultPackageRoot() {
16
+ // Source: bridge/src/python-ble-runtime.ts
17
+ // Build: bridge/dist/python-ble-runtime.js
18
+ return join(dirname(fileURLToPath(import.meta.url)), '..');
19
+ }
20
+ function pythonInVenv(venvDir, platform) {
21
+ return platform === 'win32'
22
+ ? join(venvDir, 'Scripts', 'python.exe')
23
+ : join(venvDir, 'bin', 'python');
24
+ }
25
+ export function resolveBleRuntimePaths(options = {}) {
26
+ const env = options.env ?? process.env;
27
+ const platform = options.platform ?? process.platform;
28
+ const packageRoot = options.packageRoot ?? defaultPackageRoot();
29
+ const dataDir = options.dataDir ?? env.AGENTDECK_DATA_DIR ?? join(homedir(), '.agentdeck');
30
+ const runtimeDir = join(dataDir, 'python-ble');
31
+ const venvDir = join(runtimeDir, 'venv');
32
+ const scriptsRoot = join(packageRoot, 'src');
33
+ const legacyVenvDir = join(packageRoot, '..', '.venv');
34
+ return {
35
+ packageRoot,
36
+ dataDir,
37
+ runtimeDir,
38
+ venvDir,
39
+ venvPython: pythonInVenv(venvDir, platform),
40
+ legacyPython: pythonInVenv(legacyVenvDir, platform),
41
+ requirements: join(packageRoot, 'python', 'requirements-ble.txt'),
42
+ readyMarker: join(runtimeDir, 'ready.json'),
43
+ scripts: {
44
+ idotmatrixScan: join(scriptsRoot, 'idotmatrix', 'scan.py'),
45
+ idotmatrixBrightness: join(scriptsRoot, 'idotmatrix', 'brightness.py'),
46
+ idotmatrixSync: join(scriptsRoot, 'idotmatrix', 'sync.py'),
47
+ timeboxScan: join(scriptsRoot, 'timebox', 'scan_ble.py'),
48
+ timeboxSync: join(scriptsRoot, 'timebox', 'sync_ble.py'),
49
+ sharedSync: join(scriptsRoot, 'pysync', 'matrix_sync_common.py'),
50
+ },
51
+ };
52
+ }
53
+ function packagedAssetsMissing(paths) {
54
+ return [paths.requirements, ...Object.values(paths.scripts)].filter((path) => !existsSync(path));
55
+ }
56
+ function requirementsDigest(paths) {
57
+ return createHash('sha256').update(readFileSync(paths.requirements)).digest('hex');
58
+ }
59
+ function readyMarkerMatches(paths) {
60
+ if (!existsSync(paths.readyMarker))
61
+ return false;
62
+ try {
63
+ const marker = JSON.parse(readFileSync(paths.readyMarker, 'utf8'));
64
+ return marker.requirementsSha256 === requirementsDigest(paths);
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ }
70
+ /**
71
+ * Read-only daemon probe. It deliberately does not run Python or install
72
+ * packages, so daemon startup remains deterministic and offline-safe.
73
+ */
74
+ export function getBleRuntimeStatus(options = {}) {
75
+ const env = options.env ?? process.env;
76
+ const paths = resolveBleRuntimePaths(options);
77
+ const missing = packagedAssetsMissing(paths);
78
+ if (missing.length > 0) {
79
+ return {
80
+ ready: false,
81
+ paths,
82
+ reason: `npm package is missing ${missing.map((path) => path.slice(paths.packageRoot.length + 1)).join(', ')}`,
83
+ };
84
+ }
85
+ const override = env.AGENTDECK_BLE_PYTHON;
86
+ if (override) {
87
+ return existsSync(override)
88
+ ? { ready: true, python: override, paths }
89
+ : { ready: false, paths, reason: `AGENTDECK_BLE_PYTHON does not exist: ${override}` };
90
+ }
91
+ if (existsSync(paths.venvPython) && readyMarkerMatches(paths)) {
92
+ return { ready: true, python: paths.venvPython, paths };
93
+ }
94
+ // Preserve source-checkout and pre-1.0.4 manual environments. An explicit BLE
95
+ // command will import-probe this interpreter before using it.
96
+ if (existsSync(paths.legacyPython)) {
97
+ return { ready: true, python: paths.legacyPython, paths };
98
+ }
99
+ return {
100
+ ready: false,
101
+ paths,
102
+ reason: 'optional BLE runtime is not prepared',
103
+ };
104
+ }
105
+ function defaultRun(command, args, options) {
106
+ const result = spawnSync(command, args, options);
107
+ return {
108
+ status: result.status,
109
+ error: result.error,
110
+ };
111
+ }
112
+ function commandSucceeded(run, command, args, options = {}) {
113
+ const result = run(command, args, { ...options, stdio: options.stdio ?? 'ignore' });
114
+ return !result.error && result.status === 0;
115
+ }
116
+ function dependencyProbe(run, python) {
117
+ return commandSucceeded(run, python, [
118
+ '-c',
119
+ 'import bleak; import PIL; import idotmatrix',
120
+ ]);
121
+ }
122
+ function systemPython(run, platform) {
123
+ const candidates = platform === 'win32'
124
+ ? [
125
+ { command: 'py', prefix: ['-3'] },
126
+ { command: 'python3', prefix: [] },
127
+ { command: 'python', prefix: [] },
128
+ ]
129
+ : [
130
+ { command: 'python3', prefix: [] },
131
+ { command: 'python', prefix: [] },
132
+ ];
133
+ for (const candidate of candidates) {
134
+ if (commandSucceeded(run, candidate.command, [
135
+ ...candidate.prefix,
136
+ '-c',
137
+ 'import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)',
138
+ ])) {
139
+ return candidate;
140
+ }
141
+ }
142
+ return null;
143
+ }
144
+ /**
145
+ * Ensure the optional BLE dependencies exist. This is called only from an
146
+ * explicit BLE command (`ble setup`, scan, brightness, test, or sync).
147
+ */
148
+ export function ensureBleRuntime(options = {}) {
149
+ const env = options.env ?? process.env;
150
+ const platform = options.platform ?? process.platform;
151
+ const paths = resolveBleRuntimePaths(options);
152
+ const log = options.log ?? (() => { });
153
+ const run = options.run ?? defaultRun;
154
+ const missing = packagedAssetsMissing(paths);
155
+ if (missing.length > 0) {
156
+ throw new Error(`The installed @agentdeck/bridge package is missing BLE assets: ${missing.join(', ')}. ` +
157
+ 'Reinstall @agentdeck/setup, then try again.');
158
+ }
159
+ const override = env.AGENTDECK_BLE_PYTHON;
160
+ if (override) {
161
+ if (!existsSync(override)) {
162
+ throw new Error(`AGENTDECK_BLE_PYTHON does not exist: ${override}`);
163
+ }
164
+ if (!dependencyProbe(run, override)) {
165
+ throw new Error(`AGENTDECK_BLE_PYTHON cannot import bleak, Pillow, and idotmatrix: ${override}. ` +
166
+ `Install the dependencies from ${paths.requirements}.`);
167
+ }
168
+ return { ready: true, python: override, paths };
169
+ }
170
+ if (existsSync(paths.venvPython) && dependencyProbe(run, paths.venvPython)) {
171
+ mkdirSync(paths.runtimeDir, { recursive: true });
172
+ writeFileSync(paths.readyMarker, JSON.stringify({
173
+ requirementsSha256: requirementsDigest(paths),
174
+ preparedAt: new Date().toISOString(),
175
+ }, null, 2) + '\n');
176
+ return { ready: true, python: paths.venvPython, paths };
177
+ }
178
+ if (existsSync(paths.legacyPython) && dependencyProbe(run, paths.legacyPython)) {
179
+ return { ready: true, python: paths.legacyPython, paths };
180
+ }
181
+ const python = systemPython(run, platform);
182
+ if (!python) {
183
+ throw new Error('Python 3.10 or newer is required for optional BLE device support.');
184
+ }
185
+ mkdirSync(paths.runtimeDir, { recursive: true });
186
+ log(`Preparing optional BLE support in ${paths.runtimeDir}...`);
187
+ const create = run(python.command, [
188
+ ...python.prefix,
189
+ '-m',
190
+ 'venv',
191
+ paths.venvDir,
192
+ ], { stdio: 'inherit' });
193
+ if (create.error || create.status !== 0 || !existsSync(paths.venvPython)) {
194
+ throw new Error(`Failed to create the BLE Python environment at ${paths.venvDir}.`);
195
+ }
196
+ const install = run(paths.venvPython, [
197
+ '-m',
198
+ 'pip',
199
+ 'install',
200
+ '--disable-pip-version-check',
201
+ '--requirement',
202
+ paths.requirements,
203
+ ], { stdio: 'inherit' });
204
+ if (install.error || install.status !== 0 || !dependencyProbe(run, paths.venvPython)) {
205
+ throw new Error(`Failed to install optional BLE dependencies. Retry with \`agentdeck ble setup\` ` +
206
+ `or inspect ${paths.requirements}.`);
207
+ }
208
+ writeFileSync(paths.readyMarker, JSON.stringify({
209
+ requirementsSha256: requirementsDigest(paths),
210
+ preparedAt: new Date().toISOString(),
211
+ }, null, 2) + '\n');
212
+ log('Optional BLE support is ready.');
213
+ return { ready: true, python: paths.venvPython, paths };
214
+ }
215
+ //# sourceMappingURL=python-ble-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"python-ble-runtime.js","sourceRoot":"","sources":["../src/python-ble-runtime.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"timebox-daemon-sync.d.ts","sourceRoot":"","sources":["../../src/timebox/timebox-daemon-sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAwCH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CA6BvD;AAiDD;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,aAAa,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB1E"}
1
+ {"version":3,"file":"timebox-daemon-sync.d.ts","sourceRoot":"","sources":["../../src/timebox/timebox-daemon-sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4BH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAyBvD;AAiDD;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,aAAa,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB1E"}
@@ -5,11 +5,9 @@
5
5
  * (bleak/GATT). Node has no built-in BLE support, so we spawn the small Python
6
6
  * writer. This code is terminal-managed CLI daemon only.
7
7
  */
8
- import { existsSync } from 'fs';
9
- import { dirname, join } from 'path';
10
- import { fileURLToPath } from 'url';
11
8
  import { deviceId, loadTimeboxDevices } from './timebox-settings.js';
12
9
  import { createSyncCycleSquelch, spawnPythonSync, terminateSyncChild } from '../ble-sync-spawn.js';
10
+ import { getBleRuntimeStatus } from '../python-ble-runtime.js';
13
11
  const entries = new Map();
14
12
  const BASE_BACKOFF_MS = 5_000;
15
13
  const MAX_BACKOFF_MS = 60_000;
@@ -17,32 +15,19 @@ const HEALTHY_UPTIME_MS = 30_000;
17
15
  function log(msg) {
18
16
  console.error(`[agentdeck] [timebox] ${msg}`);
19
17
  }
20
- function resolvePaths() {
21
- const here = dirname(fileURLToPath(import.meta.url));
22
- const projectRoot = join(here, '..', '..', '..');
23
- const timeboxDir = join(projectRoot, 'bridge', 'src', 'timebox');
24
- return {
25
- venvPython: join(projectRoot, '.venv', 'bin', 'python'),
26
- bleScript: join(timeboxDir, 'sync_ble.py'),
27
- };
28
- }
29
18
  export function startTimeboxSync(httpPort) {
30
19
  const devices = loadTimeboxDevices();
31
20
  if (devices.length === 0)
32
21
  return;
33
- const { venvPython, bleScript } = resolvePaths();
34
- if (!existsSync(venvPython)) {
35
- log('sync unavailable (missing Python venv (.venv)); Timebox Mini will not be driven by the daemon');
22
+ const runtime = getBleRuntimeStatus();
23
+ if (!runtime.ready || !runtime.python) {
24
+ log(`sync unavailable (${runtime.reason}); run \`agentdeck ble setup\``);
36
25
  return;
37
26
  }
38
27
  for (const device of devices) {
39
28
  const id = deviceId(device);
40
29
  if (!id || entries.has(id))
41
30
  continue;
42
- if (!existsSync(bleScript)) {
43
- log(`sync unavailable (missing sync_ble.py) for ${id}`);
44
- continue;
45
- }
46
31
  const entry = {
47
32
  device,
48
33
  child: null,
@@ -53,7 +38,7 @@ export function startTimeboxSync(httpPort) {
53
38
  squelch: createSyncCycleSquelch(log),
54
39
  };
55
40
  entries.set(id, entry);
56
- spawnSync(entry, venvPython, bleScript, httpPort);
41
+ spawnSync(entry, runtime.python, runtime.paths.scripts.timeboxSync, httpPort);
57
42
  }
58
43
  }
59
44
  function spawnSync(entry, venvPython, syncScript, httpPort) {
@@ -1 +1 @@
1
- {"version":3,"file":"timebox-daemon-sync.js","sourceRoot":"","sources":["../../src/timebox/timebox-daemon-sync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"timebox-daemon-sync.js","sourceRoot":"","sources":["../../src/timebox/timebox-daemon-sync.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"timebox-discover.d.ts","sourceRoot":"","sources":["../../src/timebox/timebox-discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAkEH;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAc3D"}
1
+ {"version":3,"file":"timebox-discover.d.ts","sourceRoot":"","sources":["../../src/timebox/timebox-discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAsDH;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAiB3D"}
@@ -12,22 +12,11 @@
12
12
  * the App Store Swift build, which does BLE discovery natively via CoreBluetooth.
13
13
  */
14
14
  import { spawn } from 'child_process';
15
- import { existsSync } from 'fs';
16
- import { dirname, join } from 'path';
17
- import { fileURLToPath } from 'url';
18
15
  import { addTimeboxDevice, isTimeboxAutoDiscoverEnabled, loadTimeboxDevices, } from './timebox-settings.js';
16
+ import { getBleRuntimeStatus } from '../python-ble-runtime.js';
19
17
  function log(msg) {
20
18
  console.error(`[agentdeck] [timebox] ${msg}`);
21
19
  }
22
- function resolvePaths() {
23
- const here = dirname(fileURLToPath(import.meta.url));
24
- const projectRoot = join(here, '..', '..', '..');
25
- const timeboxDir = join(projectRoot, 'bridge', 'src', 'timebox');
26
- return {
27
- venvPython: join(projectRoot, '.venv', 'bin', 'python'),
28
- scanScript: join(timeboxDir, 'scan_ble.py'),
29
- };
30
- }
31
20
  /** Run scan_ble.py and parse its JSON, with a hard outer timeout. */
32
21
  function runScan(venvPython, scanScript, timeoutMs) {
33
22
  return new Promise((resolve) => {
@@ -72,10 +61,12 @@ export async function autoDiscoverTimebox() {
72
61
  return 0;
73
62
  if (loadTimeboxDevices().length > 0)
74
63
  return 0; // only when nothing configured
75
- const { venvPython, scanScript } = resolvePaths();
76
- if (!existsSync(venvPython) || !existsSync(scanScript))
64
+ const runtime = getBleRuntimeStatus();
65
+ if (!runtime.ready || !runtime.python) {
66
+ log(`auto-discovery unavailable (${runtime.reason}); run \`agentdeck ble setup\``);
77
67
  return 0;
78
- const results = await runScan(venvPython, scanScript, 8_000);
68
+ }
69
+ const results = await runScan(runtime.python, runtime.paths.scripts.timeboxScan, 8_000);
79
70
  const match = results.find((r) => r.is_timebox && r.address);
80
71
  if (!match)
81
72
  return 0;
@@ -1 +1 @@
1
- {"version":3,"file":"timebox-discover.js","sourceRoot":"","sources":["../../src/timebox/timebox-discover.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"timebox-discover.js","sourceRoot":"","sources":["../../src/timebox/timebox-discover.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentdeck/bridge",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -14,7 +14,11 @@
14
14
  "assets/fonts",
15
15
  "assets/fm-helper",
16
16
  "fm-helper",
17
- "scripts/build-fm-helper.mjs"
17
+ "scripts/build-fm-helper.mjs",
18
+ "python",
19
+ "src/idotmatrix/*.py",
20
+ "src/timebox/*.py",
21
+ "src/pysync/*.py"
18
22
  ],
19
23
  "main": "./dist/index.js",
20
24
  "bin": {
@@ -28,8 +32,8 @@
28
32
  "qrcode": "^1.5.4",
29
33
  "strip-ansi": "^7.2.0",
30
34
  "ws": "^8.20.0",
31
- "@agentdeck/shared": "1.0.3",
32
- "@agentdeck/hooks": "1.0.3"
35
+ "@agentdeck/hooks": "1.0.4",
36
+ "@agentdeck/shared": "1.0.4"
33
37
  },
34
38
  "optionalDependencies": {
35
39
  "@picovoice/porcupine-node": "^4.0.2",
@@ -0,0 +1,5 @@
1
+ # Optional runtime for terminal-managed iDotMatrix and Timebox Mini BLE clients.
2
+ # Installed lazily by `agentdeck ble setup`; npm install itself stays PyPI-free.
3
+ bleak>=2.1,<3
4
+ Pillow>=12.0,<13
5
+ idotmatrix==0.0.9
@@ -0,0 +1,40 @@
1
+ import asyncio
2
+ import sys
3
+ import argparse
4
+ from idotmatrix import ConnectionManager
5
+ from idotmatrix.modules.common import Common as IdmCommon
6
+
7
+ async def set_brightness(address: str, brightness: int):
8
+ manager = ConnectionManager()
9
+ idm_common = IdmCommon()
10
+ idm_common.conn = manager
11
+
12
+ try:
13
+ print(f"Connecting to iDotMatrix ({address})...")
14
+ await manager.connectByAddress(address)
15
+ print(f"Setting brightness to {brightness}%...")
16
+ await idm_common.setBrightness(brightness)
17
+ print("Brightness set successfully.")
18
+ except Exception as e:
19
+ print(f"ERROR: Failed to set brightness: {e}")
20
+ sys.exit(1)
21
+ finally:
22
+ try:
23
+ await manager.disconnect()
24
+ except Exception:
25
+ pass
26
+
27
+ def main():
28
+ parser = argparse.ArgumentParser(description="Set iDotMatrix Brightness")
29
+ parser.add_argument("-a", "--address", required=True, help="BLE MAC/UUID Address")
30
+ parser.add_argument("-b", "--brightness", type=int, required=True, help="Brightness percent (5-100)")
31
+ args = parser.parse_args()
32
+
33
+ if args.brightness not in range(5, 101):
34
+ print("ERROR: Brightness must be between 5 and 100 percent.")
35
+ sys.exit(1)
36
+
37
+ asyncio.run(set_brightness(args.address, args.brightness))
38
+
39
+ if __name__ == "__main__":
40
+ main()
@@ -0,0 +1,35 @@
1
+ import asyncio
2
+ import json
3
+ import sys
4
+ from bleak import BleakScanner
5
+
6
+ async def scan():
7
+ # Scan for 5 seconds
8
+ devices = await BleakScanner.discover(timeout=5.0)
9
+
10
+ results = []
11
+ for d in devices:
12
+ name = d.name if d.name else "Unknown"
13
+ # Gather all devices, but flag IDM devices
14
+ is_idm = name.startswith("IDM-")
15
+ results.append({
16
+ "name": name,
17
+ "address": d.address,
18
+ "is_idotmatrix": is_idm
19
+ })
20
+
21
+ # Sort so that iDotMatrix devices are on top
22
+ results.sort(key=lambda x: x["is_idotmatrix"], reverse=True)
23
+
24
+ # Print as JSON so the calling Node.js CLI can easily parse it
25
+ print(json.dumps(results))
26
+
27
+ def main():
28
+ try:
29
+ asyncio.run(scan())
30
+ except Exception as e:
31
+ print(json.dumps({"error": str(e)}))
32
+ sys.exit(1)
33
+
34
+ if __name__ == "__main__":
35
+ main()