zam-core 0.5.2 → 0.6.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.js CHANGED
@@ -616,6 +616,24 @@ CREATE TABLE IF NOT EXISTS session_syntheses (
616
616
  PRIMARY KEY (session_id, token_id)
617
617
  );
618
618
 
619
+ -- Sources: textbook files, web links, or scan paths
620
+ CREATE TABLE IF NOT EXISTS sources (
621
+ id TEXT PRIMARY KEY,
622
+ type TEXT NOT NULL CHECK (type IN ('file', 'web', 'scan')),
623
+ uri TEXT NOT NULL UNIQUE,
624
+ content TEXT,
625
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
626
+ );
627
+
628
+ -- Token sources: mapping between tokens and their sources
629
+ CREATE TABLE IF NOT EXISTS token_sources (
630
+ token_id TEXT NOT NULL REFERENCES tokens(id) ON DELETE CASCADE,
631
+ source_id TEXT NOT NULL REFERENCES sources(id) ON DELETE CASCADE,
632
+ excerpt TEXT NOT NULL DEFAULT '',
633
+ page_number TEXT,
634
+ PRIMARY KEY (token_id, source_id)
635
+ );
636
+
619
637
  -- User configuration
620
638
  CREATE TABLE IF NOT EXISTS user_config (
621
639
  key TEXT PRIMARY KEY,
@@ -943,6 +961,24 @@ async function runMigrations(db) {
943
961
  PRIMARY KEY (session_id, token_id)
944
962
  )
945
963
  `);
964
+ await db.exec(`
965
+ CREATE TABLE IF NOT EXISTS sources (
966
+ id TEXT PRIMARY KEY,
967
+ type TEXT NOT NULL CHECK (type IN ('file', 'web', 'scan')),
968
+ uri TEXT NOT NULL UNIQUE,
969
+ content TEXT,
970
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
971
+ )
972
+ `);
973
+ await db.exec(`
974
+ CREATE TABLE IF NOT EXISTS token_sources (
975
+ token_id TEXT NOT NULL REFERENCES tokens(id) ON DELETE CASCADE,
976
+ source_id TEXT NOT NULL REFERENCES sources(id) ON DELETE CASCADE,
977
+ excerpt TEXT NOT NULL DEFAULT '',
978
+ page_number TEXT,
979
+ PRIMARY KEY (token_id, source_id)
980
+ )
981
+ `);
946
982
  }
947
983
 
948
984
  // src/kernel/db/snapshot.ts
@@ -1646,6 +1682,415 @@ async function listTokens(db, options) {
1646
1682
  "SELECT * FROM tokens WHERE deprecated_at IS NULL ORDER BY bloom_level, domain, slug"
1647
1683
  ).all();
1648
1684
  }
1685
+ function slugify(text) {
1686
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
1687
+ }
1688
+ async function generateTokenSlug(db, domain, concept, question) {
1689
+ const baseText = question && question.trim().length > 0 ? question : concept;
1690
+ const cleanDomain = slugify(domain || "");
1691
+ const cleanBase = slugify(baseText);
1692
+ let baseSlug = cleanDomain ? `${cleanDomain}-${cleanBase}` : cleanBase;
1693
+ if (baseSlug.length > 60) {
1694
+ baseSlug = baseSlug.slice(0, 60).replace(/-$/, "");
1695
+ }
1696
+ if (!baseSlug) {
1697
+ baseSlug = "token";
1698
+ }
1699
+ let slug = baseSlug;
1700
+ let counter = 1;
1701
+ while (true) {
1702
+ const existing = await db.prepare("SELECT id FROM tokens WHERE slug = ?").get(slug);
1703
+ if (!existing) {
1704
+ return slug;
1705
+ }
1706
+ const suffix = `-${counter}`;
1707
+ slug = baseSlug.slice(0, 60 - suffix.length).replace(/-$/, "") + suffix;
1708
+ counter++;
1709
+ }
1710
+ }
1711
+ async function listPersonalCards(db, userId, options) {
1712
+ let sql = `
1713
+ SELECT
1714
+ t.id AS tokenId,
1715
+ t.slug,
1716
+ t.concept,
1717
+ t.domain,
1718
+ t.bloom_level AS bloomLevel,
1719
+ t.context,
1720
+ t.symbiosis_mode AS symbiosisMode,
1721
+ t.source_link AS sourceLink,
1722
+ t.question,
1723
+ t.created_at AS createdAt,
1724
+ t.updated_at AS updatedAt,
1725
+ c.id AS cardId,
1726
+ c.state,
1727
+ c.due_at AS dueAt,
1728
+ c.stability,
1729
+ c.difficulty,
1730
+ c.reps,
1731
+ c.lapses,
1732
+ c.elapsed_days AS elapsedDays,
1733
+ c.scheduled_days AS scheduledDays,
1734
+ c.blocked
1735
+ FROM tokens t
1736
+ INNER JOIN cards c ON c.token_id = t.id AND c.user_id = ?
1737
+ WHERE t.deprecated_at IS NULL
1738
+ `;
1739
+ const values = [userId];
1740
+ if (options?.domain) {
1741
+ sql += " AND t.domain = ?";
1742
+ values.push(options.domain);
1743
+ }
1744
+ if (options?.query) {
1745
+ const terms = options.query.toLowerCase().split(/\s+/).filter(Boolean);
1746
+ for (const term of terms) {
1747
+ sql += ` AND (lower(t.slug) LIKE ? OR lower(t.concept) LIKE ? OR lower(t.domain) LIKE ? OR lower(t.question) LIKE ?)`;
1748
+ const pattern = `%${term}%`;
1749
+ values.push(pattern, pattern, pattern, pattern);
1750
+ }
1751
+ }
1752
+ sql += " ORDER BY t.created_at DESC";
1753
+ const rows = await db.prepare(sql).all(...values);
1754
+ return rows;
1755
+ }
1756
+ async function importCurriculumCards(db, userId, cards) {
1757
+ let createdCount = 0;
1758
+ let ensuredCount = 0;
1759
+ await db.transaction(async (tx) => {
1760
+ for (const card of cards) {
1761
+ const bloom = card.bloom_level !== void 0 ? card.bloom_level : 1;
1762
+ if (bloom < 1 || bloom > 5) {
1763
+ throw new Error(`bloom_level must be between 1 and 5, got ${bloom}`);
1764
+ }
1765
+ let symbiosisMode = null;
1766
+ if (card.symbiosis_mode) {
1767
+ if (!["shadowing", "copilot", "autonomy", "none"].includes(
1768
+ card.symbiosis_mode
1769
+ )) {
1770
+ throw new Error(`Invalid symbiosis_mode: ${card.symbiosis_mode}`);
1771
+ }
1772
+ symbiosisMode = card.symbiosis_mode === "none" ? null : card.symbiosis_mode;
1773
+ }
1774
+ const baseText = card.question && card.question.trim().length > 0 ? card.question : card.concept;
1775
+ const cleanDomain = slugify(card.domain || "");
1776
+ const cleanBase = slugify(baseText);
1777
+ let baseSlug = cleanDomain ? `${cleanDomain}-${cleanBase}` : cleanBase;
1778
+ if (baseSlug.length > 60) {
1779
+ baseSlug = baseSlug.slice(0, 60).replace(/-$/, "");
1780
+ }
1781
+ if (!baseSlug) {
1782
+ baseSlug = "token";
1783
+ }
1784
+ let token = await getTokenBySlug(tx, baseSlug);
1785
+ if (!token) {
1786
+ const finalSlug = await generateTokenSlug(
1787
+ tx,
1788
+ card.domain,
1789
+ card.concept,
1790
+ card.question
1791
+ );
1792
+ token = await createToken(tx, {
1793
+ slug: finalSlug,
1794
+ concept: card.concept,
1795
+ domain: card.domain,
1796
+ bloom_level: bloom,
1797
+ context: card.context || "",
1798
+ symbiosis_mode: symbiosisMode,
1799
+ source_link: card.source_link || null,
1800
+ question: card.question || null
1801
+ });
1802
+ createdCount++;
1803
+ }
1804
+ const existingCard = await getCard(tx, token.id, userId);
1805
+ if (!existingCard) {
1806
+ await ensureCard(tx, token.id, userId);
1807
+ ensuredCount++;
1808
+ }
1809
+ }
1810
+ });
1811
+ return { createdCount, ensuredCount };
1812
+ }
1813
+ async function confirmCardSplit(db, userId, originalSlug, action, originalQuestion, originalConcept, proposals) {
1814
+ if (action !== "block" && action !== "remove") {
1815
+ throw new Error(`Invalid split action: ${action}`);
1816
+ }
1817
+ if (proposals.length < 2 || proposals.length > 4) {
1818
+ throw new Error("A card split requires between 2 and 4 proposals");
1819
+ }
1820
+ const originalToken = await getTokenBySlug(db, originalSlug);
1821
+ if (!originalToken) {
1822
+ throw new Error(`Original token not found: ${originalSlug}`);
1823
+ }
1824
+ let createdCount = 0;
1825
+ let ensuredCount = 0;
1826
+ await db.transaction(async (tx) => {
1827
+ const originalCard = await getCard(tx, originalToken.id, userId);
1828
+ if (!originalCard) {
1829
+ throw new Error(
1830
+ `Card not found for token ${originalSlug} and user ${userId}`
1831
+ );
1832
+ }
1833
+ const proposalTokens = [];
1834
+ for (const card of proposals) {
1835
+ const bloom = card.bloom_level !== void 0 ? card.bloom_level : 1;
1836
+ if (bloom < 1 || bloom > 5) {
1837
+ throw new Error(`bloom_level must be between 1 and 5, got ${bloom}`);
1838
+ }
1839
+ let symbiosisMode = null;
1840
+ if (card.symbiosis_mode) {
1841
+ if (!["shadowing", "copilot", "autonomy", "none"].includes(
1842
+ card.symbiosis_mode
1843
+ )) {
1844
+ throw new Error(`Invalid symbiosis_mode: ${card.symbiosis_mode}`);
1845
+ }
1846
+ symbiosisMode = card.symbiosis_mode === "none" ? null : card.symbiosis_mode;
1847
+ }
1848
+ const baseText = card.question && card.question.trim().length > 0 ? card.question : card.concept;
1849
+ const cleanDomain = slugify(card.domain || "");
1850
+ const cleanBase = slugify(baseText);
1851
+ let baseSlug = cleanDomain ? `${cleanDomain}-${cleanBase}` : cleanBase;
1852
+ if (baseSlug.length > 60) {
1853
+ baseSlug = baseSlug.slice(0, 60).replace(/-$/, "");
1854
+ }
1855
+ if (!baseSlug) {
1856
+ baseSlug = "token";
1857
+ }
1858
+ let token = await getTokenBySlug(tx, baseSlug);
1859
+ if (!token) {
1860
+ const finalSlug = await generateTokenSlug(
1861
+ tx,
1862
+ card.domain,
1863
+ card.concept,
1864
+ card.question
1865
+ );
1866
+ token = await createToken(tx, {
1867
+ slug: finalSlug,
1868
+ concept: card.concept,
1869
+ domain: card.domain,
1870
+ bloom_level: bloom,
1871
+ context: card.context || "",
1872
+ symbiosis_mode: symbiosisMode,
1873
+ source_link: card.source_link || originalToken.source_link || null,
1874
+ question: card.question || null
1875
+ });
1876
+ createdCount++;
1877
+ }
1878
+ if (token.id === originalToken.id) {
1879
+ throw new Error("A token cannot be a prerequisite of itself");
1880
+ }
1881
+ await assertPrerequisiteDoesNotCreateCycle(
1882
+ tx,
1883
+ originalToken.id,
1884
+ token.id
1885
+ );
1886
+ proposalTokens.push(token);
1887
+ const existingCard = await getCard(tx, token.id, userId);
1888
+ if (!existingCard) {
1889
+ await ensureCard(tx, token.id, userId);
1890
+ ensuredCount++;
1891
+ }
1892
+ }
1893
+ if (action === "block") {
1894
+ await tx.prepare(
1895
+ "UPDATE tokens SET question = ?, concept = ?, updated_at = ? WHERE id = ?"
1896
+ ).run(
1897
+ originalQuestion || null,
1898
+ originalConcept,
1899
+ (/* @__PURE__ */ new Date()).toISOString(),
1900
+ originalToken.id
1901
+ );
1902
+ for (const propToken of proposalTokens) {
1903
+ await tx.prepare(
1904
+ "INSERT OR IGNORE INTO prerequisites (token_id, requires_id) VALUES (?, ?)"
1905
+ ).run(originalToken.id, propToken.id);
1906
+ }
1907
+ await tx.prepare(
1908
+ "UPDATE cards SET blocked = 1 WHERE token_id = ? AND user_id = ?"
1909
+ ).run(originalToken.id, userId);
1910
+ for (const propToken of proposalTokens) {
1911
+ const card = await ensureCard(tx, propToken.id, userId);
1912
+ if (card.blocked === 1) {
1913
+ const prereqOfPrereq = await tx.prepare(
1914
+ "SELECT COUNT(*) as n FROM prerequisites WHERE token_id = ?"
1915
+ ).get(propToken.id);
1916
+ if (prereqOfPrereq.n === 0) {
1917
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1918
+ await tx.prepare("UPDATE cards SET blocked = 0, due_at = ? WHERE id = ?").run(now, card.id);
1919
+ }
1920
+ }
1921
+ }
1922
+ } else if (action === "remove") {
1923
+ await deleteCardForUser(tx, originalToken.id, userId);
1924
+ }
1925
+ });
1926
+ return { createdCount, ensuredCount };
1927
+ }
1928
+ async function confirmFoundations(db, userId, originalSlug, proposals) {
1929
+ const originalToken = await getTokenBySlug(db, originalSlug);
1930
+ if (!originalToken) {
1931
+ throw new Error(`Original token not found: ${originalSlug}`);
1932
+ }
1933
+ let createdCount = 0;
1934
+ let linkedCount = 0;
1935
+ await db.transaction(async (tx) => {
1936
+ const originalCard = await getCard(tx, originalToken.id, userId);
1937
+ if (!originalCard) {
1938
+ throw new Error(
1939
+ `Card not found for token ${originalSlug} and user ${userId}`
1940
+ );
1941
+ }
1942
+ for (const card of proposals) {
1943
+ let targetTokenId;
1944
+ if (card.exists && card.slug) {
1945
+ const existingToken = await getTokenBySlug(tx, card.slug);
1946
+ if (!existingToken) {
1947
+ throw new Error(`Prerequisite token not found by slug: ${card.slug}`);
1948
+ }
1949
+ targetTokenId = existingToken.id;
1950
+ const existingCard = await getCard(tx, existingToken.id, userId);
1951
+ if (!existingCard) {
1952
+ await ensureCard(tx, existingToken.id, userId);
1953
+ }
1954
+ linkedCount++;
1955
+ } else {
1956
+ const bloom = card.bloom_level !== void 0 ? card.bloom_level : 1;
1957
+ if (bloom < 1 || bloom > 5) {
1958
+ throw new Error(`bloom_level must be between 1 and 5, got ${bloom}`);
1959
+ }
1960
+ let symbiosisMode = null;
1961
+ if (card.symbiosis_mode) {
1962
+ if (!["shadowing", "copilot", "autonomy", "none"].includes(
1963
+ card.symbiosis_mode
1964
+ )) {
1965
+ throw new Error(`Invalid symbiosis_mode: ${card.symbiosis_mode}`);
1966
+ }
1967
+ symbiosisMode = card.symbiosis_mode === "none" ? null : card.symbiosis_mode;
1968
+ }
1969
+ const baseText = card.question && card.question.trim().length > 0 ? card.question : card.concept;
1970
+ const cleanDomain = slugify(card.domain || "");
1971
+ const cleanBase = slugify(baseText);
1972
+ let baseSlug = cleanDomain ? `${cleanDomain}-${cleanBase}` : cleanBase;
1973
+ if (baseSlug.length > 60) {
1974
+ baseSlug = baseSlug.slice(0, 60).replace(/-$/, "");
1975
+ }
1976
+ if (!baseSlug) {
1977
+ baseSlug = "token";
1978
+ }
1979
+ let token = await getTokenBySlug(tx, baseSlug);
1980
+ if (!token) {
1981
+ const finalSlug = await generateTokenSlug(
1982
+ tx,
1983
+ card.domain,
1984
+ card.concept,
1985
+ card.question
1986
+ );
1987
+ token = await createToken(tx, {
1988
+ slug: finalSlug,
1989
+ concept: card.concept,
1990
+ domain: card.domain,
1991
+ bloom_level: bloom,
1992
+ context: card.context || "",
1993
+ symbiosis_mode: symbiosisMode,
1994
+ source_link: card.source_link || originalToken.source_link || null,
1995
+ question: card.question || null
1996
+ });
1997
+ createdCount++;
1998
+ }
1999
+ targetTokenId = token.id;
2000
+ const existingCard = await getCard(tx, token.id, userId);
2001
+ if (!existingCard) {
2002
+ await ensureCard(tx, token.id, userId);
2003
+ }
2004
+ }
2005
+ if (targetTokenId === originalToken.id) {
2006
+ throw new Error("A token cannot be a prerequisite of itself");
2007
+ }
2008
+ await assertPrerequisiteDoesNotCreateCycle(
2009
+ tx,
2010
+ originalToken.id,
2011
+ targetTokenId
2012
+ );
2013
+ await tx.prepare(
2014
+ "INSERT OR IGNORE INTO prerequisites (token_id, requires_id) VALUES (?, ?)"
2015
+ ).run(originalToken.id, targetTokenId);
2016
+ }
2017
+ });
2018
+ return { createdCount, linkedCount };
2019
+ }
2020
+ async function confirmSourceImport(db, userId, sourceId, proposals) {
2021
+ let createdCount = 0;
2022
+ let linkedCount = 0;
2023
+ await db.transaction(async (tx) => {
2024
+ const source = await tx.prepare("SELECT id FROM sources WHERE id = ?").get(sourceId);
2025
+ if (!source) {
2026
+ throw new Error(`Source not found: ${sourceId}`);
2027
+ }
2028
+ for (const card of proposals) {
2029
+ const baseText = card.question && card.question.trim().length > 0 ? card.question : card.concept;
2030
+ const cleanDomain = slugify(card.domain || "");
2031
+ const cleanBase = slugify(baseText);
2032
+ let baseSlug = cleanDomain ? `${cleanDomain}-${cleanBase}` : cleanBase;
2033
+ if (baseSlug.length > 60) {
2034
+ baseSlug = baseSlug.slice(0, 60).replace(/-$/, "");
2035
+ }
2036
+ if (!baseSlug) {
2037
+ baseSlug = "token";
2038
+ }
2039
+ let token = await getTokenBySlug(tx, baseSlug);
2040
+ if (!token) {
2041
+ const finalSlug = await generateTokenSlug(
2042
+ tx,
2043
+ card.domain,
2044
+ card.concept,
2045
+ card.question
2046
+ );
2047
+ const bloom = card.bloom_level !== void 0 ? card.bloom_level : 1;
2048
+ let symbiosisMode = null;
2049
+ if (card.symbiosis_mode && card.symbiosis_mode !== "none") {
2050
+ symbiosisMode = card.symbiosis_mode;
2051
+ }
2052
+ token = await createToken(tx, {
2053
+ slug: finalSlug,
2054
+ concept: card.concept,
2055
+ domain: card.domain,
2056
+ bloom_level: bloom,
2057
+ context: card.excerpt || "",
2058
+ symbiosis_mode: symbiosisMode,
2059
+ question: card.question || null
2060
+ });
2061
+ createdCount++;
2062
+ } else {
2063
+ linkedCount++;
2064
+ }
2065
+ const existingCard = await getCard(tx, token.id, userId);
2066
+ if (!existingCard) {
2067
+ await ensureCard(tx, token.id, userId);
2068
+ }
2069
+ await tx.prepare(
2070
+ `INSERT INTO token_sources (token_id, source_id, excerpt, page_number)
2071
+ VALUES (?, ?, ?, ?)
2072
+ ON CONFLICT(token_id, source_id) DO UPDATE SET
2073
+ excerpt = excluded.excerpt,
2074
+ page_number = excluded.page_number`
2075
+ ).run(token.id, sourceId, card.excerpt || "", card.page_number || null);
2076
+ }
2077
+ });
2078
+ return { createdCount, linkedCount };
2079
+ }
2080
+ async function assertPrerequisiteDoesNotCreateCycle(db, tokenId, prerequisiteId) {
2081
+ const cycleCheck = await db.prepare(
2082
+ `WITH RECURSIVE dependents(token_id) AS (
2083
+ SELECT token_id FROM prerequisites WHERE requires_id = ?
2084
+ UNION
2085
+ SELECT p.token_id FROM prerequisites p
2086
+ JOIN dependents d ON p.requires_id = d.token_id
2087
+ )
2088
+ SELECT COUNT(*) as n FROM dependents WHERE token_id = ?`
2089
+ ).get(tokenId, prerequisiteId);
2090
+ if (cycleCheck.n > 0) {
2091
+ throw new Error("Cannot add prerequisite: would create a cycle");
2092
+ }
2093
+ }
1649
2094
 
1650
2095
  // src/kernel/models/prerequisite.ts
1651
2096
  async function buildAncestorMap(db) {
@@ -4533,22 +4978,49 @@ function getConfiguredWorkspaces(path = defaultConfigPath()) {
4533
4978
  function saveConfiguredWorkspaces(workspaces, path = defaultConfigPath()) {
4534
4979
  const config = loadInstallConfig(path);
4535
4980
  config.workspaces = workspaces;
4981
+ if (config.activeWorkspaceId && !workspaces.some((workspace) => workspace.id === config.activeWorkspaceId)) {
4982
+ config.activeWorkspaceId = workspaces[0]?.id;
4983
+ }
4536
4984
  saveInstallConfig(config, path);
4537
4985
  }
4986
+ function getActiveWorkspaceId(path = defaultConfigPath()) {
4987
+ return loadInstallConfig(path).activeWorkspaceId;
4988
+ }
4989
+ function setActiveWorkspaceId(id, path = defaultConfigPath()) {
4990
+ const config = loadInstallConfig(path);
4991
+ if (id) {
4992
+ config.activeWorkspaceId = id;
4993
+ } else {
4994
+ delete config.activeWorkspaceId;
4995
+ }
4996
+ saveInstallConfig(config, path);
4997
+ }
4998
+ function getActiveWorkspace(path = defaultConfigPath()) {
4999
+ const config = loadInstallConfig(path);
5000
+ const id = config.activeWorkspaceId;
5001
+ return id ? config.workspaces?.find((workspace) => workspace.id === id) : void 0;
5002
+ }
4538
5003
  function upsertConfiguredWorkspace(workspace, path = defaultConfigPath()) {
4539
- const current = getConfiguredWorkspaces(path);
5004
+ const config = loadInstallConfig(path);
5005
+ const current = config.workspaces ?? [];
4540
5006
  const next = [
4541
5007
  ...current.filter((candidate) => candidate.id !== workspace.id),
4542
5008
  workspace
4543
5009
  ];
4544
- saveConfiguredWorkspaces(next, path);
5010
+ config.workspaces = next;
5011
+ saveInstallConfig(config, path);
4545
5012
  return next;
4546
5013
  }
4547
5014
  function removeConfiguredWorkspace(id, path = defaultConfigPath()) {
4548
- const next = getConfiguredWorkspaces(path).filter(
5015
+ const config = loadInstallConfig(path);
5016
+ const next = (config.workspaces ?? []).filter(
4549
5017
  (workspace) => workspace.id !== id
4550
5018
  );
4551
- saveConfiguredWorkspaces(next, path);
5019
+ config.workspaces = next;
5020
+ if (config.activeWorkspaceId === id) {
5021
+ config.activeWorkspaceId = next[0]?.id;
5022
+ }
5023
+ saveInstallConfig(config, path);
4552
5024
  return next;
4553
5025
  }
4554
5026
  function detectSyncProvider(dir) {
@@ -4880,7 +5352,7 @@ function getSystemProfile() {
4880
5352
  import { existsSync as existsSync10 } from "fs";
4881
5353
  import { resolve as resolve2 } from "path";
4882
5354
  async function getRepoPaths(db) {
4883
- const personalSetting = await getSetting(db, "repo.personal") || await getSetting(db, "personal.workspace_dir");
5355
+ const personalSetting = await getSetting(db, "repo.personal") || getActiveWorkspace()?.path;
4884
5356
  const teamSetting = await getSetting(db, "repo.team");
4885
5357
  const orgSetting = await getSetting(db, "repo.org");
4886
5358
  return {
@@ -5067,6 +5539,9 @@ export {
5067
5539
  clearReviewContextCache,
5068
5540
  clearTursoCredentials,
5069
5541
  compareVersions,
5542
+ confirmCardSplit,
5543
+ confirmFoundations,
5544
+ confirmSourceImport,
5070
5545
  createAgentSkill,
5071
5546
  createFSRS,
5072
5547
  createGoal,
@@ -5099,9 +5574,12 @@ export {
5099
5574
  generatePowerShellHooks,
5100
5575
  generatePowerShellUnhooks,
5101
5576
  generatePrompt,
5577
+ generateTokenSlug,
5102
5578
  generateZshHooks,
5103
5579
  generateZshUnhooks,
5104
5580
  getADOCredentials,
5581
+ getActiveWorkspace,
5582
+ getActiveWorkspaceId,
5105
5583
  getAgentSkill,
5106
5584
  getAllSettings,
5107
5585
  getAllSettingsDetailed,
@@ -5142,6 +5620,7 @@ export {
5142
5620
  getUiObserverDir,
5143
5621
  getUserStats,
5144
5622
  hasCommand,
5623
+ importCurriculumCards,
5145
5624
  importSnapshot,
5146
5625
  injectShellHooks,
5147
5626
  installFastFlowLM,
@@ -5152,6 +5631,7 @@ export {
5152
5631
  isUiObservationReport,
5153
5632
  listAgentSkills,
5154
5633
  listGoals,
5634
+ listPersonalCards,
5155
5635
  listProviderApiKeyRefs,
5156
5636
  listTokens,
5157
5637
  loadADOConfig,
@@ -5194,11 +5674,13 @@ export {
5194
5674
  saveMachineAiConfig,
5195
5675
  serializeGoal,
5196
5676
  setADOCredentials,
5677
+ setActiveWorkspaceId,
5197
5678
  setInstallChannel,
5198
5679
  setInstallMode,
5199
5680
  setProviderApiKey,
5200
5681
  setSetting,
5201
5682
  setTursoCredentials,
5683
+ slugify,
5202
5684
  startSession,
5203
5685
  syncObserverSidecarPolicy,
5204
5686
  t,