zam-core 0.9.0 → 0.9.1
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/dist/cli/app.js +22389 -0
- package/dist/cli/app.js.map +1 -0
- package/dist/{chunk-BOWP6D5I.js → cli/commands/mcp.js} +2873 -661
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/index.js +115 -16124
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-BOWP6D5I.js.map +0 -1
- package/dist/kernel-6JUK5NCB.js +0 -420
- package/dist/kernel-6JUK5NCB.js.map +0 -1
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res, err) => function __init() {
|
|
4
|
+
if (err) throw err[0];
|
|
5
|
+
try {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
} catch (e) {
|
|
8
|
+
throw err = [e], e;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
2
15
|
|
|
3
16
|
// src/kernel/analytics/stats.ts
|
|
4
17
|
async function q(db, sql, ...params) {
|
|
@@ -109,6 +122,11 @@ async function getDomainCompetence(db, userId) {
|
|
|
109
122
|
}
|
|
110
123
|
return competences;
|
|
111
124
|
}
|
|
125
|
+
var init_stats = __esm({
|
|
126
|
+
"src/kernel/analytics/stats.ts"() {
|
|
127
|
+
"use strict";
|
|
128
|
+
}
|
|
129
|
+
});
|
|
112
130
|
|
|
113
131
|
// src/kernel/credentials.ts
|
|
114
132
|
import {
|
|
@@ -120,7 +138,6 @@ import {
|
|
|
120
138
|
} from "fs";
|
|
121
139
|
import { homedir } from "os";
|
|
122
140
|
import { dirname, join } from "path";
|
|
123
|
-
var DEFAULT_CREDENTIALS_PATH = join(homedir(), ".zam", "credentials.json");
|
|
124
141
|
function loadCredentials(path) {
|
|
125
142
|
const p = path ?? DEFAULT_CREDENTIALS_PATH;
|
|
126
143
|
if (!existsSync(p)) return {};
|
|
@@ -211,6 +228,13 @@ function clearProviderApiKey(name, path) {
|
|
|
211
228
|
function listProviderApiKeyRefs(path) {
|
|
212
229
|
return Object.keys(loadCredentials(path).llmProviders ?? {});
|
|
213
230
|
}
|
|
231
|
+
var DEFAULT_CREDENTIALS_PATH;
|
|
232
|
+
var init_credentials = __esm({
|
|
233
|
+
"src/kernel/credentials.ts"() {
|
|
234
|
+
"use strict";
|
|
235
|
+
DEFAULT_CREDENTIALS_PATH = join(homedir(), ".zam", "credentials.json");
|
|
236
|
+
}
|
|
237
|
+
});
|
|
214
238
|
|
|
215
239
|
// src/kernel/connectors/azure-devops.ts
|
|
216
240
|
function loadADOConfig() {
|
|
@@ -267,16 +291,14 @@ async function fetchActiveWorkItems(config) {
|
|
|
267
291
|
assignedTo: wi.fields["System.AssignedTo"]?.displayName ?? ""
|
|
268
292
|
}));
|
|
269
293
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
294
|
+
var init_azure_devops = __esm({
|
|
295
|
+
"src/kernel/connectors/azure-devops.ts"() {
|
|
296
|
+
"use strict";
|
|
297
|
+
init_credentials();
|
|
298
|
+
}
|
|
299
|
+
});
|
|
276
300
|
|
|
277
301
|
// src/kernel/db/remote/hrana.ts
|
|
278
|
-
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
279
|
-
var DEFAULT_MAX_ATTEMPTS = 2;
|
|
280
302
|
function toHttpUrl(url) {
|
|
281
303
|
return url.replace(/^libsql:\/\//i, "https://").replace(/^wss:\/\//i, "https://").replace(/^ws:\/\//i, "http://").replace(/\/+$/, "");
|
|
282
304
|
}
|
|
@@ -329,80 +351,6 @@ function isRetryableTransportError(err) {
|
|
|
329
351
|
const code = err.cause?.code;
|
|
330
352
|
return code === "ECONNREFUSED" || code === "ENOTFOUND" || code === "EAI_AGAIN";
|
|
331
353
|
}
|
|
332
|
-
var HranaResponseError = class extends Error {
|
|
333
|
-
name = "HranaResponseError";
|
|
334
|
-
};
|
|
335
|
-
var HranaTransport = class {
|
|
336
|
-
pipelineUrl;
|
|
337
|
-
authToken;
|
|
338
|
-
timeoutMs;
|
|
339
|
-
maxAttempts;
|
|
340
|
-
constructor(options) {
|
|
341
|
-
this.pipelineUrl = `${toHttpUrl(options.url)}/v3/pipeline`;
|
|
342
|
-
this.authToken = options.authToken;
|
|
343
|
-
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
344
|
-
this.maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* POST one pipeline of requests. Returns the server results plus the baton
|
|
348
|
-
* for continuing an open stream. Retries transport-level failures only for
|
|
349
|
-
* stateless pipelines (no baton involved on either side).
|
|
350
|
-
*/
|
|
351
|
-
async pipeline(requests, baton, baseUrl) {
|
|
352
|
-
const url = baseUrl ? `${toHttpUrl(baseUrl)}/v3/pipeline` : this.pipelineUrl;
|
|
353
|
-
const keepsState = baton != null || !requests.some((r) => r.type === "close");
|
|
354
|
-
const attempts = keepsState ? 1 : this.maxAttempts;
|
|
355
|
-
let lastError;
|
|
356
|
-
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
357
|
-
try {
|
|
358
|
-
return await this.post(url, { baton: baton ?? null, requests });
|
|
359
|
-
} catch (err) {
|
|
360
|
-
lastError = err;
|
|
361
|
-
if (!isRetryableTransportError(err) || attempt === attempts) {
|
|
362
|
-
throw this.offline(err);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
throw this.offline(lastError);
|
|
367
|
-
}
|
|
368
|
-
async post(url, body) {
|
|
369
|
-
const controller = new AbortController();
|
|
370
|
-
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
371
|
-
let response;
|
|
372
|
-
try {
|
|
373
|
-
response = await fetch(url, {
|
|
374
|
-
method: "POST",
|
|
375
|
-
headers: {
|
|
376
|
-
"content-type": "application/json",
|
|
377
|
-
...this.authToken ? { authorization: `Bearer ${this.authToken}` } : {}
|
|
378
|
-
},
|
|
379
|
-
body: JSON.stringify(body),
|
|
380
|
-
signal: controller.signal
|
|
381
|
-
});
|
|
382
|
-
} finally {
|
|
383
|
-
clearTimeout(timer);
|
|
384
|
-
}
|
|
385
|
-
if (response.status === 401 || response.status === 403) {
|
|
386
|
-
throw new HranaResponseError(
|
|
387
|
-
`Turso rejected the configured credentials (HTTP ${response.status}). Refresh the token with: zam connector setup turso`
|
|
388
|
-
);
|
|
389
|
-
}
|
|
390
|
-
if (!response.ok) {
|
|
391
|
-
const detail = await response.text().catch(() => "");
|
|
392
|
-
throw new HranaResponseError(
|
|
393
|
-
`Turso request failed with HTTP ${response.status}${detail ? `: ${detail.slice(0, 200)}` : ""}`
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
return await response.json();
|
|
397
|
-
}
|
|
398
|
-
offline(err) {
|
|
399
|
-
if (err instanceof HranaResponseError) return err;
|
|
400
|
-
const cause = err instanceof Error ? err.cause?.message ?? err.message : String(err);
|
|
401
|
-
return new HranaResponseError(
|
|
402
|
-
`Cannot reach the Turso database at ${this.pipelineUrl}: ${cause}. Check your network connection, or switch to the local provider (ZAM_DB_PROVIDER=local).`
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
354
|
function unwrapResult(response, index) {
|
|
407
355
|
const entry = response.results[index];
|
|
408
356
|
if (!entry) {
|
|
@@ -413,9 +361,90 @@ function unwrapResult(response, index) {
|
|
|
413
361
|
}
|
|
414
362
|
return entry.response.result;
|
|
415
363
|
}
|
|
364
|
+
var DEFAULT_TIMEOUT_MS, DEFAULT_MAX_ATTEMPTS, HranaResponseError, HranaTransport;
|
|
365
|
+
var init_hrana = __esm({
|
|
366
|
+
"src/kernel/db/remote/hrana.ts"() {
|
|
367
|
+
"use strict";
|
|
368
|
+
DEFAULT_TIMEOUT_MS = 15e3;
|
|
369
|
+
DEFAULT_MAX_ATTEMPTS = 2;
|
|
370
|
+
HranaResponseError = class extends Error {
|
|
371
|
+
name = "HranaResponseError";
|
|
372
|
+
};
|
|
373
|
+
HranaTransport = class {
|
|
374
|
+
pipelineUrl;
|
|
375
|
+
authToken;
|
|
376
|
+
timeoutMs;
|
|
377
|
+
maxAttempts;
|
|
378
|
+
constructor(options) {
|
|
379
|
+
this.pipelineUrl = `${toHttpUrl(options.url)}/v3/pipeline`;
|
|
380
|
+
this.authToken = options.authToken;
|
|
381
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
382
|
+
this.maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* POST one pipeline of requests. Returns the server results plus the baton
|
|
386
|
+
* for continuing an open stream. Retries transport-level failures only for
|
|
387
|
+
* stateless pipelines (no baton involved on either side).
|
|
388
|
+
*/
|
|
389
|
+
async pipeline(requests, baton, baseUrl) {
|
|
390
|
+
const url = baseUrl ? `${toHttpUrl(baseUrl)}/v3/pipeline` : this.pipelineUrl;
|
|
391
|
+
const keepsState = baton != null || !requests.some((r) => r.type === "close");
|
|
392
|
+
const attempts = keepsState ? 1 : this.maxAttempts;
|
|
393
|
+
let lastError;
|
|
394
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
395
|
+
try {
|
|
396
|
+
return await this.post(url, { baton: baton ?? null, requests });
|
|
397
|
+
} catch (err) {
|
|
398
|
+
lastError = err;
|
|
399
|
+
if (!isRetryableTransportError(err) || attempt === attempts) {
|
|
400
|
+
throw this.offline(err);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
throw this.offline(lastError);
|
|
405
|
+
}
|
|
406
|
+
async post(url, body) {
|
|
407
|
+
const controller = new AbortController();
|
|
408
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
409
|
+
let response;
|
|
410
|
+
try {
|
|
411
|
+
response = await fetch(url, {
|
|
412
|
+
method: "POST",
|
|
413
|
+
headers: {
|
|
414
|
+
"content-type": "application/json",
|
|
415
|
+
...this.authToken ? { authorization: `Bearer ${this.authToken}` } : {}
|
|
416
|
+
},
|
|
417
|
+
body: JSON.stringify(body),
|
|
418
|
+
signal: controller.signal
|
|
419
|
+
});
|
|
420
|
+
} finally {
|
|
421
|
+
clearTimeout(timer);
|
|
422
|
+
}
|
|
423
|
+
if (response.status === 401 || response.status === 403) {
|
|
424
|
+
throw new HranaResponseError(
|
|
425
|
+
`Turso rejected the configured credentials (HTTP ${response.status}). Refresh the token with: zam connector setup turso`
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
if (!response.ok) {
|
|
429
|
+
const detail = await response.text().catch(() => "");
|
|
430
|
+
throw new HranaResponseError(
|
|
431
|
+
`Turso request failed with HTTP ${response.status}${detail ? `: ${detail.slice(0, 200)}` : ""}`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
return await response.json();
|
|
435
|
+
}
|
|
436
|
+
offline(err) {
|
|
437
|
+
if (err instanceof HranaResponseError) return err;
|
|
438
|
+
const cause = err instanceof Error ? err.cause?.message ?? err.message : String(err);
|
|
439
|
+
return new HranaResponseError(
|
|
440
|
+
`Cannot reach the Turso database at ${this.pipelineUrl}: ${cause}. Check your network connection, or switch to the local provider (ZAM_DB_PROVIDER=local).`
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
});
|
|
416
446
|
|
|
417
447
|
// src/kernel/db/remote/provider.ts
|
|
418
|
-
var TABLE_INFO_PRAGMA = /^\s*table_info\s*\(\s*['"]?(\w+)['"]?\s*\)\s*$/i;
|
|
419
448
|
function toRunResult(result) {
|
|
420
449
|
return {
|
|
421
450
|
changes: result?.affected_row_count ?? 0,
|
|
@@ -522,9 +551,21 @@ function openRemoteDatabase(options) {
|
|
|
522
551
|
};
|
|
523
552
|
return makeDatabase(statelessRun, transport);
|
|
524
553
|
}
|
|
554
|
+
var TABLE_INFO_PRAGMA;
|
|
555
|
+
var init_provider = __esm({
|
|
556
|
+
"src/kernel/db/remote/provider.ts"() {
|
|
557
|
+
"use strict";
|
|
558
|
+
init_hrana();
|
|
559
|
+
TABLE_INFO_PRAGMA = /^\s*table_info\s*\(\s*['"]?(\w+)['"]?\s*\)\s*$/i;
|
|
560
|
+
}
|
|
561
|
+
});
|
|
525
562
|
|
|
526
563
|
// src/kernel/db/schema.ts
|
|
527
|
-
var SCHEMA
|
|
564
|
+
var SCHEMA;
|
|
565
|
+
var init_schema = __esm({
|
|
566
|
+
"src/kernel/db/schema.ts"() {
|
|
567
|
+
"use strict";
|
|
568
|
+
SCHEMA = `
|
|
528
569
|
-- PRAGMAs (WAL, foreign_keys) are set programmatically in connection.ts,
|
|
529
570
|
-- not here, because libsql embedded replicas manage their own WAL.
|
|
530
571
|
|
|
@@ -700,6 +741,8 @@ CREATE INDEX IF NOT EXISTS idx_session_steps_session ON session_steps(session_id
|
|
|
700
741
|
CREATE INDEX IF NOT EXISTS idx_tokens_title ON tokens(title);
|
|
701
742
|
CREATE INDEX IF NOT EXISTS idx_token_contexts_context ON token_contexts(context_id);
|
|
702
743
|
`;
|
|
744
|
+
}
|
|
745
|
+
});
|
|
703
746
|
|
|
704
747
|
// src/kernel/db/sync-adapter.ts
|
|
705
748
|
function wrapSyncDatabase(driver) {
|
|
@@ -751,11 +794,17 @@ function wrapSyncDatabase(driver) {
|
|
|
751
794
|
};
|
|
752
795
|
return db;
|
|
753
796
|
}
|
|
797
|
+
var init_sync_adapter = __esm({
|
|
798
|
+
"src/kernel/db/sync-adapter.ts"() {
|
|
799
|
+
"use strict";
|
|
800
|
+
}
|
|
801
|
+
});
|
|
754
802
|
|
|
755
803
|
// src/kernel/db/connection.ts
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
804
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync } from "fs";
|
|
805
|
+
import { createRequire } from "module";
|
|
806
|
+
import { homedir as homedir2 } from "os";
|
|
807
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
759
808
|
function isRemoteDatabasePath(dbPath) {
|
|
760
809
|
return /^(libsql|https?|wss?):\/\//i.test(dbPath);
|
|
761
810
|
}
|
|
@@ -1061,23 +1110,22 @@ async function runMigrations(db) {
|
|
|
1061
1110
|
CREATE INDEX IF NOT EXISTS idx_token_contexts_context ON token_contexts(context_id)
|
|
1062
1111
|
`);
|
|
1063
1112
|
}
|
|
1113
|
+
var DEFAULT_DB_DIR, DEFAULT_DB_PATH, require2;
|
|
1114
|
+
var init_connection = __esm({
|
|
1115
|
+
"src/kernel/db/connection.ts"() {
|
|
1116
|
+
"use strict";
|
|
1117
|
+
init_credentials();
|
|
1118
|
+
init_provider();
|
|
1119
|
+
init_schema();
|
|
1120
|
+
init_sync_adapter();
|
|
1121
|
+
DEFAULT_DB_DIR = join2(homedir2(), ".zam");
|
|
1122
|
+
DEFAULT_DB_PATH = join2(DEFAULT_DB_DIR, "zam.db");
|
|
1123
|
+
require2 = createRequire(import.meta.url);
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1064
1126
|
|
|
1065
1127
|
// src/kernel/db/snapshot.ts
|
|
1066
1128
|
import { createHash } from "crypto";
|
|
1067
|
-
var SNAPSHOT_FORMAT = "zam-snapshot";
|
|
1068
|
-
var SNAPSHOT_VERSION = 1;
|
|
1069
|
-
var MANIFEST_PREFIX = "-- zam-snapshot: ";
|
|
1070
|
-
var SNAPSHOT_TABLES = [
|
|
1071
|
-
"tokens",
|
|
1072
|
-
"sessions",
|
|
1073
|
-
"cards",
|
|
1074
|
-
"prerequisites",
|
|
1075
|
-
"session_steps",
|
|
1076
|
-
"review_logs",
|
|
1077
|
-
"session_syntheses",
|
|
1078
|
-
"user_config",
|
|
1079
|
-
"agent_skills"
|
|
1080
|
-
];
|
|
1081
1129
|
function quoteValue(value) {
|
|
1082
1130
|
if (value === null || value === void 0) return "NULL";
|
|
1083
1131
|
if (typeof value === "number") {
|
|
@@ -1205,10 +1253,26 @@ async function importSnapshot(db, snapshot, options = {}) {
|
|
|
1205
1253
|
return { tables, total };
|
|
1206
1254
|
});
|
|
1207
1255
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1256
|
+
var SNAPSHOT_FORMAT, SNAPSHOT_VERSION, MANIFEST_PREFIX, SNAPSHOT_TABLES;
|
|
1257
|
+
var init_snapshot = __esm({
|
|
1258
|
+
"src/kernel/db/snapshot.ts"() {
|
|
1259
|
+
"use strict";
|
|
1260
|
+
SNAPSHOT_FORMAT = "zam-snapshot";
|
|
1261
|
+
SNAPSHOT_VERSION = 1;
|
|
1262
|
+
MANIFEST_PREFIX = "-- zam-snapshot: ";
|
|
1263
|
+
SNAPSHOT_TABLES = [
|
|
1264
|
+
"tokens",
|
|
1265
|
+
"sessions",
|
|
1266
|
+
"cards",
|
|
1267
|
+
"prerequisites",
|
|
1268
|
+
"session_steps",
|
|
1269
|
+
"review_logs",
|
|
1270
|
+
"session_syntheses",
|
|
1271
|
+
"user_config",
|
|
1272
|
+
"agent_skills"
|
|
1273
|
+
];
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1212
1276
|
|
|
1213
1277
|
// src/kernel/goals/parser.ts
|
|
1214
1278
|
function parseGoalFile(content, slug, filePath) {
|
|
@@ -1296,8 +1360,15 @@ function splitFrontmatter(content) {
|
|
|
1296
1360
|
}
|
|
1297
1361
|
return { frontmatter, body };
|
|
1298
1362
|
}
|
|
1363
|
+
var init_parser = __esm({
|
|
1364
|
+
"src/kernel/goals/parser.ts"() {
|
|
1365
|
+
"use strict";
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1299
1368
|
|
|
1300
1369
|
// src/kernel/goals/engine.ts
|
|
1370
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1371
|
+
import { basename, join as join3 } from "path";
|
|
1301
1372
|
function listGoals(goalsDir) {
|
|
1302
1373
|
if (!existsSync3(goalsDir)) return [];
|
|
1303
1374
|
const files = readdirSync(goalsDir).filter(
|
|
@@ -1391,6 +1462,12 @@ function getGoalTree(goalsDir) {
|
|
|
1391
1462
|
}
|
|
1392
1463
|
return roots;
|
|
1393
1464
|
}
|
|
1465
|
+
var init_engine = __esm({
|
|
1466
|
+
"src/kernel/goals/engine.ts"() {
|
|
1467
|
+
"use strict";
|
|
1468
|
+
init_parser();
|
|
1469
|
+
}
|
|
1470
|
+
});
|
|
1394
1471
|
|
|
1395
1472
|
// src/kernel/models/agent-skill.ts
|
|
1396
1473
|
import { ulid } from "ulid";
|
|
@@ -1433,6 +1510,11 @@ async function listAgentSkills(db) {
|
|
|
1433
1510
|
const rows = await db.prepare("SELECT * FROM agent_skills ORDER BY created_at ASC").all();
|
|
1434
1511
|
return rows.map(parseRow);
|
|
1435
1512
|
}
|
|
1513
|
+
var init_agent_skill = __esm({
|
|
1514
|
+
"src/kernel/models/agent-skill.ts"() {
|
|
1515
|
+
"use strict";
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1436
1518
|
|
|
1437
1519
|
// src/kernel/models/card.ts
|
|
1438
1520
|
import { ulid as ulid2 } from "ulid";
|
|
@@ -1554,6 +1636,11 @@ async function getBlockedCards(db, userId) {
|
|
|
1554
1636
|
ORDER BY t.bloom_level ASC, t.slug ASC`
|
|
1555
1637
|
).all(userId);
|
|
1556
1638
|
}
|
|
1639
|
+
var init_card = __esm({
|
|
1640
|
+
"src/kernel/models/card.ts"() {
|
|
1641
|
+
"use strict";
|
|
1642
|
+
}
|
|
1643
|
+
});
|
|
1557
1644
|
|
|
1558
1645
|
// src/kernel/models/knowledge-context.ts
|
|
1559
1646
|
import { ulid as ulid3 } from "ulid";
|
|
@@ -1659,6 +1746,11 @@ async function listContextsForToken(db, tokenId) {
|
|
|
1659
1746
|
ORDER BY c.name ASC`
|
|
1660
1747
|
).all(tokenId);
|
|
1661
1748
|
}
|
|
1749
|
+
var init_knowledge_context = __esm({
|
|
1750
|
+
"src/kernel/models/knowledge-context.ts"() {
|
|
1751
|
+
"use strict";
|
|
1752
|
+
}
|
|
1753
|
+
});
|
|
1662
1754
|
|
|
1663
1755
|
// src/kernel/models/token.ts
|
|
1664
1756
|
import { ulid as ulid4 } from "ulid";
|
|
@@ -2411,6 +2503,12 @@ async function assertPrerequisiteDoesNotCreateCycle(db, tokenId, prerequisiteId)
|
|
|
2411
2503
|
throw new Error("Cannot add prerequisite: would create a cycle");
|
|
2412
2504
|
}
|
|
2413
2505
|
}
|
|
2506
|
+
var init_token = __esm({
|
|
2507
|
+
"src/kernel/models/token.ts"() {
|
|
2508
|
+
"use strict";
|
|
2509
|
+
init_card();
|
|
2510
|
+
}
|
|
2511
|
+
});
|
|
2414
2512
|
|
|
2415
2513
|
// src/kernel/models/prerequisite.ts
|
|
2416
2514
|
async function buildAncestorMap(db) {
|
|
@@ -2542,6 +2640,13 @@ async function getTokenNeighborhood(db, tokenId, userId) {
|
|
|
2542
2640
|
);
|
|
2543
2641
|
return { center, prerequisites, dependents };
|
|
2544
2642
|
}
|
|
2643
|
+
var init_prerequisite = __esm({
|
|
2644
|
+
"src/kernel/models/prerequisite.ts"() {
|
|
2645
|
+
"use strict";
|
|
2646
|
+
init_card();
|
|
2647
|
+
init_token();
|
|
2648
|
+
}
|
|
2649
|
+
});
|
|
2545
2650
|
|
|
2546
2651
|
// src/kernel/models/review.ts
|
|
2547
2652
|
import { ulid as ulid5 } from "ulid";
|
|
@@ -2590,6 +2695,11 @@ async function getReviewsForUser(db, userId, options) {
|
|
|
2590
2695
|
}
|
|
2591
2696
|
return await db.prepare(sql).all(...params);
|
|
2592
2697
|
}
|
|
2698
|
+
var init_review = __esm({
|
|
2699
|
+
"src/kernel/models/review.ts"() {
|
|
2700
|
+
"use strict";
|
|
2701
|
+
}
|
|
2702
|
+
});
|
|
2593
2703
|
|
|
2594
2704
|
// src/kernel/models/session.ts
|
|
2595
2705
|
import { ulid as ulid6 } from "ulid";
|
|
@@ -2658,6 +2768,11 @@ async function getSessionSummary(db, sessionId) {
|
|
|
2658
2768
|
).all(sessionId);
|
|
2659
2769
|
return { session, steps };
|
|
2660
2770
|
}
|
|
2771
|
+
var init_session = __esm({
|
|
2772
|
+
"src/kernel/models/session.ts"() {
|
|
2773
|
+
"use strict";
|
|
2774
|
+
}
|
|
2775
|
+
});
|
|
2661
2776
|
|
|
2662
2777
|
// src/kernel/models/settings.ts
|
|
2663
2778
|
async function getSetting(db, key) {
|
|
@@ -2686,6 +2801,11 @@ async function deleteSetting(db, key) {
|
|
|
2686
2801
|
const result = await db.prepare("DELETE FROM user_config WHERE key = ?").run(key);
|
|
2687
2802
|
return result.changes > 0;
|
|
2688
2803
|
}
|
|
2804
|
+
var init_settings = __esm({
|
|
2805
|
+
"src/kernel/models/settings.ts"() {
|
|
2806
|
+
"use strict";
|
|
2807
|
+
}
|
|
2808
|
+
});
|
|
2689
2809
|
|
|
2690
2810
|
// src/kernel/models/token-embedding.ts
|
|
2691
2811
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -2846,6 +2966,11 @@ async function listEmbeddedTokens(db, model) {
|
|
|
2846
2966
|
}
|
|
2847
2967
|
});
|
|
2848
2968
|
}
|
|
2969
|
+
var init_token_embedding = __esm({
|
|
2970
|
+
"src/kernel/models/token-embedding.ts"() {
|
|
2971
|
+
"use strict";
|
|
2972
|
+
}
|
|
2973
|
+
});
|
|
2849
2974
|
|
|
2850
2975
|
// src/kernel/observation/analyzer.ts
|
|
2851
2976
|
function parseMonitorLog(jsonl) {
|
|
@@ -2904,8 +3029,6 @@ function pairCommands(events) {
|
|
|
2904
3029
|
);
|
|
2905
3030
|
return records;
|
|
2906
3031
|
}
|
|
2907
|
-
var HELP_PATTERNS = ["--help", "man ", "tldr ", "help "];
|
|
2908
|
-
var HELP_WINDOW_MS = 6e4;
|
|
2909
3032
|
function matchesToken(command, patterns) {
|
|
2910
3033
|
const lower = command.toLowerCase();
|
|
2911
3034
|
return patterns.some((p) => lower.includes(p.toLowerCase()));
|
|
@@ -3066,6 +3189,14 @@ function inferRating(signals) {
|
|
|
3066
3189
|
if (negatives >= 1) return 3;
|
|
3067
3190
|
return 4;
|
|
3068
3191
|
}
|
|
3192
|
+
var HELP_PATTERNS, HELP_WINDOW_MS;
|
|
3193
|
+
var init_analyzer = __esm({
|
|
3194
|
+
"src/kernel/observation/analyzer.ts"() {
|
|
3195
|
+
"use strict";
|
|
3196
|
+
HELP_PATTERNS = ["--help", "man ", "tldr ", "help "];
|
|
3197
|
+
HELP_WINDOW_MS = 6e4;
|
|
3198
|
+
}
|
|
3199
|
+
});
|
|
3069
3200
|
|
|
3070
3201
|
// src/kernel/observation/monitor-io.ts
|
|
3071
3202
|
import {
|
|
@@ -3077,7 +3208,6 @@ import {
|
|
|
3077
3208
|
} from "fs";
|
|
3078
3209
|
import { homedir as homedir3 } from "os";
|
|
3079
3210
|
import { join as join4 } from "path";
|
|
3080
|
-
var MONITOR_DIR = join4(homedir3(), ".zam", "monitor");
|
|
3081
3211
|
function getMonitorDir() {
|
|
3082
3212
|
return MONITOR_DIR;
|
|
3083
3213
|
}
|
|
@@ -3116,43 +3246,16 @@ function getMonitorLogStats(sessionId) {
|
|
|
3116
3246
|
const lineCount = content.split("\n").filter((l) => l.trim()).length;
|
|
3117
3247
|
return { exists: true, sizeBytes: stat.size, lineCount };
|
|
3118
3248
|
}
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3249
|
+
var MONITOR_DIR;
|
|
3250
|
+
var init_monitor_io = __esm({
|
|
3251
|
+
"src/kernel/observation/monitor-io.ts"() {
|
|
3252
|
+
"use strict";
|
|
3253
|
+
init_analyzer();
|
|
3254
|
+
MONITOR_DIR = join4(homedir3(), ".zam", "monitor");
|
|
3255
|
+
}
|
|
3256
|
+
});
|
|
3123
3257
|
|
|
3124
3258
|
// src/kernel/observation/policy.ts
|
|
3125
|
-
var OBSERVER_POLICY_VERSION = 1;
|
|
3126
|
-
var DEFAULT_OBSERVER_POLICY = {
|
|
3127
|
-
version: OBSERVER_POLICY_VERSION,
|
|
3128
|
-
scope: "window",
|
|
3129
|
-
allowlist: [],
|
|
3130
|
-
denylist: [],
|
|
3131
|
-
consent: "per-session",
|
|
3132
|
-
retention: "none",
|
|
3133
|
-
redactWindowTitles: true,
|
|
3134
|
-
audioOptIn: false
|
|
3135
|
-
};
|
|
3136
|
-
var BUILT_IN_SENSITIVE_MATCHERS = [
|
|
3137
|
-
// Password managers
|
|
3138
|
-
"1password",
|
|
3139
|
-
"bitwarden",
|
|
3140
|
-
"keepass",
|
|
3141
|
-
"lastpass",
|
|
3142
|
-
"dashlane",
|
|
3143
|
-
"nordpass",
|
|
3144
|
-
"enpass",
|
|
3145
|
-
"proton pass",
|
|
3146
|
-
// Authentication / credential / UAC surfaces
|
|
3147
|
-
"credentialuibroker",
|
|
3148
|
-
"consentux",
|
|
3149
|
-
"logonui",
|
|
3150
|
-
"windowssecurity",
|
|
3151
|
-
"authenticator",
|
|
3152
|
-
// Conservative banking/title hints
|
|
3153
|
-
"online banking",
|
|
3154
|
-
"onlinebanking"
|
|
3155
|
-
];
|
|
3156
3259
|
function parseList(raw) {
|
|
3157
3260
|
if (!raw) return [];
|
|
3158
3261
|
return raw.split(",").map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0);
|
|
@@ -3363,37 +3466,48 @@ async function isObserverPolicyConfigured(db) {
|
|
|
3363
3466
|
const settings = await getAllSettings(db);
|
|
3364
3467
|
return Object.keys(settings).some((key) => key.startsWith("observer."));
|
|
3365
3468
|
}
|
|
3366
|
-
var
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3469
|
+
var OBSERVER_POLICY_VERSION, DEFAULT_OBSERVER_POLICY, BUILT_IN_SENSITIVE_MATCHERS, OBSERVER_POLICY_UNSET_HINT;
|
|
3470
|
+
var init_policy = __esm({
|
|
3471
|
+
"src/kernel/observation/policy.ts"() {
|
|
3472
|
+
"use strict";
|
|
3473
|
+
init_stats();
|
|
3474
|
+
init_settings();
|
|
3475
|
+
OBSERVER_POLICY_VERSION = 1;
|
|
3476
|
+
DEFAULT_OBSERVER_POLICY = {
|
|
3477
|
+
version: OBSERVER_POLICY_VERSION,
|
|
3478
|
+
scope: "window",
|
|
3479
|
+
allowlist: [],
|
|
3480
|
+
denylist: [],
|
|
3481
|
+
consent: "per-session",
|
|
3482
|
+
retention: "none",
|
|
3483
|
+
redactWindowTitles: true,
|
|
3484
|
+
audioOptIn: false
|
|
3485
|
+
};
|
|
3486
|
+
BUILT_IN_SENSITIVE_MATCHERS = [
|
|
3487
|
+
// Password managers
|
|
3488
|
+
"1password",
|
|
3489
|
+
"bitwarden",
|
|
3490
|
+
"keepass",
|
|
3491
|
+
"lastpass",
|
|
3492
|
+
"dashlane",
|
|
3493
|
+
"nordpass",
|
|
3494
|
+
"enpass",
|
|
3495
|
+
"proton pass",
|
|
3496
|
+
// Authentication / credential / UAC surfaces
|
|
3497
|
+
"credentialuibroker",
|
|
3498
|
+
"consentux",
|
|
3499
|
+
"logonui",
|
|
3500
|
+
"windowssecurity",
|
|
3501
|
+
"authenticator",
|
|
3502
|
+
// Conservative banking/title hints
|
|
3503
|
+
"online banking",
|
|
3504
|
+
"onlinebanking"
|
|
3505
|
+
];
|
|
3506
|
+
OBSERVER_POLICY_UNSET_HINT = "Observer policy is at defaults (scope=window: only a targeted window is captured). Configure with `zam observer status|grant|revoke` or `zam settings set observer.scope <off|window|fullscreen>`.";
|
|
3507
|
+
}
|
|
3508
|
+
});
|
|
3372
3509
|
|
|
3373
3510
|
// src/kernel/observation/ui-observer.ts
|
|
3374
|
-
var UI_OBSERVATION_PROTOCOL_VERSION = 1;
|
|
3375
|
-
var OBSERVATION_KINDS = /* @__PURE__ */ new Set([
|
|
3376
|
-
"progress",
|
|
3377
|
-
"step-completed",
|
|
3378
|
-
"error",
|
|
3379
|
-
"help-seeking",
|
|
3380
|
-
"uncertain",
|
|
3381
|
-
"privacy-pause",
|
|
3382
|
-
"heartbeat"
|
|
3383
|
-
]);
|
|
3384
|
-
var ACTION_TYPES = /* @__PURE__ */ new Set([
|
|
3385
|
-
"click",
|
|
3386
|
-
"shortcut",
|
|
3387
|
-
"typing",
|
|
3388
|
-
"scroll",
|
|
3389
|
-
"window-change"
|
|
3390
|
-
]);
|
|
3391
|
-
var EVIDENCE_TYPES = /* @__PURE__ */ new Set([
|
|
3392
|
-
"uia",
|
|
3393
|
-
"keyframe",
|
|
3394
|
-
"clip",
|
|
3395
|
-
"window"
|
|
3396
|
-
]);
|
|
3397
3511
|
function isUiObservationReport(value) {
|
|
3398
3512
|
if (!isRecord(value)) return false;
|
|
3399
3513
|
if (value.version !== UI_OBSERVATION_PROTOCOL_VERSION) return false;
|
|
@@ -3466,9 +3580,40 @@ function isNonNegativeInteger(value) {
|
|
|
3466
3580
|
function isConfidence(value) {
|
|
3467
3581
|
return typeof value === "number" && value >= 0 && value <= 1;
|
|
3468
3582
|
}
|
|
3583
|
+
var UI_OBSERVATION_PROTOCOL_VERSION, OBSERVATION_KINDS, ACTION_TYPES, EVIDENCE_TYPES;
|
|
3584
|
+
var init_ui_observer = __esm({
|
|
3585
|
+
"src/kernel/observation/ui-observer.ts"() {
|
|
3586
|
+
"use strict";
|
|
3587
|
+
UI_OBSERVATION_PROTOCOL_VERSION = 1;
|
|
3588
|
+
OBSERVATION_KINDS = /* @__PURE__ */ new Set([
|
|
3589
|
+
"progress",
|
|
3590
|
+
"step-completed",
|
|
3591
|
+
"error",
|
|
3592
|
+
"help-seeking",
|
|
3593
|
+
"uncertain",
|
|
3594
|
+
"privacy-pause",
|
|
3595
|
+
"heartbeat"
|
|
3596
|
+
]);
|
|
3597
|
+
ACTION_TYPES = /* @__PURE__ */ new Set([
|
|
3598
|
+
"click",
|
|
3599
|
+
"shortcut",
|
|
3600
|
+
"typing",
|
|
3601
|
+
"scroll",
|
|
3602
|
+
"window-change"
|
|
3603
|
+
]);
|
|
3604
|
+
EVIDENCE_TYPES = /* @__PURE__ */ new Set([
|
|
3605
|
+
"uia",
|
|
3606
|
+
"keyframe",
|
|
3607
|
+
"clip",
|
|
3608
|
+
"window"
|
|
3609
|
+
]);
|
|
3610
|
+
}
|
|
3611
|
+
});
|
|
3469
3612
|
|
|
3470
3613
|
// src/kernel/observation/ui-observer-io.ts
|
|
3471
|
-
|
|
3614
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5 } from "fs";
|
|
3615
|
+
import { homedir as homedir4 } from "os";
|
|
3616
|
+
import { join as join5 } from "path";
|
|
3472
3617
|
function getUiObserverDir() {
|
|
3473
3618
|
return process.env.ZAM_OBSERVER_DIR || DEFAULT_UI_OBSERVER_DIR;
|
|
3474
3619
|
}
|
|
@@ -3504,9 +3649,18 @@ function appendUiObservationReport(report) {
|
|
|
3504
3649
|
{ encoding: "utf8", mode: 384 }
|
|
3505
3650
|
);
|
|
3506
3651
|
}
|
|
3652
|
+
var DEFAULT_UI_OBSERVER_DIR;
|
|
3653
|
+
var init_ui_observer_io = __esm({
|
|
3654
|
+
"src/kernel/observation/ui-observer-io.ts"() {
|
|
3655
|
+
"use strict";
|
|
3656
|
+
init_ui_observer();
|
|
3657
|
+
DEFAULT_UI_OBSERVER_DIR = join5(homedir4(), ".zam", "observer");
|
|
3658
|
+
}
|
|
3659
|
+
});
|
|
3507
3660
|
|
|
3508
3661
|
// src/kernel/observation/observer-sidecar-policy.ts
|
|
3509
|
-
|
|
3662
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
3663
|
+
import { join as join6 } from "path";
|
|
3510
3664
|
function toSidecarPrivacyPolicy(policy) {
|
|
3511
3665
|
return {
|
|
3512
3666
|
allowProcesses: [...policy.allowlist],
|
|
@@ -3525,41 +3679,17 @@ async function syncObserverSidecarPolicy(db, dir = getUiObserverDir()) {
|
|
|
3525
3679
|
});
|
|
3526
3680
|
return { path, policy };
|
|
3527
3681
|
}
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3682
|
+
var SIDECAR_POLICY_FILE;
|
|
3683
|
+
var init_observer_sidecar_policy = __esm({
|
|
3684
|
+
"src/kernel/observation/observer-sidecar-policy.ts"() {
|
|
3685
|
+
"use strict";
|
|
3686
|
+
init_policy();
|
|
3687
|
+
init_ui_observer_io();
|
|
3688
|
+
SIDECAR_POLICY_FILE = "policy.json";
|
|
3689
|
+
}
|
|
3690
|
+
});
|
|
3534
3691
|
|
|
3535
3692
|
// src/kernel/scheduler/fsrs.ts
|
|
3536
|
-
var DEFAULT_W = [
|
|
3537
|
-
0.4072,
|
|
3538
|
-
1.1829,
|
|
3539
|
-
3.1262,
|
|
3540
|
-
15.4722,
|
|
3541
|
-
// w0–w3: initial stability per rating
|
|
3542
|
-
7.2102,
|
|
3543
|
-
0.5316,
|
|
3544
|
-
1.0651,
|
|
3545
|
-
// w4–w6: difficulty
|
|
3546
|
-
92e-4,
|
|
3547
|
-
1.5988,
|
|
3548
|
-
0.1176,
|
|
3549
|
-
1.0014,
|
|
3550
|
-
// w7–w10: stability after forgetting
|
|
3551
|
-
2.0032,
|
|
3552
|
-
0.0266,
|
|
3553
|
-
0.3077,
|
|
3554
|
-
0.15,
|
|
3555
|
-
// w11–w14: stability increase
|
|
3556
|
-
0,
|
|
3557
|
-
2.7849,
|
|
3558
|
-
0.3477,
|
|
3559
|
-
0.6831
|
|
3560
|
-
// w15–w18: additional parameters
|
|
3561
|
-
];
|
|
3562
|
-
var DEFAULT_REQUEST_RETENTION = 0.9;
|
|
3563
3693
|
function clamp(value, lo, hi) {
|
|
3564
3694
|
return Math.min(hi, Math.max(lo, value));
|
|
3565
3695
|
}
|
|
@@ -3674,8 +3804,42 @@ function createFSRS(params) {
|
|
|
3674
3804
|
params: Object.freeze(resolvedParams)
|
|
3675
3805
|
};
|
|
3676
3806
|
}
|
|
3807
|
+
var DEFAULT_W, DEFAULT_REQUEST_RETENTION;
|
|
3808
|
+
var init_fsrs = __esm({
|
|
3809
|
+
"src/kernel/scheduler/fsrs.ts"() {
|
|
3810
|
+
"use strict";
|
|
3811
|
+
DEFAULT_W = [
|
|
3812
|
+
0.4072,
|
|
3813
|
+
1.1829,
|
|
3814
|
+
3.1262,
|
|
3815
|
+
15.4722,
|
|
3816
|
+
// w0–w3: initial stability per rating
|
|
3817
|
+
7.2102,
|
|
3818
|
+
0.5316,
|
|
3819
|
+
1.0651,
|
|
3820
|
+
// w4–w6: difficulty
|
|
3821
|
+
92e-4,
|
|
3822
|
+
1.5988,
|
|
3823
|
+
0.1176,
|
|
3824
|
+
1.0014,
|
|
3825
|
+
// w7–w10: stability after forgetting
|
|
3826
|
+
2.0032,
|
|
3827
|
+
0.0266,
|
|
3828
|
+
0.3077,
|
|
3829
|
+
0.15,
|
|
3830
|
+
// w11–w14: stability increase
|
|
3831
|
+
0,
|
|
3832
|
+
2.7849,
|
|
3833
|
+
0.3477,
|
|
3834
|
+
0.6831
|
|
3835
|
+
// w15–w18: additional parameters
|
|
3836
|
+
];
|
|
3837
|
+
DEFAULT_REQUEST_RETENTION = 0.9;
|
|
3838
|
+
}
|
|
3839
|
+
});
|
|
3677
3840
|
|
|
3678
3841
|
// src/kernel/recall/evaluator.ts
|
|
3842
|
+
import { ulid as ulid7 } from "ulid";
|
|
3679
3843
|
async function evaluateRating(db, input) {
|
|
3680
3844
|
return db.transaction((tx) => evaluateRatingWithinTransaction(tx, input));
|
|
3681
3845
|
}
|
|
@@ -3734,6 +3898,13 @@ async function evaluateRatingWithinTransaction(db, input) {
|
|
|
3734
3898
|
lapses: updated.lapses
|
|
3735
3899
|
};
|
|
3736
3900
|
}
|
|
3901
|
+
var init_evaluator = __esm({
|
|
3902
|
+
"src/kernel/recall/evaluator.ts"() {
|
|
3903
|
+
"use strict";
|
|
3904
|
+
init_card();
|
|
3905
|
+
init_fsrs();
|
|
3906
|
+
}
|
|
3907
|
+
});
|
|
3737
3908
|
|
|
3738
3909
|
// src/kernel/scheduler/blocker.ts
|
|
3739
3910
|
async function cascadeBlock(db, userId, tokenSlug) {
|
|
@@ -3795,9 +3966,16 @@ async function unblockReady(db, userId) {
|
|
|
3795
3966
|
}
|
|
3796
3967
|
return { unblocked };
|
|
3797
3968
|
}
|
|
3969
|
+
var init_blocker = __esm({
|
|
3970
|
+
"src/kernel/scheduler/blocker.ts"() {
|
|
3971
|
+
"use strict";
|
|
3972
|
+
init_card();
|
|
3973
|
+
init_prerequisite();
|
|
3974
|
+
init_token();
|
|
3975
|
+
}
|
|
3976
|
+
});
|
|
3798
3977
|
|
|
3799
3978
|
// src/kernel/observation/ui-observer-synthesis.ts
|
|
3800
|
-
var MIN_UI_CONFIDENCE = 0.6;
|
|
3801
3979
|
function kindToRating(kind) {
|
|
3802
3980
|
switch (kind) {
|
|
3803
3981
|
case "step-completed":
|
|
@@ -3889,8 +4067,16 @@ function uiObservationTimeSpan(reports) {
|
|
|
3889
4067
|
const durationMs = Math.max(0, Date.parse(end) - Date.parse(start));
|
|
3890
4068
|
return { start, end, durationMs };
|
|
3891
4069
|
}
|
|
4070
|
+
var MIN_UI_CONFIDENCE;
|
|
4071
|
+
var init_ui_observer_synthesis = __esm({
|
|
4072
|
+
"src/kernel/observation/ui-observer-synthesis.ts"() {
|
|
4073
|
+
"use strict";
|
|
4074
|
+
MIN_UI_CONFIDENCE = 0.6;
|
|
4075
|
+
}
|
|
4076
|
+
});
|
|
3892
4077
|
|
|
3893
4078
|
// src/kernel/observation/session-synthesis.ts
|
|
4079
|
+
import { ulid as ulid8 } from "ulid";
|
|
3894
4080
|
function parseSynthesisRow(row) {
|
|
3895
4081
|
return {
|
|
3896
4082
|
...row,
|
|
@@ -4099,6 +4285,22 @@ async function applySessionSynthesis(db, input) {
|
|
|
4099
4285
|
};
|
|
4100
4286
|
});
|
|
4101
4287
|
}
|
|
4288
|
+
var init_session_synthesis = __esm({
|
|
4289
|
+
"src/kernel/observation/session-synthesis.ts"() {
|
|
4290
|
+
"use strict";
|
|
4291
|
+
init_agent_skill();
|
|
4292
|
+
init_card();
|
|
4293
|
+
init_prerequisite();
|
|
4294
|
+
init_session();
|
|
4295
|
+
init_token();
|
|
4296
|
+
init_evaluator();
|
|
4297
|
+
init_blocker();
|
|
4298
|
+
init_analyzer();
|
|
4299
|
+
init_monitor_io();
|
|
4300
|
+
init_ui_observer_io();
|
|
4301
|
+
init_ui_observer_synthesis();
|
|
4302
|
+
}
|
|
4303
|
+
});
|
|
4102
4304
|
|
|
4103
4305
|
// src/kernel/observation/shell-hooks.ts
|
|
4104
4306
|
function psSingleQuoted(value) {
|
|
@@ -4319,6 +4521,11 @@ Remove-Variable -Name __ZAM_MONITOR_FILE,__ZAM_MONITOR_SEQ,__ZAM_MONITOR_SESSION
|
|
|
4319
4521
|
Write-Host "ZAM monitor stopped."
|
|
4320
4522
|
`.trim();
|
|
4321
4523
|
}
|
|
4524
|
+
var init_shell_hooks = __esm({
|
|
4525
|
+
"src/kernel/observation/shell-hooks.ts"() {
|
|
4526
|
+
"use strict";
|
|
4527
|
+
}
|
|
4528
|
+
});
|
|
4322
4529
|
|
|
4323
4530
|
// src/kernel/observation/skill-discovery.ts
|
|
4324
4531
|
function discoverSkills(sessionCommands, options = {}) {
|
|
@@ -4461,6 +4668,11 @@ function generateSlug(steps) {
|
|
|
4461
4668
|
function describeSequence(steps) {
|
|
4462
4669
|
return `Recurring pattern: ${steps.join(" \u2192 ")}`;
|
|
4463
4670
|
}
|
|
4671
|
+
var init_skill_discovery = __esm({
|
|
4672
|
+
"src/kernel/observation/skill-discovery.ts"() {
|
|
4673
|
+
"use strict";
|
|
4674
|
+
}
|
|
4675
|
+
});
|
|
4464
4676
|
|
|
4465
4677
|
// src/kernel/recall/actions.ts
|
|
4466
4678
|
async function getReviewTarget(db, cardId, userId) {
|
|
@@ -4558,25 +4770,21 @@ async function executeReviewAction(db, input) {
|
|
|
4558
4770
|
}
|
|
4559
4771
|
}
|
|
4560
4772
|
}
|
|
4773
|
+
var init_actions = __esm({
|
|
4774
|
+
"src/kernel/recall/actions.ts"() {
|
|
4775
|
+
"use strict";
|
|
4776
|
+
init_card();
|
|
4777
|
+
init_prerequisite();
|
|
4778
|
+
init_token();
|
|
4779
|
+
init_blocker();
|
|
4780
|
+
init_evaluator();
|
|
4781
|
+
}
|
|
4782
|
+
});
|
|
4561
4783
|
|
|
4562
4784
|
// src/kernel/recall/prompter.ts
|
|
4563
|
-
var BLOOM_VERBS = {
|
|
4564
|
-
1: "Remember",
|
|
4565
|
-
2: "Understand",
|
|
4566
|
-
3: "Apply",
|
|
4567
|
-
4: "Analyze",
|
|
4568
|
-
5: "Synthesize"
|
|
4569
|
-
};
|
|
4570
4785
|
function formatSlugForCue(slug) {
|
|
4571
4786
|
return slug.replace(/[-_]/g, " ");
|
|
4572
4787
|
}
|
|
4573
|
-
var BLOOM_CUES = {
|
|
4574
|
-
1: (slug) => `Recall the definition and core concept of: ${formatSlugForCue(slug)}`,
|
|
4575
|
-
2: (slug) => `Explain the concept and how ${formatSlugForCue(slug)} works.`,
|
|
4576
|
-
3: (slug) => `Describe how or where you would apply the concept of ${formatSlugForCue(slug)}.`,
|
|
4577
|
-
4: (slug) => `Analyze the trade-offs, advantages, or alternatives of ${formatSlugForCue(slug)}.`,
|
|
4578
|
-
5: (slug) => `How would you design a solution using the concept of ${formatSlugForCue(slug)}?`
|
|
4579
|
-
};
|
|
4580
4788
|
function generateConceptFreeCue(bloomLevel, slug, _domain) {
|
|
4581
4789
|
const bloom = bloomLevel >= 1 && bloomLevel <= 5 ? bloomLevel : 1;
|
|
4582
4790
|
return BLOOM_CUES[bloom](slug);
|
|
@@ -4597,13 +4805,30 @@ function generatePrompt(input) {
|
|
|
4597
4805
|
sourceLink: input.sourceLink ?? null
|
|
4598
4806
|
};
|
|
4599
4807
|
}
|
|
4808
|
+
var BLOOM_VERBS, BLOOM_CUES;
|
|
4809
|
+
var init_prompter = __esm({
|
|
4810
|
+
"src/kernel/recall/prompter.ts"() {
|
|
4811
|
+
"use strict";
|
|
4812
|
+
BLOOM_VERBS = {
|
|
4813
|
+
1: "Remember",
|
|
4814
|
+
2: "Understand",
|
|
4815
|
+
3: "Apply",
|
|
4816
|
+
4: "Analyze",
|
|
4817
|
+
5: "Synthesize"
|
|
4818
|
+
};
|
|
4819
|
+
BLOOM_CUES = {
|
|
4820
|
+
1: (slug) => `Recall the definition and core concept of: ${formatSlugForCue(slug)}`,
|
|
4821
|
+
2: (slug) => `Explain the concept and how ${formatSlugForCue(slug)} works.`,
|
|
4822
|
+
3: (slug) => `Describe how or where you would apply the concept of ${formatSlugForCue(slug)}.`,
|
|
4823
|
+
4: (slug) => `Analyze the trade-offs, advantages, or alternatives of ${formatSlugForCue(slug)}.`,
|
|
4824
|
+
5: (slug) => `How would you design a solution using the concept of ${formatSlugForCue(slug)}?`
|
|
4825
|
+
};
|
|
4826
|
+
}
|
|
4827
|
+
});
|
|
4600
4828
|
|
|
4601
4829
|
// src/kernel/recall/reference-resolver.ts
|
|
4602
4830
|
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
4603
4831
|
import { dirname as dirname3, join as join7, resolve } from "path";
|
|
4604
|
-
var DEFAULT_REVIEW_CONTEXT_MAX_CHARS = 6e3;
|
|
4605
|
-
var REVIEW_CONTEXT_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
4606
|
-
var reviewContextCache = /* @__PURE__ */ new Map();
|
|
4607
4832
|
function reviewContextCacheKey(sourceLink, maxChars) {
|
|
4608
4833
|
return `${sourceLink}\0${maxChars}`;
|
|
4609
4834
|
}
|
|
@@ -4799,6 +5024,15 @@ function matchesFilePath(sourceLink, changedFile) {
|
|
|
4799
5024
|
}
|
|
4800
5025
|
return normSource.endsWith(normChanged) || normChanged.endsWith(normSource);
|
|
4801
5026
|
}
|
|
5027
|
+
var DEFAULT_REVIEW_CONTEXT_MAX_CHARS, REVIEW_CONTEXT_CACHE_TTL_MS, reviewContextCache;
|
|
5028
|
+
var init_reference_resolver = __esm({
|
|
5029
|
+
"src/kernel/recall/reference-resolver.ts"() {
|
|
5030
|
+
"use strict";
|
|
5031
|
+
DEFAULT_REVIEW_CONTEXT_MAX_CHARS = 6e3;
|
|
5032
|
+
REVIEW_CONTEXT_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
5033
|
+
reviewContextCache = /* @__PURE__ */ new Map();
|
|
5034
|
+
}
|
|
5035
|
+
});
|
|
4802
5036
|
|
|
4803
5037
|
// src/kernel/scheduler/interleaver.ts
|
|
4804
5038
|
function interleave(items, maxConsecutive = 2) {
|
|
@@ -4865,6 +5099,11 @@ function interleave(items, maxConsecutive = 2) {
|
|
|
4865
5099
|
}
|
|
4866
5100
|
return result;
|
|
4867
5101
|
}
|
|
5102
|
+
var init_interleaver = __esm({
|
|
5103
|
+
"src/kernel/scheduler/interleaver.ts"() {
|
|
5104
|
+
"use strict";
|
|
5105
|
+
}
|
|
5106
|
+
});
|
|
4868
5107
|
|
|
4869
5108
|
// src/kernel/scheduler/queue.ts
|
|
4870
5109
|
async function buildReviewQueue(db, options) {
|
|
@@ -5007,6 +5246,13 @@ function intersperseNew(reviews, newCards, interval) {
|
|
|
5007
5246
|
}
|
|
5008
5247
|
return result;
|
|
5009
5248
|
}
|
|
5249
|
+
var init_queue = __esm({
|
|
5250
|
+
"src/kernel/scheduler/queue.ts"() {
|
|
5251
|
+
"use strict";
|
|
5252
|
+
init_token();
|
|
5253
|
+
init_interleaver();
|
|
5254
|
+
}
|
|
5255
|
+
});
|
|
5010
5256
|
|
|
5011
5257
|
// src/kernel/search/hybrid.ts
|
|
5012
5258
|
function cosineSimilarity(a, b) {
|
|
@@ -5083,6 +5329,13 @@ async function searchTokensHybrid(db, query, opts) {
|
|
|
5083
5329
|
});
|
|
5084
5330
|
return results.slice(0, limit);
|
|
5085
5331
|
}
|
|
5332
|
+
var init_hybrid = __esm({
|
|
5333
|
+
"src/kernel/search/hybrid.ts"() {
|
|
5334
|
+
"use strict";
|
|
5335
|
+
init_token();
|
|
5336
|
+
init_token_embedding();
|
|
5337
|
+
}
|
|
5338
|
+
});
|
|
5086
5339
|
|
|
5087
5340
|
// src/kernel/search/suggestions.ts
|
|
5088
5341
|
async function suggestFoundations(db, opts) {
|
|
@@ -5148,6 +5401,14 @@ async function suggestFoundations(db, opts) {
|
|
|
5148
5401
|
}
|
|
5149
5402
|
return results;
|
|
5150
5403
|
}
|
|
5404
|
+
var init_suggestions = __esm({
|
|
5405
|
+
"src/kernel/search/suggestions.ts"() {
|
|
5406
|
+
"use strict";
|
|
5407
|
+
init_prerequisite();
|
|
5408
|
+
init_token_embedding();
|
|
5409
|
+
init_hybrid();
|
|
5410
|
+
}
|
|
5411
|
+
});
|
|
5151
5412
|
|
|
5152
5413
|
// src/kernel/system/hooks.ts
|
|
5153
5414
|
import {
|
|
@@ -5161,7 +5422,6 @@ import {
|
|
|
5161
5422
|
import { homedir as homedir5 } from "os";
|
|
5162
5423
|
import { join as join8 } from "path";
|
|
5163
5424
|
import { fileURLToPath } from "url";
|
|
5164
|
-
var HOME = homedir5();
|
|
5165
5425
|
function getPackageSkillPath(agent = "default") {
|
|
5166
5426
|
const packageRoot = [
|
|
5167
5427
|
fileURLToPath(new URL("../../..", import.meta.url)),
|
|
@@ -5272,15 +5532,6 @@ function distributeGlobalSkills(home = HOME) {
|
|
|
5272
5532
|
}
|
|
5273
5533
|
return results;
|
|
5274
5534
|
}
|
|
5275
|
-
var POSIX_OLD_HOOK = `
|
|
5276
|
-
# ZAM Shell Observation Hooks
|
|
5277
|
-
if (command -v zam >/dev/null 2>&1); then eval "$(zam monitor start --quiet)"; fi
|
|
5278
|
-
`;
|
|
5279
|
-
var POWERSHELL_OLD_HOOK = `
|
|
5280
|
-
# ZAM Shell Observation Hooks
|
|
5281
|
-
if (Get-Command zam -ErrorAction SilentlyContinue) { Invoke-Expression (& zam monitor start --quiet pwsh) }
|
|
5282
|
-
`;
|
|
5283
|
-
var HOOK_MARKER = "# ZAM Monitor Session Helper";
|
|
5284
5535
|
function posixHook(shell) {
|
|
5285
5536
|
return `
|
|
5286
5537
|
${HOOK_MARKER}
|
|
@@ -5295,13 +5546,6 @@ zam-monitor-session() {
|
|
|
5295
5546
|
}
|
|
5296
5547
|
`;
|
|
5297
5548
|
}
|
|
5298
|
-
var POWERSHELL_HOOK = `
|
|
5299
|
-
${HOOK_MARKER}
|
|
5300
|
-
function Start-ZamMonitor {
|
|
5301
|
-
param([Parameter(Mandatory = $true)][string]$Session)
|
|
5302
|
-
Invoke-Expression (& zam monitor start --session $Session --shell pwsh)
|
|
5303
|
-
}
|
|
5304
|
-
`;
|
|
5305
5549
|
function installHook(file, hook, oldHook) {
|
|
5306
5550
|
try {
|
|
5307
5551
|
const content = existsSync7(file) ? readFileSync7(file, "utf8") : "";
|
|
@@ -5359,206 +5603,31 @@ function injectShellHooks(home = HOME) {
|
|
|
5359
5603
|
}
|
|
5360
5604
|
return results;
|
|
5361
5605
|
}
|
|
5606
|
+
var HOME, POSIX_OLD_HOOK, POWERSHELL_OLD_HOOK, HOOK_MARKER, POWERSHELL_HOOK;
|
|
5607
|
+
var init_hooks = __esm({
|
|
5608
|
+
"src/kernel/system/hooks.ts"() {
|
|
5609
|
+
"use strict";
|
|
5610
|
+
HOME = homedir5();
|
|
5611
|
+
POSIX_OLD_HOOK = `
|
|
5612
|
+
# ZAM Shell Observation Hooks
|
|
5613
|
+
if (command -v zam >/dev/null 2>&1); then eval "$(zam monitor start --quiet)"; fi
|
|
5614
|
+
`;
|
|
5615
|
+
POWERSHELL_OLD_HOOK = `
|
|
5616
|
+
# ZAM Shell Observation Hooks
|
|
5617
|
+
if (Get-Command zam -ErrorAction SilentlyContinue) { Invoke-Expression (& zam monitor start --quiet pwsh) }
|
|
5618
|
+
`;
|
|
5619
|
+
HOOK_MARKER = "# ZAM Monitor Session Helper";
|
|
5620
|
+
POWERSHELL_HOOK = `
|
|
5621
|
+
${HOOK_MARKER}
|
|
5622
|
+
function Start-ZamMonitor {
|
|
5623
|
+
param([Parameter(Mandatory = $true)][string]$Session)
|
|
5624
|
+
Invoke-Expression (& zam monitor start --session $Session --shell pwsh)
|
|
5625
|
+
}
|
|
5626
|
+
`;
|
|
5627
|
+
}
|
|
5628
|
+
});
|
|
5362
5629
|
|
|
5363
5630
|
// src/kernel/system/i18n.ts
|
|
5364
|
-
var TRANSLATIONS = {
|
|
5365
|
-
en: {
|
|
5366
|
-
welcome: "Learning session: {count} card(s)",
|
|
5367
|
-
new_review_relearn: " New: {newC} Review: {reviewC} Relearn: {relearnC}",
|
|
5368
|
-
domains: " Domains: {domains}",
|
|
5369
|
-
instruction: "\nRecall each answer first, reveal it, then rate yourself honestly.",
|
|
5370
|
-
quit_hint: "Type 'q' at the answer prompt (or press Ctrl+C) to stop anytime.",
|
|
5371
|
-
offline_warning: "\n\x1B[33m\u26A0 LLM-Feedback & automatic translation are disabled.\x1B[0m",
|
|
5372
|
-
offline_instruction: " Enable with: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5373
|
-
nothing_due: "Nothing due to learn. You're all caught up!",
|
|
5374
|
-
evaluating: "Evaluating answer via local AI...",
|
|
5375
|
-
generating_question: "Generating dynamic question...",
|
|
5376
|
-
translating: "Translating question dynamically...",
|
|
5377
|
-
prompt_answer: "Your answer (Enter to reveal \xB7 'q' to stop):",
|
|
5378
|
-
session_ended: "Learning session ended.",
|
|
5379
|
-
session_complete: "Learning session complete!",
|
|
5380
|
-
cards_rated: " Cards rated: {count}",
|
|
5381
|
-
avg_rating: " Average rating: {avg}",
|
|
5382
|
-
forgot: " Forgot: {count} card(s)",
|
|
5383
|
-
feedback_title: "\u2500\u2500 ZAM Feedback {line}",
|
|
5384
|
-
answer_title: "\u2500\u2500 Answer {line}",
|
|
5385
|
-
keep_waiting: "Would you like to keep waiting?",
|
|
5386
|
-
local_ai_working: "The local AI is still generating the response.",
|
|
5387
|
-
wait_warning: "\u26A0 The LLM server is taking a while to load the model.",
|
|
5388
|
-
wait_info: "(This is expected when transitioning between models or starting up from cold.)",
|
|
5389
|
-
keep_waiting_llm: "Would you like to keep waiting for the model?",
|
|
5390
|
-
proceeding_offline: "\u26A0 Proceeding in offline-mode (without active LLM evaluations for this session).",
|
|
5391
|
-
eval_skipped: " [LLM Evaluation skipped: {reason}]"
|
|
5392
|
-
},
|
|
5393
|
-
de: {
|
|
5394
|
-
welcome: "Lern-Session: {count} Karte(n)",
|
|
5395
|
-
new_review_relearn: " Neu: {newC} Wiederholen: {reviewC} Lernen: {relearnC}",
|
|
5396
|
-
domains: " Dom\xE4nen: {domains}",
|
|
5397
|
-
instruction: "\nRufe jede Antwort zuerst ab, decke sie auf und bewerte dich dann ehrlich selbst.",
|
|
5398
|
-
quit_hint: "Gib 'q' bei der Antwortaufforderung ein (oder dr\xFCcke Strg+C), um jederzeit zu beenden.",
|
|
5399
|
-
offline_warning: "\n\x1B[33m\u26A0 LLM-Feedback & automatische \xDCbersetzung sind deaktiviert.\x1B[0m",
|
|
5400
|
-
offline_instruction: " Aktivieren mit: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5401
|
-
nothing_due: "Nichts f\xE4llig zu lernen. Du bist komplett auf dem Laufenden!",
|
|
5402
|
-
evaluating: "Bewerte Antwort via lokaler KI...",
|
|
5403
|
-
generating_question: "Generiere dynamische Frage...",
|
|
5404
|
-
translating: "\xDCbersetze Frage dynamisch...",
|
|
5405
|
-
prompt_answer: "Deine Antwort (Eingabe zum Aufdecken \xB7 'q' zum Beenden):",
|
|
5406
|
-
session_ended: "Lern-Session beendet.",
|
|
5407
|
-
session_complete: "Lern-Session abgeschlossen!",
|
|
5408
|
-
cards_rated: " Bewertete Karten: {count}",
|
|
5409
|
-
avg_rating: " Durchschnittliche Bewertung: {avg}",
|
|
5410
|
-
forgot: " Vergessen: {count} Karte(n)",
|
|
5411
|
-
feedback_title: "\u2500\u2500 ZAM Feedback {line}",
|
|
5412
|
-
answer_title: "\u2500\u2500 Antwort {line}",
|
|
5413
|
-
keep_waiting: "M\xF6chtest du weiter auf die Bewertung warten?",
|
|
5414
|
-
local_ai_working: "Die lokale KI arbeitet noch an der Antwort.",
|
|
5415
|
-
wait_warning: "\u26A0 Der LLM-Server braucht ungew\xF6hnlich lange, um das Modell zu laden.",
|
|
5416
|
-
wait_info: "(Das ist normal, wenn das Modell gewechselt wird oder kalt startet.)",
|
|
5417
|
-
keep_waiting_llm: "M\xF6chtest du weiter auf das Modell warten?",
|
|
5418
|
-
proceeding_offline: "\u26A0 Fahre im Offline-Modus fort (ohne aktive LLM-Bewertungen in dieser Runde).",
|
|
5419
|
-
eval_skipped: " [LLM-Bewertung \xFCbersprungen: {reason}]"
|
|
5420
|
-
},
|
|
5421
|
-
es: {
|
|
5422
|
-
welcome: "Sesi\xF3n de aprendizaje: {count} tarjeta(s)",
|
|
5423
|
-
new_review_relearn: " Nuevas: {newC} Repasar: {reviewC} Reaprender: {relearnC}",
|
|
5424
|
-
domains: " Dominios: {domains}",
|
|
5425
|
-
instruction: "\nRecuerda cada respuesta primero, rev\xE9lala y calif\xEDcate honestamente.",
|
|
5426
|
-
quit_hint: "Escribe 'q' en la respuesta (o presiona Ctrl+C) para salir en cualquier momento.",
|
|
5427
|
-
offline_warning: "\n\x1B[33m\u26A0 Los comentarios de LLM y la traducci\xF3n autom\xE1tica est\xE1n desactivados.\x1B[0m",
|
|
5428
|
-
offline_instruction: " Activar con: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5429
|
-
nothing_due: "No hay nada pendiente para aprender. \xA1Est\xE1s al d\xEDa!",
|
|
5430
|
-
evaluating: "Evaluando respuesta con IA local...",
|
|
5431
|
-
generating_question: "Generando pregunta din\xE1mica...",
|
|
5432
|
-
translating: "Traduciendo pregunta din\xE1micamente...",
|
|
5433
|
-
prompt_answer: "Tu respuesta (Intro para revelar \xB7 'q' para salir):",
|
|
5434
|
-
session_ended: "Sesi\xF3n de aprendizaje finalizada.",
|
|
5435
|
-
session_complete: "\xA1Sesi\xF3n de aprendizaje completada!",
|
|
5436
|
-
cards_rated: " Tarjetas calificadas: {count}",
|
|
5437
|
-
avg_rating: " Calificaci\xF3n promedio: {avg}",
|
|
5438
|
-
forgot: " Olvidadas: {count} tarjeta(s)",
|
|
5439
|
-
feedback_title: "\u2500\u2500 Comentarios de ZAM {line}",
|
|
5440
|
-
answer_title: "\u2500\u2500 Respuesta {line}",
|
|
5441
|
-
keep_waiting: "\xBFDeseas seguir esperando la evaluaci\xF3n?",
|
|
5442
|
-
local_ai_working: "La IA local todav\xEDa est\xE1 generando la respuesta.",
|
|
5443
|
-
wait_warning: "\u26A0 El servidor LLM est\xE1 tardando en cargar el modelo.",
|
|
5444
|
-
wait_info: "(Esto es normal al cambiar de modelo o iniciar en fr\xEDo.)",
|
|
5445
|
-
keep_waiting_llm: "\xBFDeseas seguir esperando el modelo?",
|
|
5446
|
-
proceeding_offline: "\u26A0 Continuando en modo fuera de l\xEDnea (sin evaluaciones de LLM en esta sesi\xF3n).",
|
|
5447
|
-
eval_skipped: " [Evaluaci\xF3n de LLM omitida: {reason}]"
|
|
5448
|
-
},
|
|
5449
|
-
fr: {
|
|
5450
|
-
welcome: "Session d'apprentissage : {count} carte(s)",
|
|
5451
|
-
new_review_relearn: " Nouveau: {newC} R\xE9vision: {reviewC} Relever: {relearnC}",
|
|
5452
|
-
domains: " Domaines: {domains}",
|
|
5453
|
-
instruction: "\nRappelez-vous chaque r\xE9ponse d'abord, r\xE9v\xE9lez-la, puis \xE9valuez-vous honn\xEAtement.",
|
|
5454
|
-
quit_hint: "Tapez 'q' (ou Ctrl+C) pour quitter \xE0 tout moment.",
|
|
5455
|
-
offline_warning: "\n\x1B[33m\u26A0 Les commentaires LLM et la traduction automatique sont d\xE9sactiv\xE9s.\x1B[0m",
|
|
5456
|
-
offline_instruction: " Activer avec : \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5457
|
-
nothing_due: "Rien \xE0 apprendre. Vous \xEAtes \xE0 jour !",
|
|
5458
|
-
evaluating: "\xC9valuation de la r\xE9ponse via l'IA locale...",
|
|
5459
|
-
generating_question: "G\xE9n\xE9ration d'une question dynamique...",
|
|
5460
|
-
translating: "Traduction dynamique de la question...",
|
|
5461
|
-
prompt_answer: "Votre r\xE9ponse (Entr\xE9e pour r\xE9v\xE9ler \xB7 'q' pour quitter) :",
|
|
5462
|
-
session_ended: "Session d'apprentissage arr\xEAt\xE9e.",
|
|
5463
|
-
session_complete: "Session d'apprentissage termin\xE9e !",
|
|
5464
|
-
cards_rated: " Cartes \xE9valu\xE9es: {count}",
|
|
5465
|
-
avg_rating: " Note moyenne: {avg}",
|
|
5466
|
-
forgot: " Oubli\xE9es: {count} carte(s)",
|
|
5467
|
-
feedback_title: "\u2500\u2500 Commentaires ZAM {line}",
|
|
5468
|
-
answer_title: "\u2500\u2500 R\xE9ponse {line}",
|
|
5469
|
-
keep_waiting: "Voulez-vous continuer \xE0 attendre l'\xE9valuation ?",
|
|
5470
|
-
local_ai_working: "L'IA locale est toujours en train de g\xE9n\xE9rer la r\xE9ponse.",
|
|
5471
|
-
wait_warning: "\u26A0 Le serveur LLM prend du temps pour charger le mod\xE8le.",
|
|
5472
|
-
wait_info: "(Ceci est normal lors de la transition entre mod\xE8les ou du d\xE9marrage \xE0 froid.)",
|
|
5473
|
-
keep_waiting_llm: "Voulez-vous continuer \xE0 attendre le mod\xE8le ?",
|
|
5474
|
-
proceeding_offline: "\u26A0 Poursuite en mode hors ligne (sans \xE9valuation active de l'IA pour cette session).",
|
|
5475
|
-
eval_skipped: " [\xC9valuation LLM ignor\xE9e : {reason}]"
|
|
5476
|
-
},
|
|
5477
|
-
pt: {
|
|
5478
|
-
welcome: "Sess\xE3o de aprendizado: {count} cart\xE3o(\xF5es)",
|
|
5479
|
-
new_review_relearn: " Novos: {newC} Revisar: {reviewC} Reaprender: {relearnC}",
|
|
5480
|
-
domains: " Dom\xEDnios: {domains}",
|
|
5481
|
-
instruction: "\nLembre-se de cada resposta primeiro, revele-a e avalie-se honestamente.",
|
|
5482
|
-
quit_hint: "Digite 'q' (ou Ctrl+C) para parar a qualquer momento.",
|
|
5483
|
-
offline_warning: "\n\x1B[33m\u26A0 O feedback do LLM e a tradu\xE7\xE3o autom\xE1tica est\xE3o desativados.\x1B[0m",
|
|
5484
|
-
offline_instruction: " Ativar com: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5485
|
-
nothing_due: "Nada faturado para aprender. Voc\xEA est\xE1 atualizado!",
|
|
5486
|
-
evaluating: "Avaliando a resposta via IA local...",
|
|
5487
|
-
generating_question: "Gerando pergunta din\xE2mica...",
|
|
5488
|
-
translating: "Traduzindo pergunta dinamicamente...",
|
|
5489
|
-
prompt_answer: "Sua resposta (Enter para revelar \xB7 'q' para parar):",
|
|
5490
|
-
session_ended: "Sess\xE3o de aprendizado encerrada.",
|
|
5491
|
-
session_complete: "Sess\xE3o de aprendizado conclu\xEDda!",
|
|
5492
|
-
cards_rated: " Cart\xF5es avaliados: {count}",
|
|
5493
|
-
avg_rating: " Nota m\xE9dia: {avg}",
|
|
5494
|
-
forgot: " Esquecidos: {count} cart\xE3o(\xF5es)",
|
|
5495
|
-
feedback_title: "\u2500\u2500 Feedback ZAM {line}",
|
|
5496
|
-
answer_title: "\u2500\u2500 Resposta {line}",
|
|
5497
|
-
keep_waiting: "Deseja continuar esperando pela avalia\xE7\xE3o?",
|
|
5498
|
-
local_ai_working: "A IA local ainda est\xE1 gerando a resposta.",
|
|
5499
|
-
wait_warning: "\u26A0 O servidor LLM est\xE1 demorando para carregar o modelo.",
|
|
5500
|
-
wait_info: "(Isso \xE9 esperado ao alternar modelos ou iniciar do zero.)",
|
|
5501
|
-
keep_waiting_llm: "Deseja continuar esperando o modelo?",
|
|
5502
|
-
proceeding_offline: "\u26A0 Continuando no modo offline (sem avalia\xE7\xF5es de LLM ativas nesta sess\xE3o).",
|
|
5503
|
-
eval_skipped: " [Avalia\xE7\xE3o LLM omitida: {reason}]"
|
|
5504
|
-
},
|
|
5505
|
-
zh: {
|
|
5506
|
-
welcome: "\u5B66\u4E60\u8BFE: {count} \u5F20\u5361\u7247",
|
|
5507
|
-
new_review_relearn: " \u65B0\u5361: {newC} \u590D\u4E60: {reviewC} \u91CD\u5B66: {relearnC}",
|
|
5508
|
-
domains: " \u77E5\u8BC6\u9886\u57DF: {domains}",
|
|
5509
|
-
instruction: "\n\u9996\u5148\u5728\u8111\u4E2D\u56DE\u5FC6\u7B54\u6848\uFF0C\u7136\u540E\u63ED\u6653\u5E76\u8BDA\u5B9E\u81EA\u6211\u8BC4\u5206\u3002",
|
|
5510
|
-
quit_hint: "\u5728\u56DE\u7B54\u63D0\u793A\u5904\u8F93\u5165 'q' (\u6216\u6309 Ctrl+C) \u53EF\u968F\u65F6\u9000\u51FA\u3002",
|
|
5511
|
-
offline_warning: "\n\x1B[33m\u26A0 LLM \u53CD\u9988\u4E0E\u81EA\u52A8\u7FFB\u8BD1\u5DF2\u7981\u7528\u3002\x1B[0m",
|
|
5512
|
-
offline_instruction: " \u5F00\u542F\u547D\u4EE4: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5513
|
-
nothing_due: "\u76EE\u524D\u6CA1\u6709\u9700\u8981\u5B66\u4E60\u7684\u5185\u5BB9\u3002\u60A8\u5DF2\u5168\u90E8\u638C\u63E1\uFF01",
|
|
5514
|
-
evaluating: "\u6B63\u5728\u901A\u8FC7\u672C\u5730 AI \u8BC4\u4F30\u56DE\u7B54...",
|
|
5515
|
-
generating_question: "\u6B63\u5728\u52A8\u6001\u751F\u6210\u95EE\u9898...",
|
|
5516
|
-
translating: "\u6B63\u5728\u52A8\u6001\u7FFB\u8BD1\u95EE\u9898...",
|
|
5517
|
-
prompt_answer: "\u60A8\u7684\u56DE\u7B54 (\u6309\u56DE\u8F66\u63ED\u6653 \xB7 \u8F93\u5165 'q' \u9000\u51FA):",
|
|
5518
|
-
session_ended: "\u5B66\u4E60\u8BFE\u5DF2\u7ED3\u675F\u3002",
|
|
5519
|
-
session_complete: "\u5B66\u4E60\u8BFE\u5DF2\u5B8C\u6210\uFF01",
|
|
5520
|
-
cards_rated: " \u5DF2\u8BC4\u5206\u5361\u7247: {count}",
|
|
5521
|
-
avg_rating: " \u5E73\u5747\u5206: {avg}",
|
|
5522
|
-
forgot: " \u9057\u5FD8: {count} \u5F20\u5361\u7247",
|
|
5523
|
-
feedback_title: "\u2500\u2500 ZAM \u53CD\u9988 {line}",
|
|
5524
|
-
answer_title: "\u2500\u2500 \u53C2\u8003\u7B54\u6848 {line}",
|
|
5525
|
-
keep_waiting: "\u662F\u5426\u7EE7\u7EED\u7B49\u5F85\u8BC4\u5206\uFF1F",
|
|
5526
|
-
local_ai_working: "\u672C\u5730 AI \u4ECD\u5728\u751F\u6210\u56DE\u7B54\u3002",
|
|
5527
|
-
wait_warning: "\u26A0 LLM \u670D\u52A1\u5668\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\uFF0C\u8FD9\u53EF\u80FD\u9700\u8981\u4E00\u4E9B\u65F6\u95F4\u3002",
|
|
5528
|
-
wait_info: "(\u8FD9\u5728\u5207\u6362\u6A21\u578B\u6216\u51B7\u542F\u52A8\u65F6\u662F\u6B63\u5E38\u73B0\u8C61\u3002)",
|
|
5529
|
-
keep_waiting_llm: "\u662F\u5426\u7EE7\u7EED\u7B49\u5F85\u6A21\u578B\u52A0\u8F7D\uFF1F",
|
|
5530
|
-
proceeding_offline: "\u26A0 \u6B63\u5728\u4EE5\u79BB\u7EBF\u6A21\u5F0F\u7EE7\u7EED\uFF08\u672C\u6B21\u5B66\u4E60\u8BFE\u5C06\u4E0D\u5305\u542B\u6D3B\u8DC3\u7684 AI \u8BC4\u4F30\uFF09\u3002",
|
|
5531
|
-
eval_skipped: " [\u5DF2\u8DF3\u8FC7 LLM \u8BC4\u4F30: {reason}]"
|
|
5532
|
-
},
|
|
5533
|
-
ja: {
|
|
5534
|
-
welcome: "\u5B66\u7FD2\u30BB\u30C3\u30B7\u30E7\u30F3: {count} \u679A\u306E\u30AB\u30FC\u30C9",
|
|
5535
|
-
new_review_relearn: " \u65B0\u898F: {newC} \u5FA9\u7FD2: {reviewC} \u518D\u5B66\u7FD2: {relearnC}",
|
|
5536
|
-
domains: " \u30C9\u30E1\u30A4\u30F3: {domains}",
|
|
5537
|
-
instruction: "\n\u6700\u521D\u306B\u56DE\u7B54\u3092\u601D\u3044\u51FA\u3057\u3001\u6B21\u306B\u56DE\u7B54\u3092\u8868\u793A\u3057\u3066\u3001\u6B63\u76F4\u306B\u81EA\u5DF1\u8A55\u4FA1\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
5538
|
-
quit_hint: "\u56DE\u7B54\u30D7\u30ED\u30F3\u30D7\u30C8\u3067\u300Cq\u300D\u3092\u5165\u529B\u3059\u308B\uFF08\u307E\u305F\u306F Ctrl+C \u3092\u62BC\u3059\uFF09\u3068\u3001\u3044\u3064\u3067\u3082\u7D42\u4E86\u3067\u304D\u307E\u3059\u3002",
|
|
5539
|
-
offline_warning: "\n\x1B[33m\u26A0 LLM \u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF\u3068\u81EA\u52D5\u7FFB\u8A33\u306F\u7121\u52B9\u3067\u3059\u3002\x1B[0m",
|
|
5540
|
-
offline_instruction: " \u6709\u52B9\u5316\u3059\u308B\u306B\u306F: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5541
|
-
nothing_due: "\u5B66\u7FD2\u4E88\u5B9A\u306E\u30AB\u30FC\u30C9\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u3059\u3079\u3066\u5B8C\u4E86\u3057\u3066\u3044\u307E\u3059\uFF01",
|
|
5542
|
-
evaluating: "\u30ED\u30FC\u30AB\u30EBAI\u306B\u3088\u308B\u56DE\u7B54\u306E\u8A55\u4FA1\u4E2D...",
|
|
5543
|
-
generating_question: "\u8CEA\u554F\u3092\u52D5\u7684\u306B\u751F\u6210\u4E2D...",
|
|
5544
|
-
translating: "\u8CEA\u554F\u3092\u52D5\u7684\u306B\u7FFB\u8A33\u4E2D...",
|
|
5545
|
-
prompt_answer: "\u3042\u306A\u305F\u306E\u56DE\u7B54 (Enter\u3067\u8868\u793A \xB7 'q'\u3067\u7D42\u4E86):",
|
|
5546
|
-
session_ended: "\u5B66\u7FD2\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u7D42\u4E86\u3057\u307E\u3057\u305F\u3002",
|
|
5547
|
-
session_complete: "\u5B66\u7FD2\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\uFF01",
|
|
5548
|
-
cards_rated: " \u8A55\u4FA1\u6E08\u307F\u30AB\u30FC\u30C9\u6570: {count}",
|
|
5549
|
-
avg_rating: " \u5E73\u5747\u8A55\u4FA1: {avg}",
|
|
5550
|
-
forgot: " \u5FD8\u308C\u305F\u30AB\u30FC\u30C9\u6570: {count} \u679A",
|
|
5551
|
-
feedback_title: "\u2500\u2500 ZAM \u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF {line}",
|
|
5552
|
-
answer_title: "\u2500\u2500 \u89E3\u7B54 {line}",
|
|
5553
|
-
keep_waiting: "\u8A55\u4FA1\u306E\u751F\u6210\u3092\u5F85\u3061\u307E\u3059\u304B\uFF1F",
|
|
5554
|
-
local_ai_working: "\u30ED\u30FC\u30AB\u30EBAI\u304C\u56DE\u7B54\u3092\u751F\u6210\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
5555
|
-
wait_warning: "\u26A0 LLM \u30B5\u30FC\u30D0\u30FC\u304C\u30E2\u30C7\u30EB\u3092\u30ED\u30FC\u30C9\u3059\u308B\u306E\u306B\u6642\u9593\u304C\u304B\u304B\u3063\u3066\u3044\u307E\u3059\u3002",
|
|
5556
|
-
wait_info: "(\u30E2\u30C7\u30EB\u306E\u79FB\u884C\u4E2D\u3084\u30B3\u30FC\u30EB\u30C9\u30B9\u30BF\u30FC\u30C8\u6642\u306B\u306F\u3001\u3053\u308C\u304C\u4E88\u60F3\u3055\u308C\u307E\u3059\u3002)",
|
|
5557
|
-
keep_waiting_llm: "\u30E2\u30C7\u30EB\u306E\u30ED\u30FC\u30C9\u3092\u5F85\u3061\u7D9A\u3051\u307E\u3059\u304B\uFF1F",
|
|
5558
|
-
proceeding_offline: "\u26A0 \u30AA\u30D5\u30E9\u30A4\u30F3\u30E2\u30FC\u30C9\u3067\u7D9A\u884C\u3057\u307E\u3059\uFF08\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u306F\u30A2\u30AF\u30C6\u30A3\u30D6\u306A AI \u8A55\u4FA1\u306F\u884C\u308F\u308C\u307E\u305B\u3093\uFF09\u3002",
|
|
5559
|
-
eval_skipped: " [LLM \u8A55\u4FA1\u304C\u30B9\u30AD\u30C3\u30D7\u3055\u308C\u307E\u3057\u305F: {reason}]"
|
|
5560
|
-
}
|
|
5561
|
-
};
|
|
5562
5631
|
function t(locale, key, params = {}) {
|
|
5563
5632
|
const dict = TRANSLATIONS[locale] || TRANSLATIONS.en;
|
|
5564
5633
|
let str = dict[key] || TRANSLATIONS.en[key] || "";
|
|
@@ -5567,6 +5636,210 @@ function t(locale, key, params = {}) {
|
|
|
5567
5636
|
}
|
|
5568
5637
|
return str;
|
|
5569
5638
|
}
|
|
5639
|
+
var TRANSLATIONS;
|
|
5640
|
+
var init_i18n = __esm({
|
|
5641
|
+
"src/kernel/system/i18n.ts"() {
|
|
5642
|
+
"use strict";
|
|
5643
|
+
TRANSLATIONS = {
|
|
5644
|
+
en: {
|
|
5645
|
+
welcome: "Learning session: {count} card(s)",
|
|
5646
|
+
new_review_relearn: " New: {newC} Review: {reviewC} Relearn: {relearnC}",
|
|
5647
|
+
domains: " Domains: {domains}",
|
|
5648
|
+
instruction: "\nRecall each answer first, reveal it, then rate yourself honestly.",
|
|
5649
|
+
quit_hint: "Type 'q' at the answer prompt (or press Ctrl+C) to stop anytime.",
|
|
5650
|
+
offline_warning: "\n\x1B[33m\u26A0 LLM-Feedback & automatic translation are disabled.\x1B[0m",
|
|
5651
|
+
offline_instruction: " Enable with: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5652
|
+
nothing_due: "Nothing due to learn. You're all caught up!",
|
|
5653
|
+
evaluating: "Evaluating answer via local AI...",
|
|
5654
|
+
generating_question: "Generating dynamic question...",
|
|
5655
|
+
translating: "Translating question dynamically...",
|
|
5656
|
+
prompt_answer: "Your answer (Enter to reveal \xB7 'q' to stop):",
|
|
5657
|
+
session_ended: "Learning session ended.",
|
|
5658
|
+
session_complete: "Learning session complete!",
|
|
5659
|
+
cards_rated: " Cards rated: {count}",
|
|
5660
|
+
avg_rating: " Average rating: {avg}",
|
|
5661
|
+
forgot: " Forgot: {count} card(s)",
|
|
5662
|
+
feedback_title: "\u2500\u2500 ZAM Feedback {line}",
|
|
5663
|
+
answer_title: "\u2500\u2500 Answer {line}",
|
|
5664
|
+
keep_waiting: "Would you like to keep waiting?",
|
|
5665
|
+
local_ai_working: "The local AI is still generating the response.",
|
|
5666
|
+
wait_warning: "\u26A0 The LLM server is taking a while to load the model.",
|
|
5667
|
+
wait_info: "(This is expected when transitioning between models or starting up from cold.)",
|
|
5668
|
+
keep_waiting_llm: "Would you like to keep waiting for the model?",
|
|
5669
|
+
proceeding_offline: "\u26A0 Proceeding in offline-mode (without active LLM evaluations for this session).",
|
|
5670
|
+
eval_skipped: " [LLM Evaluation skipped: {reason}]"
|
|
5671
|
+
},
|
|
5672
|
+
de: {
|
|
5673
|
+
welcome: "Lern-Session: {count} Karte(n)",
|
|
5674
|
+
new_review_relearn: " Neu: {newC} Wiederholen: {reviewC} Lernen: {relearnC}",
|
|
5675
|
+
domains: " Dom\xE4nen: {domains}",
|
|
5676
|
+
instruction: "\nRufe jede Antwort zuerst ab, decke sie auf und bewerte dich dann ehrlich selbst.",
|
|
5677
|
+
quit_hint: "Gib 'q' bei der Antwortaufforderung ein (oder dr\xFCcke Strg+C), um jederzeit zu beenden.",
|
|
5678
|
+
offline_warning: "\n\x1B[33m\u26A0 LLM-Feedback & automatische \xDCbersetzung sind deaktiviert.\x1B[0m",
|
|
5679
|
+
offline_instruction: " Aktivieren mit: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5680
|
+
nothing_due: "Nichts f\xE4llig zu lernen. Du bist komplett auf dem Laufenden!",
|
|
5681
|
+
evaluating: "Bewerte Antwort via lokaler KI...",
|
|
5682
|
+
generating_question: "Generiere dynamische Frage...",
|
|
5683
|
+
translating: "\xDCbersetze Frage dynamisch...",
|
|
5684
|
+
prompt_answer: "Deine Antwort (Eingabe zum Aufdecken \xB7 'q' zum Beenden):",
|
|
5685
|
+
session_ended: "Lern-Session beendet.",
|
|
5686
|
+
session_complete: "Lern-Session abgeschlossen!",
|
|
5687
|
+
cards_rated: " Bewertete Karten: {count}",
|
|
5688
|
+
avg_rating: " Durchschnittliche Bewertung: {avg}",
|
|
5689
|
+
forgot: " Vergessen: {count} Karte(n)",
|
|
5690
|
+
feedback_title: "\u2500\u2500 ZAM Feedback {line}",
|
|
5691
|
+
answer_title: "\u2500\u2500 Antwort {line}",
|
|
5692
|
+
keep_waiting: "M\xF6chtest du weiter auf die Bewertung warten?",
|
|
5693
|
+
local_ai_working: "Die lokale KI arbeitet noch an der Antwort.",
|
|
5694
|
+
wait_warning: "\u26A0 Der LLM-Server braucht ungew\xF6hnlich lange, um das Modell zu laden.",
|
|
5695
|
+
wait_info: "(Das ist normal, wenn das Modell gewechselt wird oder kalt startet.)",
|
|
5696
|
+
keep_waiting_llm: "M\xF6chtest du weiter auf das Modell warten?",
|
|
5697
|
+
proceeding_offline: "\u26A0 Fahre im Offline-Modus fort (ohne aktive LLM-Bewertungen in dieser Runde).",
|
|
5698
|
+
eval_skipped: " [LLM-Bewertung \xFCbersprungen: {reason}]"
|
|
5699
|
+
},
|
|
5700
|
+
es: {
|
|
5701
|
+
welcome: "Sesi\xF3n de aprendizaje: {count} tarjeta(s)",
|
|
5702
|
+
new_review_relearn: " Nuevas: {newC} Repasar: {reviewC} Reaprender: {relearnC}",
|
|
5703
|
+
domains: " Dominios: {domains}",
|
|
5704
|
+
instruction: "\nRecuerda cada respuesta primero, rev\xE9lala y calif\xEDcate honestamente.",
|
|
5705
|
+
quit_hint: "Escribe 'q' en la respuesta (o presiona Ctrl+C) para salir en cualquier momento.",
|
|
5706
|
+
offline_warning: "\n\x1B[33m\u26A0 Los comentarios de LLM y la traducci\xF3n autom\xE1tica est\xE1n desactivados.\x1B[0m",
|
|
5707
|
+
offline_instruction: " Activar con: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5708
|
+
nothing_due: "No hay nada pendiente para aprender. \xA1Est\xE1s al d\xEDa!",
|
|
5709
|
+
evaluating: "Evaluando respuesta con IA local...",
|
|
5710
|
+
generating_question: "Generando pregunta din\xE1mica...",
|
|
5711
|
+
translating: "Traduciendo pregunta din\xE1micamente...",
|
|
5712
|
+
prompt_answer: "Tu respuesta (Intro para revelar \xB7 'q' para salir):",
|
|
5713
|
+
session_ended: "Sesi\xF3n de aprendizaje finalizada.",
|
|
5714
|
+
session_complete: "\xA1Sesi\xF3n de aprendizaje completada!",
|
|
5715
|
+
cards_rated: " Tarjetas calificadas: {count}",
|
|
5716
|
+
avg_rating: " Calificaci\xF3n promedio: {avg}",
|
|
5717
|
+
forgot: " Olvidadas: {count} tarjeta(s)",
|
|
5718
|
+
feedback_title: "\u2500\u2500 Comentarios de ZAM {line}",
|
|
5719
|
+
answer_title: "\u2500\u2500 Respuesta {line}",
|
|
5720
|
+
keep_waiting: "\xBFDeseas seguir esperando la evaluaci\xF3n?",
|
|
5721
|
+
local_ai_working: "La IA local todav\xEDa est\xE1 generando la respuesta.",
|
|
5722
|
+
wait_warning: "\u26A0 El servidor LLM est\xE1 tardando en cargar el modelo.",
|
|
5723
|
+
wait_info: "(Esto es normal al cambiar de modelo o iniciar en fr\xEDo.)",
|
|
5724
|
+
keep_waiting_llm: "\xBFDeseas seguir esperando el modelo?",
|
|
5725
|
+
proceeding_offline: "\u26A0 Continuando en modo fuera de l\xEDnea (sin evaluaciones de LLM en esta sesi\xF3n).",
|
|
5726
|
+
eval_skipped: " [Evaluaci\xF3n de LLM omitida: {reason}]"
|
|
5727
|
+
},
|
|
5728
|
+
fr: {
|
|
5729
|
+
welcome: "Session d'apprentissage : {count} carte(s)",
|
|
5730
|
+
new_review_relearn: " Nouveau: {newC} R\xE9vision: {reviewC} Relever: {relearnC}",
|
|
5731
|
+
domains: " Domaines: {domains}",
|
|
5732
|
+
instruction: "\nRappelez-vous chaque r\xE9ponse d'abord, r\xE9v\xE9lez-la, puis \xE9valuez-vous honn\xEAtement.",
|
|
5733
|
+
quit_hint: "Tapez 'q' (ou Ctrl+C) pour quitter \xE0 tout moment.",
|
|
5734
|
+
offline_warning: "\n\x1B[33m\u26A0 Les commentaires LLM et la traduction automatique sont d\xE9sactiv\xE9s.\x1B[0m",
|
|
5735
|
+
offline_instruction: " Activer avec : \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5736
|
+
nothing_due: "Rien \xE0 apprendre. Vous \xEAtes \xE0 jour !",
|
|
5737
|
+
evaluating: "\xC9valuation de la r\xE9ponse via l'IA locale...",
|
|
5738
|
+
generating_question: "G\xE9n\xE9ration d'une question dynamique...",
|
|
5739
|
+
translating: "Traduction dynamique de la question...",
|
|
5740
|
+
prompt_answer: "Votre r\xE9ponse (Entr\xE9e pour r\xE9v\xE9ler \xB7 'q' pour quitter) :",
|
|
5741
|
+
session_ended: "Session d'apprentissage arr\xEAt\xE9e.",
|
|
5742
|
+
session_complete: "Session d'apprentissage termin\xE9e !",
|
|
5743
|
+
cards_rated: " Cartes \xE9valu\xE9es: {count}",
|
|
5744
|
+
avg_rating: " Note moyenne: {avg}",
|
|
5745
|
+
forgot: " Oubli\xE9es: {count} carte(s)",
|
|
5746
|
+
feedback_title: "\u2500\u2500 Commentaires ZAM {line}",
|
|
5747
|
+
answer_title: "\u2500\u2500 R\xE9ponse {line}",
|
|
5748
|
+
keep_waiting: "Voulez-vous continuer \xE0 attendre l'\xE9valuation ?",
|
|
5749
|
+
local_ai_working: "L'IA locale est toujours en train de g\xE9n\xE9rer la r\xE9ponse.",
|
|
5750
|
+
wait_warning: "\u26A0 Le serveur LLM prend du temps pour charger le mod\xE8le.",
|
|
5751
|
+
wait_info: "(Ceci est normal lors de la transition entre mod\xE8les ou du d\xE9marrage \xE0 froid.)",
|
|
5752
|
+
keep_waiting_llm: "Voulez-vous continuer \xE0 attendre le mod\xE8le ?",
|
|
5753
|
+
proceeding_offline: "\u26A0 Poursuite en mode hors ligne (sans \xE9valuation active de l'IA pour cette session).",
|
|
5754
|
+
eval_skipped: " [\xC9valuation LLM ignor\xE9e : {reason}]"
|
|
5755
|
+
},
|
|
5756
|
+
pt: {
|
|
5757
|
+
welcome: "Sess\xE3o de aprendizado: {count} cart\xE3o(\xF5es)",
|
|
5758
|
+
new_review_relearn: " Novos: {newC} Revisar: {reviewC} Reaprender: {relearnC}",
|
|
5759
|
+
domains: " Dom\xEDnios: {domains}",
|
|
5760
|
+
instruction: "\nLembre-se de cada resposta primeiro, revele-a e avalie-se honestamente.",
|
|
5761
|
+
quit_hint: "Digite 'q' (ou Ctrl+C) para parar a qualquer momento.",
|
|
5762
|
+
offline_warning: "\n\x1B[33m\u26A0 O feedback do LLM e a tradu\xE7\xE3o autom\xE1tica est\xE3o desativados.\x1B[0m",
|
|
5763
|
+
offline_instruction: " Ativar com: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5764
|
+
nothing_due: "Nada faturado para aprender. Voc\xEA est\xE1 atualizado!",
|
|
5765
|
+
evaluating: "Avaliando a resposta via IA local...",
|
|
5766
|
+
generating_question: "Gerando pergunta din\xE2mica...",
|
|
5767
|
+
translating: "Traduzindo pergunta dinamicamente...",
|
|
5768
|
+
prompt_answer: "Sua resposta (Enter para revelar \xB7 'q' para parar):",
|
|
5769
|
+
session_ended: "Sess\xE3o de aprendizado encerrada.",
|
|
5770
|
+
session_complete: "Sess\xE3o de aprendizado conclu\xEDda!",
|
|
5771
|
+
cards_rated: " Cart\xF5es avaliados: {count}",
|
|
5772
|
+
avg_rating: " Nota m\xE9dia: {avg}",
|
|
5773
|
+
forgot: " Esquecidos: {count} cart\xE3o(\xF5es)",
|
|
5774
|
+
feedback_title: "\u2500\u2500 Feedback ZAM {line}",
|
|
5775
|
+
answer_title: "\u2500\u2500 Resposta {line}",
|
|
5776
|
+
keep_waiting: "Deseja continuar esperando pela avalia\xE7\xE3o?",
|
|
5777
|
+
local_ai_working: "A IA local ainda est\xE1 gerando a resposta.",
|
|
5778
|
+
wait_warning: "\u26A0 O servidor LLM est\xE1 demorando para carregar o modelo.",
|
|
5779
|
+
wait_info: "(Isso \xE9 esperado ao alternar modelos ou iniciar do zero.)",
|
|
5780
|
+
keep_waiting_llm: "Deseja continuar esperando o modelo?",
|
|
5781
|
+
proceeding_offline: "\u26A0 Continuando no modo offline (sem avalia\xE7\xF5es de LLM ativas nesta sess\xE3o).",
|
|
5782
|
+
eval_skipped: " [Avalia\xE7\xE3o LLM omitida: {reason}]"
|
|
5783
|
+
},
|
|
5784
|
+
zh: {
|
|
5785
|
+
welcome: "\u5B66\u4E60\u8BFE: {count} \u5F20\u5361\u7247",
|
|
5786
|
+
new_review_relearn: " \u65B0\u5361: {newC} \u590D\u4E60: {reviewC} \u91CD\u5B66: {relearnC}",
|
|
5787
|
+
domains: " \u77E5\u8BC6\u9886\u57DF: {domains}",
|
|
5788
|
+
instruction: "\n\u9996\u5148\u5728\u8111\u4E2D\u56DE\u5FC6\u7B54\u6848\uFF0C\u7136\u540E\u63ED\u6653\u5E76\u8BDA\u5B9E\u81EA\u6211\u8BC4\u5206\u3002",
|
|
5789
|
+
quit_hint: "\u5728\u56DE\u7B54\u63D0\u793A\u5904\u8F93\u5165 'q' (\u6216\u6309 Ctrl+C) \u53EF\u968F\u65F6\u9000\u51FA\u3002",
|
|
5790
|
+
offline_warning: "\n\x1B[33m\u26A0 LLM \u53CD\u9988\u4E0E\u81EA\u52A8\u7FFB\u8BD1\u5DF2\u7981\u7528\u3002\x1B[0m",
|
|
5791
|
+
offline_instruction: " \u5F00\u542F\u547D\u4EE4: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5792
|
+
nothing_due: "\u76EE\u524D\u6CA1\u6709\u9700\u8981\u5B66\u4E60\u7684\u5185\u5BB9\u3002\u60A8\u5DF2\u5168\u90E8\u638C\u63E1\uFF01",
|
|
5793
|
+
evaluating: "\u6B63\u5728\u901A\u8FC7\u672C\u5730 AI \u8BC4\u4F30\u56DE\u7B54...",
|
|
5794
|
+
generating_question: "\u6B63\u5728\u52A8\u6001\u751F\u6210\u95EE\u9898...",
|
|
5795
|
+
translating: "\u6B63\u5728\u52A8\u6001\u7FFB\u8BD1\u95EE\u9898...",
|
|
5796
|
+
prompt_answer: "\u60A8\u7684\u56DE\u7B54 (\u6309\u56DE\u8F66\u63ED\u6653 \xB7 \u8F93\u5165 'q' \u9000\u51FA):",
|
|
5797
|
+
session_ended: "\u5B66\u4E60\u8BFE\u5DF2\u7ED3\u675F\u3002",
|
|
5798
|
+
session_complete: "\u5B66\u4E60\u8BFE\u5DF2\u5B8C\u6210\uFF01",
|
|
5799
|
+
cards_rated: " \u5DF2\u8BC4\u5206\u5361\u7247: {count}",
|
|
5800
|
+
avg_rating: " \u5E73\u5747\u5206: {avg}",
|
|
5801
|
+
forgot: " \u9057\u5FD8: {count} \u5F20\u5361\u7247",
|
|
5802
|
+
feedback_title: "\u2500\u2500 ZAM \u53CD\u9988 {line}",
|
|
5803
|
+
answer_title: "\u2500\u2500 \u53C2\u8003\u7B54\u6848 {line}",
|
|
5804
|
+
keep_waiting: "\u662F\u5426\u7EE7\u7EED\u7B49\u5F85\u8BC4\u5206\uFF1F",
|
|
5805
|
+
local_ai_working: "\u672C\u5730 AI \u4ECD\u5728\u751F\u6210\u56DE\u7B54\u3002",
|
|
5806
|
+
wait_warning: "\u26A0 LLM \u670D\u52A1\u5668\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\uFF0C\u8FD9\u53EF\u80FD\u9700\u8981\u4E00\u4E9B\u65F6\u95F4\u3002",
|
|
5807
|
+
wait_info: "(\u8FD9\u5728\u5207\u6362\u6A21\u578B\u6216\u51B7\u542F\u52A8\u65F6\u662F\u6B63\u5E38\u73B0\u8C61\u3002)",
|
|
5808
|
+
keep_waiting_llm: "\u662F\u5426\u7EE7\u7EED\u7B49\u5F85\u6A21\u578B\u52A0\u8F7D\uFF1F",
|
|
5809
|
+
proceeding_offline: "\u26A0 \u6B63\u5728\u4EE5\u79BB\u7EBF\u6A21\u5F0F\u7EE7\u7EED\uFF08\u672C\u6B21\u5B66\u4E60\u8BFE\u5C06\u4E0D\u5305\u542B\u6D3B\u8DC3\u7684 AI \u8BC4\u4F30\uFF09\u3002",
|
|
5810
|
+
eval_skipped: " [\u5DF2\u8DF3\u8FC7 LLM \u8BC4\u4F30: {reason}]"
|
|
5811
|
+
},
|
|
5812
|
+
ja: {
|
|
5813
|
+
welcome: "\u5B66\u7FD2\u30BB\u30C3\u30B7\u30E7\u30F3: {count} \u679A\u306E\u30AB\u30FC\u30C9",
|
|
5814
|
+
new_review_relearn: " \u65B0\u898F: {newC} \u5FA9\u7FD2: {reviewC} \u518D\u5B66\u7FD2: {relearnC}",
|
|
5815
|
+
domains: " \u30C9\u30E1\u30A4\u30F3: {domains}",
|
|
5816
|
+
instruction: "\n\u6700\u521D\u306B\u56DE\u7B54\u3092\u601D\u3044\u51FA\u3057\u3001\u6B21\u306B\u56DE\u7B54\u3092\u8868\u793A\u3057\u3066\u3001\u6B63\u76F4\u306B\u81EA\u5DF1\u8A55\u4FA1\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
5817
|
+
quit_hint: "\u56DE\u7B54\u30D7\u30ED\u30F3\u30D7\u30C8\u3067\u300Cq\u300D\u3092\u5165\u529B\u3059\u308B\uFF08\u307E\u305F\u306F Ctrl+C \u3092\u62BC\u3059\uFF09\u3068\u3001\u3044\u3064\u3067\u3082\u7D42\u4E86\u3067\u304D\u307E\u3059\u3002",
|
|
5818
|
+
offline_warning: "\n\x1B[33m\u26A0 LLM \u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF\u3068\u81EA\u52D5\u7FFB\u8A33\u306F\u7121\u52B9\u3067\u3059\u3002\x1B[0m",
|
|
5819
|
+
offline_instruction: " \u6709\u52B9\u5316\u3059\u308B\u306B\u306F: \x1B[36mnpm run dev -- settings llm on\x1B[0m\n",
|
|
5820
|
+
nothing_due: "\u5B66\u7FD2\u4E88\u5B9A\u306E\u30AB\u30FC\u30C9\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u3059\u3079\u3066\u5B8C\u4E86\u3057\u3066\u3044\u307E\u3059\uFF01",
|
|
5821
|
+
evaluating: "\u30ED\u30FC\u30AB\u30EBAI\u306B\u3088\u308B\u56DE\u7B54\u306E\u8A55\u4FA1\u4E2D...",
|
|
5822
|
+
generating_question: "\u8CEA\u554F\u3092\u52D5\u7684\u306B\u751F\u6210\u4E2D...",
|
|
5823
|
+
translating: "\u8CEA\u554F\u3092\u52D5\u7684\u306B\u7FFB\u8A33\u4E2D...",
|
|
5824
|
+
prompt_answer: "\u3042\u306A\u305F\u306E\u56DE\u7B54 (Enter\u3067\u8868\u793A \xB7 'q'\u3067\u7D42\u4E86):",
|
|
5825
|
+
session_ended: "\u5B66\u7FD2\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u7D42\u4E86\u3057\u307E\u3057\u305F\u3002",
|
|
5826
|
+
session_complete: "\u5B66\u7FD2\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\uFF01",
|
|
5827
|
+
cards_rated: " \u8A55\u4FA1\u6E08\u307F\u30AB\u30FC\u30C9\u6570: {count}",
|
|
5828
|
+
avg_rating: " \u5E73\u5747\u8A55\u4FA1: {avg}",
|
|
5829
|
+
forgot: " \u5FD8\u308C\u305F\u30AB\u30FC\u30C9\u6570: {count} \u679A",
|
|
5830
|
+
feedback_title: "\u2500\u2500 ZAM \u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF {line}",
|
|
5831
|
+
answer_title: "\u2500\u2500 \u89E3\u7B54 {line}",
|
|
5832
|
+
keep_waiting: "\u8A55\u4FA1\u306E\u751F\u6210\u3092\u5F85\u3061\u307E\u3059\u304B\uFF1F",
|
|
5833
|
+
local_ai_working: "\u30ED\u30FC\u30AB\u30EBAI\u304C\u56DE\u7B54\u3092\u751F\u6210\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
5834
|
+
wait_warning: "\u26A0 LLM \u30B5\u30FC\u30D0\u30FC\u304C\u30E2\u30C7\u30EB\u3092\u30ED\u30FC\u30C9\u3059\u308B\u306E\u306B\u6642\u9593\u304C\u304B\u304B\u3063\u3066\u3044\u307E\u3059\u3002",
|
|
5835
|
+
wait_info: "(\u30E2\u30C7\u30EB\u306E\u79FB\u884C\u4E2D\u3084\u30B3\u30FC\u30EB\u30C9\u30B9\u30BF\u30FC\u30C8\u6642\u306B\u306F\u3001\u3053\u308C\u304C\u4E88\u60F3\u3055\u308C\u307E\u3059\u3002)",
|
|
5836
|
+
keep_waiting_llm: "\u30E2\u30C7\u30EB\u306E\u30ED\u30FC\u30C9\u3092\u5F85\u3061\u7D9A\u3051\u307E\u3059\u304B\uFF1F",
|
|
5837
|
+
proceeding_offline: "\u26A0 \u30AA\u30D5\u30E9\u30A4\u30F3\u30E2\u30FC\u30C9\u3067\u7D9A\u884C\u3057\u307E\u3059\uFF08\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u306F\u30A2\u30AF\u30C6\u30A3\u30D6\u306A AI \u8A55\u4FA1\u306F\u884C\u308F\u308C\u307E\u305B\u3093\uFF09\u3002",
|
|
5838
|
+
eval_skipped: " [LLM \u8A55\u4FA1\u304C\u30B9\u30AD\u30C3\u30D7\u3055\u308C\u307E\u3057\u305F: {reason}]"
|
|
5839
|
+
}
|
|
5840
|
+
};
|
|
5841
|
+
}
|
|
5842
|
+
});
|
|
5570
5843
|
|
|
5571
5844
|
// src/kernel/system/install-config.ts
|
|
5572
5845
|
import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
@@ -5699,6 +5972,11 @@ function setActiveWorkspaceContext(contextName, path = defaultConfigPath()) {
|
|
|
5699
5972
|
}
|
|
5700
5973
|
return false;
|
|
5701
5974
|
}
|
|
5975
|
+
var init_install_config = __esm({
|
|
5976
|
+
"src/kernel/system/install-config.ts"() {
|
|
5977
|
+
"use strict";
|
|
5978
|
+
}
|
|
5979
|
+
});
|
|
5702
5980
|
|
|
5703
5981
|
// src/kernel/system/installer.ts
|
|
5704
5982
|
import { execFileSync, execSync } from "child_process";
|
|
@@ -5907,18 +6185,14 @@ function installOpenCode() {
|
|
|
5907
6185
|
};
|
|
5908
6186
|
}
|
|
5909
6187
|
}
|
|
6188
|
+
var init_installer = __esm({
|
|
6189
|
+
"src/kernel/system/installer.ts"() {
|
|
6190
|
+
"use strict";
|
|
6191
|
+
}
|
|
6192
|
+
});
|
|
5910
6193
|
|
|
5911
6194
|
// src/kernel/system/locale.ts
|
|
5912
6195
|
import { execSync as execSync2 } from "child_process";
|
|
5913
|
-
var SUPPORTED_LOCALES = /* @__PURE__ */ new Set([
|
|
5914
|
-
"en",
|
|
5915
|
-
"de",
|
|
5916
|
-
"es",
|
|
5917
|
-
"fr",
|
|
5918
|
-
"pt",
|
|
5919
|
-
"zh",
|
|
5920
|
-
"ja"
|
|
5921
|
-
]);
|
|
5922
6196
|
function normalizeLocale(raw) {
|
|
5923
6197
|
const clean = raw.trim().toLowerCase().split(/[_-]/)[0];
|
|
5924
6198
|
if (SUPPORTED_LOCALES.has(clean)) {
|
|
@@ -5952,6 +6226,21 @@ function detectSystemLocale() {
|
|
|
5952
6226
|
}
|
|
5953
6227
|
return "en";
|
|
5954
6228
|
}
|
|
6229
|
+
var SUPPORTED_LOCALES;
|
|
6230
|
+
var init_locale = __esm({
|
|
6231
|
+
"src/kernel/system/locale.ts"() {
|
|
6232
|
+
"use strict";
|
|
6233
|
+
SUPPORTED_LOCALES = /* @__PURE__ */ new Set([
|
|
6234
|
+
"en",
|
|
6235
|
+
"de",
|
|
6236
|
+
"es",
|
|
6237
|
+
"fr",
|
|
6238
|
+
"pt",
|
|
6239
|
+
"zh",
|
|
6240
|
+
"ja"
|
|
6241
|
+
]);
|
|
6242
|
+
}
|
|
6243
|
+
});
|
|
5955
6244
|
|
|
5956
6245
|
// src/kernel/system/profiler.ts
|
|
5957
6246
|
import { execSync as execSync3 } from "child_process";
|
|
@@ -6010,6 +6299,11 @@ function getSystemProfile() {
|
|
|
6010
6299
|
recommendedModel
|
|
6011
6300
|
};
|
|
6012
6301
|
}
|
|
6302
|
+
var init_profiler = __esm({
|
|
6303
|
+
"src/kernel/system/profiler.ts"() {
|
|
6304
|
+
"use strict";
|
|
6305
|
+
}
|
|
6306
|
+
});
|
|
6013
6307
|
|
|
6014
6308
|
// src/kernel/system/repos.ts
|
|
6015
6309
|
import { existsSync as existsSync10 } from "fs";
|
|
@@ -6062,10 +6356,15 @@ async function resolveAllGoalPaths(db) {
|
|
|
6062
6356
|
}
|
|
6063
6357
|
return dirs;
|
|
6064
6358
|
}
|
|
6359
|
+
var init_repos = __esm({
|
|
6360
|
+
"src/kernel/system/repos.ts"() {
|
|
6361
|
+
"use strict";
|
|
6362
|
+
init_settings();
|
|
6363
|
+
init_install_config();
|
|
6364
|
+
}
|
|
6365
|
+
});
|
|
6065
6366
|
|
|
6066
6367
|
// src/kernel/system/update-check.ts
|
|
6067
|
-
var WINGET_PACKAGE_ID = "ZAM.ZAM";
|
|
6068
|
-
var HOMEBREW_CASK = "zam";
|
|
6069
6368
|
function parseVersion(version) {
|
|
6070
6369
|
const clean = version.trim().replace(/^v/i, "");
|
|
6071
6370
|
const [main, pre = ""] = clean.split("-", 2);
|
|
@@ -6155,6 +6454,7 @@ function planUpdate(decision) {
|
|
|
6155
6454
|
{ kind: "git-pull", label: "Pull the latest source" },
|
|
6156
6455
|
{ kind: "npm-install", label: "Install dependencies" },
|
|
6157
6456
|
{ kind: "npm-build", label: "Rebuild the CLI" },
|
|
6457
|
+
{ kind: "smoke-test", label: "Verify the rebuilt CLI launches" },
|
|
6158
6458
|
{
|
|
6159
6459
|
kind: "distribute-skills",
|
|
6160
6460
|
label: "Refresh skill files (zam setup --force)"
|
|
@@ -6178,214 +6478,2126 @@ function planUpdate(decision) {
|
|
|
6178
6478
|
];
|
|
6179
6479
|
}
|
|
6180
6480
|
}
|
|
6481
|
+
var WINGET_PACKAGE_ID, HOMEBREW_CASK;
|
|
6482
|
+
var init_update_check = __esm({
|
|
6483
|
+
"src/kernel/system/update-check.ts"() {
|
|
6484
|
+
"use strict";
|
|
6485
|
+
WINGET_PACKAGE_ID = "ZAM.ZAM";
|
|
6486
|
+
HOMEBREW_CASK = "zam";
|
|
6487
|
+
}
|
|
6488
|
+
});
|
|
6489
|
+
|
|
6490
|
+
// src/kernel/index.ts
|
|
6491
|
+
var kernel_exports = {};
|
|
6492
|
+
__export(kernel_exports, {
|
|
6493
|
+
BUILT_IN_SENSITIVE_MATCHERS: () => BUILT_IN_SENSITIVE_MATCHERS,
|
|
6494
|
+
DEFAULT_OBSERVER_POLICY: () => DEFAULT_OBSERVER_POLICY,
|
|
6495
|
+
DEFAULT_REVIEW_CONTEXT_MAX_CHARS: () => DEFAULT_REVIEW_CONTEXT_MAX_CHARS,
|
|
6496
|
+
HOMEBREW_CASK: () => HOMEBREW_CASK,
|
|
6497
|
+
OBSERVER_POLICY_UNSET_HINT: () => OBSERVER_POLICY_UNSET_HINT,
|
|
6498
|
+
OBSERVER_POLICY_VERSION: () => OBSERVER_POLICY_VERSION,
|
|
6499
|
+
REVIEW_CONTEXT_CACHE_TTL_MS: () => REVIEW_CONTEXT_CACHE_TTL_MS,
|
|
6500
|
+
SIDECAR_POLICY_FILE: () => SIDECAR_POLICY_FILE,
|
|
6501
|
+
SNAPSHOT_VERSION: () => SNAPSHOT_VERSION,
|
|
6502
|
+
UI_OBSERVATION_PROTOCOL_VERSION: () => UI_OBSERVATION_PROTOCOL_VERSION,
|
|
6503
|
+
WINGET_PACKAGE_ID: () => WINGET_PACKAGE_ID,
|
|
6504
|
+
addPrerequisite: () => addPrerequisite,
|
|
6505
|
+
analyzeObservation: () => analyzeObservation,
|
|
6506
|
+
appendUiObservationReport: () => appendUiObservationReport,
|
|
6507
|
+
applySessionSynthesis: () => applySessionSynthesis,
|
|
6508
|
+
assignTokenToContext: () => assignTokenToContext,
|
|
6509
|
+
buildAncestorMap: () => buildAncestorMap,
|
|
6510
|
+
buildReviewQueue: () => buildReviewQueue,
|
|
6511
|
+
buildUiSynthesisCandidates: () => buildUiSynthesisCandidates,
|
|
6512
|
+
cascadeBlock: () => cascadeBlock,
|
|
6513
|
+
clearADOCredentials: () => clearADOCredentials,
|
|
6514
|
+
clearProviderApiKey: () => clearProviderApiKey,
|
|
6515
|
+
clearReviewContextCache: () => clearReviewContextCache,
|
|
6516
|
+
clearTursoCredentials: () => clearTursoCredentials,
|
|
6517
|
+
compareVersions: () => compareVersions,
|
|
6518
|
+
computeContentHash: () => computeContentHash,
|
|
6519
|
+
confirmCardSplit: () => confirmCardSplit,
|
|
6520
|
+
confirmFoundations: () => confirmFoundations,
|
|
6521
|
+
confirmSourceImport: () => confirmSourceImport,
|
|
6522
|
+
cosineSimilarity: () => cosineSimilarity,
|
|
6523
|
+
createAgentSkill: () => createAgentSkill,
|
|
6524
|
+
createFSRS: () => createFSRS,
|
|
6525
|
+
createGoal: () => createGoal,
|
|
6526
|
+
createKnowledgeContext: () => createKnowledgeContext,
|
|
6527
|
+
createToken: () => createToken,
|
|
6528
|
+
decidePostCapture: () => decidePostCapture,
|
|
6529
|
+
decidePreCapture: () => decidePreCapture,
|
|
6530
|
+
decideUpdate: () => decideUpdate,
|
|
6531
|
+
decodeEmbedding: () => decodeEmbedding,
|
|
6532
|
+
deleteCardForUser: () => deleteCardForUser,
|
|
6533
|
+
deleteKnowledgeContext: () => deleteKnowledgeContext,
|
|
6534
|
+
deleteSetting: () => deleteSetting,
|
|
6535
|
+
deleteToken: () => deleteToken,
|
|
6536
|
+
deprecateToken: () => deprecateToken,
|
|
6537
|
+
detectSyncProvider: () => detectSyncProvider,
|
|
6538
|
+
detectSystemLocale: () => detectSystemLocale,
|
|
6539
|
+
discoverSkills: () => discoverSkills,
|
|
6540
|
+
distributeGlobalSkills: () => distributeGlobalSkills,
|
|
6541
|
+
embeddingContentForToken: () => embeddingContentForToken,
|
|
6542
|
+
encodeEmbedding: () => encodeEmbedding,
|
|
6543
|
+
endSession: () => endSession,
|
|
6544
|
+
ensureCard: () => ensureCard,
|
|
6545
|
+
ensureMonitorDir: () => ensureMonitorDir,
|
|
6546
|
+
ensureUiObserverDir: () => ensureUiObserverDir,
|
|
6547
|
+
evaluateRating: () => evaluateRating,
|
|
6548
|
+
executeReviewAction: () => executeReviewAction,
|
|
6549
|
+
exportSnapshot: () => exportSnapshot,
|
|
6550
|
+
extractTasks: () => extractTasks,
|
|
6551
|
+
extractTokenRefs: () => extractTokenRefs,
|
|
6552
|
+
fetchActiveWorkItems: () => fetchActiveWorkItems,
|
|
6553
|
+
findTokens: () => findTokens,
|
|
6554
|
+
generateBashHooks: () => generateBashHooks,
|
|
6555
|
+
generateBashUnhooks: () => generateBashUnhooks,
|
|
6556
|
+
generateConceptFreeCue: () => generateConceptFreeCue,
|
|
6557
|
+
generatePowerShellHooks: () => generatePowerShellHooks,
|
|
6558
|
+
generatePowerShellUnhooks: () => generatePowerShellUnhooks,
|
|
6559
|
+
generatePrompt: () => generatePrompt,
|
|
6560
|
+
generateTokenSlug: () => generateTokenSlug,
|
|
6561
|
+
generateZshHooks: () => generateZshHooks,
|
|
6562
|
+
generateZshUnhooks: () => generateZshUnhooks,
|
|
6563
|
+
getADOCredentials: () => getADOCredentials,
|
|
6564
|
+
getActiveWorkspace: () => getActiveWorkspace,
|
|
6565
|
+
getActiveWorkspaceContext: () => getActiveWorkspaceContext,
|
|
6566
|
+
getActiveWorkspaceId: () => getActiveWorkspaceId,
|
|
6567
|
+
getAgentSkill: () => getAgentSkill,
|
|
6568
|
+
getAllSettings: () => getAllSettings,
|
|
6569
|
+
getAllSettingsDetailed: () => getAllSettingsDetailed,
|
|
6570
|
+
getBlockedCards: () => getBlockedCards,
|
|
6571
|
+
getCard: () => getCard,
|
|
6572
|
+
getCardById: () => getCardById,
|
|
6573
|
+
getCardDeletionImpact: () => getCardDeletionImpact,
|
|
6574
|
+
getConfiguredWorkspaces: () => getConfiguredWorkspaces,
|
|
6575
|
+
getDatabaseTargetInfo: () => getDatabaseTargetInfo,
|
|
6576
|
+
getDefaultDbPath: () => getDefaultDbPath,
|
|
6577
|
+
getDependents: () => getDependents,
|
|
6578
|
+
getDisplayTitle: () => getDisplayTitle,
|
|
6579
|
+
getDomainCompetence: () => getDomainCompetence,
|
|
6580
|
+
getDueCards: () => getDueCards,
|
|
6581
|
+
getEmbeddingCoverage: () => getEmbeddingCoverage,
|
|
6582
|
+
getGoal: () => getGoal,
|
|
6583
|
+
getGoalTree: () => getGoalTree,
|
|
6584
|
+
getInstallChannel: () => getInstallChannel,
|
|
6585
|
+
getInstallMode: () => getInstallMode,
|
|
6586
|
+
getKnowledgeContextById: () => getKnowledgeContextById,
|
|
6587
|
+
getKnowledgeContextByName: () => getKnowledgeContextByName,
|
|
6588
|
+
getMachineAiConfig: () => getMachineAiConfig,
|
|
6589
|
+
getMonitorDir: () => getMonitorDir,
|
|
6590
|
+
getMonitorLogStats: () => getMonitorLogStats,
|
|
6591
|
+
getMonitorPath: () => getMonitorPath,
|
|
6592
|
+
getPackageSkillPath: () => getPackageSkillPath,
|
|
6593
|
+
getPrerequisites: () => getPrerequisites,
|
|
6594
|
+
getProviderApiKey: () => getProviderApiKey,
|
|
6595
|
+
getRepoPaths: () => getRepoPaths,
|
|
6596
|
+
getReviewsForCard: () => getReviewsForCard,
|
|
6597
|
+
getReviewsForUser: () => getReviewsForUser,
|
|
6598
|
+
getSessionSummary: () => getSessionSummary,
|
|
6599
|
+
getSessionSynthesisRecords: () => getSessionSynthesisRecords,
|
|
6600
|
+
getSetting: () => getSetting,
|
|
6601
|
+
getShortSlug: () => getShortSlug,
|
|
6602
|
+
getSystemProfile: () => getSystemProfile,
|
|
6603
|
+
getTokenById: () => getTokenById,
|
|
6604
|
+
getTokenBySlug: () => getTokenBySlug,
|
|
6605
|
+
getTokenDeleteImpact: () => getTokenDeleteImpact,
|
|
6606
|
+
getTokenEmbedding: () => getTokenEmbedding,
|
|
6607
|
+
getTokenNeighborhood: () => getTokenNeighborhood,
|
|
6608
|
+
getTursoCredentials: () => getTursoCredentials,
|
|
6609
|
+
getUiObservationPath: () => getUiObservationPath,
|
|
6610
|
+
getUiObserverDir: () => getUiObserverDir,
|
|
6611
|
+
getUserStats: () => getUserStats,
|
|
6612
|
+
hasCommand: () => hasCommand,
|
|
6613
|
+
importCurriculumCards: () => importCurriculumCards,
|
|
6614
|
+
importSnapshot: () => importSnapshot,
|
|
6615
|
+
injectShellHooks: () => injectShellHooks,
|
|
6616
|
+
installFastFlowLM: () => installFastFlowLM,
|
|
6617
|
+
installOllama: () => installOllama,
|
|
6618
|
+
installOpenCode: () => installOpenCode,
|
|
6619
|
+
interleave: () => interleave,
|
|
6620
|
+
isObserverPolicyConfigured: () => isObserverPolicyConfigured,
|
|
6621
|
+
isOllamaInstalled: () => isOllamaInstalled,
|
|
6622
|
+
isUiObservationReport: () => isUiObservationReport,
|
|
6623
|
+
listAgentSkills: () => listAgentSkills,
|
|
6624
|
+
listContextsForToken: () => listContextsForToken,
|
|
6625
|
+
listEmbeddedTokens: () => listEmbeddedTokens,
|
|
6626
|
+
listGoals: () => listGoals,
|
|
6627
|
+
listKnowledgeContexts: () => listKnowledgeContexts,
|
|
6628
|
+
listPersonalCards: () => listPersonalCards,
|
|
6629
|
+
listProviderApiKeyRefs: () => listProviderApiKeyRefs,
|
|
6630
|
+
listTokens: () => listTokens,
|
|
6631
|
+
listTokensNeedingEmbedding: () => listTokensNeedingEmbedding,
|
|
6632
|
+
loadADOConfig: () => loadADOConfig,
|
|
6633
|
+
loadCredentials: () => loadCredentials,
|
|
6634
|
+
loadInstallConfig: () => loadInstallConfig,
|
|
6635
|
+
logReview: () => logReview,
|
|
6636
|
+
logStep: () => logStep,
|
|
6637
|
+
matchBuiltInSensitive: () => matchBuiltInSensitive,
|
|
6638
|
+
matchDenylist: () => matchDenylist,
|
|
6639
|
+
matchesFilePath: () => matchesFilePath,
|
|
6640
|
+
monitorLogExists: () => monitorLogExists,
|
|
6641
|
+
normalizeLocale: () => normalizeLocale,
|
|
6642
|
+
normalizePath: () => normalizePath,
|
|
6643
|
+
openDatabase: () => openDatabase,
|
|
6644
|
+
openDatabaseWithSync: () => openDatabaseWithSync,
|
|
6645
|
+
openRemoteDatabase: () => openRemoteDatabase,
|
|
6646
|
+
pairCommands: () => pairCommands,
|
|
6647
|
+
parseGoalFile: () => parseGoalFile,
|
|
6648
|
+
parseMonitorLog: () => parseMonitorLog,
|
|
6649
|
+
parseObserverList: () => parseObserverList,
|
|
6650
|
+
parseObserverPolicy: () => parseObserverPolicy,
|
|
6651
|
+
parseSnapshot: () => parseSnapshot,
|
|
6652
|
+
parseUiObservationLog: () => parseUiObservationLog,
|
|
6653
|
+
planOpenCodeInstall: () => planOpenCodeInstall,
|
|
6654
|
+
planUpdate: () => planUpdate,
|
|
6655
|
+
prepareLocalModel: () => prepareLocalModel,
|
|
6656
|
+
prepareSessionSynthesis: () => prepareSessionSynthesis,
|
|
6657
|
+
readMonitorLog: () => readMonitorLog,
|
|
6658
|
+
readUiObservationLog: () => readUiObservationLog,
|
|
6659
|
+
removeConfiguredWorkspace: () => removeConfiguredWorkspace,
|
|
6660
|
+
resolveAllBeliefPaths: () => resolveAllBeliefPaths,
|
|
6661
|
+
resolveAllGoalPaths: () => resolveAllGoalPaths,
|
|
6662
|
+
resolveObserverPolicy: () => resolveObserverPolicy,
|
|
6663
|
+
resolveOllamaCommand: () => resolveOllamaCommand,
|
|
6664
|
+
resolveReference: () => resolveReference,
|
|
6665
|
+
resolveRepoPath: () => resolveRepoPath,
|
|
6666
|
+
resolveReviewContext: () => resolveReviewContext,
|
|
6667
|
+
saveConfiguredWorkspaces: () => saveConfiguredWorkspaces,
|
|
6668
|
+
saveCredentials: () => saveCredentials,
|
|
6669
|
+
saveInstallConfig: () => saveInstallConfig,
|
|
6670
|
+
saveMachineAiConfig: () => saveMachineAiConfig,
|
|
6671
|
+
searchTokensHybrid: () => searchTokensHybrid,
|
|
6672
|
+
serializeGoal: () => serializeGoal,
|
|
6673
|
+
setADOCredentials: () => setADOCredentials,
|
|
6674
|
+
setActiveWorkspaceContext: () => setActiveWorkspaceContext,
|
|
6675
|
+
setActiveWorkspaceId: () => setActiveWorkspaceId,
|
|
6676
|
+
setInstallChannel: () => setInstallChannel,
|
|
6677
|
+
setInstallMode: () => setInstallMode,
|
|
6678
|
+
setProviderApiKey: () => setProviderApiKey,
|
|
6679
|
+
setSetting: () => setSetting,
|
|
6680
|
+
setTursoCredentials: () => setTursoCredentials,
|
|
6681
|
+
slugify: () => slugify,
|
|
6682
|
+
startSession: () => startSession,
|
|
6683
|
+
suggestFoundations: () => suggestFoundations,
|
|
6684
|
+
syncObserverSidecarPolicy: () => syncObserverSidecarPolicy,
|
|
6685
|
+
t: () => t,
|
|
6686
|
+
toSidecarPrivacyPolicy: () => toSidecarPrivacyPolicy,
|
|
6687
|
+
uiObservationLogExists: () => uiObservationLogExists,
|
|
6688
|
+
uiObservationTimeSpan: () => uiObservationTimeSpan,
|
|
6689
|
+
unassignTokenFromContext: () => unassignTokenFromContext,
|
|
6690
|
+
unblockReady: () => unblockReady,
|
|
6691
|
+
updateCard: () => updateCard,
|
|
6692
|
+
updateGoalStatus: () => updateGoalStatus,
|
|
6693
|
+
updateKnowledgeContext: () => updateKnowledgeContext,
|
|
6694
|
+
updateToken: () => updateToken,
|
|
6695
|
+
upsertConfiguredWorkspace: () => upsertConfiguredWorkspace,
|
|
6696
|
+
upsertTokenEmbedding: () => upsertTokenEmbedding,
|
|
6697
|
+
verifySnapshot: () => verifySnapshot,
|
|
6698
|
+
wouldCreateCycle: () => wouldCreateCycle,
|
|
6699
|
+
writeMonitorEvent: () => writeMonitorEvent
|
|
6700
|
+
});
|
|
6701
|
+
var init_kernel = __esm({
|
|
6702
|
+
"src/kernel/index.ts"() {
|
|
6703
|
+
"use strict";
|
|
6704
|
+
init_stats();
|
|
6705
|
+
init_azure_devops();
|
|
6706
|
+
init_credentials();
|
|
6707
|
+
init_connection();
|
|
6708
|
+
init_provider();
|
|
6709
|
+
init_snapshot();
|
|
6710
|
+
init_engine();
|
|
6711
|
+
init_parser();
|
|
6712
|
+
init_agent_skill();
|
|
6713
|
+
init_card();
|
|
6714
|
+
init_knowledge_context();
|
|
6715
|
+
init_prerequisite();
|
|
6716
|
+
init_review();
|
|
6717
|
+
init_session();
|
|
6718
|
+
init_settings();
|
|
6719
|
+
init_token();
|
|
6720
|
+
init_token_embedding();
|
|
6721
|
+
init_analyzer();
|
|
6722
|
+
init_monitor_io();
|
|
6723
|
+
init_observer_sidecar_policy();
|
|
6724
|
+
init_policy();
|
|
6725
|
+
init_session_synthesis();
|
|
6726
|
+
init_shell_hooks();
|
|
6727
|
+
init_skill_discovery();
|
|
6728
|
+
init_ui_observer();
|
|
6729
|
+
init_ui_observer_io();
|
|
6730
|
+
init_ui_observer_synthesis();
|
|
6731
|
+
init_actions();
|
|
6732
|
+
init_evaluator();
|
|
6733
|
+
init_prompter();
|
|
6734
|
+
init_reference_resolver();
|
|
6735
|
+
init_blocker();
|
|
6736
|
+
init_fsrs();
|
|
6737
|
+
init_interleaver();
|
|
6738
|
+
init_queue();
|
|
6739
|
+
init_hybrid();
|
|
6740
|
+
init_suggestions();
|
|
6741
|
+
init_hooks();
|
|
6742
|
+
init_i18n();
|
|
6743
|
+
init_install_config();
|
|
6744
|
+
init_installer();
|
|
6745
|
+
init_locale();
|
|
6746
|
+
init_profiler();
|
|
6747
|
+
init_repos();
|
|
6748
|
+
init_update_check();
|
|
6749
|
+
}
|
|
6750
|
+
});
|
|
6751
|
+
|
|
6752
|
+
// src/cli/commands/mcp.ts
|
|
6753
|
+
init_kernel();
|
|
6754
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
|
|
6755
|
+
import { dirname as dirname5, join as join11 } from "path";
|
|
6756
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6757
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6758
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6759
|
+
import { z } from "zod";
|
|
6760
|
+
|
|
6761
|
+
// src/cli/bridge-handlers.ts
|
|
6762
|
+
init_kernel();
|
|
6763
|
+
|
|
6764
|
+
// src/cli/knowledge-contexts.ts
|
|
6765
|
+
init_kernel();
|
|
6766
|
+
async function resolveOperationKnowledgeContexts(db, requestedNames) {
|
|
6767
|
+
const explicitNames = [
|
|
6768
|
+
...new Set(requestedNames.map((name) => name.trim()).filter(Boolean))
|
|
6769
|
+
];
|
|
6770
|
+
const activeDefault = getActiveWorkspaceContext();
|
|
6771
|
+
const selectedNames = explicitNames.length > 0 ? explicitNames : activeDefault ? [activeDefault] : [];
|
|
6772
|
+
const contexts = [];
|
|
6773
|
+
for (const name of selectedNames) {
|
|
6774
|
+
const context = await getKnowledgeContextByName(db, name);
|
|
6775
|
+
if (!context) {
|
|
6776
|
+
const subject = explicitNames.length > 0 ? "Knowledge" : "Active knowledge";
|
|
6777
|
+
throw new Error(`${subject} context not found: ${name}`);
|
|
6778
|
+
}
|
|
6779
|
+
contexts.push(context);
|
|
6780
|
+
}
|
|
6781
|
+
return contexts;
|
|
6782
|
+
}
|
|
6783
|
+
|
|
6784
|
+
// src/cli/llm/client.ts
|
|
6785
|
+
init_kernel();
|
|
6786
|
+
import { spawn } from "child_process";
|
|
6787
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, statSync as statSync2 } from "fs";
|
|
6788
|
+
var DEFAULT_LLM_URL = "http://localhost:8000/v1";
|
|
6789
|
+
var RECALL_QUESTION_MAX_OUTPUT_TOKENS = 400;
|
|
6790
|
+
var RECALL_ENDPOINT_CACHE_MS = 6e4;
|
|
6791
|
+
var cachedRecallEndpoint = null;
|
|
6792
|
+
function recallEndpointSignature(cfg) {
|
|
6793
|
+
return [
|
|
6794
|
+
cfg.enabled ? "on" : "off",
|
|
6795
|
+
cfg.providerName ?? "",
|
|
6796
|
+
cfg.url,
|
|
6797
|
+
cfg.model,
|
|
6798
|
+
cfg.apiFlavor,
|
|
6799
|
+
cfg.fallback?.url ?? "",
|
|
6800
|
+
cfg.fallback?.model ?? ""
|
|
6801
|
+
].join("|");
|
|
6802
|
+
}
|
|
6803
|
+
var DEFAULT_LLM_MODEL = "qwen3.5:4b";
|
|
6804
|
+
var DEFAULT_LLM_API_KEY = "sk-none";
|
|
6805
|
+
async function getLlmConfig(db) {
|
|
6806
|
+
return {
|
|
6807
|
+
enabled: await getSetting(db, "llm.enabled") === "true",
|
|
6808
|
+
url: await getSetting(db, "llm.url") || DEFAULT_LLM_URL,
|
|
6809
|
+
model: await getSetting(db, "llm.model") || DEFAULT_LLM_MODEL,
|
|
6810
|
+
apiKey: await getSetting(db, "llm.api_key") || DEFAULT_LLM_API_KEY,
|
|
6811
|
+
locale: await getSetting(db, "system.locale") || "en"
|
|
6812
|
+
};
|
|
6813
|
+
}
|
|
6814
|
+
function getCloudModelRecommendation(url) {
|
|
6815
|
+
const lowercase = url.toLowerCase();
|
|
6816
|
+
if (lowercase.includes("openrouter.ai")) {
|
|
6817
|
+
return { model: "openrouter/free", flavor: "chat-completions" };
|
|
6818
|
+
}
|
|
6819
|
+
if (lowercase.includes("openai.com") || lowercase.includes("api.openai")) {
|
|
6820
|
+
return { model: "gpt-5-mini", flavor: "chat-completions" };
|
|
6821
|
+
}
|
|
6822
|
+
if (lowercase.includes("googleapis.com") || lowercase.includes("google")) {
|
|
6823
|
+
return { model: "gemini-3.5-flash", flavor: "chat-completions" };
|
|
6824
|
+
}
|
|
6825
|
+
if (lowercase.includes("deepseek.com")) {
|
|
6826
|
+
return { model: "deepseek-v4-flash", flavor: "chat-completions" };
|
|
6827
|
+
}
|
|
6828
|
+
if (lowercase.includes("mimo")) {
|
|
6829
|
+
return { model: "mimo-v2.5", flavor: "chat-completions" };
|
|
6830
|
+
}
|
|
6831
|
+
if (lowercase.includes("anthropic.com")) {
|
|
6832
|
+
return {
|
|
6833
|
+
model: "claude-haiku-4-5-20251001",
|
|
6834
|
+
flavor: "anthropic-messages"
|
|
6835
|
+
};
|
|
6836
|
+
}
|
|
6837
|
+
return null;
|
|
6838
|
+
}
|
|
6839
|
+
function inferApiFlavor(url) {
|
|
6840
|
+
try {
|
|
6841
|
+
return new URL(url).hostname.toLowerCase().endsWith("anthropic.com") ? "anthropic-messages" : "chat-completions";
|
|
6842
|
+
} catch {
|
|
6843
|
+
return "chat-completions";
|
|
6844
|
+
}
|
|
6845
|
+
}
|
|
6846
|
+
async function readJsonSetting(db, key) {
|
|
6847
|
+
const raw = await getSetting(db, key);
|
|
6848
|
+
if (!raw) return null;
|
|
6849
|
+
try {
|
|
6850
|
+
return JSON.parse(raw);
|
|
6851
|
+
} catch {
|
|
6852
|
+
return null;
|
|
6853
|
+
}
|
|
6854
|
+
}
|
|
6855
|
+
function resolveProviderApiKey(rec) {
|
|
6856
|
+
if (rec.apiKey) return rec.apiKey;
|
|
6857
|
+
if (rec.apiKeyRef) {
|
|
6858
|
+
const key = getProviderApiKey(rec.apiKeyRef);
|
|
6859
|
+
if (key) return key;
|
|
6860
|
+
}
|
|
6861
|
+
return DEFAULT_LLM_API_KEY;
|
|
6862
|
+
}
|
|
6863
|
+
async function getProviderForRole(db, role) {
|
|
6864
|
+
const enabled = role === "vision" ? await getSetting(db, "llm.vision.enabled") === "true" : await getSetting(db, "llm.enabled") === "true";
|
|
6865
|
+
const base = await getLegacyRoleConfig(db, role, enabled);
|
|
6866
|
+
const providers = await readJsonSetting(db, "llm.providers");
|
|
6867
|
+
const roles = await readJsonSetting(db, "llm.roles");
|
|
6868
|
+
const binding = roles?.[role];
|
|
6869
|
+
let resolved = base;
|
|
6870
|
+
if (providers && binding?.primary && providers[binding.primary]) {
|
|
6871
|
+
const primary = materializeProvider(
|
|
6872
|
+
providers[binding.primary],
|
|
6873
|
+
base,
|
|
6874
|
+
role,
|
|
6875
|
+
{
|
|
6876
|
+
providerName: binding.primary,
|
|
6877
|
+
source: "shared"
|
|
6878
|
+
}
|
|
6879
|
+
);
|
|
6880
|
+
const fallback = binding.fallback && providers[binding.fallback] ? materializeProvider(providers[binding.fallback], base, role, {
|
|
6881
|
+
providerName: binding.fallback,
|
|
6882
|
+
source: "shared"
|
|
6883
|
+
}) : void 0;
|
|
6884
|
+
resolved = { ...primary, fallback };
|
|
6885
|
+
}
|
|
6886
|
+
const machine = getMachineAiConfig();
|
|
6887
|
+
const machineProviders = machine.providers;
|
|
6888
|
+
const machineBinding = machine.roles?.[role];
|
|
6889
|
+
if (machineProviders && machineBinding?.primary && machineProviders[machineBinding.primary]) {
|
|
6890
|
+
const primary = materializeProvider(
|
|
6891
|
+
machineProviders[machineBinding.primary],
|
|
6892
|
+
resolved,
|
|
6893
|
+
role,
|
|
6894
|
+
{ providerName: machineBinding.primary, source: "machine" }
|
|
6895
|
+
);
|
|
6896
|
+
const fallback = machineBinding.fallback && machineProviders[machineBinding.fallback] ? materializeProvider(
|
|
6897
|
+
machineProviders[machineBinding.fallback],
|
|
6898
|
+
resolved,
|
|
6899
|
+
role,
|
|
6900
|
+
{ providerName: machineBinding.fallback, source: "machine" }
|
|
6901
|
+
) : void 0;
|
|
6902
|
+
return { ...primary, fallback };
|
|
6903
|
+
}
|
|
6904
|
+
return resolved;
|
|
6905
|
+
}
|
|
6906
|
+
function materializeProvider(rec, base, role, meta) {
|
|
6907
|
+
const url = rec.url || base.url;
|
|
6908
|
+
return {
|
|
6909
|
+
enabled: base.enabled,
|
|
6910
|
+
url,
|
|
6911
|
+
model: rec.model || base.model,
|
|
6912
|
+
apiKey: resolveProviderApiKey(rec),
|
|
6913
|
+
apiFlavor: rec.apiFlavor || inferApiFlavor(url),
|
|
6914
|
+
locale: base.locale,
|
|
6915
|
+
providerName: meta.providerName,
|
|
6916
|
+
label: rec.label,
|
|
6917
|
+
source: meta.source,
|
|
6918
|
+
local: rec.local ?? isLocalEndpoint(url),
|
|
6919
|
+
...rec.runner ? { runner: rec.runner } : {},
|
|
6920
|
+
...role === "vision" ? { maxFrames: base.maxFrames } : {}
|
|
6921
|
+
};
|
|
6922
|
+
}
|
|
6923
|
+
async function getLegacyRoleConfig(db, role, enabled) {
|
|
6924
|
+
const base = await getLlmConfig(db);
|
|
6925
|
+
if (role === "vision") {
|
|
6926
|
+
const maxFramesStr = await getSetting(db, "llm.vision.max_frames");
|
|
6927
|
+
const parsed = maxFramesStr ? parseInt(maxFramesStr, 10) : 100;
|
|
6928
|
+
const url = await getSetting(db, "llm.vision.url") || base.url;
|
|
6929
|
+
const recommendation = getCloudModelRecommendation(url);
|
|
6930
|
+
let model = await getSetting(db, "llm.vision.model");
|
|
6931
|
+
if (!model) model = recommendation?.model || base.model;
|
|
6932
|
+
return {
|
|
6933
|
+
enabled,
|
|
6934
|
+
url,
|
|
6935
|
+
model,
|
|
6936
|
+
apiKey: await getSetting(db, "llm.vision.api_key") || base.apiKey,
|
|
6937
|
+
apiFlavor: recommendation?.flavor || inferApiFlavor(url),
|
|
6938
|
+
locale: base.locale,
|
|
6939
|
+
source: "legacy",
|
|
6940
|
+
local: isLocalEndpoint(url),
|
|
6941
|
+
maxFrames: Number.isNaN(parsed) ? 100 : parsed
|
|
6942
|
+
};
|
|
6943
|
+
}
|
|
6944
|
+
if (role === "embedding") {
|
|
6945
|
+
const url = await getSetting(db, "llm.embedding.url") || base.url;
|
|
6946
|
+
return {
|
|
6947
|
+
enabled,
|
|
6948
|
+
url,
|
|
6949
|
+
// Kept as a literal (not imported) to avoid a client.ts <-> embedder.ts
|
|
6950
|
+
// import cycle; must match DEFAULT_EMBEDDING_MODEL in embedder.ts.
|
|
6951
|
+
model: await getSetting(db, "llm.embedding.model") || "embeddinggemma",
|
|
6952
|
+
apiKey: await getSetting(db, "llm.embedding.api_key") || base.apiKey,
|
|
6953
|
+
apiFlavor: inferApiFlavor(url),
|
|
6954
|
+
locale: base.locale,
|
|
6955
|
+
source: "legacy",
|
|
6956
|
+
local: isLocalEndpoint(url)
|
|
6957
|
+
};
|
|
6958
|
+
}
|
|
6959
|
+
return {
|
|
6960
|
+
enabled,
|
|
6961
|
+
url: base.url,
|
|
6962
|
+
model: base.model,
|
|
6963
|
+
apiKey: base.apiKey,
|
|
6964
|
+
apiFlavor: inferApiFlavor(base.url),
|
|
6965
|
+
locale: base.locale,
|
|
6966
|
+
source: "legacy",
|
|
6967
|
+
local: isLocalEndpoint(base.url)
|
|
6968
|
+
};
|
|
6969
|
+
}
|
|
6970
|
+
function assertChatCompletions(cfg) {
|
|
6971
|
+
if (cfg.apiFlavor !== "chat-completions") {
|
|
6972
|
+
throw new Error(
|
|
6973
|
+
`This role is configured for a "${cfg.apiFlavor}" provider, which is not supported here yet. Use a chat-completions provider for this role.`
|
|
6974
|
+
);
|
|
6975
|
+
}
|
|
6976
|
+
}
|
|
6977
|
+
var LANGUAGE_NAMES = {
|
|
6978
|
+
en: "English",
|
|
6979
|
+
de: "German",
|
|
6980
|
+
es: "Spanish",
|
|
6981
|
+
fr: "French",
|
|
6982
|
+
pt: "Portuguese",
|
|
6983
|
+
zh: "Chinese",
|
|
6984
|
+
ja: "Japanese"
|
|
6985
|
+
};
|
|
6986
|
+
var BLOOM_VERBS2 = {
|
|
6987
|
+
1: "Remember",
|
|
6988
|
+
2: "Understand",
|
|
6989
|
+
3: "Apply",
|
|
6990
|
+
4: "Analyze",
|
|
6991
|
+
5: "Synthesize"
|
|
6992
|
+
};
|
|
6993
|
+
var LlmResponseTruncatedError = class extends Error {
|
|
6994
|
+
constructor(label) {
|
|
6995
|
+
super(
|
|
6996
|
+
`${label}: the model's response was cut off before producing usable output (finish_reason=length). The prompt likely left no room in the model's context window for a reply.`
|
|
6997
|
+
);
|
|
6998
|
+
this.name = "LlmResponseTruncatedError";
|
|
6999
|
+
}
|
|
7000
|
+
};
|
|
7001
|
+
async function readChatContent(res, label) {
|
|
7002
|
+
if (!res.ok) {
|
|
7003
|
+
const errorText = await res.text().catch(() => "");
|
|
7004
|
+
throw new Error(
|
|
7005
|
+
`${label} failed: ${res.statusText} (${res.status}) - ${errorText}`
|
|
7006
|
+
);
|
|
7007
|
+
}
|
|
7008
|
+
const data = await res.json();
|
|
7009
|
+
const choice = data.choices?.[0];
|
|
7010
|
+
const content = choice?.message?.content;
|
|
7011
|
+
const trimmed = content?.trim() ?? "";
|
|
7012
|
+
if (choice?.finish_reason === "length") {
|
|
7013
|
+
throw new LlmResponseTruncatedError(label);
|
|
7014
|
+
}
|
|
7015
|
+
if (!trimmed) {
|
|
7016
|
+
throw new Error("Empty response from LLM");
|
|
7017
|
+
}
|
|
7018
|
+
return trimmed;
|
|
7019
|
+
}
|
|
7020
|
+
async function generateQuestionViaLLM(db, input) {
|
|
7021
|
+
const cfg = await getProviderForRole(db, "recall");
|
|
7022
|
+
const endpoint = await resolveUsableRecallEndpoint(db);
|
|
7023
|
+
const bloom = input.bloomLevel >= 1 && input.bloomLevel <= 5 ? input.bloomLevel : 1;
|
|
7024
|
+
const verb = BLOOM_VERBS2[bloom];
|
|
7025
|
+
const langName = LANGUAGE_NAMES[cfg.locale] || "English";
|
|
7026
|
+
const systemPrompt = `You are ZAM, a highly precise agentic skills trainer.
|
|
7027
|
+
Your task is to generate a single, clear, conceptual active-recall question (flashcard front) in ${langName} for a knowledge token.
|
|
6181
7028
|
|
|
7029
|
+
Guidelines:
|
|
7030
|
+
1. The question MUST match the Bloom level: ${verb} (Level ${bloom}).
|
|
7031
|
+
2. CRITICAL: The question MUST NOT contain or reveal the concept text itself! The concept is the answer (flashcard back) that the learner needs to recall.
|
|
7032
|
+
3. Keep the question concise, highly specific, and clear. Avoid generic prompts like "What is the concept of..." if possible, and ask about the core mechanism, function, or purpose of the slug/concept without giving the answer away.
|
|
7033
|
+
4. Output ONLY the raw question text in ${langName}. Do not include any preamble, headers, markdown fences, or conversational filler.`;
|
|
7034
|
+
const userPrompt = `Domain: ${input.domain}
|
|
7035
|
+
Slug: ${input.slug}
|
|
7036
|
+
Concept to Recall (DO NOT REVEAL IN QUESTION): ${input.concept}
|
|
7037
|
+
Context: ${input.context || "(none)"}
|
|
7038
|
+
${input.sourceLinkContent ? `Source Reference:
|
|
7039
|
+
${input.sourceLinkContent}` : ""}
|
|
7040
|
+
|
|
7041
|
+
Active-Recall Question:`;
|
|
7042
|
+
const res = await fetchWithInteractiveTimeout(
|
|
7043
|
+
`${endpoint.url}/chat/completions`,
|
|
7044
|
+
{
|
|
7045
|
+
method: "POST",
|
|
7046
|
+
headers: {
|
|
7047
|
+
"Content-Type": "application/json",
|
|
7048
|
+
Authorization: `Bearer ${endpoint.apiKey}`
|
|
7049
|
+
},
|
|
7050
|
+
body: JSON.stringify({
|
|
7051
|
+
model: endpoint.model,
|
|
7052
|
+
messages: [
|
|
7053
|
+
{ role: "system", content: systemPrompt },
|
|
7054
|
+
{ role: "user", content: userPrompt }
|
|
7055
|
+
],
|
|
7056
|
+
temperature: 0.1,
|
|
7057
|
+
max_tokens: RECALL_QUESTION_MAX_OUTPUT_TOKENS
|
|
7058
|
+
}),
|
|
7059
|
+
locale: cfg.locale
|
|
7060
|
+
}
|
|
7061
|
+
);
|
|
7062
|
+
const text = await readChatContent(res, "LLM request");
|
|
7063
|
+
return {
|
|
7064
|
+
text,
|
|
7065
|
+
model: endpoint.model,
|
|
7066
|
+
providerName: endpoint.providerName
|
|
7067
|
+
};
|
|
7068
|
+
}
|
|
7069
|
+
async function isLlmOnline(url) {
|
|
7070
|
+
try {
|
|
7071
|
+
const controller = new AbortController();
|
|
7072
|
+
const timeoutId = setTimeout(() => controller.abort(), 1500);
|
|
7073
|
+
const res = await fetch(`${url}/models`, {
|
|
7074
|
+
method: "GET",
|
|
7075
|
+
signal: controller.signal
|
|
7076
|
+
});
|
|
7077
|
+
clearTimeout(timeoutId);
|
|
7078
|
+
return res.ok || res.status < 500;
|
|
7079
|
+
} catch {
|
|
7080
|
+
return false;
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
7083
|
+
async function getAvailableModels(url, apiKey = DEFAULT_LLM_API_KEY) {
|
|
7084
|
+
try {
|
|
7085
|
+
const controller = new AbortController();
|
|
7086
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e3);
|
|
7087
|
+
const res = await fetch(`${url}/models`, {
|
|
7088
|
+
method: "GET",
|
|
7089
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
7090
|
+
signal: controller.signal
|
|
7091
|
+
});
|
|
7092
|
+
clearTimeout(timeoutId);
|
|
7093
|
+
if (!res.ok) return [];
|
|
7094
|
+
const data = await res.json();
|
|
7095
|
+
return (data.data ?? []).map((m) => m.id).filter((id) => typeof id === "string" && id.length > 0);
|
|
7096
|
+
} catch {
|
|
7097
|
+
return [];
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
function isLocalEndpoint(url) {
|
|
7101
|
+
return url.includes("localhost") || url.includes("127.0.0.1") || url.includes("[::1]") || url.includes("::1");
|
|
7102
|
+
}
|
|
7103
|
+
async function checkProviderEndpoint(endpoint) {
|
|
7104
|
+
const online = await isLlmOnline(endpoint.url);
|
|
7105
|
+
if (!online) {
|
|
7106
|
+
return {
|
|
7107
|
+
endpoint,
|
|
7108
|
+
online: false,
|
|
7109
|
+
availableModels: [],
|
|
7110
|
+
modelAvailable: false
|
|
7111
|
+
};
|
|
7112
|
+
}
|
|
7113
|
+
const availableModels = await getAvailableModels(
|
|
7114
|
+
endpoint.url,
|
|
7115
|
+
endpoint.apiKey
|
|
7116
|
+
);
|
|
7117
|
+
const modelAvailable = availableModels.length === 0 || availableModels.some(
|
|
7118
|
+
(candidate) => candidate.toLowerCase() === endpoint.model.toLowerCase()
|
|
7119
|
+
);
|
|
7120
|
+
return { endpoint, online, availableModels, modelAvailable };
|
|
7121
|
+
}
|
|
7122
|
+
function isEndpointUsable(readiness) {
|
|
7123
|
+
return readiness.online && readiness.modelAvailable;
|
|
7124
|
+
}
|
|
7125
|
+
function providerChain(primary) {
|
|
7126
|
+
return [primary, ...primary.fallback ? [primary.fallback] : []];
|
|
7127
|
+
}
|
|
7128
|
+
async function checkProviderChain(primary) {
|
|
7129
|
+
let first;
|
|
7130
|
+
for (const endpoint of providerChain(primary)) {
|
|
7131
|
+
const readiness = await checkProviderEndpoint(endpoint);
|
|
7132
|
+
first ??= readiness;
|
|
7133
|
+
if (isEndpointUsable(readiness)) {
|
|
7134
|
+
return { primary: first, firstUsable: readiness };
|
|
7135
|
+
}
|
|
7136
|
+
}
|
|
7137
|
+
return { primary: first };
|
|
7138
|
+
}
|
|
7139
|
+
async function resolveUsableRecallEndpoint(db) {
|
|
7140
|
+
const cfg = await getProviderForRole(db, "recall");
|
|
7141
|
+
if (!cfg.enabled) {
|
|
7142
|
+
throw new Error("LLM integration is disabled in settings (llm.enabled)");
|
|
7143
|
+
}
|
|
7144
|
+
assertChatCompletions(cfg);
|
|
7145
|
+
const signature = recallEndpointSignature(cfg);
|
|
7146
|
+
if (cachedRecallEndpoint && cachedRecallEndpoint.signature === signature && cachedRecallEndpoint.expiresAt > Date.now()) {
|
|
7147
|
+
return cachedRecallEndpoint.endpoint;
|
|
7148
|
+
}
|
|
7149
|
+
const chain = await checkProviderChain(cfg);
|
|
7150
|
+
const selected = chain.firstUsable;
|
|
7151
|
+
if (!selected || !isEndpointUsable(selected)) {
|
|
7152
|
+
throw new Error("No recall LLM endpoint is online");
|
|
7153
|
+
}
|
|
7154
|
+
cachedRecallEndpoint = {
|
|
7155
|
+
endpoint: selected.endpoint,
|
|
7156
|
+
signature,
|
|
7157
|
+
expiresAt: Date.now() + RECALL_ENDPOINT_CACHE_MS
|
|
7158
|
+
};
|
|
7159
|
+
return selected.endpoint;
|
|
7160
|
+
}
|
|
7161
|
+
async function fetchWithInteractiveTimeout(url, options = {}) {
|
|
7162
|
+
const {
|
|
7163
|
+
timeoutMs = 2e4,
|
|
7164
|
+
hardTimeoutMs = 12e4,
|
|
7165
|
+
locale = "en",
|
|
7166
|
+
...fetchOptions
|
|
7167
|
+
} = options;
|
|
7168
|
+
const controller = new AbortController();
|
|
7169
|
+
const fetchPromise = fetch(url, {
|
|
7170
|
+
...fetchOptions,
|
|
7171
|
+
signal: controller.signal
|
|
7172
|
+
});
|
|
7173
|
+
if (!process.stdout.isTTY || process.env.ZAM_BRIDGE === "true") {
|
|
7174
|
+
let timeoutId;
|
|
7175
|
+
const hardTimeout = new Promise((_resolve, reject) => {
|
|
7176
|
+
timeoutId = setTimeout(() => {
|
|
7177
|
+
reject(new Error(`LLM request timed out after ${hardTimeoutMs}ms`));
|
|
7178
|
+
controller.abort();
|
|
7179
|
+
}, hardTimeoutMs);
|
|
7180
|
+
});
|
|
7181
|
+
try {
|
|
7182
|
+
return await Promise.race([fetchPromise, hardTimeout]);
|
|
7183
|
+
} finally {
|
|
7184
|
+
clearTimeout(timeoutId);
|
|
7185
|
+
}
|
|
7186
|
+
}
|
|
7187
|
+
let attempts = 0;
|
|
7188
|
+
const dotsPerLine = 30;
|
|
7189
|
+
while (true) {
|
|
7190
|
+
let timeoutId;
|
|
7191
|
+
const timeoutPromise = new Promise((resolve3) => {
|
|
7192
|
+
timeoutId = setTimeout(() => resolve3("timeout"), timeoutMs);
|
|
7193
|
+
});
|
|
7194
|
+
const dotsInterval = setInterval(() => {
|
|
7195
|
+
process.stdout.write(".");
|
|
7196
|
+
attempts++;
|
|
7197
|
+
if (attempts % dotsPerLine === 0) process.stdout.write("\n");
|
|
7198
|
+
}, 500);
|
|
7199
|
+
try {
|
|
7200
|
+
const result = await Promise.race([fetchPromise, timeoutPromise]);
|
|
7201
|
+
clearInterval(dotsInterval);
|
|
7202
|
+
clearTimeout(timeoutId);
|
|
7203
|
+
if (result !== "timeout") {
|
|
7204
|
+
if (attempts > 0) process.stdout.write("\n");
|
|
7205
|
+
return result;
|
|
7206
|
+
}
|
|
7207
|
+
console.log(`
|
|
7208
|
+
\x1B[33m${t(locale, "local_ai_working")}\x1B[0m`);
|
|
7209
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
7210
|
+
const keepWaiting = await confirm({
|
|
7211
|
+
message: t(locale, "keep_waiting"),
|
|
7212
|
+
default: true
|
|
7213
|
+
}).catch(() => false);
|
|
7214
|
+
if (!keepWaiting) {
|
|
7215
|
+
controller.abort();
|
|
7216
|
+
console.log(`\x1B[33m${t(locale, "proceeding_offline")}\x1B[0m
|
|
7217
|
+
`);
|
|
7218
|
+
throw new Error("User cancelled waiting for slow LLM response");
|
|
7219
|
+
}
|
|
7220
|
+
attempts = 0;
|
|
7221
|
+
} catch (err) {
|
|
7222
|
+
clearInterval(dotsInterval);
|
|
7223
|
+
clearTimeout(timeoutId);
|
|
7224
|
+
if (attempts > 0) process.stdout.write("\n");
|
|
7225
|
+
throw err;
|
|
7226
|
+
}
|
|
7227
|
+
}
|
|
7228
|
+
}
|
|
7229
|
+
async function ensureHighQualityQuestion(db, token) {
|
|
7230
|
+
const { enabled } = await getLlmConfig(db);
|
|
7231
|
+
if (enabled) {
|
|
7232
|
+
try {
|
|
7233
|
+
let sourceLinkContent = null;
|
|
7234
|
+
if (token.sourceLink) {
|
|
7235
|
+
const resolved = await resolveReviewContext(token.sourceLink).catch(
|
|
7236
|
+
() => null
|
|
7237
|
+
);
|
|
7238
|
+
if (resolved) {
|
|
7239
|
+
sourceLinkContent = resolved.content;
|
|
7240
|
+
}
|
|
7241
|
+
}
|
|
7242
|
+
const generated = await generateQuestionViaLLM(db, {
|
|
7243
|
+
slug: token.slug,
|
|
7244
|
+
concept: token.concept,
|
|
7245
|
+
domain: token.domain,
|
|
7246
|
+
bloomLevel: token.bloomLevel,
|
|
7247
|
+
sourceLinkContent
|
|
7248
|
+
});
|
|
7249
|
+
if (generated.text.trim().length > 0) {
|
|
7250
|
+
await updateToken(db, token.slug, { question: generated.text });
|
|
7251
|
+
return {
|
|
7252
|
+
question: generated.text,
|
|
7253
|
+
source: "llm",
|
|
7254
|
+
model: generated.model
|
|
7255
|
+
};
|
|
7256
|
+
}
|
|
7257
|
+
} catch {
|
|
7258
|
+
}
|
|
7259
|
+
}
|
|
7260
|
+
if (token.question && token.question.trim().length > 0) {
|
|
7261
|
+
return {
|
|
7262
|
+
question: token.question.trim(),
|
|
7263
|
+
source: "original"
|
|
7264
|
+
};
|
|
7265
|
+
}
|
|
7266
|
+
return null;
|
|
7267
|
+
}
|
|
7268
|
+
|
|
7269
|
+
// src/cli/llm/embedder.ts
|
|
7270
|
+
init_kernel();
|
|
7271
|
+
var CANONICAL_EMBEDDING_MODEL_ID = "embeddinggemma-300m";
|
|
7272
|
+
var EMBEDDINGGEMMA_ALIASES = /* @__PURE__ */ new Set([
|
|
7273
|
+
"embeddinggemma",
|
|
7274
|
+
"embeddinggemma:300m",
|
|
7275
|
+
"embeddinggemma-300m",
|
|
7276
|
+
"embed-gemma",
|
|
7277
|
+
"embed-gemma:300m",
|
|
7278
|
+
"google/embeddinggemma-300m"
|
|
7279
|
+
]);
|
|
7280
|
+
function canonicalEmbeddingModelId(model) {
|
|
7281
|
+
const lowered = model.trim().toLowerCase();
|
|
7282
|
+
if (EMBEDDINGGEMMA_ALIASES.has(lowered)) {
|
|
7283
|
+
return CANONICAL_EMBEDDING_MODEL_ID;
|
|
7284
|
+
}
|
|
7285
|
+
return lowered;
|
|
7286
|
+
}
|
|
7287
|
+
function embeddingTextForToken(t2, model) {
|
|
7288
|
+
const isGemma = EMBEDDINGGEMMA_ALIASES.has(model.trim().toLowerCase());
|
|
7289
|
+
const content = embeddingContentForToken(t2);
|
|
7290
|
+
return isGemma ? `title: none | text: ${content}` : content;
|
|
7291
|
+
}
|
|
7292
|
+
function embeddingTextForQuery(text, model) {
|
|
7293
|
+
const isGemma = EMBEDDINGGEMMA_ALIASES.has(model.trim().toLowerCase());
|
|
7294
|
+
return isGemma ? `task: search result | query: ${text}` : text;
|
|
7295
|
+
}
|
|
7296
|
+
async function resolveUsableEmbeddingEndpoint(db) {
|
|
7297
|
+
const cfg = await getProviderForRole(db, "embedding");
|
|
7298
|
+
if (!cfg.enabled) return null;
|
|
7299
|
+
for (const endpoint of [cfg, ...cfg.fallback ? [cfg.fallback] : []]) {
|
|
7300
|
+
if (endpoint.apiFlavor !== "chat-completions") continue;
|
|
7301
|
+
const online = await isLlmOnline(endpoint.url);
|
|
7302
|
+
if (!online) continue;
|
|
7303
|
+
const availableModels = await getAvailableModels(
|
|
7304
|
+
endpoint.url,
|
|
7305
|
+
endpoint.apiKey
|
|
7306
|
+
);
|
|
7307
|
+
const modelAvailable = availableModels.length === 0 || availableModels.some(
|
|
7308
|
+
(candidate) => candidate.toLowerCase() === endpoint.model.toLowerCase()
|
|
7309
|
+
);
|
|
7310
|
+
if (modelAvailable) return endpoint;
|
|
7311
|
+
}
|
|
7312
|
+
return null;
|
|
7313
|
+
}
|
|
7314
|
+
async function embedTexts(endpoint, texts) {
|
|
7315
|
+
const controller = new AbortController();
|
|
7316
|
+
const timeoutId = setTimeout(() => controller.abort(), 6e4);
|
|
7317
|
+
let res;
|
|
7318
|
+
try {
|
|
7319
|
+
res = await fetch(`${endpoint.url}/embeddings`, {
|
|
7320
|
+
method: "POST",
|
|
7321
|
+
headers: {
|
|
7322
|
+
"Content-Type": "application/json",
|
|
7323
|
+
Authorization: `Bearer ${endpoint.apiKey || DEFAULT_LLM_API_KEY}`
|
|
7324
|
+
},
|
|
7325
|
+
body: JSON.stringify({ model: endpoint.model, input: texts }),
|
|
7326
|
+
signal: controller.signal
|
|
7327
|
+
});
|
|
7328
|
+
} finally {
|
|
7329
|
+
clearTimeout(timeoutId);
|
|
7330
|
+
}
|
|
7331
|
+
if (!res.ok) {
|
|
7332
|
+
const body = await res.text().catch(() => "");
|
|
7333
|
+
throw new Error(
|
|
7334
|
+
`Embedding request failed: ${res.statusText} (${res.status}) - ${body}`
|
|
7335
|
+
);
|
|
7336
|
+
}
|
|
7337
|
+
const data = await res.json();
|
|
7338
|
+
const items = data.data ?? [];
|
|
7339
|
+
if (items.length !== texts.length) {
|
|
7340
|
+
throw new Error(
|
|
7341
|
+
`Embedding response returned ${items.length} vectors for ${texts.length} inputs`
|
|
7342
|
+
);
|
|
7343
|
+
}
|
|
7344
|
+
const ordered = new Array(texts.length);
|
|
7345
|
+
for (let i = 0; i < items.length; i++) {
|
|
7346
|
+
const item = items[i];
|
|
7347
|
+
const index = typeof item.index === "number" ? item.index : i;
|
|
7348
|
+
if (!Number.isInteger(index)) {
|
|
7349
|
+
throw new Error("Embedding response item is missing a valid index");
|
|
7350
|
+
}
|
|
7351
|
+
if (index < 0 || index >= texts.length) {
|
|
7352
|
+
throw new Error(`Embedding response index out of range: ${index}`);
|
|
7353
|
+
}
|
|
7354
|
+
if (!Array.isArray(item.embedding) || item.embedding.length === 0 || !item.embedding.every((n) => typeof n === "number" && Number.isFinite(n))) {
|
|
7355
|
+
throw new Error(
|
|
7356
|
+
`Embedding response at index ${index} is not a non-empty array of finite numbers`
|
|
7357
|
+
);
|
|
7358
|
+
}
|
|
7359
|
+
ordered[index] = item.embedding;
|
|
7360
|
+
}
|
|
7361
|
+
const firstLength = ordered[0]?.length;
|
|
7362
|
+
if (ordered.some((vec) => vec === void 0 || vec.length !== firstLength)) {
|
|
7363
|
+
throw new Error("Embedding response vectors have inconsistent lengths");
|
|
7364
|
+
}
|
|
7365
|
+
return ordered;
|
|
7366
|
+
}
|
|
7367
|
+
var EMBED_BATCH_SIZE = 16;
|
|
7368
|
+
async function ensureTokenEmbeddings(db, opts) {
|
|
7369
|
+
const endpoint = await resolveUsableEmbeddingEndpoint(db);
|
|
7370
|
+
if (!endpoint) {
|
|
7371
|
+
const reason = await describeUnavailableReason(db);
|
|
7372
|
+
return { status: "unavailable", embedded: 0, remaining: 0, reason };
|
|
7373
|
+
}
|
|
7374
|
+
const model = canonicalEmbeddingModelId(endpoint.model);
|
|
7375
|
+
const pending = await listTokensNeedingEmbedding(db, model, {
|
|
7376
|
+
limit: opts?.limit ?? 64,
|
|
7377
|
+
force: opts?.force,
|
|
7378
|
+
dims: opts?.dims
|
|
7379
|
+
});
|
|
7380
|
+
let embedded = 0;
|
|
7381
|
+
let failure;
|
|
7382
|
+
try {
|
|
7383
|
+
for (let i = 0; i < pending.length; i += EMBED_BATCH_SIZE) {
|
|
7384
|
+
const batch = pending.slice(i, i + EMBED_BATCH_SIZE);
|
|
7385
|
+
const formattedTexts = batch.map(
|
|
7386
|
+
(item) => embeddingTextForToken(item.token, endpoint.model)
|
|
7387
|
+
);
|
|
7388
|
+
const vectors = await embedTexts(
|
|
7389
|
+
{ url: endpoint.url, model: endpoint.model, apiKey: endpoint.apiKey },
|
|
7390
|
+
formattedTexts
|
|
7391
|
+
);
|
|
7392
|
+
for (const [index, item] of batch.entries()) {
|
|
7393
|
+
await upsertTokenEmbedding(db, {
|
|
7394
|
+
tokenId: item.token.id,
|
|
7395
|
+
embedding: vectors[index],
|
|
7396
|
+
model,
|
|
7397
|
+
contentHash: computeContentHash(item.text)
|
|
7398
|
+
});
|
|
7399
|
+
embedded++;
|
|
7400
|
+
}
|
|
7401
|
+
}
|
|
7402
|
+
} catch (err) {
|
|
7403
|
+
failure = err instanceof Error ? err.message : String(err);
|
|
7404
|
+
}
|
|
7405
|
+
const coverage = await getEmbeddingCoverage(db, model, { dims: opts?.dims });
|
|
7406
|
+
const remaining = coverage.missing + coverage.stale;
|
|
7407
|
+
if (failure !== void 0) {
|
|
7408
|
+
return { status: "unavailable", embedded, remaining, reason: failure };
|
|
7409
|
+
}
|
|
7410
|
+
return { status: "ok", embedded, remaining };
|
|
7411
|
+
}
|
|
7412
|
+
async function describeUnavailableReason(db) {
|
|
7413
|
+
const cfg = await getProviderForRole(db, "embedding");
|
|
7414
|
+
if (!cfg.enabled) {
|
|
7415
|
+
return "embedding role is disabled in settings (llm.enabled)";
|
|
7416
|
+
}
|
|
7417
|
+
const endpoints = [cfg, ...cfg.fallback ? [cfg.fallback] : []];
|
|
7418
|
+
const online = await Promise.all(
|
|
7419
|
+
endpoints.map((endpoint) => isLlmOnline(endpoint.url))
|
|
7420
|
+
);
|
|
7421
|
+
if (!online.some(Boolean)) {
|
|
7422
|
+
return `embedding endpoints offline (${endpoints.map((endpoint) => endpoint.url).join(", ")})`;
|
|
7423
|
+
}
|
|
7424
|
+
return `no configured embedding model is available (${endpoints.map((endpoint) => endpoint.model).join(", ")})`;
|
|
7425
|
+
}
|
|
7426
|
+
async function embedQuery(db, text) {
|
|
7427
|
+
const endpoint = await resolveUsableEmbeddingEndpoint(db);
|
|
7428
|
+
if (!endpoint) return null;
|
|
7429
|
+
try {
|
|
7430
|
+
const [vector] = await embedTexts(
|
|
7431
|
+
{ url: endpoint.url, model: endpoint.model, apiKey: endpoint.apiKey },
|
|
7432
|
+
[embeddingTextForQuery(text, endpoint.model)]
|
|
7433
|
+
);
|
|
7434
|
+
return { vector, model: canonicalEmbeddingModelId(endpoint.model) };
|
|
7435
|
+
} catch {
|
|
7436
|
+
return null;
|
|
7437
|
+
}
|
|
7438
|
+
}
|
|
7439
|
+
async function findPossibleDuplicates(db, candidate, embed = embedQuery) {
|
|
7440
|
+
const queryText = embeddingContentForToken({
|
|
7441
|
+
concept: candidate.concept,
|
|
7442
|
+
question: candidate.question ?? null,
|
|
7443
|
+
domain: candidate.domain ?? "",
|
|
7444
|
+
title: candidate.title ?? null
|
|
7445
|
+
});
|
|
7446
|
+
const q2 = await embed(db, queryText);
|
|
7447
|
+
if (!q2) {
|
|
7448
|
+
return [];
|
|
7449
|
+
}
|
|
7450
|
+
const coverage = await getEmbeddingCoverage(db, q2.model, {
|
|
7451
|
+
dims: q2.vector.length
|
|
7452
|
+
});
|
|
7453
|
+
const totalNeeding = coverage.missing + coverage.stale;
|
|
7454
|
+
if (totalNeeding > 0) {
|
|
7455
|
+
await ensureTokenEmbeddings(db, { limit: 100, dims: q2.vector.length });
|
|
7456
|
+
if (totalNeeding > 100) {
|
|
7457
|
+
console.warn(
|
|
7458
|
+
`Warning: Duplicate check is incomplete. ${totalNeeding - 100} tokens are still missing embeddings. Run 'zam token reembed' to complete indexing.`
|
|
7459
|
+
);
|
|
7460
|
+
}
|
|
7461
|
+
}
|
|
7462
|
+
const threshold = await resolveDedupThreshold(db);
|
|
7463
|
+
const hits = await searchTokensHybrid(db, queryText, {
|
|
7464
|
+
queryEmbedding: q2.vector,
|
|
7465
|
+
model: q2.model,
|
|
7466
|
+
limit: 1e3,
|
|
7467
|
+
vectorTopK: 1e3
|
|
7468
|
+
});
|
|
7469
|
+
const results = [];
|
|
7470
|
+
for (const hit of hits) {
|
|
7471
|
+
if (hit.similarity !== null && hit.similarity >= threshold) {
|
|
7472
|
+
results.push({
|
|
7473
|
+
slug: hit.slug,
|
|
7474
|
+
concept: hit.concept,
|
|
7475
|
+
title: hit.title,
|
|
7476
|
+
similarity: hit.similarity
|
|
7477
|
+
});
|
|
7478
|
+
}
|
|
7479
|
+
}
|
|
7480
|
+
return results;
|
|
7481
|
+
}
|
|
7482
|
+
async function resolveDedupThreshold(db) {
|
|
7483
|
+
const thresholdStr = await getSetting(db, "search.dedup_threshold");
|
|
7484
|
+
const parsed = thresholdStr ? Number.parseFloat(thresholdStr) : Number.NaN;
|
|
7485
|
+
return Number.isFinite(parsed) && parsed > 0 && parsed <= 1 ? parsed : 0.85;
|
|
7486
|
+
}
|
|
7487
|
+
async function resolveSuggestMinSimilarity(db) {
|
|
7488
|
+
const minStr = await getSetting(db, "search.suggest_min_similarity");
|
|
7489
|
+
const parsed = minStr ? Number.parseFloat(minStr) : Number.NaN;
|
|
7490
|
+
return Number.isFinite(parsed) && parsed > 0 && parsed <= 1 ? parsed : 0.45;
|
|
7491
|
+
}
|
|
7492
|
+
|
|
7493
|
+
// src/cli/bridge-handlers.ts
|
|
7494
|
+
var BLOOM_VERBS3 = {
|
|
7495
|
+
1: "Remember",
|
|
7496
|
+
2: "Understand",
|
|
7497
|
+
3: "Apply",
|
|
7498
|
+
4: "Analyze",
|
|
7499
|
+
5: "Synthesize"
|
|
7500
|
+
};
|
|
7501
|
+
async function resolveHandlerUser(db, user) {
|
|
7502
|
+
if (user) return user;
|
|
7503
|
+
const stored = await getSetting(db, "user.id");
|
|
7504
|
+
if (stored) return stored;
|
|
7505
|
+
throw new Error(
|
|
7506
|
+
"No user specified. Set a default with: zam whoami --set <id>"
|
|
7507
|
+
);
|
|
7508
|
+
}
|
|
7509
|
+
function parseKnowledgeContextNames(value) {
|
|
7510
|
+
if (value == null) return [];
|
|
7511
|
+
if (!Array.isArray(value) || value.some((name) => typeof name !== "string" || !name.trim())) {
|
|
7512
|
+
throw new Error(
|
|
7513
|
+
"knowledgeContexts must be an array of non-empty context names"
|
|
7514
|
+
);
|
|
7515
|
+
}
|
|
7516
|
+
return [...new Set(value.map((name) => name.trim()))];
|
|
7517
|
+
}
|
|
7518
|
+
async function resolveKnowledgeContexts(db, names) {
|
|
7519
|
+
return await resolveOperationKnowledgeContexts(db, names);
|
|
7520
|
+
}
|
|
7521
|
+
async function checkDue(db, params) {
|
|
7522
|
+
const userId = await resolveHandlerUser(db, params.user);
|
|
7523
|
+
const dueCards = await getDueCards(
|
|
7524
|
+
db,
|
|
7525
|
+
userId,
|
|
7526
|
+
void 0,
|
|
7527
|
+
params.domain,
|
|
7528
|
+
params.knowledgeContext
|
|
7529
|
+
);
|
|
7530
|
+
const domains = [
|
|
7531
|
+
...new Set(dueCards.map((c) => c.domain).filter(Boolean))
|
|
7532
|
+
].sort();
|
|
7533
|
+
const stats = await getUserStats(db, userId);
|
|
7534
|
+
return {
|
|
7535
|
+
database: getDatabaseTargetInfo(),
|
|
7536
|
+
stats,
|
|
7537
|
+
userId,
|
|
7538
|
+
domain: params.domain ?? null,
|
|
7539
|
+
knowledgeContext: params.knowledgeContext ?? null,
|
|
7540
|
+
dueCount: dueCards.length,
|
|
7541
|
+
domains,
|
|
7542
|
+
cards: dueCards.map((c) => ({
|
|
7543
|
+
cardId: c.id,
|
|
7544
|
+
tokenId: c.token_id,
|
|
7545
|
+
slug: c.slug,
|
|
7546
|
+
concept: c.concept,
|
|
7547
|
+
domain: c.domain,
|
|
7548
|
+
bloomLevel: c.bloom_level,
|
|
7549
|
+
state: c.state,
|
|
7550
|
+
dueAt: c.due_at
|
|
7551
|
+
}))
|
|
7552
|
+
};
|
|
7553
|
+
}
|
|
7554
|
+
async function getReviewsBatch(db, params) {
|
|
7555
|
+
const userId = await resolveHandlerUser(db, params.user);
|
|
7556
|
+
const dueCards = await getDueCards(
|
|
7557
|
+
db,
|
|
7558
|
+
userId,
|
|
7559
|
+
void 0,
|
|
7560
|
+
params.domain,
|
|
7561
|
+
params.knowledgeContext
|
|
7562
|
+
);
|
|
7563
|
+
const isLlmEnabled = await getSetting(db, "llm.enabled") === "true";
|
|
7564
|
+
const cards = [];
|
|
7565
|
+
for (const card of dueCards) {
|
|
7566
|
+
if (params.includeQuestions) {
|
|
7567
|
+
const token = await getTokenBySlug(db, card.slug);
|
|
7568
|
+
if (!token) {
|
|
7569
|
+
cards.push({
|
|
7570
|
+
cardId: card.id,
|
|
7571
|
+
tokenId: card.token_id,
|
|
7572
|
+
slug: card.slug,
|
|
7573
|
+
concept: card.concept,
|
|
7574
|
+
domain: card.domain,
|
|
7575
|
+
bloomLevel: card.bloom_level,
|
|
7576
|
+
state: card.state,
|
|
7577
|
+
dueAt: card.due_at
|
|
7578
|
+
});
|
|
7579
|
+
continue;
|
|
7580
|
+
}
|
|
7581
|
+
let resolvedQuestion = token.question;
|
|
7582
|
+
if (isLlmEnabled && params.noDynamicQuestion !== true) {
|
|
7583
|
+
try {
|
|
7584
|
+
const healed = await ensureHighQualityQuestion(db, {
|
|
7585
|
+
id: token.id,
|
|
7586
|
+
slug: token.slug,
|
|
7587
|
+
concept: token.concept,
|
|
7588
|
+
domain: token.domain,
|
|
7589
|
+
bloomLevel: token.bloom_level,
|
|
7590
|
+
sourceLink: token.source_link,
|
|
7591
|
+
question: token.question
|
|
7592
|
+
});
|
|
7593
|
+
if (healed) {
|
|
7594
|
+
resolvedQuestion = healed.question;
|
|
7595
|
+
}
|
|
7596
|
+
} catch {
|
|
7597
|
+
}
|
|
7598
|
+
}
|
|
7599
|
+
const finalQuestion = resolvedQuestion?.trim() ? resolvedQuestion.trim() : generateConceptFreeCue(
|
|
7600
|
+
token.bloom_level,
|
|
7601
|
+
token.slug,
|
|
7602
|
+
token.domain
|
|
7603
|
+
);
|
|
7604
|
+
let resolvedContext = null;
|
|
7605
|
+
if (params.noResolve !== true && token.source_link) {
|
|
7606
|
+
try {
|
|
7607
|
+
resolvedContext = await resolveReviewContext(token.source_link);
|
|
7608
|
+
} catch {
|
|
7609
|
+
resolvedContext = null;
|
|
7610
|
+
}
|
|
7611
|
+
}
|
|
7612
|
+
const bloom = token.bloom_level >= 1 && token.bloom_level <= 5 ? token.bloom_level : 1;
|
|
7613
|
+
cards.push({
|
|
7614
|
+
cardId: card.id,
|
|
7615
|
+
tokenId: card.token_id,
|
|
7616
|
+
slug: card.slug,
|
|
7617
|
+
concept: card.concept,
|
|
7618
|
+
domain: card.domain,
|
|
7619
|
+
bloomLevel: card.bloom_level,
|
|
7620
|
+
state: card.state,
|
|
7621
|
+
dueAt: card.due_at,
|
|
7622
|
+
bloomVerb: BLOOM_VERBS3[bloom],
|
|
7623
|
+
question: finalQuestion,
|
|
7624
|
+
sourceLink: token.source_link ?? null,
|
|
7625
|
+
resolvedContext
|
|
7626
|
+
});
|
|
7627
|
+
} else {
|
|
7628
|
+
cards.push({
|
|
7629
|
+
cardId: card.id,
|
|
7630
|
+
tokenId: card.token_id,
|
|
7631
|
+
slug: card.slug,
|
|
7632
|
+
concept: card.concept,
|
|
7633
|
+
domain: card.domain,
|
|
7634
|
+
bloomLevel: card.bloom_level,
|
|
7635
|
+
state: card.state,
|
|
7636
|
+
dueAt: card.due_at
|
|
7637
|
+
});
|
|
7638
|
+
}
|
|
7639
|
+
}
|
|
7640
|
+
return { cards };
|
|
7641
|
+
}
|
|
7642
|
+
async function submitReview(db, params) {
|
|
7643
|
+
const userId = await resolveHandlerUser(db, params.user);
|
|
7644
|
+
if (params.doneBy !== void 0 && !["user", "agent"].includes(params.doneBy)) {
|
|
7645
|
+
throw new Error("doneBy must be user or agent");
|
|
7646
|
+
}
|
|
7647
|
+
if (params.doneBy === "agent") {
|
|
7648
|
+
if (params.rating !== void 0) {
|
|
7649
|
+
throw new Error("Agent-completed steps must not include a rating");
|
|
7650
|
+
}
|
|
7651
|
+
if (!params.sessionId) {
|
|
7652
|
+
throw new Error("sessionId is required for an agent-completed step");
|
|
7653
|
+
}
|
|
7654
|
+
if (!params.cardId) {
|
|
7655
|
+
throw new Error("cardId is required for an agent-completed step");
|
|
7656
|
+
}
|
|
7657
|
+
const card = await getCardById(db, params.cardId);
|
|
7658
|
+
if (!card) {
|
|
7659
|
+
throw new Error(`Card not found: ${params.cardId}`);
|
|
7660
|
+
}
|
|
7661
|
+
if (card.user_id !== userId) {
|
|
7662
|
+
throw new Error(
|
|
7663
|
+
`Card ${params.cardId} does not belong to user ${userId}`
|
|
7664
|
+
);
|
|
7665
|
+
}
|
|
7666
|
+
await logStep(db, {
|
|
7667
|
+
session_id: params.sessionId,
|
|
7668
|
+
token_id: card.token_id,
|
|
7669
|
+
done_by: "agent"
|
|
7670
|
+
});
|
|
7671
|
+
return {
|
|
7672
|
+
success: true,
|
|
7673
|
+
rating: null,
|
|
7674
|
+
evaluation: null,
|
|
7675
|
+
blocked: null,
|
|
7676
|
+
recordedOnly: true
|
|
7677
|
+
};
|
|
7678
|
+
}
|
|
7679
|
+
if (params.rating == null || params.rating < 1 || params.rating > 4) {
|
|
7680
|
+
throw new Error("Rating must be between 1 and 4");
|
|
7681
|
+
}
|
|
7682
|
+
let cardId = params.cardId;
|
|
7683
|
+
if (!cardId) {
|
|
7684
|
+
if (!params.tokenId) {
|
|
7685
|
+
throw new Error("cardId or tokenId is required");
|
|
7686
|
+
}
|
|
7687
|
+
const token = await getTokenById(db, params.tokenId);
|
|
7688
|
+
if (!token || token.deprecated_at) {
|
|
7689
|
+
throw new Error(`Active token not found: ${params.tokenId}`);
|
|
7690
|
+
}
|
|
7691
|
+
cardId = (await ensureCard(db, token.id, userId)).id;
|
|
7692
|
+
}
|
|
7693
|
+
const result = await executeReviewAction(db, {
|
|
7694
|
+
action: "rate",
|
|
7695
|
+
cardId,
|
|
7696
|
+
userId,
|
|
7697
|
+
rating: params.rating
|
|
7698
|
+
});
|
|
7699
|
+
let stepError;
|
|
7700
|
+
if (params.sessionId) {
|
|
7701
|
+
try {
|
|
7702
|
+
await logStep(db, {
|
|
7703
|
+
session_id: params.sessionId,
|
|
7704
|
+
token_id: result.token.id,
|
|
7705
|
+
done_by: "user",
|
|
7706
|
+
rating: params.rating
|
|
7707
|
+
});
|
|
7708
|
+
} catch (err) {
|
|
7709
|
+
stepError = err.message;
|
|
7710
|
+
}
|
|
7711
|
+
}
|
|
7712
|
+
return {
|
|
7713
|
+
success: true,
|
|
7714
|
+
rating: params.rating,
|
|
7715
|
+
evaluation: result.evaluation,
|
|
7716
|
+
blocked: result.blocked ?? null,
|
|
7717
|
+
...stepError ? { stepError } : {}
|
|
7718
|
+
};
|
|
7719
|
+
}
|
|
7720
|
+
async function reviewAction(db, params) {
|
|
7721
|
+
const userId = await resolveHandlerUser(db, params.user);
|
|
7722
|
+
const action = params.action;
|
|
7723
|
+
const validActions = [
|
|
7724
|
+
"rate",
|
|
7725
|
+
"skip",
|
|
7726
|
+
"edit-token",
|
|
7727
|
+
"deprecate-token",
|
|
7728
|
+
"delete-token",
|
|
7729
|
+
"delete-card",
|
|
7730
|
+
"stop"
|
|
7731
|
+
];
|
|
7732
|
+
if (!validActions.includes(action)) {
|
|
7733
|
+
throw new Error(`Unsupported action: ${action}`);
|
|
7734
|
+
}
|
|
7735
|
+
const target = await db.prepare(
|
|
7736
|
+
`SELECT c.id AS card_id, c.token_id, c.user_id, t.slug
|
|
7737
|
+
FROM cards c
|
|
7738
|
+
JOIN tokens t ON t.id = c.token_id
|
|
7739
|
+
WHERE c.id = ?`
|
|
7740
|
+
).get(params.cardId);
|
|
7741
|
+
if (!target) {
|
|
7742
|
+
throw new Error(`Card not found: ${params.cardId}`);
|
|
7743
|
+
}
|
|
7744
|
+
if (target.user_id !== userId) {
|
|
7745
|
+
throw new Error(`Card ${params.cardId} does not belong to user ${userId}`);
|
|
7746
|
+
}
|
|
7747
|
+
if ((action === "delete-token" || action === "delete-card") && !params.confirm) {
|
|
7748
|
+
if (action === "delete-token") {
|
|
7749
|
+
return {
|
|
7750
|
+
success: true,
|
|
7751
|
+
action,
|
|
7752
|
+
preview: true,
|
|
7753
|
+
requiresConfirmation: true,
|
|
7754
|
+
token: { slug: target.slug, tokenId: target.token_id },
|
|
7755
|
+
impact: await getTokenDeleteImpact(db, target.slug)
|
|
7756
|
+
};
|
|
7757
|
+
}
|
|
7758
|
+
return {
|
|
7759
|
+
success: true,
|
|
7760
|
+
action,
|
|
7761
|
+
preview: true,
|
|
7762
|
+
requiresConfirmation: true,
|
|
7763
|
+
token: { slug: target.slug, tokenId: target.token_id },
|
|
7764
|
+
impact: await getCardDeletionImpact(db, target.token_id, userId)
|
|
7765
|
+
};
|
|
7766
|
+
}
|
|
7767
|
+
if (action === "rate" && (params.rating == null || params.rating < 1 || params.rating > 4)) {
|
|
7768
|
+
throw new Error("Rating must be between 1 and 4 for action=rate");
|
|
7769
|
+
}
|
|
7770
|
+
let tokenUpdates;
|
|
7771
|
+
if (action === "edit-token") {
|
|
7772
|
+
tokenUpdates = {};
|
|
7773
|
+
if (params.concept !== void 0) tokenUpdates.concept = params.concept;
|
|
7774
|
+
if (params.domain !== void 0) tokenUpdates.domain = params.domain;
|
|
7775
|
+
if (params.bloomLevel !== void 0)
|
|
7776
|
+
tokenUpdates.bloom_level = params.bloomLevel;
|
|
7777
|
+
if (params.context !== void 0) tokenUpdates.context = params.context;
|
|
7778
|
+
if (params.sourceLink !== void 0) {
|
|
7779
|
+
tokenUpdates.source_link = params.sourceLink === "" ? null : params.sourceLink;
|
|
7780
|
+
}
|
|
7781
|
+
if (params.symbiosisMode !== void 0) {
|
|
7782
|
+
const validModes = ["shadowing", "copilot", "autonomy", "none"];
|
|
7783
|
+
if (!validModes.includes(params.symbiosisMode)) {
|
|
7784
|
+
throw new Error(`Invalid mode: ${params.symbiosisMode}`);
|
|
7785
|
+
}
|
|
7786
|
+
tokenUpdates.symbiosis_mode = params.symbiosisMode === "none" ? null : params.symbiosisMode;
|
|
7787
|
+
}
|
|
7788
|
+
}
|
|
7789
|
+
const result = await executeReviewAction(db, {
|
|
7790
|
+
action,
|
|
7791
|
+
cardId: params.cardId,
|
|
7792
|
+
userId,
|
|
7793
|
+
rating: params.rating,
|
|
7794
|
+
tokenUpdates
|
|
7795
|
+
});
|
|
7796
|
+
return {
|
|
7797
|
+
success: true,
|
|
7798
|
+
action,
|
|
7799
|
+
token: {
|
|
7800
|
+
slug: result.token.slug,
|
|
7801
|
+
tokenId: result.token.id
|
|
7802
|
+
},
|
|
7803
|
+
rating: params.rating ?? null,
|
|
7804
|
+
evaluation: result.evaluation ?? null,
|
|
7805
|
+
blocked: result.blocked ?? null,
|
|
7806
|
+
updatedToken: result.updatedToken ?? null,
|
|
7807
|
+
deletedToken: result.deletedToken ?? null,
|
|
7808
|
+
deletedCard: result.deletedCard ?? null,
|
|
7809
|
+
skipped: result.skipped ?? false,
|
|
7810
|
+
stopped: result.stopped ?? false
|
|
7811
|
+
};
|
|
7812
|
+
}
|
|
7813
|
+
async function addToken(db, params) {
|
|
7814
|
+
const userId = await resolveHandlerUser(db, params.user);
|
|
7815
|
+
if (!params.slug.trim() || !params.concept.trim()) {
|
|
7816
|
+
throw new Error("slug and concept must be non-empty");
|
|
7817
|
+
}
|
|
7818
|
+
if (params.bloomLevel !== void 0 && (!Number.isInteger(params.bloomLevel) || params.bloomLevel < 1 || params.bloomLevel > 5)) {
|
|
7819
|
+
throw new Error("bloomLevel must be an integer between 1 and 5");
|
|
7820
|
+
}
|
|
7821
|
+
const possibleDuplicates = await findPossibleDuplicates(db, {
|
|
7822
|
+
concept: params.concept,
|
|
7823
|
+
question: params.question ?? null,
|
|
7824
|
+
domain: params.domain,
|
|
7825
|
+
title: params.title ?? null
|
|
7826
|
+
});
|
|
7827
|
+
const ctxNames = parseKnowledgeContextNames(
|
|
7828
|
+
params.knowledgeContexts ?? params.knowledge_contexts
|
|
7829
|
+
);
|
|
7830
|
+
const assignedContexts = await resolveKnowledgeContexts(db, ctxNames);
|
|
7831
|
+
const prerequisiteSlugs = [
|
|
7832
|
+
...new Set(
|
|
7833
|
+
(params.prerequisites ?? []).map((slug) => slug.trim()).filter(Boolean)
|
|
7834
|
+
)
|
|
7835
|
+
];
|
|
7836
|
+
const prerequisites = [];
|
|
7837
|
+
for (const slug of prerequisiteSlugs) {
|
|
7838
|
+
const prerequisite = await getTokenBySlug(db, slug);
|
|
7839
|
+
if (!prerequisite) {
|
|
7840
|
+
throw new Error(`Prerequisite token not found: ${slug}`);
|
|
7841
|
+
}
|
|
7842
|
+
prerequisites.push(prerequisite);
|
|
7843
|
+
}
|
|
7844
|
+
const token = await createToken(db, {
|
|
7845
|
+
slug: params.slug,
|
|
7846
|
+
title: params.title,
|
|
7847
|
+
concept: params.concept,
|
|
7848
|
+
domain: params.domain,
|
|
7849
|
+
bloom_level: params.bloomLevel ?? 1,
|
|
7850
|
+
context: params.context,
|
|
7851
|
+
symbiosis_mode: params.symbiosisMode,
|
|
7852
|
+
source_link: params.sourceLink ?? null,
|
|
7853
|
+
question: params.question ?? null
|
|
7854
|
+
});
|
|
7855
|
+
for (const context of assignedContexts) {
|
|
7856
|
+
await assignTokenToContext(db, token.id, context.id);
|
|
7857
|
+
}
|
|
7858
|
+
for (const prerequisite of prerequisites) {
|
|
7859
|
+
await addPrerequisite(db, token.id, prerequisite.id);
|
|
7860
|
+
}
|
|
7861
|
+
const card = await ensureCard(db, token.id, userId);
|
|
7862
|
+
try {
|
|
7863
|
+
await ensureTokenEmbeddings(db, { limit: 8 });
|
|
7864
|
+
} catch {
|
|
7865
|
+
}
|
|
7866
|
+
return {
|
|
7867
|
+
success: true,
|
|
7868
|
+
token: {
|
|
7869
|
+
...token,
|
|
7870
|
+
knowledgeContexts: assignedContexts.map((c) => ({
|
|
7871
|
+
name: c.name,
|
|
7872
|
+
label: c.label,
|
|
7873
|
+
language: c.language
|
|
7874
|
+
})),
|
|
7875
|
+
prerequisites: prerequisites.map((prerequisite) => prerequisite.slug)
|
|
7876
|
+
},
|
|
7877
|
+
card: {
|
|
7878
|
+
id: card.id,
|
|
7879
|
+
tokenId: card.token_id,
|
|
7880
|
+
userId: card.user_id,
|
|
7881
|
+
state: card.state,
|
|
7882
|
+
dueAt: card.due_at,
|
|
7883
|
+
blocked: card.blocked
|
|
7884
|
+
},
|
|
7885
|
+
possible_duplicates: possibleDuplicates
|
|
7886
|
+
};
|
|
7887
|
+
}
|
|
7888
|
+
async function findTokens2(db, params) {
|
|
7889
|
+
const userId = await resolveHandlerUser(db, params.user);
|
|
7890
|
+
if (!params.context.trim()) {
|
|
7891
|
+
throw new Error("context must be non-empty");
|
|
7892
|
+
}
|
|
7893
|
+
const truncatedContext = params.context.slice(0, 2e3);
|
|
7894
|
+
const q2 = await embedQuery(db, truncatedContext);
|
|
7895
|
+
try {
|
|
7896
|
+
await ensureTokenEmbeddings(db, {
|
|
7897
|
+
limit: 32,
|
|
7898
|
+
dims: q2?.vector.length
|
|
7899
|
+
});
|
|
7900
|
+
} catch {
|
|
7901
|
+
}
|
|
7902
|
+
let limit = params.limit ?? 10;
|
|
7903
|
+
if (typeof limit !== "number" || limit <= 0 || !Number.isInteger(limit)) {
|
|
7904
|
+
limit = 10;
|
|
7905
|
+
}
|
|
7906
|
+
if (limit > 100) {
|
|
7907
|
+
limit = 100;
|
|
7908
|
+
}
|
|
7909
|
+
const results = await searchTokensHybrid(db, truncatedContext, {
|
|
7910
|
+
queryEmbedding: q2?.vector,
|
|
7911
|
+
model: q2?.model,
|
|
7912
|
+
limit
|
|
7913
|
+
});
|
|
7914
|
+
const tokens = [];
|
|
7915
|
+
const contextMap = /* @__PURE__ */ new Map();
|
|
7916
|
+
if (results.length > 0) {
|
|
7917
|
+
const ids = results.map((t2) => t2.id);
|
|
7918
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
7919
|
+
const mappings = await db.prepare(
|
|
7920
|
+
`SELECT tc.token_id, c.name, c.label, c.language
|
|
7921
|
+
FROM token_contexts tc
|
|
7922
|
+
INNER JOIN contexts c ON c.id = tc.context_id
|
|
7923
|
+
WHERE tc.token_id IN (${placeholders})`
|
|
7924
|
+
).all(...ids);
|
|
7925
|
+
for (const m of mappings) {
|
|
7926
|
+
const list = contextMap.get(m.token_id) ?? [];
|
|
7927
|
+
list.push({ name: m.name, label: m.label, language: m.language });
|
|
7928
|
+
contextMap.set(m.token_id, list);
|
|
7929
|
+
}
|
|
7930
|
+
}
|
|
7931
|
+
for (const t2 of results) {
|
|
7932
|
+
const card = await getCard(db, t2.id, userId);
|
|
7933
|
+
tokens.push({
|
|
7934
|
+
slug: t2.slug,
|
|
7935
|
+
title: t2.title,
|
|
7936
|
+
display_title: getDisplayTitle(t2),
|
|
7937
|
+
concept: t2.concept,
|
|
7938
|
+
domain: t2.domain,
|
|
7939
|
+
bloom_level: t2.bloom_level,
|
|
7940
|
+
score: t2.score,
|
|
7941
|
+
similarity: t2.similarity,
|
|
7942
|
+
knowledgeContexts: contextMap.get(t2.id) ?? [],
|
|
7943
|
+
card: card ? {
|
|
7944
|
+
state: card.state,
|
|
7945
|
+
due_at: card.due_at,
|
|
7946
|
+
blocked: card.blocked
|
|
7947
|
+
} : null
|
|
7948
|
+
});
|
|
7949
|
+
}
|
|
7950
|
+
return {
|
|
7951
|
+
semantic: q2 !== null,
|
|
7952
|
+
tokens
|
|
7953
|
+
};
|
|
7954
|
+
}
|
|
7955
|
+
async function suggestFoundations2(db, params) {
|
|
7956
|
+
let queryText = "";
|
|
7957
|
+
let targetTokenId;
|
|
7958
|
+
let targetBloomLevel;
|
|
7959
|
+
let targetJson = null;
|
|
7960
|
+
if (params.slug !== void 0) {
|
|
7961
|
+
if (typeof params.slug !== "string" || params.slug.trim() === "") {
|
|
7962
|
+
throw new Error("Invalid slug");
|
|
7963
|
+
}
|
|
7964
|
+
const token = await getTokenBySlug(db, params.slug);
|
|
7965
|
+
if (!token) {
|
|
7966
|
+
throw new Error(`Token not found: ${params.slug}`);
|
|
7967
|
+
}
|
|
7968
|
+
const { embeddingContentForToken: getContent } = await Promise.resolve().then(() => (init_kernel(), kernel_exports));
|
|
7969
|
+
queryText = getContent(token);
|
|
7970
|
+
targetTokenId = token.id;
|
|
7971
|
+
targetBloomLevel = token.bloom_level;
|
|
7972
|
+
targetJson = { slug: token.slug };
|
|
7973
|
+
} else {
|
|
7974
|
+
if (!params.concept || typeof params.concept !== "string" || params.concept.trim() === "") {
|
|
7975
|
+
throw new Error(
|
|
7976
|
+
"JSON must include a non-empty 'slug' or 'concept' field"
|
|
7977
|
+
);
|
|
7978
|
+
}
|
|
7979
|
+
const { embeddingContentForToken: getContent } = await Promise.resolve().then(() => (init_kernel(), kernel_exports));
|
|
7980
|
+
queryText = getContent({
|
|
7981
|
+
concept: params.concept,
|
|
7982
|
+
question: typeof params.question === "string" ? params.question : null,
|
|
7983
|
+
domain: typeof params.domain === "string" ? params.domain : "",
|
|
7984
|
+
title: typeof params.title === "string" ? params.title : null
|
|
7985
|
+
});
|
|
7986
|
+
if (params.bloom_level !== void 0) {
|
|
7987
|
+
if (typeof params.bloom_level !== "number" || !Number.isInteger(params.bloom_level) || params.bloom_level < 1 || params.bloom_level > 5) {
|
|
7988
|
+
throw new Error("bloom_level must be an integer between 1 and 5");
|
|
7989
|
+
}
|
|
7990
|
+
targetBloomLevel = params.bloom_level;
|
|
7991
|
+
}
|
|
7992
|
+
}
|
|
7993
|
+
let limit = params.limit ?? 5;
|
|
7994
|
+
if (typeof limit !== "number" || limit <= 0 || !Number.isInteger(limit)) {
|
|
7995
|
+
limit = 5;
|
|
7996
|
+
}
|
|
7997
|
+
if (limit > 20) {
|
|
7998
|
+
limit = 20;
|
|
7999
|
+
}
|
|
8000
|
+
const q2 = await embedQuery(db, queryText);
|
|
8001
|
+
if (q2 === null) {
|
|
8002
|
+
return {
|
|
8003
|
+
semantic: false,
|
|
8004
|
+
target: targetJson,
|
|
8005
|
+
suggestions: []
|
|
8006
|
+
};
|
|
8007
|
+
}
|
|
8008
|
+
try {
|
|
8009
|
+
await ensureTokenEmbeddings(db, {
|
|
8010
|
+
limit: 100,
|
|
8011
|
+
dims: q2.vector.length
|
|
8012
|
+
});
|
|
8013
|
+
} catch {
|
|
8014
|
+
}
|
|
8015
|
+
const maxSimilarity = await resolveDedupThreshold(db);
|
|
8016
|
+
const minSimilarity = await resolveSuggestMinSimilarity(db);
|
|
8017
|
+
if (minSimilarity >= maxSimilarity) {
|
|
8018
|
+
return {
|
|
8019
|
+
semantic: true,
|
|
8020
|
+
target: targetJson,
|
|
8021
|
+
suggestions: []
|
|
8022
|
+
};
|
|
8023
|
+
}
|
|
8024
|
+
const suggestions = await suggestFoundations(db, {
|
|
8025
|
+
queryEmbedding: q2.vector,
|
|
8026
|
+
model: q2.model,
|
|
8027
|
+
targetTokenId,
|
|
8028
|
+
targetBloomLevel,
|
|
8029
|
+
limit,
|
|
8030
|
+
minSimilarity,
|
|
8031
|
+
maxSimilarity
|
|
8032
|
+
});
|
|
8033
|
+
return {
|
|
8034
|
+
semantic: true,
|
|
8035
|
+
target: targetJson,
|
|
8036
|
+
suggestions: suggestions.map((s) => ({
|
|
8037
|
+
slug: s.token.slug,
|
|
8038
|
+
concept: s.token.concept,
|
|
8039
|
+
domain: s.token.domain,
|
|
8040
|
+
bloom_level: s.token.bloom_level,
|
|
8041
|
+
similarity: s.similarity,
|
|
8042
|
+
already_prerequisite: s.alreadyPrerequisite,
|
|
8043
|
+
would_create_cycle: s.wouldCreateCycle,
|
|
8044
|
+
bloom_above_target: s.bloomAboveTarget
|
|
8045
|
+
}))
|
|
8046
|
+
};
|
|
8047
|
+
}
|
|
8048
|
+
async function linkPrereq(db, params) {
|
|
8049
|
+
if (!params.token.trim() || !params.requires.trim()) {
|
|
8050
|
+
throw new Error("token and requires must be non-empty slugs");
|
|
8051
|
+
}
|
|
8052
|
+
const token = await getTokenBySlug(db, params.token);
|
|
8053
|
+
if (!token) {
|
|
8054
|
+
throw new Error(`Token not found: ${params.token}`);
|
|
8055
|
+
}
|
|
8056
|
+
const requires = await getTokenBySlug(db, params.requires);
|
|
8057
|
+
if (!requires) {
|
|
8058
|
+
throw new Error(`Prerequisite token not found: ${params.requires}`);
|
|
8059
|
+
}
|
|
8060
|
+
await addPrerequisite(db, token.id, requires.id);
|
|
8061
|
+
let blockedCardId;
|
|
8062
|
+
if (params.blockUser) {
|
|
8063
|
+
const card = await getCard(db, token.id, params.blockUser);
|
|
8064
|
+
if (card) {
|
|
8065
|
+
await updateCard(db, card.id, { blocked: 1 });
|
|
8066
|
+
blockedCardId = card.id;
|
|
8067
|
+
}
|
|
8068
|
+
}
|
|
8069
|
+
return {
|
|
8070
|
+
success: true,
|
|
8071
|
+
token: params.token,
|
|
8072
|
+
requires: params.requires,
|
|
8073
|
+
...blockedCardId ? { blockedCardId } : {}
|
|
8074
|
+
};
|
|
8075
|
+
}
|
|
8076
|
+
async function startSession2(db, params) {
|
|
8077
|
+
if (!params.task.trim()) {
|
|
8078
|
+
throw new Error("task must be non-empty");
|
|
8079
|
+
}
|
|
8080
|
+
const context = params.context ?? "shell";
|
|
8081
|
+
if (!["shell", "ui", "reallife"].includes(context)) {
|
|
8082
|
+
throw new Error("context must be shell, ui, or reallife");
|
|
8083
|
+
}
|
|
8084
|
+
const userId = await resolveHandlerUser(db, params.user);
|
|
8085
|
+
const session = await startSession(db, {
|
|
8086
|
+
user_id: userId,
|
|
8087
|
+
task: params.task,
|
|
8088
|
+
execution_context: context
|
|
8089
|
+
});
|
|
8090
|
+
const observerPolicyHint = context === "ui" && !await isObserverPolicyConfigured(db) ? OBSERVER_POLICY_UNSET_HINT : void 0;
|
|
8091
|
+
return {
|
|
8092
|
+
id: session.id,
|
|
8093
|
+
userId: session.user_id,
|
|
8094
|
+
task: session.task,
|
|
8095
|
+
executionContext: session.execution_context,
|
|
8096
|
+
startedAt: session.started_at,
|
|
8097
|
+
completedAt: session.completed_at,
|
|
8098
|
+
...observerPolicyHint ? { observerPolicyHint } : {}
|
|
8099
|
+
};
|
|
8100
|
+
}
|
|
8101
|
+
async function endSession2(db, params) {
|
|
8102
|
+
const synthesisPreview = params.synthesize ? await prepareSessionSynthesis(db, {
|
|
8103
|
+
sessionId: params.session,
|
|
8104
|
+
explicitPatterns: params.patterns,
|
|
8105
|
+
minConfidence: params.minConfidence ?? "medium"
|
|
8106
|
+
}) : void 0;
|
|
8107
|
+
const synthesis = synthesisPreview ? {
|
|
8108
|
+
...synthesisPreview,
|
|
8109
|
+
candidates: await Promise.all(
|
|
8110
|
+
synthesisPreview.candidates.map(async (candidate) => ({
|
|
8111
|
+
...candidate,
|
|
8112
|
+
cardId: (await getCard(db, candidate.tokenId, synthesisPreview.userId))?.id ?? null
|
|
8113
|
+
}))
|
|
8114
|
+
)
|
|
8115
|
+
} : void 0;
|
|
8116
|
+
const session = await endSession(db, params.session);
|
|
8117
|
+
const summary = await getSessionSummary(db, params.session);
|
|
8118
|
+
return {
|
|
8119
|
+
id: session.id,
|
|
8120
|
+
userId: session.user_id,
|
|
8121
|
+
task: session.task,
|
|
8122
|
+
executionContext: session.execution_context,
|
|
8123
|
+
startedAt: session.started_at,
|
|
8124
|
+
completedAt: session.completed_at,
|
|
8125
|
+
summary,
|
|
8126
|
+
...synthesis ? { synthesis } : {}
|
|
8127
|
+
};
|
|
8128
|
+
}
|
|
8129
|
+
async function getMonitor(_db, params) {
|
|
8130
|
+
if (!monitorLogExists(params.session)) {
|
|
8131
|
+
return {
|
|
8132
|
+
sessionId: params.session,
|
|
8133
|
+
exists: false,
|
|
8134
|
+
commands: [],
|
|
8135
|
+
timeSpan: null
|
|
8136
|
+
};
|
|
8137
|
+
}
|
|
8138
|
+
const events = readMonitorLog(params.session);
|
|
8139
|
+
const commands = pairCommands(events);
|
|
8140
|
+
let timeSpan = null;
|
|
8141
|
+
if (commands.length > 0) {
|
|
8142
|
+
const first = commands[0];
|
|
8143
|
+
const last = commands[commands.length - 1];
|
|
8144
|
+
const endTs = last.endedAt ?? last.startedAt;
|
|
8145
|
+
timeSpan = {
|
|
8146
|
+
start: first.startedAt,
|
|
8147
|
+
end: endTs,
|
|
8148
|
+
durationMs: new Date(endTs).getTime() - new Date(first.startedAt).getTime()
|
|
8149
|
+
};
|
|
8150
|
+
}
|
|
8151
|
+
return {
|
|
8152
|
+
sessionId: params.session,
|
|
8153
|
+
exists: true,
|
|
8154
|
+
commands: commands.map((c) => ({
|
|
8155
|
+
seq: c.seq,
|
|
8156
|
+
command: c.command,
|
|
8157
|
+
cwd: c.cwd,
|
|
8158
|
+
startedAt: c.startedAt,
|
|
8159
|
+
endedAt: c.endedAt,
|
|
8160
|
+
durationMs: c.durationMs,
|
|
8161
|
+
exitCode: c.exitCode
|
|
8162
|
+
})),
|
|
8163
|
+
timeSpan
|
|
8164
|
+
};
|
|
8165
|
+
}
|
|
8166
|
+
async function analyzeMonitor(_db, params) {
|
|
8167
|
+
if (!monitorLogExists(params.session)) {
|
|
8168
|
+
return {
|
|
8169
|
+
sessionId: params.session,
|
|
8170
|
+
ratings: [],
|
|
8171
|
+
unmatchedCommands: [],
|
|
8172
|
+
timeSpan: null
|
|
8173
|
+
};
|
|
8174
|
+
}
|
|
8175
|
+
const events = readMonitorLog(params.session);
|
|
8176
|
+
const commands = pairCommands(events);
|
|
8177
|
+
const result = analyzeObservation(commands, params.patterns);
|
|
8178
|
+
return {
|
|
8179
|
+
sessionId: params.session,
|
|
8180
|
+
...result
|
|
8181
|
+
};
|
|
8182
|
+
}
|
|
8183
|
+
|
|
8184
|
+
// src/cli/commands/mcp.ts
|
|
8185
|
+
var __dirname = dirname5(fileURLToPath2(import.meta.url));
|
|
8186
|
+
var pkgPath = join11(__dirname, "..", "..", "package.json");
|
|
8187
|
+
if (!existsSync12(pkgPath)) {
|
|
8188
|
+
pkgPath = join11(__dirname, "..", "..", "..", "package.json");
|
|
8189
|
+
}
|
|
8190
|
+
var pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
8191
|
+
function createMcpServer(db) {
|
|
8192
|
+
const server = new McpServer({
|
|
8193
|
+
name: "zam",
|
|
8194
|
+
version: pkg.version
|
|
8195
|
+
});
|
|
8196
|
+
async function getUserId(paramUser) {
|
|
8197
|
+
if (paramUser) return paramUser;
|
|
8198
|
+
const stored = await getSetting(db, "user.id");
|
|
8199
|
+
if (stored) return stored;
|
|
8200
|
+
throw new Error(
|
|
8201
|
+
"No user specified. Set a default with: zam whoami --set <id>"
|
|
8202
|
+
);
|
|
8203
|
+
}
|
|
8204
|
+
const commonAnnotations = {
|
|
8205
|
+
openWorldHint: false
|
|
8206
|
+
};
|
|
8207
|
+
const externalAnnotations = {
|
|
8208
|
+
openWorldHint: true
|
|
8209
|
+
};
|
|
8210
|
+
function wrapHandler(fn) {
|
|
8211
|
+
return async (params) => {
|
|
8212
|
+
try {
|
|
8213
|
+
const result = await fn(params);
|
|
8214
|
+
const structuredContent = typeof result === "object" && result !== null && !Array.isArray(result) ? result : { result };
|
|
8215
|
+
return {
|
|
8216
|
+
structuredContent,
|
|
8217
|
+
content: [
|
|
8218
|
+
{
|
|
8219
|
+
type: "text",
|
|
8220
|
+
text: JSON.stringify(result, null, 2)
|
|
8221
|
+
}
|
|
8222
|
+
]
|
|
8223
|
+
};
|
|
8224
|
+
} catch (error) {
|
|
8225
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
8226
|
+
return {
|
|
8227
|
+
isError: true,
|
|
8228
|
+
content: [
|
|
8229
|
+
{
|
|
8230
|
+
type: "text",
|
|
8231
|
+
text: JSON.stringify({ error: errMsg }, null, 2)
|
|
8232
|
+
}
|
|
8233
|
+
]
|
|
8234
|
+
};
|
|
8235
|
+
}
|
|
8236
|
+
};
|
|
8237
|
+
}
|
|
8238
|
+
server.registerTool(
|
|
8239
|
+
"zam_status",
|
|
8240
|
+
{
|
|
8241
|
+
description: "Check due cards and review stats",
|
|
8242
|
+
inputSchema: {
|
|
8243
|
+
user: z.string().optional().describe("User ID to query cards for"),
|
|
8244
|
+
domain: z.string().optional().describe("Filter by domain prefix"),
|
|
8245
|
+
knowledgeContext: z.string().optional().describe("Filter by knowledge context")
|
|
8246
|
+
},
|
|
8247
|
+
annotations: {
|
|
8248
|
+
...commonAnnotations,
|
|
8249
|
+
readOnlyHint: true
|
|
8250
|
+
}
|
|
8251
|
+
},
|
|
8252
|
+
wrapHandler(async (params) => {
|
|
8253
|
+
const userId = await getUserId(params.user);
|
|
8254
|
+
return await checkDue(db, {
|
|
8255
|
+
user: userId,
|
|
8256
|
+
domain: params.domain,
|
|
8257
|
+
knowledgeContext: params.knowledgeContext
|
|
8258
|
+
});
|
|
8259
|
+
})
|
|
8260
|
+
);
|
|
8261
|
+
server.registerTool(
|
|
8262
|
+
"zam_session_start",
|
|
8263
|
+
{
|
|
8264
|
+
description: "Start a learning/work session",
|
|
8265
|
+
inputSchema: {
|
|
8266
|
+
user: z.string().optional().describe("User ID starting the session"),
|
|
8267
|
+
task: z.string().describe("Task description for the session"),
|
|
8268
|
+
context: z.enum(["shell", "ui", "reallife"]).optional().describe("Execution context")
|
|
8269
|
+
},
|
|
8270
|
+
annotations: {
|
|
8271
|
+
...commonAnnotations,
|
|
8272
|
+
destructiveHint: false
|
|
8273
|
+
}
|
|
8274
|
+
},
|
|
8275
|
+
wrapHandler(async (params) => {
|
|
8276
|
+
const userId = await getUserId(params.user);
|
|
8277
|
+
return await startSession2(db, {
|
|
8278
|
+
user: userId,
|
|
8279
|
+
task: params.task,
|
|
8280
|
+
context: params.context
|
|
8281
|
+
});
|
|
8282
|
+
})
|
|
8283
|
+
);
|
|
8284
|
+
server.registerTool(
|
|
8285
|
+
"zam_session_end",
|
|
8286
|
+
{
|
|
8287
|
+
description: "End a learning/work session",
|
|
8288
|
+
inputSchema: {
|
|
8289
|
+
session: z.string().describe("Session ULID to end"),
|
|
8290
|
+
synthesize: z.boolean().optional().describe("Return monitor-based rating candidates before ending"),
|
|
8291
|
+
patterns: z.array(
|
|
8292
|
+
z.object({
|
|
8293
|
+
slug: z.string(),
|
|
8294
|
+
patterns: z.array(z.string())
|
|
8295
|
+
})
|
|
8296
|
+
).optional().describe("Additional token command patterns for synthesis"),
|
|
8297
|
+
minConfidence: z.enum(["medium", "high"]).optional().describe("Minimum confidence for synthesis candidates")
|
|
8298
|
+
},
|
|
8299
|
+
annotations: {
|
|
8300
|
+
...commonAnnotations,
|
|
8301
|
+
destructiveHint: false
|
|
8302
|
+
}
|
|
8303
|
+
},
|
|
8304
|
+
wrapHandler(async (params) => {
|
|
8305
|
+
return await endSession2(db, {
|
|
8306
|
+
session: params.session,
|
|
8307
|
+
synthesize: params.synthesize,
|
|
8308
|
+
patterns: params.patterns,
|
|
8309
|
+
minConfidence: params.minConfidence
|
|
8310
|
+
});
|
|
8311
|
+
})
|
|
8312
|
+
);
|
|
8313
|
+
server.registerTool(
|
|
8314
|
+
"zam_get_reviews",
|
|
8315
|
+
{
|
|
8316
|
+
description: "Fetch a batch of review cards",
|
|
8317
|
+
inputSchema: {
|
|
8318
|
+
user: z.string().optional().describe("User ID to review for"),
|
|
8319
|
+
domain: z.string().optional().describe("Filter by domain prefix"),
|
|
8320
|
+
knowledgeContext: z.string().optional().describe("Filter by knowledge context"),
|
|
8321
|
+
includeQuestions: z.boolean().optional().describe("Include question contents in response"),
|
|
8322
|
+
noResolve: z.boolean().optional().describe("Do not auto-generate missing questions"),
|
|
8323
|
+
noDynamicQuestion: z.literal(true).optional().describe("Keep review retrieval read-only (always true over MCP)")
|
|
8324
|
+
},
|
|
8325
|
+
annotations: {
|
|
8326
|
+
...externalAnnotations,
|
|
8327
|
+
readOnlyHint: true
|
|
8328
|
+
}
|
|
8329
|
+
},
|
|
8330
|
+
wrapHandler(async (params) => {
|
|
8331
|
+
const userId = await getUserId(params.user);
|
|
8332
|
+
return await getReviewsBatch(db, {
|
|
8333
|
+
user: userId,
|
|
8334
|
+
domain: params.domain,
|
|
8335
|
+
knowledgeContext: params.knowledgeContext,
|
|
8336
|
+
includeQuestions: params.includeQuestions,
|
|
8337
|
+
noResolve: params.noResolve,
|
|
8338
|
+
noDynamicQuestion: true
|
|
8339
|
+
});
|
|
8340
|
+
})
|
|
8341
|
+
);
|
|
8342
|
+
server.registerTool(
|
|
8343
|
+
"zam_submit_review",
|
|
8344
|
+
{
|
|
8345
|
+
description: "Submit a user rating or log an unrated agent step",
|
|
8346
|
+
inputSchema: {
|
|
8347
|
+
user: z.string().optional().describe("User ID submitting the review"),
|
|
8348
|
+
cardId: z.string().optional().describe("Card ULID; required for agent steps"),
|
|
8349
|
+
tokenId: z.string().optional().describe("Token ULID for a confirmed synthesis without a card yet"),
|
|
8350
|
+
rating: z.coerce.number().int().min(1).max(4).optional().describe(
|
|
8351
|
+
"User FSRS rating (1=Again, 2=Hard, 3=Good, 4=Easy); omit when doneBy is agent"
|
|
8352
|
+
),
|
|
8353
|
+
sessionId: z.string().optional().describe("Optional active session ULID to log step"),
|
|
8354
|
+
doneBy: z.enum(["user", "agent"]).optional().describe("Who performed the review step")
|
|
8355
|
+
},
|
|
8356
|
+
annotations: {
|
|
8357
|
+
...commonAnnotations,
|
|
8358
|
+
destructiveHint: false,
|
|
8359
|
+
idempotentHint: false
|
|
8360
|
+
}
|
|
8361
|
+
},
|
|
8362
|
+
wrapHandler(async (params) => {
|
|
8363
|
+
const userId = await getUserId(params.user);
|
|
8364
|
+
return await submitReview(db, {
|
|
8365
|
+
user: userId,
|
|
8366
|
+
cardId: params.cardId,
|
|
8367
|
+
tokenId: params.tokenId,
|
|
8368
|
+
rating: params.rating,
|
|
8369
|
+
sessionId: params.sessionId,
|
|
8370
|
+
doneBy: params.doneBy
|
|
8371
|
+
});
|
|
8372
|
+
})
|
|
8373
|
+
);
|
|
8374
|
+
server.registerTool(
|
|
8375
|
+
"zam_review_action",
|
|
8376
|
+
{
|
|
8377
|
+
description: "Perform a review action (e.g. rate, edit, delete)",
|
|
8378
|
+
inputSchema: {
|
|
8379
|
+
user: z.string().optional().describe("User ID performing the action"),
|
|
8380
|
+
cardId: z.string().describe("Card ULID target"),
|
|
8381
|
+
action: z.enum([
|
|
8382
|
+
"rate",
|
|
8383
|
+
"skip",
|
|
8384
|
+
"edit-token",
|
|
8385
|
+
"deprecate-token",
|
|
8386
|
+
"delete-token",
|
|
8387
|
+
"delete-card",
|
|
8388
|
+
"stop"
|
|
8389
|
+
]).describe("The action type"),
|
|
8390
|
+
rating: z.coerce.number().int().min(1).max(4).optional().describe(
|
|
8391
|
+
"Rating (1=Again, 2=Hard, 3=Good, 4=Easy; required for rate)"
|
|
8392
|
+
),
|
|
8393
|
+
concept: z.string().optional().describe("Updated concept text (for edit-token)"),
|
|
8394
|
+
domain: z.string().optional().describe("Updated domain (for edit-token)"),
|
|
8395
|
+
bloomLevel: z.number().int().min(1).max(5).optional().describe("Updated Bloom level (for edit-token)"),
|
|
8396
|
+
context: z.string().optional().describe("Updated context text (for edit-token)"),
|
|
8397
|
+
symbiosisMode: z.string().optional().describe("Updated symbiosis mode (for edit-token)"),
|
|
8398
|
+
sourceLink: z.string().optional().describe("Updated source link (for edit-token)"),
|
|
8399
|
+
confirm: z.boolean().optional().describe("Confirm deletion (required for delete action)")
|
|
8400
|
+
},
|
|
8401
|
+
annotations: {
|
|
8402
|
+
...commonAnnotations,
|
|
8403
|
+
destructiveHint: true
|
|
8404
|
+
}
|
|
8405
|
+
},
|
|
8406
|
+
wrapHandler(async (params) => {
|
|
8407
|
+
const userId = await getUserId(params.user);
|
|
8408
|
+
return await reviewAction(db, {
|
|
8409
|
+
user: userId,
|
|
8410
|
+
cardId: params.cardId,
|
|
8411
|
+
action: params.action,
|
|
8412
|
+
rating: params.rating,
|
|
8413
|
+
concept: params.concept,
|
|
8414
|
+
domain: params.domain,
|
|
8415
|
+
bloomLevel: params.bloomLevel,
|
|
8416
|
+
context: params.context,
|
|
8417
|
+
symbiosisMode: params.symbiosisMode,
|
|
8418
|
+
sourceLink: params.sourceLink,
|
|
8419
|
+
confirm: params.confirm
|
|
8420
|
+
});
|
|
8421
|
+
})
|
|
8422
|
+
);
|
|
8423
|
+
server.registerTool(
|
|
8424
|
+
"zam_add_token",
|
|
8425
|
+
{
|
|
8426
|
+
description: "Add a new knowledge token",
|
|
8427
|
+
inputSchema: {
|
|
8428
|
+
user: z.string().optional().describe("User ID to auto-create card for"),
|
|
8429
|
+
slug: z.string().describe("Unique slug for the token"),
|
|
8430
|
+
concept: z.string().describe("Detailed description of the concept"),
|
|
8431
|
+
title: z.string().optional().describe("Optional display title"),
|
|
8432
|
+
domain: z.string().optional().describe("Domain path"),
|
|
8433
|
+
bloomLevel: z.number().int().min(1).max(5).optional().describe("Bloom taxonomy level (1-5)"),
|
|
8434
|
+
context: z.string().optional().describe("Markdown content block/context"),
|
|
8435
|
+
symbiosisMode: z.enum(["shadowing", "copilot", "autonomy"]).nullable().optional().describe("Symbiosis mode override"),
|
|
8436
|
+
sourceLink: z.string().nullable().optional().describe("Optional URL/file path source"),
|
|
8437
|
+
question: z.string().nullable().optional().describe("Pre-defined review question"),
|
|
8438
|
+
knowledgeContexts: z.array(z.string()).optional().describe("List of contexts to assign the token to"),
|
|
8439
|
+
prerequisites: z.array(z.string()).optional().describe("Existing token slugs required by the new token")
|
|
8440
|
+
},
|
|
8441
|
+
annotations: {
|
|
8442
|
+
...externalAnnotations,
|
|
8443
|
+
destructiveHint: false
|
|
8444
|
+
}
|
|
8445
|
+
},
|
|
8446
|
+
wrapHandler(async (params) => {
|
|
8447
|
+
const userId = await getUserId(params.user);
|
|
8448
|
+
return await addToken(db, {
|
|
8449
|
+
user: userId,
|
|
8450
|
+
slug: params.slug,
|
|
8451
|
+
concept: params.concept,
|
|
8452
|
+
title: params.title,
|
|
8453
|
+
domain: params.domain,
|
|
8454
|
+
bloomLevel: params.bloomLevel,
|
|
8455
|
+
context: params.context,
|
|
8456
|
+
symbiosisMode: params.symbiosisMode,
|
|
8457
|
+
sourceLink: params.sourceLink,
|
|
8458
|
+
question: params.question,
|
|
8459
|
+
knowledgeContexts: params.knowledgeContexts,
|
|
8460
|
+
prerequisites: params.prerequisites
|
|
8461
|
+
});
|
|
8462
|
+
})
|
|
8463
|
+
);
|
|
8464
|
+
server.registerTool(
|
|
8465
|
+
"zam_find_tokens",
|
|
8466
|
+
{
|
|
8467
|
+
description: "Search/find matching tokens using semantic search",
|
|
8468
|
+
inputSchema: {
|
|
8469
|
+
user: z.string().optional().describe("User ID"),
|
|
8470
|
+
context: z.string().describe("Query context to embed and match"),
|
|
8471
|
+
limit: z.number().int().positive().optional().describe("Max number of matches to return")
|
|
8472
|
+
},
|
|
8473
|
+
annotations: {
|
|
8474
|
+
...externalAnnotations,
|
|
8475
|
+
readOnlyHint: true
|
|
8476
|
+
}
|
|
8477
|
+
},
|
|
8478
|
+
wrapHandler(async (params) => {
|
|
8479
|
+
const userId = await getUserId(params.user);
|
|
8480
|
+
return await findTokens2(db, {
|
|
8481
|
+
user: userId,
|
|
8482
|
+
context: params.context,
|
|
8483
|
+
limit: params.limit
|
|
8484
|
+
});
|
|
8485
|
+
})
|
|
8486
|
+
);
|
|
8487
|
+
server.registerTool(
|
|
8488
|
+
"zam_suggest_foundations",
|
|
8489
|
+
{
|
|
8490
|
+
description: "Suggest foundational concept prerequisites",
|
|
8491
|
+
inputSchema: {
|
|
8492
|
+
user: z.string().optional().describe("User ID"),
|
|
8493
|
+
slug: z.string().optional().describe("Target token slug to find prereqs for"),
|
|
8494
|
+
concept: z.string().optional().describe("Or concept text description for pre-registration"),
|
|
8495
|
+
question: z.string().optional().describe("Optional question content for pre-registration"),
|
|
8496
|
+
domain: z.string().optional().describe("Domain filter"),
|
|
8497
|
+
title: z.string().optional().describe("Optional title"),
|
|
8498
|
+
bloom_level: z.number().int().min(1).max(5).optional().describe("Bloom level of target"),
|
|
8499
|
+
limit: z.number().int().positive().optional().describe("Max number of suggestions")
|
|
8500
|
+
},
|
|
8501
|
+
annotations: {
|
|
8502
|
+
...externalAnnotations,
|
|
8503
|
+
readOnlyHint: true
|
|
8504
|
+
}
|
|
8505
|
+
},
|
|
8506
|
+
wrapHandler(async (params) => {
|
|
8507
|
+
return await suggestFoundations2(db, {
|
|
8508
|
+
user: params.user,
|
|
8509
|
+
slug: params.slug,
|
|
8510
|
+
concept: params.concept,
|
|
8511
|
+
question: params.question,
|
|
8512
|
+
domain: params.domain,
|
|
8513
|
+
title: params.title,
|
|
8514
|
+
bloom_level: params.bloom_level,
|
|
8515
|
+
limit: params.limit
|
|
8516
|
+
});
|
|
8517
|
+
})
|
|
8518
|
+
);
|
|
8519
|
+
server.registerTool(
|
|
8520
|
+
"zam_link_prereq",
|
|
8521
|
+
{
|
|
8522
|
+
description: "Link a prerequisite dependency between two tokens",
|
|
8523
|
+
inputSchema: {
|
|
8524
|
+
token: z.string().describe("Slug of dependent token"),
|
|
8525
|
+
requires: z.string().describe("Slug of required prerequisite token"),
|
|
8526
|
+
blockUser: z.string().optional().describe("Block card for this user until prereq is learned")
|
|
8527
|
+
},
|
|
8528
|
+
annotations: {
|
|
8529
|
+
...commonAnnotations,
|
|
8530
|
+
destructiveHint: false
|
|
8531
|
+
}
|
|
8532
|
+
},
|
|
8533
|
+
wrapHandler(async (params) => {
|
|
8534
|
+
return await linkPrereq(db, {
|
|
8535
|
+
token: params.token,
|
|
8536
|
+
requires: params.requires,
|
|
8537
|
+
blockUser: params.blockUser
|
|
8538
|
+
});
|
|
8539
|
+
})
|
|
8540
|
+
);
|
|
8541
|
+
server.registerTool(
|
|
8542
|
+
"zam_monitor",
|
|
8543
|
+
{
|
|
8544
|
+
description: "Get or analyze session monitor commands",
|
|
8545
|
+
inputSchema: {
|
|
8546
|
+
session: z.string().describe("Session ULID to monitor"),
|
|
8547
|
+
patterns: z.array(
|
|
8548
|
+
z.object({
|
|
8549
|
+
slug: z.string(),
|
|
8550
|
+
patterns: z.array(z.string())
|
|
8551
|
+
})
|
|
8552
|
+
).optional().describe("Patterns to match against monitor events for evaluation")
|
|
8553
|
+
},
|
|
8554
|
+
annotations: {
|
|
8555
|
+
...commonAnnotations,
|
|
8556
|
+
readOnlyHint: true
|
|
8557
|
+
}
|
|
8558
|
+
},
|
|
8559
|
+
wrapHandler(async (params) => {
|
|
8560
|
+
if (params.patterns) {
|
|
8561
|
+
return await analyzeMonitor(db, {
|
|
8562
|
+
session: params.session,
|
|
8563
|
+
patterns: params.patterns
|
|
8564
|
+
});
|
|
8565
|
+
}
|
|
8566
|
+
return await getMonitor(db, {
|
|
8567
|
+
session: params.session
|
|
8568
|
+
});
|
|
8569
|
+
})
|
|
8570
|
+
);
|
|
8571
|
+
return server;
|
|
8572
|
+
}
|
|
8573
|
+
async function runMcpServer() {
|
|
8574
|
+
console.log = console.error;
|
|
8575
|
+
const db = await openDatabase();
|
|
8576
|
+
const server = createMcpServer(db);
|
|
8577
|
+
let dbClosed = false;
|
|
8578
|
+
async function cleanup() {
|
|
8579
|
+
if (dbClosed) return;
|
|
8580
|
+
dbClosed = true;
|
|
8581
|
+
try {
|
|
8582
|
+
await server.close();
|
|
8583
|
+
} catch {
|
|
8584
|
+
}
|
|
8585
|
+
try {
|
|
8586
|
+
await db.close();
|
|
8587
|
+
} catch {
|
|
8588
|
+
}
|
|
8589
|
+
process.exit(0);
|
|
8590
|
+
}
|
|
8591
|
+
process.on("SIGINT", cleanup);
|
|
8592
|
+
process.on("SIGTERM", cleanup);
|
|
8593
|
+
const transport = new StdioServerTransport();
|
|
8594
|
+
transport.onclose = () => {
|
|
8595
|
+
cleanup();
|
|
8596
|
+
};
|
|
8597
|
+
await server.connect(transport);
|
|
8598
|
+
}
|
|
6182
8599
|
export {
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
loadCredentials,
|
|
6186
|
-
saveCredentials,
|
|
6187
|
-
getTursoCredentials,
|
|
6188
|
-
setTursoCredentials,
|
|
6189
|
-
clearTursoCredentials,
|
|
6190
|
-
getADOCredentials,
|
|
6191
|
-
setADOCredentials,
|
|
6192
|
-
clearADOCredentials,
|
|
6193
|
-
getProviderApiKey,
|
|
6194
|
-
setProviderApiKey,
|
|
6195
|
-
clearProviderApiKey,
|
|
6196
|
-
listProviderApiKeyRefs,
|
|
6197
|
-
loadADOConfig,
|
|
6198
|
-
fetchActiveWorkItems,
|
|
6199
|
-
openRemoteDatabase,
|
|
6200
|
-
getDatabaseTargetInfo,
|
|
6201
|
-
openDatabase,
|
|
6202
|
-
openDatabaseWithSync,
|
|
6203
|
-
getDefaultDbPath,
|
|
6204
|
-
SNAPSHOT_VERSION,
|
|
6205
|
-
exportSnapshot,
|
|
6206
|
-
parseSnapshot,
|
|
6207
|
-
verifySnapshot,
|
|
6208
|
-
importSnapshot,
|
|
6209
|
-
parseGoalFile,
|
|
6210
|
-
serializeGoal,
|
|
6211
|
-
extractTasks,
|
|
6212
|
-
extractTokenRefs,
|
|
6213
|
-
listGoals,
|
|
6214
|
-
getGoal,
|
|
6215
|
-
createGoal,
|
|
6216
|
-
updateGoalStatus,
|
|
6217
|
-
getGoalTree,
|
|
6218
|
-
createAgentSkill,
|
|
6219
|
-
getAgentSkill,
|
|
6220
|
-
listAgentSkills,
|
|
6221
|
-
ensureCard,
|
|
6222
|
-
getCard,
|
|
6223
|
-
getCardById,
|
|
6224
|
-
updateCard,
|
|
6225
|
-
getCardDeletionImpact,
|
|
6226
|
-
deleteCardForUser,
|
|
6227
|
-
getDueCards,
|
|
6228
|
-
getBlockedCards,
|
|
6229
|
-
createKnowledgeContext,
|
|
6230
|
-
getKnowledgeContextByName,
|
|
6231
|
-
getKnowledgeContextById,
|
|
6232
|
-
listKnowledgeContexts,
|
|
6233
|
-
updateKnowledgeContext,
|
|
6234
|
-
deleteKnowledgeContext,
|
|
6235
|
-
assignTokenToContext,
|
|
6236
|
-
unassignTokenFromContext,
|
|
6237
|
-
listContextsForToken,
|
|
6238
|
-
createToken,
|
|
6239
|
-
getTokenBySlug,
|
|
6240
|
-
getTokenById,
|
|
6241
|
-
updateToken,
|
|
6242
|
-
deprecateToken,
|
|
6243
|
-
getTokenDeleteImpact,
|
|
6244
|
-
deleteToken,
|
|
6245
|
-
findTokens,
|
|
6246
|
-
listTokens,
|
|
6247
|
-
slugify,
|
|
6248
|
-
getShortSlug,
|
|
6249
|
-
getDisplayTitle,
|
|
6250
|
-
generateTokenSlug,
|
|
6251
|
-
listPersonalCards,
|
|
6252
|
-
importCurriculumCards,
|
|
6253
|
-
confirmCardSplit,
|
|
6254
|
-
confirmFoundations,
|
|
6255
|
-
confirmSourceImport,
|
|
6256
|
-
buildAncestorMap,
|
|
6257
|
-
wouldCreateCycle,
|
|
6258
|
-
addPrerequisite,
|
|
6259
|
-
getPrerequisites,
|
|
6260
|
-
getDependents,
|
|
6261
|
-
getTokenNeighborhood,
|
|
6262
|
-
logReview,
|
|
6263
|
-
getReviewsForCard,
|
|
6264
|
-
getReviewsForUser,
|
|
6265
|
-
startSession,
|
|
6266
|
-
endSession,
|
|
6267
|
-
logStep,
|
|
6268
|
-
getSessionSummary,
|
|
6269
|
-
getSetting,
|
|
6270
|
-
getAllSettings,
|
|
6271
|
-
getAllSettingsDetailed,
|
|
6272
|
-
setSetting,
|
|
6273
|
-
deleteSetting,
|
|
6274
|
-
embeddingContentForToken,
|
|
6275
|
-
computeContentHash,
|
|
6276
|
-
encodeEmbedding,
|
|
6277
|
-
decodeEmbedding,
|
|
6278
|
-
upsertTokenEmbedding,
|
|
6279
|
-
getTokenEmbedding,
|
|
6280
|
-
listTokensNeedingEmbedding,
|
|
6281
|
-
getEmbeddingCoverage,
|
|
6282
|
-
listEmbeddedTokens,
|
|
6283
|
-
parseMonitorLog,
|
|
6284
|
-
pairCommands,
|
|
6285
|
-
analyzeObservation,
|
|
6286
|
-
getMonitorDir,
|
|
6287
|
-
getMonitorPath,
|
|
6288
|
-
ensureMonitorDir,
|
|
6289
|
-
writeMonitorEvent,
|
|
6290
|
-
readMonitorLog,
|
|
6291
|
-
monitorLogExists,
|
|
6292
|
-
getMonitorLogStats,
|
|
6293
|
-
OBSERVER_POLICY_VERSION,
|
|
6294
|
-
DEFAULT_OBSERVER_POLICY,
|
|
6295
|
-
BUILT_IN_SENSITIVE_MATCHERS,
|
|
6296
|
-
parseObserverList,
|
|
6297
|
-
parseObserverPolicy,
|
|
6298
|
-
resolveObserverPolicy,
|
|
6299
|
-
matchBuiltInSensitive,
|
|
6300
|
-
matchDenylist,
|
|
6301
|
-
decidePreCapture,
|
|
6302
|
-
decidePostCapture,
|
|
6303
|
-
isObserverPolicyConfigured,
|
|
6304
|
-
OBSERVER_POLICY_UNSET_HINT,
|
|
6305
|
-
UI_OBSERVATION_PROTOCOL_VERSION,
|
|
6306
|
-
isUiObservationReport,
|
|
6307
|
-
parseUiObservationLog,
|
|
6308
|
-
getUiObserverDir,
|
|
6309
|
-
getUiObservationPath,
|
|
6310
|
-
ensureUiObserverDir,
|
|
6311
|
-
uiObservationLogExists,
|
|
6312
|
-
readUiObservationLog,
|
|
6313
|
-
appendUiObservationReport,
|
|
6314
|
-
SIDECAR_POLICY_FILE,
|
|
6315
|
-
toSidecarPrivacyPolicy,
|
|
6316
|
-
syncObserverSidecarPolicy,
|
|
6317
|
-
createFSRS,
|
|
6318
|
-
evaluateRating,
|
|
6319
|
-
cascadeBlock,
|
|
6320
|
-
unblockReady,
|
|
6321
|
-
buildUiSynthesisCandidates,
|
|
6322
|
-
uiObservationTimeSpan,
|
|
6323
|
-
getSessionSynthesisRecords,
|
|
6324
|
-
prepareSessionSynthesis,
|
|
6325
|
-
applySessionSynthesis,
|
|
6326
|
-
generateZshHooks,
|
|
6327
|
-
generateBashHooks,
|
|
6328
|
-
generatePowerShellHooks,
|
|
6329
|
-
generateZshUnhooks,
|
|
6330
|
-
generateBashUnhooks,
|
|
6331
|
-
generatePowerShellUnhooks,
|
|
6332
|
-
discoverSkills,
|
|
6333
|
-
executeReviewAction,
|
|
6334
|
-
generateConceptFreeCue,
|
|
6335
|
-
generatePrompt,
|
|
6336
|
-
DEFAULT_REVIEW_CONTEXT_MAX_CHARS,
|
|
6337
|
-
REVIEW_CONTEXT_CACHE_TTL_MS,
|
|
6338
|
-
clearReviewContextCache,
|
|
6339
|
-
resolveReference,
|
|
6340
|
-
resolveReviewContext,
|
|
6341
|
-
normalizePath,
|
|
6342
|
-
matchesFilePath,
|
|
6343
|
-
interleave,
|
|
6344
|
-
buildReviewQueue,
|
|
6345
|
-
cosineSimilarity,
|
|
6346
|
-
searchTokensHybrid,
|
|
6347
|
-
suggestFoundations,
|
|
6348
|
-
getPackageSkillPath,
|
|
6349
|
-
distributeGlobalSkills,
|
|
6350
|
-
injectShellHooks,
|
|
6351
|
-
t,
|
|
6352
|
-
loadInstallConfig,
|
|
6353
|
-
saveInstallConfig,
|
|
6354
|
-
getInstallMode,
|
|
6355
|
-
setInstallMode,
|
|
6356
|
-
getInstallChannel,
|
|
6357
|
-
setInstallChannel,
|
|
6358
|
-
getMachineAiConfig,
|
|
6359
|
-
saveMachineAiConfig,
|
|
6360
|
-
getConfiguredWorkspaces,
|
|
6361
|
-
saveConfiguredWorkspaces,
|
|
6362
|
-
getActiveWorkspaceId,
|
|
6363
|
-
setActiveWorkspaceId,
|
|
6364
|
-
getActiveWorkspace,
|
|
6365
|
-
upsertConfiguredWorkspace,
|
|
6366
|
-
removeConfiguredWorkspace,
|
|
6367
|
-
detectSyncProvider,
|
|
6368
|
-
getActiveWorkspaceContext,
|
|
6369
|
-
setActiveWorkspaceContext,
|
|
6370
|
-
hasCommand,
|
|
6371
|
-
installFastFlowLM,
|
|
6372
|
-
installOllama,
|
|
6373
|
-
resolveOllamaCommand,
|
|
6374
|
-
isOllamaInstalled,
|
|
6375
|
-
prepareLocalModel,
|
|
6376
|
-
planOpenCodeInstall,
|
|
6377
|
-
installOpenCode,
|
|
6378
|
-
normalizeLocale,
|
|
6379
|
-
detectSystemLocale,
|
|
6380
|
-
getSystemProfile,
|
|
6381
|
-
getRepoPaths,
|
|
6382
|
-
resolveRepoPath,
|
|
6383
|
-
resolveAllBeliefPaths,
|
|
6384
|
-
resolveAllGoalPaths,
|
|
6385
|
-
WINGET_PACKAGE_ID,
|
|
6386
|
-
HOMEBREW_CASK,
|
|
6387
|
-
compareVersions,
|
|
6388
|
-
decideUpdate,
|
|
6389
|
-
planUpdate
|
|
8600
|
+
createMcpServer,
|
|
8601
|
+
runMcpServer
|
|
6390
8602
|
};
|
|
6391
|
-
//# sourceMappingURL=
|
|
8603
|
+
//# sourceMappingURL=mcp.js.map
|