noteconnection 1.7.0 → 1.8.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.
Files changed (211) hide show
  1. package/LICENSE +674 -21
  2. package/README.md +242 -62
  3. package/dist/src/agent_workspace.contract.parity.test.js +475 -0
  4. package/dist/src/agent_workspace.frontend.test.js +9989 -0
  5. package/dist/src/agent_workspace.locale.contract.test.js +95 -0
  6. package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
  7. package/dist/src/copy.assets.contract.test.js +130 -0
  8. package/dist/src/core/PathBridge.js +28 -3
  9. package/dist/src/export/WorkspaceExportBundle.js +1130 -0
  10. package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
  11. package/dist/src/export/index.js +18 -0
  12. package/dist/src/export/types.js +2 -0
  13. package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
  14. package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
  15. package/dist/src/foundation.release.evidence.contract.test.js +406 -0
  16. package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
  17. package/dist/src/frontend/README.md +242 -62
  18. package/dist/src/frontend/agent_workspace.js +5353 -0
  19. package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
  20. package/dist/src/frontend/analysis.js +31 -4
  21. package/dist/src/frontend/app.js +2178 -62
  22. package/dist/src/frontend/focus_mode_interactions.js +33 -0
  23. package/dist/src/frontend/godot_future_path_renderer.js +540 -0
  24. package/dist/src/frontend/godot_tree_interactions.js +178 -0
  25. package/dist/src/frontend/graph_state.mjs +105 -0
  26. package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
  27. package/dist/src/frontend/i18n.mjs +186 -0
  28. package/dist/src/frontend/index.html +641 -266
  29. package/dist/src/frontend/layout_gpu.js +12 -4
  30. package/dist/src/frontend/locales/en.json +721 -5
  31. package/dist/src/frontend/locales/zh.json +721 -5
  32. package/dist/src/frontend/main.mjs +60 -0
  33. package/dist/src/frontend/markdown_runtime.js +827 -0
  34. package/dist/src/frontend/notemd.css +49 -0
  35. package/dist/src/frontend/notemd.html +7 -1
  36. package/dist/src/frontend/notemd.js +64 -0
  37. package/dist/src/frontend/path.html +107 -0
  38. package/dist/src/frontend/path_app.js +2108 -130
  39. package/dist/src/frontend/path_layout.mjs +143 -0
  40. package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
  41. package/dist/src/frontend/path_modules_bridge.js +486 -0
  42. package/dist/src/frontend/path_state.mjs +118 -0
  43. package/dist/src/frontend/path_styles.css +146 -0
  44. package/dist/src/frontend/path_worker_bridge.mjs +85 -0
  45. package/dist/src/frontend/reader.js +393 -33
  46. package/dist/src/frontend/runtime_bridge.js +67 -54
  47. package/dist/src/frontend/runtime_bridge.mjs +279 -0
  48. package/dist/src/frontend/settings.js +130 -12
  49. package/dist/src/frontend/source_manager.js +190 -21
  50. package/dist/src/frontend/styles.css +2720 -72
  51. package/dist/src/frontend/workbench_state.mjs +101 -0
  52. package/dist/src/frontend/workspace_panes.js +10168 -0
  53. package/dist/src/frontend.locale.contract.test.js +62 -0
  54. package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
  55. package/dist/src/indexing/IndexLifecycle.js +195 -0
  56. package/dist/src/indexing/IndexLifecycle.test.js +49 -0
  57. package/dist/src/indexing/SegmentBuilder.js +64 -0
  58. package/dist/src/indexing/UnitBuilder.js +48 -0
  59. package/dist/src/indexing/types.js +2 -0
  60. package/dist/src/knowledge.api.contract.test.js +170 -0
  61. package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
  62. package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
  63. package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
  64. package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
  65. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
  66. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
  67. package/dist/src/learning/answerReleaseReview.js +4319 -0
  68. package/dist/src/learning/answerReleaseReview.test.js +2888 -0
  69. package/dist/src/learning/api.js +2 -0
  70. package/dist/src/learning/conversationComposer.js +1480 -0
  71. package/dist/src/learning/conversationComposer.test.js +1817 -0
  72. package/dist/src/learning/domains/ConversationManager.js +53 -0
  73. package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
  74. package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
  75. package/dist/src/learning/domains/MasteryEngine.js +387 -0
  76. package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
  77. package/dist/src/learning/domains/QualityEvaluator.js +307 -0
  78. package/dist/src/learning/domains/TutorRouter.js +313 -0
  79. package/dist/src/learning/domains/index.js +33 -0
  80. package/dist/src/learning/domains/types.js +7 -0
  81. package/dist/src/learning/errors.js +29 -0
  82. package/dist/src/learning/evidenceContextAssembler.js +1176 -0
  83. package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
  84. package/dist/src/learning/graphContextAssembler.js +870 -0
  85. package/dist/src/learning/graphContextAssembler.test.js +1033 -0
  86. package/dist/src/learning/index.js +28 -0
  87. package/dist/src/learning/queryBackend.js +1898 -0
  88. package/dist/src/learning/queryBackend.test.js +955 -0
  89. package/dist/src/learning/ragContextPack.js +257 -0
  90. package/dist/src/learning/ragContextPack.test.js +160 -0
  91. package/dist/src/learning/ragPublicText.js +38 -0
  92. package/dist/src/learning/ragSufficiencyJudge.js +161 -0
  93. package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
  94. package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
  95. package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
  96. package/dist/src/learning/requestNormalization.js +198 -0
  97. package/dist/src/learning/runtimeCapability.js +4677 -0
  98. package/dist/src/learning/runtimeCapability.test.js +3635 -0
  99. package/dist/src/learning/store.js +1240 -0
  100. package/dist/src/learning/store.test.js +1126 -0
  101. package/dist/src/learning/tutorAdapter.js +2 -0
  102. package/dist/src/learning/types.js +2 -0
  103. package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
  104. package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
  105. package/dist/src/lfs.asset.policy.contract.test.js +153 -0
  106. package/dist/src/license.policy.contract.test.js +66 -0
  107. package/dist/src/memory/MemoryGovernance.js +74 -0
  108. package/dist/src/memory/MemoryGovernance.test.js +46 -0
  109. package/dist/src/memory/types.js +2 -0
  110. package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
  111. package/dist/src/middleware/auth.js +17 -0
  112. package/dist/src/middleware/body-parser.js +45 -0
  113. package/dist/src/middleware/cors.js +44 -0
  114. package/dist/src/middleware/index.js +21 -0
  115. package/dist/src/middleware/request-trace.js +96 -0
  116. package/dist/src/notemd/AppConfigToml.js +6 -4
  117. package/dist/src/notemd/MermaidProcessor.js +400 -50
  118. package/dist/src/notemd/NotemdService.js +498 -13
  119. package/dist/src/notemd/PromptManager.js +15 -0
  120. package/dist/src/notemd/cli/commands.js +357 -0
  121. package/dist/src/notemd/cli/dispatcher.js +225 -0
  122. package/dist/src/notemd/cli/index.js +169 -0
  123. package/dist/src/notemd/cli/parser.js +68 -0
  124. package/dist/src/notemd/cli/types.js +2 -0
  125. package/dist/src/notemd/constants.js +43 -0
  126. package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
  127. package/dist/src/notemd/diagram/diagramSpec.js +79 -0
  128. package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
  129. package/dist/src/notemd/diagram/intent.js +95 -0
  130. package/dist/src/notemd/diagram/planner.js +71 -0
  131. package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
  132. package/dist/src/notemd/diagram/types.js +18 -0
  133. package/dist/src/notemd/index.js +26 -0
  134. package/dist/src/notemd/operations/capabilityManifest.js +23 -0
  135. package/dist/src/notemd/operations/cliContracts.js +17 -0
  136. package/dist/src/notemd/operations/configProfileCommands.js +85 -0
  137. package/dist/src/notemd/operations/registry.contract.test.js +95 -0
  138. package/dist/src/notemd/operations/registry.js +991 -0
  139. package/dist/src/notemd/operations/types.js +2 -0
  140. package/dist/src/notemd/providerDiagnostics.js +220 -0
  141. package/dist/src/notemd/providerProfiles.js +42 -0
  142. package/dist/src/notemd/providerTemplates.js +231 -0
  143. package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
  144. package/dist/src/notemd/search/SearchManager.js +13 -0
  145. package/dist/src/notemd/search/SearchProvider.js +2 -0
  146. package/dist/src/notemd/search/TavilyProvider.js +44 -0
  147. package/dist/src/notemd.agent.manifest.test.js +85 -0
  148. package/dist/src/notemd.api.contract.test.js +14 -1
  149. package/dist/src/notemd.app_config_toml.test.js +2 -1
  150. package/dist/src/notemd.batch.workflow.test.js +117 -0
  151. package/dist/src/notemd.cli.e2e.test.js +136 -0
  152. package/dist/src/notemd.core.test.js +51 -0
  153. package/dist/src/notemd.diagram.pipeline.test.js +233 -0
  154. package/dist/src/notemd.providerTemplates.test.js +34 -0
  155. package/dist/src/notemd.server.integration.test.js +143 -35
  156. package/dist/src/notemd.workflow.pipeline.test.js +162 -0
  157. package/dist/src/pathbridge.handshake.contract.test.js +16 -2
  158. package/dist/src/pathmode.background.contract.test.js +69 -0
  159. package/dist/src/pathmode.settings.api.contract.test.js +9 -0
  160. package/dist/src/pkg.sidecar.contract.test.js +9 -3
  161. package/dist/src/platform/ExportProfile.js +58 -0
  162. package/dist/src/platform/PlatformCapabilities.js +45 -0
  163. package/dist/src/platform/PlatformCapabilities.test.js +30 -0
  164. package/dist/src/platform/RenderMaterializer.js +33 -0
  165. package/dist/src/platform/RenderMaterializer.test.js +32 -0
  166. package/dist/src/query_backend.external_http.integration.test.js +410 -0
  167. package/dist/src/reader_renderer.js +404 -3
  168. package/dist/src/reader_renderer.test.js +87 -0
  169. package/dist/src/release.godot.mirror.contract.test.js +73 -0
  170. package/dist/src/resources/ResourceRegistry.js +223 -0
  171. package/dist/src/resources/ResourceRegistry.test.js +61 -0
  172. package/dist/src/resources/types.js +2 -0
  173. package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
  174. package/dist/src/routes/data.js +267 -0
  175. package/dist/src/routes/diagnostics.js +51 -0
  176. package/dist/src/routes/index.js +23 -0
  177. package/dist/src/routes/knowledge.js +968 -0
  178. package/dist/src/routes/markdown.js +287 -0
  179. package/dist/src/routes/notemd.js +565 -0
  180. package/dist/src/routes/registry.contract.test.js +130 -0
  181. package/dist/src/routes/render.js +285 -0
  182. package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
  183. package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
  184. package/dist/src/routes/settings.js +6 -0
  185. package/dist/src/routes/staticFiles.js +94 -0
  186. package/dist/src/routes/types.js +2 -0
  187. package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
  188. package/dist/src/server.js +11090 -1549
  189. package/dist/src/server.migration.test.js +193 -21
  190. package/dist/src/server.port.fallback.contract.test.js +63 -0
  191. package/dist/src/session/SessionStateStore.js +81 -0
  192. package/dist/src/session/SessionStateStore.test.js +58 -0
  193. package/dist/src/session/types.js +2 -0
  194. package/dist/src/settings.runtime.contract.test.js +50 -0
  195. package/dist/src/shared/types.contract.test.js +107 -0
  196. package/dist/src/shared/types.js +22 -0
  197. package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
  198. package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
  199. package/dist/src/source_manager.loadflow.test.js +46 -0
  200. package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
  201. package/dist/src/tauri.frontend.build.contract.test.js +60 -0
  202. package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
  203. package/dist/src/utils/RuntimePaths.js +4 -13
  204. package/dist/src/utils/platform.js +153 -0
  205. package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
  206. package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
  207. package/dist/src/workflows/types.js +2 -0
  208. package/dist/src/workspace/WorkspaceRegistry.js +122 -0
  209. package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
  210. package/dist/src/workspace/types.js +2 -0
  211. package/package.json +53 -10
@@ -37,6 +37,7 @@ exports.resolveRuntimePaths = resolveRuntimePaths;
37
37
  const fs = __importStar(require("fs"));
38
38
  const os = __importStar(require("os"));
39
39
  const path = __importStar(require("path"));
40
+ const platform_1 = require("./platform");
40
41
  function isDirectory(targetPath) {
41
42
  try {
42
43
  return fs.existsSync(targetPath) && fs.statSync(targetPath).isDirectory();
@@ -65,17 +66,6 @@ function pickExisting(candidates) {
65
66
  }
66
67
  return null;
67
68
  }
68
- function resolveAppDataRoot(cwd) {
69
- const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
70
- if (localAppData) {
71
- return path.join(localAppData, 'NoteConnection');
72
- }
73
- const home = process.env.HOME || process.env.USERPROFILE;
74
- if (home) {
75
- return path.join(home, '.noteconnection');
76
- }
77
- return path.join(cwd, '.noteconnection');
78
- }
79
69
  function ensureWritableDirectory(targetPath) {
80
70
  try {
81
71
  fs.mkdirSync(targetPath, { recursive: true });
@@ -138,15 +128,16 @@ function resolveRuntimePaths(moduleDir) {
138
128
  path.join(moduleDir, 'frontend')
139
129
  ].filter((v) => Boolean(v)));
140
130
  const frontendDir = pickExisting(frontendCandidates) || path.join(projectRoot, 'dist', 'src', 'frontend');
131
+ const appDataRoot = (0, platform_1.getAppDataDir)();
141
132
  const runtimeDataCandidates = uniqPaths([
142
133
  envRuntimeDataDir,
143
- path.join(resolveAppDataRoot(cwd), 'runtime_data'),
134
+ path.join(appDataRoot, 'runtime_data'),
144
135
  path.join(projectRoot, 'runtime_data'),
145
136
  path.join(cwd, 'runtime_data'),
146
137
  path.join(os.tmpdir(), 'noteconnection', 'runtime_data')
147
138
  ].filter((v) => Boolean(v)));
148
139
  const runtimeDataDirCandidate = runtimeDataCandidates.find((candidate) => ensureWritableDirectory(candidate))
149
- || path.join(resolveAppDataRoot(cwd), 'runtime_data');
140
+ || path.join(appDataRoot, 'runtime_data');
150
141
  if (!ensureWritableDirectory(runtimeDataDirCandidate)) {
151
142
  throw new Error(`Unable to provision writable runtime data directory: ${runtimeDataDirCandidate}`);
152
143
  }
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getPlatform = getPlatform;
37
+ exports.getAppDataDir = getAppDataDir;
38
+ exports.getConfigDir = getConfigDir;
39
+ exports.getCacheDir = getCacheDir;
40
+ exports.getSidecarName = getSidecarName;
41
+ exports.getGodotEnv = getGodotEnv;
42
+ const os = __importStar(require("os"));
43
+ const path = __importStar(require("path"));
44
+ const cachedPlatform = detectPlatform();
45
+ function detectPlatform() {
46
+ const rawOs = process.platform;
47
+ const rawArch = process.arch;
48
+ let osName;
49
+ if (rawOs === 'linux')
50
+ osName = 'linux';
51
+ else if (rawOs === 'darwin')
52
+ osName = 'macos';
53
+ else if (rawOs === 'win32')
54
+ osName = 'windows';
55
+ else if (rawOs === 'android')
56
+ osName = 'android';
57
+ else
58
+ osName = 'unknown';
59
+ let archName;
60
+ if (rawArch === 'x64')
61
+ archName = 'x64';
62
+ else if (rawArch === 'arm64')
63
+ archName = 'arm64';
64
+ else
65
+ archName = 'unknown';
66
+ const triplet = buildTargetTriple(osName, archName);
67
+ const exeSuffix = osName === 'windows' ? '.exe' : '';
68
+ const isWayland = osName === 'linux' && process.env.XDG_SESSION_TYPE === 'wayland';
69
+ return { os: osName, arch: archName, triplet, exeSuffix, isWayland };
70
+ }
71
+ function buildTargetTriple(osName, archName) {
72
+ switch (osName) {
73
+ case 'linux':
74
+ return `x86_64-unknown-linux-gnu`;
75
+ case 'macos':
76
+ return archName === 'arm64'
77
+ ? 'aarch64-apple-darwin'
78
+ : 'x86_64-apple-darwin';
79
+ case 'windows':
80
+ return 'x86_64-pc-windows-msvc';
81
+ default:
82
+ return `${process.arch}-unknown-${process.platform}`;
83
+ }
84
+ }
85
+ function getPlatform() {
86
+ return cachedPlatform;
87
+ }
88
+ function getAppDataDir() {
89
+ const home = os.homedir();
90
+ const platform = cachedPlatform.os;
91
+ switch (platform) {
92
+ case 'macos':
93
+ return path.join(home, 'Library', 'Application Support', 'NoteConnection');
94
+ case 'linux': {
95
+ const xdgData = process.env.XDG_DATA_HOME || path.join(home, '.local', 'share');
96
+ return path.join(xdgData, 'NoteConnection');
97
+ }
98
+ case 'windows': {
99
+ const localAppData = process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local');
100
+ return path.join(localAppData, 'NoteConnection');
101
+ }
102
+ default:
103
+ return path.join(home, '.noteconnection');
104
+ }
105
+ }
106
+ function getConfigDir() {
107
+ const home = os.homedir();
108
+ const platform = cachedPlatform.os;
109
+ switch (platform) {
110
+ case 'macos':
111
+ return path.join(home, 'Library', 'Preferences', 'NoteConnection');
112
+ case 'linux': {
113
+ const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(home, '.config');
114
+ return path.join(xdgConfig, 'NoteConnection');
115
+ }
116
+ case 'windows': {
117
+ const appData = process.env.APPDATA || path.join(home, 'AppData', 'Roaming');
118
+ return path.join(appData, 'NoteConnection');
119
+ }
120
+ default:
121
+ return path.join(home, '.config', 'noteconnection');
122
+ }
123
+ }
124
+ function getCacheDir() {
125
+ const home = os.homedir();
126
+ const platform = cachedPlatform.os;
127
+ switch (platform) {
128
+ case 'macos':
129
+ return path.join(home, 'Library', 'Caches', 'NoteConnection');
130
+ case 'linux': {
131
+ const xdgCache = process.env.XDG_CACHE_HOME || path.join(home, '.cache');
132
+ return path.join(xdgCache, 'NoteConnection');
133
+ }
134
+ case 'windows': {
135
+ const localAppData = process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local');
136
+ return path.join(localAppData, 'NoteConnection', 'Cache');
137
+ }
138
+ default:
139
+ return path.join(home, '.cache', 'noteconnection');
140
+ }
141
+ }
142
+ function getSidecarName(baseName) {
143
+ return `${baseName}-${cachedPlatform.triplet}${cachedPlatform.exeSuffix}`;
144
+ }
145
+ function getGodotEnv() {
146
+ if (cachedPlatform.isWayland) {
147
+ return {
148
+ GDK_BACKEND: 'x11',
149
+ WEBKIT_DISABLE_DMABUF_RENDERER: '1',
150
+ };
151
+ }
152
+ return {};
153
+ }
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkflowArtifactStore = void 0;
4
+ class WorkflowArtifactStore {
5
+ constructor(nextId) {
6
+ this.nextId = nextId;
7
+ this.artifacts = [];
8
+ }
9
+ clonePayload(payload) {
10
+ return JSON.parse(JSON.stringify(payload || {}));
11
+ }
12
+ cloneArtifact(record) {
13
+ return {
14
+ ...record,
15
+ sourceResourceIds: [...record.sourceResourceIds],
16
+ sourceProjectionIds: [...record.sourceProjectionIds],
17
+ payload: this.clonePayload(record.payload),
18
+ };
19
+ }
20
+ recordArtifact(input) {
21
+ const record = {
22
+ artifactId: this.nextId('workflow_artifact'),
23
+ kind: input.kind,
24
+ sessionId: input.sessionId || null,
25
+ userId: input.userId || null,
26
+ workspaceId: input.workspaceId || null,
27
+ corpusId: input.corpusId || null,
28
+ title: input.title,
29
+ sourceResourceIds: Array.from(new Set(input.sourceResourceIds)).filter(Boolean),
30
+ sourceProjectionIds: Array.from(new Set(input.sourceProjectionIds)).filter(Boolean),
31
+ summary: input.summary,
32
+ payload: this.clonePayload(input.payload || {}),
33
+ status: input.status,
34
+ createdAt: input.recordedAt,
35
+ updatedAt: input.recordedAt,
36
+ };
37
+ this.artifacts.unshift(record);
38
+ if (this.artifacts.length > 400) {
39
+ this.artifacts.splice(400);
40
+ }
41
+ return this.cloneArtifact(record);
42
+ }
43
+ getArtifactById(artifactId) {
44
+ const normalizedArtifactId = String(artifactId || '').trim();
45
+ if (!normalizedArtifactId) {
46
+ return null;
47
+ }
48
+ const record = this.artifacts.find((artifact) => artifact.artifactId === normalizedArtifactId);
49
+ return record ? this.cloneArtifact(record) : null;
50
+ }
51
+ listAll() {
52
+ return this.artifacts.map((record) => this.cloneArtifact(record));
53
+ }
54
+ updateArtifact(artifactId, updater) {
55
+ const normalizedArtifactId = String(artifactId || '').trim();
56
+ if (!normalizedArtifactId) {
57
+ return null;
58
+ }
59
+ const index = this.artifacts.findIndex((artifact) => artifact.artifactId === normalizedArtifactId);
60
+ if (index < 0) {
61
+ return null;
62
+ }
63
+ const current = this.cloneArtifact(this.artifacts[index]);
64
+ const updated = updater(current);
65
+ this.artifacts[index] = this.cloneArtifact(updated);
66
+ return this.cloneArtifact(this.artifacts[index]);
67
+ }
68
+ listBySession(sessionId) {
69
+ return this.artifacts
70
+ .filter((record) => record.sessionId === String(sessionId || '').trim())
71
+ .map((record) => this.cloneArtifact(record));
72
+ }
73
+ listByWorkspace(workspaceId, userId) {
74
+ const normalizedWorkspaceId = String(workspaceId || '').trim().toLowerCase();
75
+ const normalizedUserId = String(userId || '').trim();
76
+ if (!normalizedWorkspaceId) {
77
+ return [];
78
+ }
79
+ return this.artifacts
80
+ .filter((record) => record.workspaceId === normalizedWorkspaceId)
81
+ .filter((record) => !normalizedUserId || record.userId === normalizedUserId)
82
+ .map((record) => this.cloneArtifact(record));
83
+ }
84
+ buildSnapshot() {
85
+ return {
86
+ artifacts: this.artifacts.map((artifact) => this.cloneArtifact(artifact)),
87
+ };
88
+ }
89
+ restoreFromSnapshot(snapshot) {
90
+ this.artifacts.length = 0;
91
+ (snapshot?.artifacts || []).forEach((artifact) => {
92
+ this.artifacts.push(this.cloneArtifact(artifact));
93
+ });
94
+ }
95
+ }
96
+ exports.WorkflowArtifactStore = WorkflowArtifactStore;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const WorkflowArtifactStore_1 = require("./WorkflowArtifactStore");
4
+ describe('WorkflowArtifactStore', () => {
5
+ test('records artifacts and lists them by session and workspace', () => {
6
+ let idCounter = 0;
7
+ const store = new WorkflowArtifactStore_1.WorkflowArtifactStore((prefix = 'workflow_artifact') => `${prefix}_${++idCounter}`);
8
+ const artifact = store.recordArtifact({
9
+ kind: 'knowledge_run',
10
+ sessionId: 'session_a',
11
+ userId: 'user_a',
12
+ workspaceId: 'optics',
13
+ corpusId: 'optics',
14
+ title: 'Knowledge run',
15
+ sourceResourceIds: ['resource_1'],
16
+ sourceProjectionIds: ['projection_1'],
17
+ summary: 'Evidence claims recorded',
18
+ payload: {
19
+ knowledgeRun: {
20
+ runId: 'knowledge_run_1',
21
+ },
22
+ },
23
+ status: 'active',
24
+ recordedAt: '2026-05-26T00:00:00.000Z',
25
+ });
26
+ expect(store.listBySession('session_a')).toEqual([artifact]);
27
+ expect(store.listByWorkspace('optics')).toHaveLength(1);
28
+ const restored = new WorkflowArtifactStore_1.WorkflowArtifactStore((prefix = 'workflow_artifact') => `${prefix}_${++idCounter}`);
29
+ restored.restoreFromSnapshot(store.buildSnapshot());
30
+ expect(restored.listByWorkspace('optics')[0]?.artifactId).toBe(artifact.artifactId);
31
+ });
32
+ test('updates persisted artifacts without exposing mutable internal references', () => {
33
+ let idCounter = 0;
34
+ const store = new WorkflowArtifactStore_1.WorkflowArtifactStore((prefix = 'workflow_artifact') => `${prefix}_${++idCounter}`);
35
+ const artifact = store.recordArtifact({
36
+ kind: 'flashcard_batch',
37
+ sessionId: 'session_b',
38
+ userId: 'user_b',
39
+ workspaceId: 'optics',
40
+ corpusId: 'optics',
41
+ title: 'Review batch',
42
+ sourceResourceIds: ['resource_2'],
43
+ sourceProjectionIds: ['projection_2'],
44
+ summary: 'Prepared 1 review card.',
45
+ payload: {
46
+ reviewState: {
47
+ consumedCardIds: [],
48
+ completedReviewCardCount: 0,
49
+ remainingReviewCardCount: 1,
50
+ completedAt: null,
51
+ },
52
+ },
53
+ status: 'active',
54
+ recordedAt: '2026-05-26T01:00:00.000Z',
55
+ });
56
+ const updated = store.updateArtifact(artifact.artifactId, (current) => ({
57
+ ...current,
58
+ status: 'archived',
59
+ updatedAt: '2026-05-26T01:05:00.000Z',
60
+ payload: {
61
+ ...current.payload,
62
+ reviewState: {
63
+ consumedCardIds: ['card_1'],
64
+ completedReviewCardCount: 1,
65
+ remainingReviewCardCount: 0,
66
+ completedAt: '2026-05-26T01:05:00.000Z',
67
+ },
68
+ },
69
+ }));
70
+ expect(updated).not.toBeNull();
71
+ expect(updated?.status).toBe('archived');
72
+ expect((updated?.payload.reviewState).consumedCardIds).toEqual(['card_1']);
73
+ const fetched = store.getArtifactById(artifact.artifactId);
74
+ expect(fetched?.status).toBe('archived');
75
+ expect((fetched?.payload.reviewState).remainingReviewCardCount).toBe(0);
76
+ (updated?.payload.reviewState).consumedCardIds.push('card_2');
77
+ const refetched = store.getArtifactById(artifact.artifactId);
78
+ expect((refetched?.payload.reviewState).consumedCardIds).toEqual(['card_1']);
79
+ });
80
+ });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkspaceRegistry = void 0;
4
+ class WorkspaceRegistry {
5
+ constructor(nextId) {
6
+ this.nextId = nextId;
7
+ this.workspaces = new Map();
8
+ this.bindings = new Map();
9
+ this.bindingIdsByDocumentId = new Map();
10
+ }
11
+ normalizePathPrefix(value) {
12
+ return String(value || '')
13
+ .trim()
14
+ .replace(/\\/g, '/')
15
+ .replace(/\/{2,}/g, '/')
16
+ .replace(/\/+$/g, '')
17
+ .toLowerCase();
18
+ }
19
+ inferCorpusIdFromSourcePath(sourcePath) {
20
+ const normalized = String(sourcePath || '').replace(/\\/g, '/');
21
+ const segments = normalized.split('/').filter(Boolean);
22
+ const normalizeSegment = (value) => String(value || '')
23
+ .trim()
24
+ .toLowerCase()
25
+ .replace(/\.[^.]+$/g, '');
26
+ const kbIndex = segments.findIndex((segment) => segment.toLowerCase() === 'knowledge_base');
27
+ if (kbIndex >= 0 && segments[kbIndex + 1]) {
28
+ return normalizeSegment(segments[kbIndex + 1]) || 'default';
29
+ }
30
+ return segments[0] ? normalizeSegment(segments[0]) || 'default' : 'default';
31
+ }
32
+ ensureWorkspace(params) {
33
+ const corpusId = String(params.corpusId || '').trim().toLowerCase()
34
+ || this.inferCorpusIdFromSourcePath(params.sourcePath);
35
+ const workspaceId = String(params.workspaceId || '').trim().toLowerCase() || corpusId;
36
+ const sourcePathPrefix = this.normalizePathPrefix(params.sourcePath).split('/').slice(0, 2).join('/');
37
+ const existing = this.workspaces.get(workspaceId);
38
+ const nextLanguage = String(params.language || 'unknown').trim().toLowerCase() || 'unknown';
39
+ const languages = Array.from(new Set([...(existing?.languages || []), nextLanguage])).sort((left, right) => left.localeCompare(right));
40
+ const record = {
41
+ workspaceId,
42
+ corpusId,
43
+ name: corpusId,
44
+ sourcePathPrefix,
45
+ languages,
46
+ exportProfileId: String(params.exportProfileId || existing?.exportProfileId || 'desktop-full').trim() || 'desktop-full',
47
+ status: 'active',
48
+ createdAt: existing?.createdAt || params.createdAt,
49
+ updatedAt: params.createdAt,
50
+ };
51
+ this.workspaces.set(workspaceId, record);
52
+ return record;
53
+ }
54
+ bindProjection(params) {
55
+ const documentId = String(params.documentId || '').trim();
56
+ const existingBindingId = documentId ? this.bindingIdsByDocumentId.get(documentId) || '' : '';
57
+ const bindingId = existingBindingId || this.nextId('workspace_binding');
58
+ const previousBinding = existingBindingId ? this.bindings.get(existingBindingId) || null : null;
59
+ const record = {
60
+ bindingId,
61
+ workspaceId: String(params.workspaceId || '').trim().toLowerCase(),
62
+ corpusId: String(params.corpusId || '').trim().toLowerCase(),
63
+ resourceId: params.resourceId,
64
+ projectionId: params.projectionId,
65
+ documentId: documentId || null,
66
+ sourcePath: params.sourcePath,
67
+ createdAt: previousBinding?.createdAt || params.boundAt,
68
+ updatedAt: params.boundAt,
69
+ };
70
+ this.bindings.set(bindingId, record);
71
+ if (documentId) {
72
+ this.bindingIdsByDocumentId.set(documentId, bindingId);
73
+ }
74
+ return record;
75
+ }
76
+ resolveBindingByDocumentId(documentId) {
77
+ const bindingId = this.bindingIdsByDocumentId.get(String(documentId || '').trim());
78
+ if (!bindingId) {
79
+ return null;
80
+ }
81
+ return this.bindings.get(bindingId) || null;
82
+ }
83
+ getWorkspaceById(workspaceId) {
84
+ return this.workspaces.get(String(workspaceId || '').trim().toLowerCase()) || null;
85
+ }
86
+ listBindingsByWorkspace(workspaceId) {
87
+ const normalizedWorkspaceId = String(workspaceId || '').trim().toLowerCase();
88
+ if (!normalizedWorkspaceId) {
89
+ return [];
90
+ }
91
+ return Array.from(this.bindings.values())
92
+ .filter((binding) => binding.workspaceId === normalizedWorkspaceId)
93
+ .sort((left, right) => left.bindingId.localeCompare(right.bindingId));
94
+ }
95
+ listActiveWorkspaces() {
96
+ return Array.from(this.workspaces.values()).filter((workspace) => workspace.status === 'active');
97
+ }
98
+ buildSnapshot() {
99
+ return {
100
+ workspaces: Array.from(this.workspaces.values()).map((workspace) => ({ ...workspace, languages: [...workspace.languages] })),
101
+ bindings: Array.from(this.bindings.values()).map((binding) => ({ ...binding })),
102
+ };
103
+ }
104
+ restoreFromSnapshot(snapshot) {
105
+ this.workspaces.clear();
106
+ this.bindings.clear();
107
+ this.bindingIdsByDocumentId.clear();
108
+ (snapshot?.workspaces || []).forEach((workspace) => {
109
+ this.workspaces.set(workspace.workspaceId, {
110
+ ...workspace,
111
+ languages: [...workspace.languages],
112
+ });
113
+ });
114
+ (snapshot?.bindings || []).forEach((binding) => {
115
+ this.bindings.set(binding.bindingId, { ...binding });
116
+ if (binding.documentId) {
117
+ this.bindingIdsByDocumentId.set(binding.documentId, binding.bindingId);
118
+ }
119
+ });
120
+ }
121
+ }
122
+ exports.WorkspaceRegistry = WorkspaceRegistry;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const WorkspaceRegistry_1 = require("./WorkspaceRegistry");
4
+ describe('WorkspaceRegistry', () => {
5
+ test('ensures workspace from source path and exposes bindings by workspace and document', () => {
6
+ let idCounter = 0;
7
+ const registry = new WorkspaceRegistry_1.WorkspaceRegistry((prefix = 'workspace') => `${prefix}_${++idCounter}`);
8
+ const workspace = registry.ensureWorkspace({
9
+ sourcePath: 'Knowledge_Base/optics/absorption.md',
10
+ language: 'zh',
11
+ exportProfileId: 'mobile-slim',
12
+ createdAt: '2026-05-26T00:00:00.000Z',
13
+ });
14
+ expect(workspace.workspaceId).toBe('optics');
15
+ expect(workspace.exportProfileId).toBe('mobile-slim');
16
+ const binding = registry.bindProjection({
17
+ workspaceId: workspace.workspaceId,
18
+ corpusId: workspace.corpusId,
19
+ resourceId: 'resource_1',
20
+ projectionId: 'projection_1',
21
+ documentId: 'doc_optics',
22
+ sourcePath: 'Knowledge_Base/optics/absorption.md',
23
+ boundAt: '2026-05-26T00:01:00.000Z',
24
+ });
25
+ expect(registry.resolveBindingByDocumentId('doc_optics')).toEqual(binding);
26
+ expect(registry.getWorkspaceById('optics')).toEqual(workspace);
27
+ expect(registry.listBindingsByWorkspace('optics')).toHaveLength(1);
28
+ });
29
+ });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });