2ndbrain 2026.1.34 → 2026.1.36
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/.claude/settings.local.json +5 -1
- package/package.json +1 -1
- package/src/config.js +16 -3
- package/src/embeddings/engine.js +15 -0
- package/src/embeddings/worker.js +22 -1
- package/src/index.js +1 -1
- package/src/web/server.js +2 -3
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
"Bash(node:*)",
|
|
16
16
|
"Bash(ls -la \"c:\\\\dev\\\\fingerskier\\\\agent\\\\2ndbrain\\\\src\\\\web\"\" 2>/dev/null || echo \"web directory not found \")",
|
|
17
17
|
"Bash(ls -la \"c:\\\\dev\\\\fingerskier\\\\agent\\\\2ndbrain\\\\db\"\" 2>/dev/null || echo \"Directory not accessible \")",
|
|
18
|
-
"Bash(npm install:*)"
|
|
18
|
+
"Bash(npm install:*)",
|
|
19
|
+
"mcp__dude__get_project_context",
|
|
20
|
+
"mcp__dude__create_project",
|
|
21
|
+
"mcp__dude__create_issue",
|
|
22
|
+
"mcp__dude__update_issue"
|
|
19
23
|
]
|
|
20
24
|
}
|
|
21
25
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "2ndbrain",
|
|
3
|
-
"version": "2026.1.
|
|
3
|
+
"version": "2026.1.36",
|
|
4
4
|
"description": "Always-on Node.js service bridging Telegram messaging to Claude AI with knowledge graph, journal, project management, and semantic search.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/src/config.js
CHANGED
|
@@ -7,9 +7,22 @@ import { fileURLToPath } from 'node:url';
|
|
|
7
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
8
|
const __dirname = path.dirname(__filename);
|
|
9
9
|
const PROJECT_ROOT = path.resolve(__dirname, '..');
|
|
10
|
-
const
|
|
10
|
+
const SETTINGS_DIR = path.join(os.homedir(), '.2ndbrain');
|
|
11
|
+
const ENV_PATH = path.join(SETTINGS_DIR, '.env');
|
|
12
|
+
const LEGACY_ENV_PATH = path.join(PROJECT_ROOT, '.env');
|
|
11
13
|
|
|
12
|
-
//
|
|
14
|
+
// Migrate legacy .env from package root to stable user directory
|
|
15
|
+
if (!fs.existsSync(ENV_PATH) && fs.existsSync(LEGACY_ENV_PATH)) {
|
|
16
|
+
try {
|
|
17
|
+
fs.mkdirSync(SETTINGS_DIR, { recursive: true });
|
|
18
|
+
fs.copyFileSync(LEGACY_ENV_PATH, ENV_PATH);
|
|
19
|
+
} catch { /* fall through to first-run */ }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Ensure settings directory exists
|
|
23
|
+
try { fs.mkdirSync(SETTINGS_DIR, { recursive: true }); } catch { /* ignore */ }
|
|
24
|
+
|
|
25
|
+
// Load .env from stable user directory
|
|
13
26
|
dotenvConfig({ path: ENV_PATH });
|
|
14
27
|
|
|
15
28
|
const env = process.env;
|
|
@@ -99,5 +112,5 @@ function isFirstRun() {
|
|
|
99
112
|
return !valid;
|
|
100
113
|
}
|
|
101
114
|
|
|
102
|
-
export { config, validateConfig, isFirstRun, PROJECT_ROOT, ENV_PATH };
|
|
115
|
+
export { config, validateConfig, isFirstRun, PROJECT_ROOT, ENV_PATH, SETTINGS_DIR };
|
|
103
116
|
export default config;
|
package/src/embeddings/engine.js
CHANGED
|
@@ -31,6 +31,7 @@ class EmbeddingsEngine {
|
|
|
31
31
|
this.config = config;
|
|
32
32
|
this.logger = logger;
|
|
33
33
|
this._dimensions = null;
|
|
34
|
+
this._initialized = false;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -42,6 +43,16 @@ class EmbeddingsEngine {
|
|
|
42
43
|
return Boolean(this.config.EMBEDDING_PROVIDER);
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Returns true when the embedding engine has been successfully initialized
|
|
48
|
+
* (tables created / verified).
|
|
49
|
+
*
|
|
50
|
+
* @returns {boolean}
|
|
51
|
+
*/
|
|
52
|
+
isInitialized() {
|
|
53
|
+
return this._initialized;
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
/**
|
|
46
57
|
* Run startup configuration resolution.
|
|
47
58
|
*
|
|
@@ -87,6 +98,7 @@ class EmbeddingsEngine {
|
|
|
87
98
|
|
|
88
99
|
if (!tableCheck.rows[0].table_exists) {
|
|
89
100
|
await this._firstTimeSetup(provider, model, dimensions);
|
|
101
|
+
this._initialized = true;
|
|
90
102
|
return;
|
|
91
103
|
}
|
|
92
104
|
|
|
@@ -98,6 +110,7 @@ class EmbeddingsEngine {
|
|
|
98
110
|
if (configRow.rows.length === 0) {
|
|
99
111
|
// Table present but empty -- treat as first-time setup
|
|
100
112
|
await this._firstTimeSetup(provider, model, dimensions);
|
|
113
|
+
this._initialized = true;
|
|
101
114
|
return;
|
|
102
115
|
}
|
|
103
116
|
|
|
@@ -110,11 +123,13 @@ class EmbeddingsEngine {
|
|
|
110
123
|
) {
|
|
111
124
|
// Configuration unchanged
|
|
112
125
|
this.logger.info('embeddings', 'Embedding configuration unchanged.');
|
|
126
|
+
this._initialized = true;
|
|
113
127
|
return;
|
|
114
128
|
}
|
|
115
129
|
|
|
116
130
|
// Configuration differs -- perform model switch
|
|
117
131
|
await this._handleModelSwitch(current, { provider, model, dimensions });
|
|
132
|
+
this._initialized = true;
|
|
118
133
|
}
|
|
119
134
|
|
|
120
135
|
/**
|
package/src/embeddings/worker.js
CHANGED
|
@@ -53,7 +53,9 @@ class EmbeddingWorker {
|
|
|
53
53
|
|
|
54
54
|
/** Guard to prevent overlapping iterations. */
|
|
55
55
|
this._processing = false;
|
|
56
|
-
|
|
56
|
+
|
|
57
|
+
/** Whether the embeddings table has been verified to exist. */
|
|
58
|
+
this._tableVerified = false;
|
|
57
59
|
|
|
58
60
|
/**
|
|
59
61
|
* Start the periodic embedding worker loop.
|
|
@@ -125,6 +127,25 @@ class EmbeddingWorker {
|
|
|
125
127
|
* Fetch and process a batch of rows with NULL vectors.
|
|
126
128
|
*/
|
|
127
129
|
async _processQueue() {
|
|
130
|
+
// On first call, verify the embeddings table exists
|
|
131
|
+
if (!this._tableVerified) {
|
|
132
|
+
const check = await this.db.query(
|
|
133
|
+
`SELECT EXISTS (
|
|
134
|
+
SELECT FROM information_schema.tables
|
|
135
|
+
WHERE table_schema = 'public' AND table_name = 'embeddings'
|
|
136
|
+
) AS ok`,
|
|
137
|
+
);
|
|
138
|
+
if (!check.rows[0].ok) {
|
|
139
|
+
this.logger.warn(
|
|
140
|
+
'embedding-worker',
|
|
141
|
+
'Embeddings table does not exist; stopping worker.',
|
|
142
|
+
);
|
|
143
|
+
this.stop();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
this._tableVerified = true;
|
|
147
|
+
}
|
|
148
|
+
|
|
128
149
|
const result = await this.db.query(
|
|
129
150
|
`SELECT id, entity_type, entity_id
|
|
130
151
|
FROM embeddings
|
package/src/index.js
CHANGED
|
@@ -518,7 +518,7 @@ async function main() {
|
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
// Start background embedding worker
|
|
521
|
-
if (embeddingsEngine.
|
|
521
|
+
if (embeddingsEngine.isInitialized() && dbReady) {
|
|
522
522
|
embeddingWorker = new EmbeddingWorker({ db: { query }, config, logger });
|
|
523
523
|
embeddingWorker.start();
|
|
524
524
|
}
|
package/src/web/server.js
CHANGED
|
@@ -4,11 +4,10 @@ import fs from 'node:fs';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { migrate, getMigrationFiles, ensureMigrationsTable } from '../db/migrate.js';
|
|
7
|
+
import { ENV_PATH } from '../config.js';
|
|
7
8
|
|
|
8
|
-
// Resolve project root (two directories up from src/web/)
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = path.dirname(__filename);
|
|
11
|
-
const DEFAULT_ENV_PATH = path.resolve(__dirname, '..', '..', '.env');
|
|
12
11
|
|
|
13
12
|
// ---------------------------------------------------------------------------
|
|
14
13
|
// Settings field definitions -- drives both the form UI and save logic
|
|
@@ -107,7 +106,7 @@ class WebServer {
|
|
|
107
106
|
this._logger = logger;
|
|
108
107
|
this._server = null;
|
|
109
108
|
this._app = null;
|
|
110
|
-
this._envPath =
|
|
109
|
+
this._envPath = ENV_PATH;
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
/**
|