zam-core 0.7.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -537,9 +537,10 @@ declare function deleteCardForUser(db: Database, tokenId: string, userId: string
537
537
  *
538
538
  * Ported from the PoC's due-tokens command.
539
539
  *
540
- * When `domain` is set, only due cards in that token domain are returned.
540
+ * When `domain` or `knowledgeContext` is set, only matching due cards are
541
+ * returned.
541
542
  */
542
- declare function getDueCards(db: Database, userId: string, now?: string, domain?: string): Promise<DueCard[]>;
543
+ declare function getDueCards(db: Database, userId: string, now?: string, domain?: string, knowledgeContext?: string): Promise<DueCard[]>;
543
544
  /**
544
545
  * Get all blocked cards for a user.
545
546
  *
@@ -548,6 +549,68 @@ declare function getDueCards(db: Database, userId: string, now?: string, domain?
548
549
  */
549
550
  declare function getBlockedCards(db: Database, userId: string): Promise<BlockedCard[]>;
550
551
 
552
+ /**
553
+ * Knowledge Context repository — typed wrappers around the contexts and token_contexts tables.
554
+ *
555
+ * A context represents a first-class facet (e.g. work, school, private) that can have
556
+ * attributes like default generation language.
557
+ */
558
+
559
+ interface KnowledgeContext {
560
+ id: string;
561
+ name: string;
562
+ label: string | null;
563
+ language: string | null;
564
+ created_at: string;
565
+ }
566
+ interface CreateKnowledgeContextInput {
567
+ name: string;
568
+ label?: string | null;
569
+ language?: string | null;
570
+ }
571
+ interface UpdateKnowledgeContextInput {
572
+ name?: string;
573
+ label?: string | null;
574
+ language?: string | null;
575
+ }
576
+ /**
577
+ * Create a new knowledge context.
578
+ */
579
+ declare function createKnowledgeContext(db: Database, input: CreateKnowledgeContextInput): Promise<KnowledgeContext>;
580
+ /**
581
+ * Retrieve a knowledge context by its unique name.
582
+ */
583
+ declare function getKnowledgeContextByName(db: Database, name: string): Promise<KnowledgeContext | undefined>;
584
+ /**
585
+ * Retrieve a knowledge context by its ULID.
586
+ */
587
+ declare function getKnowledgeContextById(db: Database, id: string): Promise<KnowledgeContext | undefined>;
588
+ /**
589
+ * List all knowledge contexts ordered by creation date (oldest first) or name.
590
+ */
591
+ declare function listKnowledgeContexts(db: Database): Promise<KnowledgeContext[]>;
592
+ /**
593
+ * Update mutable fields on a knowledge context.
594
+ */
595
+ declare function updateKnowledgeContext(db: Database, id: string, updates: UpdateKnowledgeContextInput): Promise<KnowledgeContext>;
596
+ /**
597
+ * Delete a knowledge context. Cascades deletion of associated token mappings.
598
+ */
599
+ declare function deleteKnowledgeContext(db: Database, id: string): Promise<void>;
600
+ /**
601
+ * Assign a token to a knowledge context.
602
+ * Safe to call repeatedly (noop if already assigned).
603
+ */
604
+ declare function assignTokenToContext(db: Database, tokenId: string, contextId: string): Promise<void>;
605
+ /**
606
+ * Remove a token from a knowledge context.
607
+ */
608
+ declare function unassignTokenFromContext(db: Database, tokenId: string, contextId: string): Promise<void>;
609
+ /**
610
+ * List all knowledge contexts assigned to a given token.
611
+ */
612
+ declare function listContextsForToken(db: Database, tokenId: string): Promise<KnowledgeContext[]>;
613
+
551
614
  /**
552
615
  * Prerequisite repository — typed wrappers around the prerequisites table.
553
616
  *
@@ -846,10 +909,14 @@ interface UpdateTokenInput {
846
909
  interface ListTokensOptions {
847
910
  domain?: string;
848
911
  /**
849
- * Filter by domain prefix using `/` as separator (e.g. "docuware-cops").
912
+ * Filter by domain prefix using `/` as separator (e.g. "company-team").
850
913
  * Matches exact or startsWith(prefix + "/").
851
914
  */
852
915
  domainPrefix?: string;
916
+ /**
917
+ * Filter by knowledge context name (e.g. "work-company").
918
+ */
919
+ knowledgeContext?: string;
853
920
  }
854
921
  interface TokenDeleteImpact {
855
922
  cards: number;
@@ -918,8 +985,8 @@ declare function deleteToken(db: Database, slug: string): Promise<DeleteTokenRes
918
985
  */
919
986
  declare function findTokens(db: Database, query: string): Promise<ScoredToken[]>;
920
987
  /**
921
- * List all tokens, optionally filtered by domain.
922
- * Results are ordered by bloom_level then slug.
988
+ * List all tokens, optionally filtered by domain or knowledge context.
989
+ * Results are ordered by bloom_level then domain then slug (or bloom_level then slug if domain-filtered).
923
990
  */
924
991
  declare function listTokens(db: Database, options?: ListTokensOptions): Promise<Token[]>;
925
992
  interface PersonalCard {
@@ -965,6 +1032,7 @@ declare function generateTokenSlug(db: Database, domain: string, concept: string
965
1032
  declare function listPersonalCards(db: Database, userId: string, options?: {
966
1033
  query?: string;
967
1034
  domain?: string;
1035
+ knowledgeContext?: string;
968
1036
  }): Promise<PersonalCard[]>;
969
1037
  interface CurriculumCardInput {
970
1038
  question: string;
@@ -1878,6 +1946,7 @@ interface ReviewQueueOptions {
1878
1946
  maxNew?: number;
1879
1947
  maxReviews?: number;
1880
1948
  now?: Date;
1949
+ knowledgeContext?: string;
1881
1950
  }
1882
1951
  interface ReviewQueueItem {
1883
1952
  cardId: string;
@@ -2131,6 +2200,7 @@ interface WorkspaceConfig {
2131
2200
  sourceControl?: WorkspaceSourceControl;
2132
2201
  knowledgeScopes?: string[];
2133
2202
  defaultAgent?: string;
2203
+ activeKnowledgeContext?: string;
2134
2204
  }
2135
2205
  /** Load ~/.zam/config.json. Returns an empty config if missing or unreadable. */
2136
2206
  declare function loadInstallConfig(path?: string): InstallConfig;
@@ -2165,6 +2235,8 @@ declare function removeConfiguredWorkspace(id: string, path?: string): Workspace
2165
2235
  * good for moving snapshots between machines"), never for behavior.
2166
2236
  */
2167
2237
  declare function detectSyncProvider(dir: string): string | null;
2238
+ declare function getActiveWorkspaceContext(path?: string): string | undefined;
2239
+ declare function setActiveWorkspaceContext(contextName: string | undefined, path?: string): boolean;
2168
2240
 
2169
2241
  interface InstallResult {
2170
2242
  success: boolean;
@@ -2262,4 +2334,4 @@ declare function resolveAllBeliefPaths(db: Database): Promise<string[]>;
2262
2334
  */
2263
2335
  declare function resolveAllGoalPaths(db: Database): Promise<string[]>;
2264
2336
 
2265
- export { type ADOConfig, type ADOCredentials, type AgentSkill, type AnalysisResult, type ApplySessionSynthesisInput, type ApplySessionSynthesisResult, BUILT_IN_SENSITIVE_MATCHERS, type BloomLevel$1 as BloomLevel, type CaptureDecision, type CaptureDenialReason, type CaptureRequest, type Card, type CardDeletionImpact, type CardState$1 as CardState, type CascadeBlockResult, type CommandRecord, type CommandSequence, type ConfirmFoundationsResult, type ConnectionOptions, type CreateAgentSkillInput, type CreateGoalInput, type CreateReviewInput, type CreateSessionInput, type CreateTokenInput, type Credentials, type CurriculumCardInput, DEFAULT_OBSERVER_POLICY, DEFAULT_REVIEW_CONTEXT_MAX_CHARS, type Database, type DatabaseProvider, type DatabaseTargetInfo, type DatabaseValue, type DeleteCardResult, type DeleteTokenResult, type DiscoveryOptions, type DomainCompetence, type EmbeddedTokenRow, type EmbeddingCoverage, type EmbeddingStaleness, type EvaluateInput, type EvaluateResult, type ExecuteReviewActionInput, type ExecutionContext, type FSRSParameters, type FoundationProposalInput, type FoundationSuggestion, type Goal, type GoalFrontmatter, type GoalStatus, type GoalSummary, HOMEBREW_CASK, type HybridScoredToken, type HybridSearchOptions, type ImportCurriculumResult, type ImportResult, type InstallChannel, type InstallConfig, type InstallMode, type InstallPlan, type InstallResult, type ListTokensOptions, type LocalLLMRunner, type LogStepInput, type MachineAiConfig, type MachineProviderRecord, type MachineRoleBinding, type MonitorEvent, type Neighborhood, type NeighborhoodToken, OBSERVER_POLICY_UNSET_HINT, OBSERVER_POLICY_VERSION, type ObservationRating, type ObserverConsent, type ObserverPolicy, type ObserverRetention, type ObserverScope, type ObserverSettingKey, type OllamaDetectionOptions, type PersonalCard, type PrepareSessionSynthesisInput, type Prerequisite, type PrerequisiteWithToken, type PromptInput, REVIEW_CONTEXT_CACHE_TTL_MS, type Rating, type RecallPrompt, type RemoteDatabaseOptions, type RepoPaths, type ResolvedCaptureTarget, type ResolvedReference, type ReviewActionResult, type ReviewActionType, type ReviewContext, type ReviewLog, type ReviewQueue, type ReviewQueueItem, type ReviewQueueOptions, type RunResult, SIDECAR_POLICY_FILE, SNAPSHOT_VERSION, type SchedulingCard, type Session, type SessionStep, type SessionSummary, type SessionSynthesisCandidate, type SessionSynthesisEvidence, type SessionSynthesisPreview, type SessionSynthesisRecord, type SidecarPrivacyPolicy, type SkillProposal, type SkillSource, type SnapshotManifest, type SourceProposalInput, type SplitProposalInput, type Statement, type SuggestFoundationsOptions, type SupportedLocale, type SymbiosisMode, type SynthesisConfidence, type SystemProfile, type Token, type TokenDeleteImpact, type TokenEmbedding, type TokenNeedingEmbedding, type TokenPattern, type TranslationKey, type TursoCredentials, UI_OBSERVATION_PROTOCOL_VERSION, type UiActionType, type UiApplicationContext, type UiCandidateToken, type UiEvidenceRef, type UiEvidenceType, type UiObservationKind, type UiObservationReport, type UiObservedAction, type UnblockResult, type UpdateActionKind, type UpdateCardInput, type UpdateDecision, type UpdateStep, type UpdateStepKind, type UpdateTokenInput, type UserSetting, type UserStats, WINGET_PACKAGE_ID, type WorkItem, type WorkspaceConfig, type WorkspaceKind, type WorkspaceSourceControl, addPrerequisite, analyzeObservation, appendUiObservationReport, applySessionSynthesis, buildAncestorMap, buildReviewQueue, buildUiSynthesisCandidates, cascadeBlock, clearADOCredentials, clearProviderApiKey, clearReviewContextCache, clearTursoCredentials, compareVersions, computeContentHash, confirmCardSplit, confirmFoundations, confirmSourceImport, cosineSimilarity, createAgentSkill, createFSRS, createGoal, createToken, decidePostCapture, decidePreCapture, decideUpdate, decodeEmbedding, deleteCardForUser, deleteSetting, deleteToken, deprecateToken, detectSyncProvider, detectSystemLocale, discoverSkills, distributeGlobalSkills, embeddingContentForToken, encodeEmbedding, endSession, ensureCard, ensureMonitorDir, ensureUiObserverDir, evaluateRating, executeReviewAction, exportSnapshot, extractTasks, extractTokenRefs, fetchActiveWorkItems, findTokens, generateBashHooks, generateBashUnhooks, generateConceptFreeCue, generatePowerShellHooks, generatePowerShellUnhooks, generatePrompt, generateTokenSlug, generateZshHooks, generateZshUnhooks, getADOCredentials, getActiveWorkspace, getActiveWorkspaceId, getAgentSkill, getAllSettings, getAllSettingsDetailed, getBlockedCards, getCard, getCardById, getCardDeletionImpact, getConfiguredWorkspaces, getDatabaseTargetInfo, getDefaultDbPath, getDependents, getDisplayTitle, getDomainCompetence, getDueCards, getEmbeddingCoverage, getGoal, getGoalTree, getInstallChannel, getInstallMode, getMachineAiConfig, getMonitorDir, getMonitorLogStats, getMonitorPath, getPackageSkillPath, getPrerequisites, getProviderApiKey, getRepoPaths, getReviewsForCard, getReviewsForUser, getSessionSummary, getSessionSynthesisRecords, getSetting, getShortSlug, getSystemProfile, getTokenById, getTokenBySlug, getTokenDeleteImpact, getTokenEmbedding, getTokenNeighborhood, getTursoCredentials, getUiObservationPath, getUiObserverDir, getUserStats, hasCommand, importCurriculumCards, importSnapshot, injectShellHooks, installFastFlowLM, installOllama, installOpenCode, interleave, isObserverPolicyConfigured, isOllamaInstalled, isUiObservationReport, listAgentSkills, listEmbeddedTokens, listGoals, listPersonalCards, listProviderApiKeyRefs, listTokens, listTokensNeedingEmbedding, loadADOConfig, loadCredentials, loadInstallConfig, logReview, logStep, matchBuiltInSensitive, matchDenylist, matchesFilePath, monitorLogExists, normalizeLocale, normalizePath, openDatabase, openDatabaseWithSync, openRemoteDatabase, pairCommands, parseGoalFile, parseMonitorLog, parseObserverList, parseObserverPolicy, parseSnapshot, parseUiObservationLog, planOpenCodeInstall, planUpdate, prepareLocalModel, prepareSessionSynthesis, readMonitorLog, readUiObservationLog, removeConfiguredWorkspace, resolveAllBeliefPaths, resolveAllGoalPaths, resolveObserverPolicy, resolveOllamaCommand, resolveReference, resolveRepoPath, resolveReviewContext, saveConfiguredWorkspaces, saveCredentials, saveInstallConfig, saveMachineAiConfig, searchTokensHybrid, serializeGoal, setADOCredentials, setActiveWorkspaceId, setInstallChannel, setInstallMode, setProviderApiKey, setSetting, setTursoCredentials, slugify, startSession, suggestFoundations, syncObserverSidecarPolicy, t, toSidecarPrivacyPolicy, uiObservationLogExists, uiObservationTimeSpan, unblockReady, updateCard, updateGoalStatus, updateToken, upsertConfiguredWorkspace, upsertTokenEmbedding, verifySnapshot, wouldCreateCycle, writeMonitorEvent };
2337
+ export { type ADOConfig, type ADOCredentials, type AgentSkill, type AnalysisResult, type ApplySessionSynthesisInput, type ApplySessionSynthesisResult, BUILT_IN_SENSITIVE_MATCHERS, type BloomLevel$1 as BloomLevel, type CaptureDecision, type CaptureDenialReason, type CaptureRequest, type Card, type CardDeletionImpact, type CardState$1 as CardState, type CascadeBlockResult, type CommandRecord, type CommandSequence, type ConfirmFoundationsResult, type ConnectionOptions, type CreateAgentSkillInput, type CreateGoalInput, type CreateKnowledgeContextInput, type CreateReviewInput, type CreateSessionInput, type CreateTokenInput, type Credentials, type CurriculumCardInput, DEFAULT_OBSERVER_POLICY, DEFAULT_REVIEW_CONTEXT_MAX_CHARS, type Database, type DatabaseProvider, type DatabaseTargetInfo, type DatabaseValue, type DeleteCardResult, type DeleteTokenResult, type DiscoveryOptions, type DomainCompetence, type EmbeddedTokenRow, type EmbeddingCoverage, type EmbeddingStaleness, type EvaluateInput, type EvaluateResult, type ExecuteReviewActionInput, type ExecutionContext, type FSRSParameters, type FoundationProposalInput, type FoundationSuggestion, type Goal, type GoalFrontmatter, type GoalStatus, type GoalSummary, HOMEBREW_CASK, type HybridScoredToken, type HybridSearchOptions, type ImportCurriculumResult, type ImportResult, type InstallChannel, type InstallConfig, type InstallMode, type InstallPlan, type InstallResult, type KnowledgeContext, type ListTokensOptions, type LocalLLMRunner, type LogStepInput, type MachineAiConfig, type MachineProviderRecord, type MachineRoleBinding, type MonitorEvent, type Neighborhood, type NeighborhoodToken, OBSERVER_POLICY_UNSET_HINT, OBSERVER_POLICY_VERSION, type ObservationRating, type ObserverConsent, type ObserverPolicy, type ObserverRetention, type ObserverScope, type ObserverSettingKey, type OllamaDetectionOptions, type PersonalCard, type PrepareSessionSynthesisInput, type Prerequisite, type PrerequisiteWithToken, type PromptInput, REVIEW_CONTEXT_CACHE_TTL_MS, type Rating, type RecallPrompt, type RemoteDatabaseOptions, type RepoPaths, type ResolvedCaptureTarget, type ResolvedReference, type ReviewActionResult, type ReviewActionType, type ReviewContext, type ReviewLog, type ReviewQueue, type ReviewQueueItem, type ReviewQueueOptions, type RunResult, SIDECAR_POLICY_FILE, SNAPSHOT_VERSION, type SchedulingCard, type Session, type SessionStep, type SessionSummary, type SessionSynthesisCandidate, type SessionSynthesisEvidence, type SessionSynthesisPreview, type SessionSynthesisRecord, type SidecarPrivacyPolicy, type SkillProposal, type SkillSource, type SnapshotManifest, type SourceProposalInput, type SplitProposalInput, type Statement, type SuggestFoundationsOptions, type SupportedLocale, type SymbiosisMode, type SynthesisConfidence, type SystemProfile, type Token, type TokenDeleteImpact, type TokenEmbedding, type TokenNeedingEmbedding, type TokenPattern, type TranslationKey, type TursoCredentials, UI_OBSERVATION_PROTOCOL_VERSION, type UiActionType, type UiApplicationContext, type UiCandidateToken, type UiEvidenceRef, type UiEvidenceType, type UiObservationKind, type UiObservationReport, type UiObservedAction, type UnblockResult, type UpdateActionKind, type UpdateCardInput, type UpdateDecision, type UpdateKnowledgeContextInput, type UpdateStep, type UpdateStepKind, type UpdateTokenInput, type UserSetting, type UserStats, WINGET_PACKAGE_ID, type WorkItem, type WorkspaceConfig, type WorkspaceKind, type WorkspaceSourceControl, addPrerequisite, analyzeObservation, appendUiObservationReport, applySessionSynthesis, assignTokenToContext, buildAncestorMap, buildReviewQueue, buildUiSynthesisCandidates, cascadeBlock, clearADOCredentials, clearProviderApiKey, clearReviewContextCache, clearTursoCredentials, compareVersions, computeContentHash, confirmCardSplit, confirmFoundations, confirmSourceImport, cosineSimilarity, createAgentSkill, createFSRS, createGoal, createKnowledgeContext, createToken, decidePostCapture, decidePreCapture, decideUpdate, decodeEmbedding, deleteCardForUser, deleteKnowledgeContext, deleteSetting, deleteToken, deprecateToken, detectSyncProvider, detectSystemLocale, discoverSkills, distributeGlobalSkills, embeddingContentForToken, encodeEmbedding, endSession, ensureCard, ensureMonitorDir, ensureUiObserverDir, evaluateRating, executeReviewAction, exportSnapshot, extractTasks, extractTokenRefs, fetchActiveWorkItems, findTokens, generateBashHooks, generateBashUnhooks, generateConceptFreeCue, generatePowerShellHooks, generatePowerShellUnhooks, generatePrompt, generateTokenSlug, generateZshHooks, generateZshUnhooks, getADOCredentials, getActiveWorkspace, getActiveWorkspaceContext, getActiveWorkspaceId, getAgentSkill, getAllSettings, getAllSettingsDetailed, getBlockedCards, getCard, getCardById, getCardDeletionImpact, getConfiguredWorkspaces, getDatabaseTargetInfo, getDefaultDbPath, getDependents, getDisplayTitle, getDomainCompetence, getDueCards, getEmbeddingCoverage, getGoal, getGoalTree, getInstallChannel, getInstallMode, getKnowledgeContextById, getKnowledgeContextByName, getMachineAiConfig, getMonitorDir, getMonitorLogStats, getMonitorPath, getPackageSkillPath, getPrerequisites, getProviderApiKey, getRepoPaths, getReviewsForCard, getReviewsForUser, getSessionSummary, getSessionSynthesisRecords, getSetting, getShortSlug, getSystemProfile, getTokenById, getTokenBySlug, getTokenDeleteImpact, getTokenEmbedding, getTokenNeighborhood, getTursoCredentials, getUiObservationPath, getUiObserverDir, getUserStats, hasCommand, importCurriculumCards, importSnapshot, injectShellHooks, installFastFlowLM, installOllama, installOpenCode, interleave, isObserverPolicyConfigured, isOllamaInstalled, isUiObservationReport, listAgentSkills, listContextsForToken, listEmbeddedTokens, listGoals, listKnowledgeContexts, listPersonalCards, listProviderApiKeyRefs, listTokens, listTokensNeedingEmbedding, loadADOConfig, loadCredentials, loadInstallConfig, logReview, logStep, matchBuiltInSensitive, matchDenylist, matchesFilePath, monitorLogExists, normalizeLocale, normalizePath, openDatabase, openDatabaseWithSync, openRemoteDatabase, pairCommands, parseGoalFile, parseMonitorLog, parseObserverList, parseObserverPolicy, parseSnapshot, parseUiObservationLog, planOpenCodeInstall, planUpdate, prepareLocalModel, prepareSessionSynthesis, readMonitorLog, readUiObservationLog, removeConfiguredWorkspace, resolveAllBeliefPaths, resolveAllGoalPaths, resolveObserverPolicy, resolveOllamaCommand, resolveReference, resolveRepoPath, resolveReviewContext, saveConfiguredWorkspaces, saveCredentials, saveInstallConfig, saveMachineAiConfig, searchTokensHybrid, serializeGoal, setADOCredentials, setActiveWorkspaceContext, setActiveWorkspaceId, setInstallChannel, setInstallMode, setProviderApiKey, setSetting, setTursoCredentials, slugify, startSession, suggestFoundations, syncObserverSidecarPolicy, t, toSidecarPrivacyPolicy, uiObservationLogExists, uiObservationTimeSpan, unassignTokenFromContext, unblockReady, updateCard, updateGoalStatus, updateKnowledgeContext, updateToken, upsertConfiguredWorkspace, upsertTokenEmbedding, verifySnapshot, wouldCreateCycle, writeMonitorEvent };
package/dist/index.js CHANGED
@@ -669,6 +669,22 @@ CREATE TABLE IF NOT EXISTS agent_skills (
669
669
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
670
670
  );
671
671
 
672
+ -- Knowledge contexts: work, school, private
673
+ CREATE TABLE IF NOT EXISTS contexts (
674
+ id TEXT PRIMARY KEY,
675
+ name TEXT NOT NULL UNIQUE,
676
+ label TEXT,
677
+ language TEXT,
678
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
679
+ );
680
+
681
+ -- Join table mapping tokens to their knowledge contexts
682
+ CREATE TABLE IF NOT EXISTS token_contexts (
683
+ token_id TEXT NOT NULL REFERENCES tokens(id) ON DELETE CASCADE,
684
+ context_id TEXT NOT NULL REFERENCES contexts(id) ON DELETE CASCADE,
685
+ PRIMARY KEY (token_id, context_id)
686
+ );
687
+
672
688
  -- Performance indexes
673
689
  CREATE INDEX IF NOT EXISTS idx_tokens_domain ON tokens(domain);
674
690
  CREATE INDEX IF NOT EXISTS idx_tokens_slug ON tokens(slug);
@@ -680,7 +696,7 @@ CREATE INDEX IF NOT EXISTS idx_review_logs_card ON review_logs(card_id);
680
696
  CREATE INDEX IF NOT EXISTS idx_review_logs_user ON review_logs(user_id, reviewed_at);
681
697
  CREATE INDEX IF NOT EXISTS idx_session_steps_session ON session_steps(session_id);
682
698
  CREATE INDEX IF NOT EXISTS idx_tokens_title ON tokens(title);
683
- CREATE INDEX IF NOT EXISTS idx_tokens_domain ON tokens(domain);
699
+ CREATE INDEX IF NOT EXISTS idx_token_contexts_context ON token_contexts(context_id);
684
700
  `;
685
701
 
686
702
  // src/kernel/db/sync-adapter.ts
@@ -1023,6 +1039,25 @@ async function runMigrations(db) {
1023
1039
  await db.exec(
1024
1040
  `CREATE INDEX IF NOT EXISTS idx_tokens_domain ON tokens(domain)`
1025
1041
  );
1042
+ await db.exec(`
1043
+ CREATE TABLE IF NOT EXISTS contexts (
1044
+ id TEXT PRIMARY KEY,
1045
+ name TEXT NOT NULL UNIQUE,
1046
+ label TEXT,
1047
+ language TEXT,
1048
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
1049
+ )
1050
+ `);
1051
+ await db.exec(`
1052
+ CREATE TABLE IF NOT EXISTS token_contexts (
1053
+ token_id TEXT NOT NULL REFERENCES tokens(id) ON DELETE CASCADE,
1054
+ context_id TEXT NOT NULL REFERENCES contexts(id) ON DELETE CASCADE,
1055
+ PRIMARY KEY (token_id, context_id)
1056
+ )
1057
+ `);
1058
+ await db.exec(`
1059
+ CREATE INDEX IF NOT EXISTS idx_token_contexts_context ON token_contexts(context_id)
1060
+ `);
1026
1061
  }
1027
1062
 
1028
1063
  // src/kernel/db/snapshot.ts
@@ -1486,24 +1521,27 @@ async function deleteCardForUser(db, tokenId, userId) {
1486
1521
  await db.prepare("DELETE FROM cards WHERE id = ?").run(card.id);
1487
1522
  return { card, impact };
1488
1523
  }
1489
- async function getDueCards(db, userId, now, domain) {
1524
+ async function getDueCards(db, userId, now, domain, knowledgeContext) {
1490
1525
  const cutoff = now ?? (/* @__PURE__ */ new Date()).toISOString();
1526
+ let sql = `SELECT c.*, t.slug, t.concept, t.domain, t.bloom_level
1527
+ FROM cards c
1528
+ JOIN tokens t ON t.id = c.token_id
1529
+ WHERE c.user_id = ? AND c.blocked = 0 AND c.due_at <= ?`;
1530
+ const params = [userId, cutoff];
1491
1531
  if (domain) {
1492
- return await db.prepare(
1493
- `SELECT c.*, t.slug, t.concept, t.domain, t.bloom_level
1494
- FROM cards c
1495
- JOIN tokens t ON t.id = c.token_id
1496
- WHERE c.user_id = ? AND c.blocked = 0 AND c.due_at <= ? AND t.domain = ?
1497
- ORDER BY t.bloom_level ASC, c.due_at ASC`
1498
- ).all(userId, cutoff, domain);
1532
+ sql += " AND t.domain = ?";
1533
+ params.push(domain);
1499
1534
  }
1500
- return await db.prepare(
1501
- `SELECT c.*, t.slug, t.concept, t.domain, t.bloom_level
1502
- FROM cards c
1503
- JOIN tokens t ON t.id = c.token_id
1504
- WHERE c.user_id = ? AND c.blocked = 0 AND c.due_at <= ?
1505
- ORDER BY t.bloom_level ASC, c.due_at ASC`
1506
- ).all(userId, cutoff);
1535
+ if (knowledgeContext) {
1536
+ sql += ` AND EXISTS (
1537
+ SELECT 1 FROM token_contexts tc
1538
+ INNER JOIN contexts context_filter ON context_filter.id = tc.context_id
1539
+ WHERE tc.token_id = t.id AND context_filter.name = ?
1540
+ )`;
1541
+ params.push(knowledgeContext);
1542
+ }
1543
+ sql += " ORDER BY t.bloom_level ASC, c.due_at ASC";
1544
+ return await db.prepare(sql).all(...params);
1507
1545
  }
1508
1546
  async function getBlockedCards(db, userId) {
1509
1547
  return await db.prepare(
@@ -1515,11 +1553,116 @@ async function getBlockedCards(db, userId) {
1515
1553
  ).all(userId);
1516
1554
  }
1517
1555
 
1518
- // src/kernel/models/token.ts
1556
+ // src/kernel/models/knowledge-context.ts
1519
1557
  import { ulid as ulid3 } from "ulid";
1520
- async function createToken(db, input) {
1558
+ function normalizeContextName(name) {
1559
+ const normalized = name.trim();
1560
+ if (!normalized) {
1561
+ throw new Error("Context name cannot be empty");
1562
+ }
1563
+ return normalized;
1564
+ }
1565
+ function normalizeOptionalText(value) {
1566
+ if (value == null) return null;
1567
+ const normalized = value.trim();
1568
+ return normalized || null;
1569
+ }
1570
+ async function createKnowledgeContext(db, input) {
1521
1571
  const id = ulid3();
1522
1572
  const now = (/* @__PURE__ */ new Date()).toISOString();
1573
+ const name = normalizeContextName(input.name);
1574
+ const existing = await getKnowledgeContextByName(db, name);
1575
+ if (existing) {
1576
+ throw new Error(`Knowledge context with name "${name}" already exists`);
1577
+ }
1578
+ await db.prepare(
1579
+ `INSERT INTO contexts (id, name, label, language, created_at)
1580
+ VALUES (?, ?, ?, ?, ?)`
1581
+ ).run(
1582
+ id,
1583
+ name,
1584
+ normalizeOptionalText(input.label),
1585
+ normalizeOptionalText(input.language),
1586
+ now
1587
+ );
1588
+ const context = await getKnowledgeContextById(db, id);
1589
+ if (!context) {
1590
+ throw new Error(
1591
+ `Failed to retrieve newly created knowledge context: ${id}`
1592
+ );
1593
+ }
1594
+ return context;
1595
+ }
1596
+ async function getKnowledgeContextByName(db, name) {
1597
+ const normalized = name.trim();
1598
+ if (!normalized) return void 0;
1599
+ return await db.prepare("SELECT * FROM contexts WHERE name = ?").get(normalized);
1600
+ }
1601
+ async function getKnowledgeContextById(db, id) {
1602
+ return await db.prepare("SELECT * FROM contexts WHERE id = ?").get(id);
1603
+ }
1604
+ async function listKnowledgeContexts(db) {
1605
+ return await db.prepare("SELECT * FROM contexts ORDER BY name ASC").all();
1606
+ }
1607
+ async function updateKnowledgeContext(db, id, updates) {
1608
+ const context = await getKnowledgeContextById(db, id);
1609
+ if (!context) {
1610
+ throw new Error(`Knowledge context not found: ${id}`);
1611
+ }
1612
+ const fields = [];
1613
+ const values = [];
1614
+ if (updates.name !== void 0) {
1615
+ const name = normalizeContextName(updates.name);
1616
+ if (name !== context.name) {
1617
+ const existing = await getKnowledgeContextByName(db, name);
1618
+ if (existing) {
1619
+ throw new Error(`Knowledge context with name "${name}" already exists`);
1620
+ }
1621
+ fields.push("name = ?");
1622
+ values.push(name);
1623
+ }
1624
+ }
1625
+ if (updates.label !== void 0) {
1626
+ fields.push("label = ?");
1627
+ values.push(normalizeOptionalText(updates.label));
1628
+ }
1629
+ if (updates.language !== void 0) {
1630
+ fields.push("language = ?");
1631
+ values.push(normalizeOptionalText(updates.language));
1632
+ }
1633
+ if (fields.length === 0) {
1634
+ return context;
1635
+ }
1636
+ values.push(id);
1637
+ await db.prepare(`UPDATE contexts SET ${fields.join(", ")} WHERE id = ?`).run(...values);
1638
+ return await getKnowledgeContextById(db, id);
1639
+ }
1640
+ async function deleteKnowledgeContext(db, id) {
1641
+ await db.prepare("DELETE FROM contexts WHERE id = ?").run(id);
1642
+ }
1643
+ async function assignTokenToContext(db, tokenId, contextId) {
1644
+ await db.prepare(
1645
+ `INSERT OR IGNORE INTO token_contexts (token_id, context_id)
1646
+ VALUES (?, ?)`
1647
+ ).run(tokenId, contextId);
1648
+ }
1649
+ async function unassignTokenFromContext(db, tokenId, contextId) {
1650
+ await db.prepare("DELETE FROM token_contexts WHERE token_id = ? AND context_id = ?").run(tokenId, contextId);
1651
+ }
1652
+ async function listContextsForToken(db, tokenId) {
1653
+ return await db.prepare(
1654
+ `SELECT c.* FROM contexts c
1655
+ INNER JOIN token_contexts tc ON tc.context_id = c.id
1656
+ WHERE tc.token_id = ?
1657
+ ORDER BY c.name ASC`
1658
+ ).all(tokenId);
1659
+ }
1660
+
1661
+ // src/kernel/models/token.ts
1662
+ import { ulid as ulid4 } from "ulid";
1663
+ async function createToken(db, input) {
1664
+ const id = ulid4();
1665
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1523
1666
  const bloom = input.bloom_level ?? 1;
1524
1667
  if (bloom < 1 || bloom > 5) {
1525
1668
  throw new Error(`bloom_level must be between 1 and 5, got ${bloom}`);
@@ -1755,21 +1898,27 @@ async function findTokens(db, query) {
1755
1898
  return scored;
1756
1899
  }
1757
1900
  async function listTokens(db, options) {
1758
- let tokens;
1901
+ const whereClauses = ["deprecated_at IS NULL"];
1902
+ const params = [];
1759
1903
  if (options?.domain) {
1760
- tokens = await db.prepare(
1761
- "SELECT * FROM tokens WHERE domain = ? AND deprecated_at IS NULL ORDER BY bloom_level, slug"
1762
- ).all(options.domain);
1904
+ whereClauses.push("domain = ?");
1905
+ params.push(options.domain);
1763
1906
  } else if (options?.domainPrefix) {
1764
1907
  const prefix = options.domainPrefix;
1765
- tokens = await db.prepare(
1766
- `SELECT * FROM tokens WHERE (domain = ? OR domain LIKE ?) AND deprecated_at IS NULL ORDER BY bloom_level, slug`
1767
- ).all(prefix, `${prefix}/%`);
1768
- } else {
1769
- tokens = await db.prepare(
1770
- "SELECT * FROM tokens WHERE deprecated_at IS NULL ORDER BY bloom_level, domain, slug"
1771
- ).all();
1772
- }
1908
+ whereClauses.push("(domain = ? OR domain LIKE ?)");
1909
+ params.push(prefix, `${prefix}/%`);
1910
+ }
1911
+ if (options?.knowledgeContext) {
1912
+ whereClauses.push(`EXISTS (
1913
+ SELECT 1 FROM token_contexts tc
1914
+ INNER JOIN contexts c ON c.id = tc.context_id
1915
+ WHERE tc.token_id = tokens.id AND c.name = ?
1916
+ )`);
1917
+ params.push(options.knowledgeContext);
1918
+ }
1919
+ const orderBy = options?.domain || options?.domainPrefix ? "ORDER BY bloom_level, slug" : "ORDER BY bloom_level, domain, slug";
1920
+ const sql = `SELECT * FROM tokens WHERE ${whereClauses.join(" AND ")} ${orderBy}`;
1921
+ const tokens = await db.prepare(sql).all(...params);
1773
1922
  for (const token of tokens) {
1774
1923
  parseTokenFallback(token);
1775
1924
  }
@@ -1860,6 +2009,14 @@ async function listPersonalCards(db, userId, options) {
1860
2009
  sql += " AND t.domain = ?";
1861
2010
  values.push(options.domain);
1862
2011
  }
2012
+ if (options?.knowledgeContext) {
2013
+ sql += ` AND EXISTS (
2014
+ SELECT 1 FROM token_contexts tc
2015
+ INNER JOIN contexts kc ON kc.id = tc.context_id
2016
+ WHERE tc.token_id = t.id AND kc.name = ?
2017
+ )`;
2018
+ values.push(options.knowledgeContext);
2019
+ }
1863
2020
  if (options?.query) {
1864
2021
  const terms = options.query.toLowerCase().split(/\s+/).filter(Boolean);
1865
2022
  for (const term of terms) {
@@ -2385,12 +2542,12 @@ async function getTokenNeighborhood(db, tokenId, userId) {
2385
2542
  }
2386
2543
 
2387
2544
  // src/kernel/models/review.ts
2388
- import { ulid as ulid4 } from "ulid";
2545
+ import { ulid as ulid5 } from "ulid";
2389
2546
  async function logReview(db, input) {
2390
2547
  if (input.rating < 1 || input.rating > 4) {
2391
2548
  throw new Error(`Rating must be between 1 and 4, got ${input.rating}`);
2392
2549
  }
2393
- const id = ulid4();
2550
+ const id = ulid5();
2394
2551
  const now = (/* @__PURE__ */ new Date()).toISOString();
2395
2552
  await db.prepare(
2396
2553
  `INSERT INTO review_logs (id, card_id, token_id, user_id, rating, response_time_ms, reviewed_at, scheduled_at, session_id)
@@ -2433,9 +2590,9 @@ async function getReviewsForUser(db, userId, options) {
2433
2590
  }
2434
2591
 
2435
2592
  // src/kernel/models/session.ts
2436
- import { ulid as ulid5 } from "ulid";
2593
+ import { ulid as ulid6 } from "ulid";
2437
2594
  async function startSession(db, input) {
2438
- const id = ulid5();
2595
+ const id = ulid6();
2439
2596
  const now = (/* @__PURE__ */ new Date()).toISOString();
2440
2597
  const ctx = input.execution_context ?? "shell";
2441
2598
  await db.prepare(
@@ -2469,7 +2626,7 @@ async function logStep(db, input) {
2469
2626
  if (!session) {
2470
2627
  throw new Error(`Session not found: ${input.session_id}`);
2471
2628
  }
2472
- const id = ulid5();
2629
+ const id = ulid6();
2473
2630
  const now = (/* @__PURE__ */ new Date()).toISOString();
2474
2631
  await db.prepare(
2475
2632
  `INSERT INTO session_steps (id, session_id, token_id, done_by, rating, notes, created_at)
@@ -3368,10 +3525,10 @@ async function syncObserverSidecarPolicy(db, dir = getUiObserverDir()) {
3368
3525
  }
3369
3526
 
3370
3527
  // src/kernel/observation/session-synthesis.ts
3371
- import { ulid as ulid7 } from "ulid";
3528
+ import { ulid as ulid8 } from "ulid";
3372
3529
 
3373
3530
  // src/kernel/recall/evaluator.ts
3374
- import { ulid as ulid6 } from "ulid";
3531
+ import { ulid as ulid7 } from "ulid";
3375
3532
 
3376
3533
  // src/kernel/scheduler/fsrs.ts
3377
3534
  var DEFAULT_W = [
@@ -3550,7 +3707,7 @@ async function evaluateRatingWithinTransaction(db, input) {
3550
3707
  due_at: updated.dueAt.toISOString(),
3551
3708
  last_review_at: now.toISOString()
3552
3709
  });
3553
- const reviewLogId = input.reviewLogId ?? ulid6();
3710
+ const reviewLogId = input.reviewLogId ?? ulid7();
3554
3711
  await db.prepare(
3555
3712
  `INSERT INTO review_logs (id, card_id, token_id, user_id, rating, response_time_ms, reviewed_at, scheduled_at, session_id)
3556
3713
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
@@ -3884,7 +4041,7 @@ async function applySessionSynthesis(db, input) {
3884
4041
  return { applied: false, record: parseSynthesisRow(existing) };
3885
4042
  }
3886
4043
  const card = await ensureCard(tx, token.id, session.user_id);
3887
- const reviewLogId = ulid7();
4044
+ const reviewLogId = ulid8();
3888
4045
  await evaluateRatingWithinTransaction(tx, {
3889
4046
  cardId: card.id,
3890
4047
  tokenId: token.id,
@@ -4713,8 +4870,7 @@ async function buildReviewQueue(db, options) {
4713
4870
  const maxReviews = options.maxReviews ?? 50;
4714
4871
  const now = options.now ?? /* @__PURE__ */ new Date();
4715
4872
  const nowISO = now.toISOString();
4716
- const dueRows = await db.prepare(
4717
- `SELECT
4873
+ let dueSql = `SELECT
4718
4874
  c.id AS card_id,
4719
4875
  c.token_id AS token_id,
4720
4876
  t.slug AS slug,
@@ -4732,11 +4888,19 @@ async function buildReviewQueue(db, options) {
4732
4888
  AND c.blocked = 0
4733
4889
  AND c.due_at <= ?
4734
4890
  AND c.state IN ('review', 'relearning', 'learning')
4735
- AND t.deprecated_at IS NULL
4736
- ORDER BY c.due_at ASC`
4737
- ).all(options.userId, nowISO);
4738
- const newRows = await db.prepare(
4739
- `SELECT
4891
+ AND t.deprecated_at IS NULL`;
4892
+ const dueParams = [options.userId, nowISO];
4893
+ if (options.knowledgeContext) {
4894
+ dueSql += ` AND EXISTS (
4895
+ SELECT 1 FROM token_contexts tc
4896
+ INNER JOIN contexts ctx ON ctx.id = tc.context_id
4897
+ WHERE tc.token_id = t.id AND ctx.name = ?
4898
+ )`;
4899
+ dueParams.push(options.knowledgeContext);
4900
+ }
4901
+ dueSql += ` ORDER BY c.due_at ASC`;
4902
+ const dueRows = await db.prepare(dueSql).all(...dueParams);
4903
+ let newSql = `SELECT
4740
4904
  c.id AS card_id,
4741
4905
  c.token_id AS token_id,
4742
4906
  t.slug AS slug,
@@ -4753,10 +4917,19 @@ async function buildReviewQueue(db, options) {
4753
4917
  WHERE c.user_id = ?
4754
4918
  AND c.blocked = 0
4755
4919
  AND c.state = 'new'
4756
- AND t.deprecated_at IS NULL
4757
- ORDER BY t.bloom_level ASC, t.slug ASC
4758
- LIMIT ?`
4759
- ).all(options.userId, maxNew);
4920
+ AND t.deprecated_at IS NULL`;
4921
+ const newParams = [options.userId];
4922
+ if (options.knowledgeContext) {
4923
+ newSql += ` AND EXISTS (
4924
+ SELECT 1 FROM token_contexts tc
4925
+ INNER JOIN contexts ctx ON ctx.id = tc.context_id
4926
+ WHERE tc.token_id = t.id AND ctx.name = ?
4927
+ )`;
4928
+ newParams.push(options.knowledgeContext);
4929
+ }
4930
+ newSql += ` ORDER BY t.bloom_level ASC, t.slug ASC LIMIT ?`;
4931
+ newParams.push(maxNew);
4932
+ const newRows = await db.prepare(newSql).all(...newParams);
4760
4933
  const nowMs = now.getTime();
4761
4934
  const sortedDue = [...dueRows].sort((a, b) => {
4762
4935
  const overdueA = nowMs - new Date(a.due_at).getTime();
@@ -5503,6 +5676,27 @@ function detectSyncProvider(dir) {
5503
5676
  }
5504
5677
  return null;
5505
5678
  }
5679
+ function getActiveWorkspaceContext(path = defaultConfigPath()) {
5680
+ const activeWorkspace = getActiveWorkspace(path);
5681
+ return activeWorkspace?.activeKnowledgeContext;
5682
+ }
5683
+ function setActiveWorkspaceContext(contextName, path = defaultConfigPath()) {
5684
+ const config = loadInstallConfig(path);
5685
+ const activeId = config.activeWorkspaceId;
5686
+ if (activeId && config.workspaces) {
5687
+ const workspace = config.workspaces.find((w) => w.id === activeId);
5688
+ if (workspace) {
5689
+ if (contextName) {
5690
+ workspace.activeKnowledgeContext = contextName;
5691
+ } else {
5692
+ delete workspace.activeKnowledgeContext;
5693
+ }
5694
+ saveInstallConfig(config, path);
5695
+ return true;
5696
+ }
5697
+ }
5698
+ return false;
5699
+ }
5506
5700
 
5507
5701
  // src/kernel/system/installer.ts
5508
5702
  import { execFileSync, execSync } from "child_process";
@@ -5998,6 +6192,7 @@ export {
5998
6192
  analyzeObservation,
5999
6193
  appendUiObservationReport,
6000
6194
  applySessionSynthesis,
6195
+ assignTokenToContext,
6001
6196
  buildAncestorMap,
6002
6197
  buildReviewQueue,
6003
6198
  buildUiSynthesisCandidates,
@@ -6015,12 +6210,14 @@ export {
6015
6210
  createAgentSkill,
6016
6211
  createFSRS,
6017
6212
  createGoal,
6213
+ createKnowledgeContext,
6018
6214
  createToken,
6019
6215
  decidePostCapture,
6020
6216
  decidePreCapture,
6021
6217
  decideUpdate,
6022
6218
  decodeEmbedding,
6023
6219
  deleteCardForUser,
6220
+ deleteKnowledgeContext,
6024
6221
  deleteSetting,
6025
6222
  deleteToken,
6026
6223
  deprecateToken,
@@ -6052,6 +6249,7 @@ export {
6052
6249
  generateZshUnhooks,
6053
6250
  getADOCredentials,
6054
6251
  getActiveWorkspace,
6252
+ getActiveWorkspaceContext,
6055
6253
  getActiveWorkspaceId,
6056
6254
  getAgentSkill,
6057
6255
  getAllSettings,
@@ -6072,6 +6270,8 @@ export {
6072
6270
  getGoalTree,
6073
6271
  getInstallChannel,
6074
6272
  getInstallMode,
6273
+ getKnowledgeContextById,
6274
+ getKnowledgeContextByName,
6075
6275
  getMachineAiConfig,
6076
6276
  getMonitorDir,
6077
6277
  getMonitorLogStats,
@@ -6108,8 +6308,10 @@ export {
6108
6308
  isOllamaInstalled,
6109
6309
  isUiObservationReport,
6110
6310
  listAgentSkills,
6311
+ listContextsForToken,
6111
6312
  listEmbeddedTokens,
6112
6313
  listGoals,
6314
+ listKnowledgeContexts,
6113
6315
  listPersonalCards,
6114
6316
  listProviderApiKeyRefs,
6115
6317
  listTokens,
@@ -6156,6 +6358,7 @@ export {
6156
6358
  searchTokensHybrid,
6157
6359
  serializeGoal,
6158
6360
  setADOCredentials,
6361
+ setActiveWorkspaceContext,
6159
6362
  setActiveWorkspaceId,
6160
6363
  setInstallChannel,
6161
6364
  setInstallMode,
@@ -6170,9 +6373,11 @@ export {
6170
6373
  toSidecarPrivacyPolicy,
6171
6374
  uiObservationLogExists,
6172
6375
  uiObservationTimeSpan,
6376
+ unassignTokenFromContext,
6173
6377
  unblockReady,
6174
6378
  updateCard,
6175
6379
  updateGoalStatus,
6380
+ updateKnowledgeContext,
6176
6381
  updateToken,
6177
6382
  upsertConfiguredWorkspace,
6178
6383
  upsertTokenEmbedding,