smart-home-engine 0.21.3 → 0.23.0
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/LICENSE +1 -1
- package/README.md +3 -3
- package/dist/web/assets/index-BPk8Jr3B.css +1 -0
- package/dist/web/assets/index-BWPgohd9.js +225 -0
- package/dist/web/assets/{tsMode-C_u8kXol.js → tsMode-Cvp4skWL.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/service/install.sh +3 -2
- package/service/smart-home-engine.service +2 -2
- package/src/config.js +12 -6
- package/src/index.js +10 -1
- package/src/lib/storage.js +1 -1
- package/src/web/ai-api.js +67 -0
- package/src/web/server.js +1 -0
- package/src/web/shedb-api.js +2 -1
- package/dist/web/assets/index-8jYnbrY_.js +0 -225
- package/dist/web/assets/index-c8FUuDqy.css +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{m as O}from"./monaco-langs-BW2J83t5.js";import{t as I}from"./index-
|
|
1
|
+
import{m as O}from"./monaco-langs-BW2J83t5.js";import{t as I}from"./index-BWPgohd9.js";/*!-----------------------------------------------------------------------------
|
|
2
2
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
3
|
* Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
|
|
4
4
|
* Released under the MIT license
|
package/dist/web/index.html
CHANGED
|
@@ -155,10 +155,10 @@
|
|
|
155
155
|
}
|
|
156
156
|
})();
|
|
157
157
|
</script>
|
|
158
|
-
<script type="module" crossorigin src="/assets/index-
|
|
158
|
+
<script type="module" crossorigin src="/assets/index-BWPgohd9.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
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
161
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BPk8Jr3B.css">
|
|
162
162
|
</head>
|
|
163
163
|
<body>
|
|
164
164
|
<div id="app"></div>
|
package/package.json
CHANGED
package/service/install.sh
CHANGED
|
@@ -32,8 +32,9 @@ else
|
|
|
32
32
|
echo "user '$SHE_USER' already exists, skipping"
|
|
33
33
|
fi
|
|
34
34
|
|
|
35
|
-
# --- state directory
|
|
36
|
-
install -d -o "$SHE_USER" -g "$SHE_USER" -m
|
|
35
|
+
# --- state directory ------------------------------------------------------
|
|
36
|
+
install -d -o "$SHE_USER" -g "$SHE_USER" -m 750 /var/lib/she
|
|
37
|
+
echo "created /var/lib/she"
|
|
37
38
|
|
|
38
39
|
# --- sudoers rules -------------------------------------------------------
|
|
39
40
|
NPM_BIN="$(command -v npm)"
|
|
@@ -11,9 +11,9 @@ Group=she
|
|
|
11
11
|
Restart=on-failure
|
|
12
12
|
RestartSec=5s
|
|
13
13
|
|
|
14
|
-
ExecStart=/usr/local/bin/she
|
|
14
|
+
ExecStart=/usr/local/bin/she --data-dir /var/lib/she
|
|
15
15
|
|
|
16
|
-
ReadWritePaths=/
|
|
16
|
+
ReadWritePaths=/var/lib/she
|
|
17
17
|
|
|
18
18
|
StandardOutput=journal
|
|
19
19
|
StandardError=journal
|
package/src/config.js
CHANGED
|
@@ -4,23 +4,29 @@ const fs = require('fs');
|
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
|
|
7
|
-
//
|
|
8
|
-
|
|
7
|
+
// Resolve data root: --data-dir is pre-parsed in index.js and written to SHE_DATA_DIR
|
|
8
|
+
// so that this module and storage.js both see the same root when first required.
|
|
9
|
+
const DATA_ROOT = process.env.SHE_DATA_DIR || path.join(os.homedir(), '.she');
|
|
9
10
|
|
|
10
11
|
const config = require('yargs')
|
|
12
|
+
.option('data-dir', {
|
|
13
|
+
describe: 'root data directory for scripts, db, config, etc. (default: ~/.she)',
|
|
14
|
+
default: DATA_ROOT,
|
|
15
|
+
type: 'string',
|
|
16
|
+
})
|
|
11
17
|
.option('dir', {
|
|
12
18
|
alias: 'd',
|
|
13
19
|
describe: 'directory to load user scripts from',
|
|
14
|
-
default: path.join(
|
|
20
|
+
default: path.join(DATA_ROOT, 'scripts'),
|
|
15
21
|
type: 'string',
|
|
16
22
|
})
|
|
17
23
|
.option('db-path', {
|
|
18
24
|
describe: 'path to sheDB data directory (empty string to disable)',
|
|
19
|
-
default: path.join(
|
|
25
|
+
default: path.join(DATA_ROOT, 'db'),
|
|
20
26
|
type: 'string',
|
|
21
27
|
})
|
|
22
28
|
.option('matter-storage', {
|
|
23
|
-
describe: 'enable Matter controller; pass a directory path or true to use
|
|
29
|
+
describe: 'enable Matter controller; pass a directory path or true to use <data-dir>/matter',
|
|
24
30
|
type: 'string',
|
|
25
31
|
})
|
|
26
32
|
.option('port', {
|
|
@@ -36,7 +42,7 @@ const config = require('yargs')
|
|
|
36
42
|
return {};
|
|
37
43
|
}
|
|
38
44
|
})
|
|
39
|
-
.default('config',
|
|
45
|
+
.default('config', path.join(DATA_ROOT, 'config', 'config.json'))
|
|
40
46
|
.hide('config')
|
|
41
47
|
// Sensible defaults for values not present in config.json
|
|
42
48
|
.default({
|
package/src/index.js
CHANGED
|
@@ -25,7 +25,16 @@ if (process.argv.includes('--install')) {
|
|
|
25
25
|
process.exit(0);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
//
|
|
28
|
+
// Resolve --data-dir early so that storage.js and config.js both see the correct
|
|
29
|
+
// data root when they are first require()'d below.
|
|
30
|
+
;(function () {
|
|
31
|
+
const idx = process.argv.indexOf('--data-dir');
|
|
32
|
+
if (idx !== -1 && process.argv[idx + 1] && !process.argv[idx + 1].startsWith('-')) {
|
|
33
|
+
process.env.SHE_DATA_DIR = process.argv[idx + 1];
|
|
34
|
+
}
|
|
35
|
+
}());
|
|
36
|
+
|
|
37
|
+
// Ensure the data directory exists before anything else runs
|
|
29
38
|
require('./lib/storage').ensureRoot();
|
|
30
39
|
|
|
31
40
|
const PinoPretty = require('pino-pretty');
|
package/src/lib/storage.js
CHANGED
|
@@ -4,7 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
|
|
7
|
-
const STORAGE_ROOT = path.join(os.homedir(), '.she');
|
|
7
|
+
const STORAGE_ROOT = process.env.SHE_DATA_DIR || path.join(os.homedir(), '.she');
|
|
8
8
|
const CONFIG_ROOT = path.join(STORAGE_ROOT, 'config');
|
|
9
9
|
const SCRIPTS_ROOT = path.join(STORAGE_ROOT, 'scripts');
|
|
10
10
|
const DB_ROOT = path.join(STORAGE_ROOT, 'db');
|
package/src/web/ai-api.js
CHANGED
|
@@ -18,9 +18,11 @@
|
|
|
18
18
|
|
|
19
19
|
const express = require('express');
|
|
20
20
|
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
21
22
|
|
|
22
23
|
const { buildSystemPrompt } = require('./ai-context');
|
|
23
24
|
const { TOOL_DEFINITIONS, TOOL_DEFINITIONS_ANTHROPIC, executeTool } = require('./ai-tools');
|
|
25
|
+
const { STORAGE_ROOT } = require('../lib/storage');
|
|
24
26
|
|
|
25
27
|
const router = express.Router();
|
|
26
28
|
let _store = null;
|
|
@@ -521,4 +523,69 @@ router.post('/chat/stream', async (req, res) => {
|
|
|
521
523
|
}
|
|
522
524
|
});
|
|
523
525
|
|
|
526
|
+
// ---------------------------------------------------------------------------
|
|
527
|
+
// Conversation persistence — GET/PUT/DELETE /she/ai/conversations[/:id]
|
|
528
|
+
// ---------------------------------------------------------------------------
|
|
529
|
+
|
|
530
|
+
const AI_DIR = path.join(STORAGE_ROOT, 'ai');
|
|
531
|
+
|
|
532
|
+
function ensureAiDir() {
|
|
533
|
+
fs.mkdirSync(AI_DIR, { recursive: true });
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function convPath(id) {
|
|
537
|
+
// Sanitize: only allow alphanumerics, hyphens, underscores
|
|
538
|
+
if (!/^[a-z0-9_-]{1,64}$/i.test(id)) return null;
|
|
539
|
+
return path.join(AI_DIR, `${id}.json`);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// GET /she/ai/conversations — list conversations sorted by updatedAt desc
|
|
543
|
+
router.get('/conversations', (req, res) => {
|
|
544
|
+
ensureAiDir();
|
|
545
|
+
let list = [];
|
|
546
|
+
try {
|
|
547
|
+
const files = fs.readdirSync(AI_DIR).filter(f => f.endsWith('.json'));
|
|
548
|
+
list = files.map(f => {
|
|
549
|
+
try {
|
|
550
|
+
const data = JSON.parse(fs.readFileSync(path.join(AI_DIR, f), 'utf8'));
|
|
551
|
+
return { id: data.id, title: data.title || data.id, updatedAt: data.updatedAt || 0 };
|
|
552
|
+
} catch { return null; }
|
|
553
|
+
}).filter(Boolean);
|
|
554
|
+
list.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
555
|
+
} catch { /* empty dir */ }
|
|
556
|
+
res.json(list);
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// GET /she/ai/conversations/:id
|
|
560
|
+
router.get('/conversations/:id', (req, res) => {
|
|
561
|
+
const p = convPath(req.params.id);
|
|
562
|
+
if (!p) return res.status(400).json({ error: 'invalid id' });
|
|
563
|
+
try {
|
|
564
|
+
const data = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
565
|
+
res.json(data);
|
|
566
|
+
} catch {
|
|
567
|
+
res.status(404).json({ error: 'not found' });
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// PUT /she/ai/conversations/:id — { title, messages }
|
|
572
|
+
router.put('/conversations/:id', (req, res) => {
|
|
573
|
+
const p = convPath(req.params.id);
|
|
574
|
+
if (!p) return res.status(400).json({ error: 'invalid id' });
|
|
575
|
+
const { title, messages } = req.body || {};
|
|
576
|
+
if (!Array.isArray(messages)) return res.status(400).json({ error: 'messages must be an array' });
|
|
577
|
+
ensureAiDir();
|
|
578
|
+
const data = { id: req.params.id, title: String(title || req.params.id).slice(0, 200), updatedAt: Date.now(), messages };
|
|
579
|
+
fs.writeFileSync(p, JSON.stringify(data), 'utf8');
|
|
580
|
+
res.json({ ok: true });
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// DELETE /she/ai/conversations/:id
|
|
584
|
+
router.delete('/conversations/:id', (req, res) => {
|
|
585
|
+
const p = convPath(req.params.id);
|
|
586
|
+
if (!p) return res.status(400).json({ error: 'invalid id' });
|
|
587
|
+
try { fs.unlinkSync(p); } catch { /* already gone */ }
|
|
588
|
+
res.json({ ok: true });
|
|
589
|
+
});
|
|
590
|
+
|
|
524
591
|
module.exports = { router, init };
|
package/src/web/server.js
CHANGED
|
@@ -107,6 +107,7 @@ function setStatsProvider(fn) {
|
|
|
107
107
|
app.get('/she/status', (req, res) => {
|
|
108
108
|
const s = _getStats ? _getStats() : { scripts: 0, topics: 0 };
|
|
109
109
|
if (_latestNpmVersion) s.latestVersion = _latestNpmVersion;
|
|
110
|
+
s.dataDir = require('../lib/storage').STORAGE_ROOT;
|
|
110
111
|
res.json(s);
|
|
111
112
|
});
|
|
112
113
|
|
package/src/web/shedb-api.js
CHANGED
|
@@ -114,7 +114,7 @@ router.use('/views', (req, res) => {
|
|
|
114
114
|
// PUT /she/db/views/<id> — create/update view
|
|
115
115
|
if (method === 'PUT') {
|
|
116
116
|
if (!id || isResult) return res.status(400).json({ error: 'id required' });
|
|
117
|
-
const { filter, map, reduce, mqttpub, retain } = req.body || {};
|
|
117
|
+
const { filter, map, reduce, mqttpub, retain, description } = req.body || {};
|
|
118
118
|
if (typeof map !== 'string' || !map.trim()) return res.status(400).json({ error: '"map" function string is required' });
|
|
119
119
|
const payload = {
|
|
120
120
|
filter: filter || undefined,
|
|
@@ -122,6 +122,7 @@ router.use('/views', (req, res) => {
|
|
|
122
122
|
reduce: reduce || undefined,
|
|
123
123
|
...(mqttpub ? { mqttpub: true } : {}),
|
|
124
124
|
...(retain ? { retain: true } : {}),
|
|
125
|
+
...(description ? { description: String(description).slice(0, 500) } : {}),
|
|
125
126
|
};
|
|
126
127
|
core.query(id, payload);
|
|
127
128
|
return res.json({ ok: true });
|