smart-home-engine 0.23.0 → 0.23.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.
@@ -1,4 +1,4 @@
1
- import{m as O}from"./monaco-langs-BW2J83t5.js";import{t as I}from"./index-BWPgohd9.js";/*!-----------------------------------------------------------------------------
1
+ import{m as O}from"./monaco-langs-BW2J83t5.js";import{t as I}from"./index-IaTuET9d.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -155,7 +155,7 @@
155
155
  }
156
156
  })();
157
157
  </script>
158
- <script type="module" crossorigin src="/assets/index-BWPgohd9.js"></script>
158
+ <script type="module" crossorigin src="/assets/index-IaTuET9d.js"></script>
159
159
  <link rel="modulepreload" crossorigin href="/assets/monaco-langs-BW2J83t5.js">
160
160
  <link rel="stylesheet" crossorigin href="/assets/monaco-langs-DyX1CsEw.css">
161
161
  <link rel="stylesheet" crossorigin href="/assets/index-BPk8Jr3B.css">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-home-engine",
3
- "version": "0.23.0",
3
+ "version": "0.23.2",
4
4
  "description": "Node.js based script runner for use in MQTT based Smart Home environments",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -1041,14 +1041,17 @@ function unloadScript(file) {
1041
1041
  log.info(unloadLabel, 'unloading');
1042
1042
  scriptOrigins.delete(file);
1043
1043
 
1044
+ let removedCallbacks = 0;
1045
+ let removedTimers = 0;
1046
+
1044
1047
  // Remove MQTT subscriptions belonging to this script
1045
1048
  for (let i = subscriptions.length - 1; i >= 0; i--) {
1046
- if (subscriptions[i]._script === file) subscriptions.splice(i, 1);
1049
+ if (subscriptions[i]._script === file) { subscriptions.splice(i, 1); removedCallbacks++; }
1047
1050
  }
1048
1051
 
1049
1052
  // Remove MQTT event callbacks (connect/disconnect) belonging to this script
1050
1053
  for (let i = mqttEventCallbacks.length - 1; i >= 0; i--) {
1051
- if (mqttEventCallbacks[i]._script === file) mqttEventCallbacks.splice(i, 1);
1054
+ if (mqttEventCallbacks[i]._script === file) { mqttEventCallbacks.splice(i, 1); removedCallbacks++; }
1052
1055
  }
1053
1056
 
1054
1057
  // Remove HTTP routes registered by this script via she.api
@@ -1059,6 +1062,7 @@ function unloadScript(file) {
1059
1062
  const jobs = scriptJobs.get(file);
1060
1063
  if (jobs) {
1061
1064
  jobs.forEach((job) => job && job.cancel());
1065
+ removedTimers += jobs.length;
1062
1066
  scriptJobs.delete(file);
1063
1067
  }
1064
1068
 
@@ -1067,6 +1071,7 @@ function unloadScript(file) {
1067
1071
  if (sunEvents[i]._script === file) {
1068
1072
  if (sunEvents[i]._job) sunEvents[i]._job.cancel();
1069
1073
  sunEvents.splice(i, 1);
1074
+ removedTimers++;
1070
1075
  }
1071
1076
  }
1072
1077
 
@@ -1074,6 +1079,7 @@ function unloadScript(file) {
1074
1079
  const timers = scriptTimers.get(file);
1075
1080
  if (timers) {
1076
1081
  timers.forEach((id) => clearTimeout(id));
1082
+ removedTimers += timers.size;
1077
1083
  scriptTimers.delete(file);
1078
1084
  }
1079
1085
 
@@ -1082,6 +1088,7 @@ function unloadScript(file) {
1082
1088
  if (varSubscriptions[i]._script === file) {
1083
1089
  store.removeListener('change', varSubscriptions[i].handler);
1084
1090
  varSubscriptions.splice(i, 1);
1091
+ removedCallbacks++;
1085
1092
  }
1086
1093
  }
1087
1094
 
@@ -1095,6 +1102,13 @@ function unloadScript(file) {
1095
1102
  matterSandbox.cleanup(file);
1096
1103
  }
1097
1104
 
1105
+ if (removedCallbacks > 0 || removedTimers > 0) {
1106
+ const parts = [];
1107
+ if (removedCallbacks > 0) parts.push(`${removedCallbacks} callback${removedCallbacks !== 1 ? 's' : ''}`);
1108
+ if (removedTimers > 0) parts.push(`${removedTimers} timer${removedTimers !== 1 ? 's' : ''}`);
1109
+ log.debug(unloadLabel, `unregistered ${parts.join(' and ')}`);
1110
+ }
1111
+
1098
1112
  // Remove from scripts map so it can be re-loaded
1099
1113
  delete scripts[file];
1100
1114
  }
package/src/web/ai-api.js CHANGED
@@ -441,14 +441,15 @@ router.post('/prompt', (req, res) => {
441
441
  // POST /she/ai/chat — non-streaming
442
442
  router.post('/chat', async (req, res) => {
443
443
  const ai = readAiConfig(req.app.locals.configPath);
444
- if (!ai?.provider || !ai?.model) {
444
+ const { messages = [], currentScript, currentView, currentDoc, context = {}, modelOverride, extraFiles } = req.body || {};
445
+ const effectiveModel = (modelOverride && typeof modelOverride === 'string') ? modelOverride : ai?.model;
446
+ if (!ai?.provider || !effectiveModel) {
445
447
  return res.status(400).json({ error: 'AI provider not configured. Set ai.provider and ai.model in Config.' });
446
448
  }
447
449
 
448
- const { messages = [], currentScript, currentView, currentDoc, context = {}, modelOverride, extraFiles } = req.body || {};
449
450
  if (!Array.isArray(messages)) return res.status(400).json({ error: 'messages must be an array' });
450
451
 
451
- const aiWithModel = modelOverride && typeof modelOverride === 'string' ? { ...ai, model: modelOverride } : ai;
452
+ const aiWithModel = { ...ai, model: effectiveModel };
452
453
  const systemPrompt = buildSystemPrompt(context, currentScript ?? null, currentView ?? null, currentDoc ?? null, _store, extraFiles || []);
453
454
  const fullMessages = [{ role: 'system', content: systemPrompt }, ...messages];
454
455
 
@@ -471,14 +472,15 @@ router.post('/chat', async (req, res) => {
471
472
  // POST /she/ai/chat/stream — SSE streaming
472
473
  router.post('/chat/stream', async (req, res) => {
473
474
  const ai = readAiConfig(req.app.locals.configPath);
474
- if (!ai?.provider || !ai?.model) {
475
+ const { messages = [], currentScript, currentView, currentDoc, context = {}, modelOverride, extraFiles } = req.body || {};
476
+ const effectiveModel = (modelOverride && typeof modelOverride === 'string') ? modelOverride : ai?.model;
477
+ if (!ai?.provider || !effectiveModel) {
475
478
  return res.status(400).json({ error: 'AI provider not configured. Set ai.provider and ai.model in Config.' });
476
479
  }
477
480
 
478
- const { messages = [], currentScript, currentView, currentDoc, context = {}, modelOverride, extraFiles } = req.body || {};
479
481
  if (!Array.isArray(messages)) return res.status(400).json({ error: 'messages must be an array' });
480
482
 
481
- const aiWithModel = modelOverride && typeof modelOverride === 'string' ? { ...ai, model: modelOverride } : ai;
483
+ const aiWithModel = { ...ai, model: effectiveModel };
482
484
 
483
485
  // Build system prompt BEFORE flushing headers so errors can still return a proper HTTP status
484
486
  let systemPrompt;