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.
@@ -1,4 +1,17 @@
1
- #!/usr/bin/env node
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
- // src/kernel/db/connection.ts
272
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync } from "fs";
273
- import { createRequire } from "module";
274
- import { homedir as homedir2 } from "os";
275
- import { dirname as dirname2, join as join2 } from "path";
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
- var DEFAULT_DB_DIR = join2(homedir2(), ".zam");
757
- var DEFAULT_DB_PATH = join2(DEFAULT_DB_DIR, "zam.db");
758
- var require2 = createRequire(import.meta.url);
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
- // src/kernel/goals/engine.ts
1210
- import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
1211
- import { basename, join as join3 } from "path";
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
- // src/kernel/observation/observer-sidecar-policy.ts
3121
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "fs";
3122
- import { join as join6 } from "path";
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 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>`.";
3367
-
3368
- // src/kernel/observation/ui-observer-io.ts
3369
- import { appendFileSync as appendFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5 } from "fs";
3370
- import { homedir as homedir4 } from "os";
3371
- import { join as join5 } from "path";
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
- var DEFAULT_UI_OBSERVER_DIR = join5(homedir4(), ".zam", "observer");
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
- var SIDECAR_POLICY_FILE = "policy.json";
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
- // src/kernel/observation/session-synthesis.ts
3530
- import { ulid as ulid8 } from "ulid";
3531
-
3532
- // src/kernel/recall/evaluator.ts
3533
- import { ulid as ulid7 } from "ulid";
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
- getUserStats,
6184
- getDomainCompetence,
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=chunk-BOWP6D5I.js.map
8603
+ //# sourceMappingURL=mcp.js.map