noteconnection 1.7.0 → 1.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/LICENSE +674 -21
- package/README.md +260 -1626
- package/dist/src/agent_workspace.contract.parity.test.js +159 -0
- package/dist/src/agent_workspace.frontend.test.js +10388 -0
- package/dist/src/agent_workspace.locale.contract.test.js +95 -0
- package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
- package/dist/src/android.knowledgebase.picker.contract.test.js +102 -0
- package/dist/src/appimage.patchelf.test.js +113 -0
- package/dist/src/appimage.portability.test.js +156 -0
- package/dist/src/backend/FileLoader.js +18 -4
- package/dist/src/backend/FileLoader.test.js +125 -0
- package/dist/src/backend/GraphBuilder.identity.test.js +86 -0
- package/dist/src/backend/GraphBuilder.js +66 -18
- package/dist/src/backend/GraphBuilder.matching.test.js +127 -0
- package/dist/src/backend/GraphMetrics.js +0 -3
- package/dist/src/backend/ResourceIdentity.js +155 -0
- package/dist/src/backend/ResourceIdentity.test.js +113 -0
- package/dist/src/backend/algorithms/CycleDetection.js +0 -1
- package/dist/src/backend/algorithms/HybridEngine.js +0 -3
- package/dist/src/backend/algorithms/LayoutEngine.js +0 -1
- package/dist/src/backend/algorithms/StatisticalAnalyzer.js +0 -4
- package/dist/src/backend/algorithms/TopologicalSort.js +0 -2
- package/dist/src/backend/build_dag.js +0 -1
- package/dist/src/capacitor.bridge.serialization.contract.test.js +3 -0
- package/dist/src/capacitor.runtime.contract.test.js +11 -2
- package/dist/src/copy.assets.contract.test.js +130 -0
- package/dist/src/core/Graph.js +138 -42
- package/dist/src/core/Graph.test.js +74 -0
- package/dist/src/core/NoteConnection.js +2 -2
- package/dist/src/core/PathBridge.js +293 -5
- package/dist/src/core/ResourceReference.js +17 -0
- package/dist/src/desktop.godot.pack.test.js +142 -0
- package/dist/src/desktop.runtime.graph.test.js +66 -0
- package/dist/src/export/WorkspaceExportBundle.js +1174 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +1541 -0
- package/dist/src/export/index.js +18 -0
- package/dist/src/export/types.js +2 -0
- package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
- package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
- package/dist/src/foundation.release.evidence.contract.test.js +524 -0
- package/dist/src/foundation.sqlite.runtime.contract.test.js +88 -0
- package/dist/src/frontend/README.md +260 -1626
- package/dist/src/frontend/agent_workspace.js +6011 -0
- package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
- package/dist/src/frontend/analysis.js +31 -4
- package/dist/src/frontend/app.js +2178 -62
- package/dist/src/frontend/focus_mode_interactions.js +33 -0
- package/dist/src/frontend/godot_future_path_renderer.js +540 -0
- package/dist/src/frontend/godot_tree_interactions.js +178 -0
- package/dist/src/frontend/graph_state.mjs +105 -0
- package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
- package/dist/src/frontend/i18n.mjs +186 -0
- package/dist/src/frontend/index.html +672 -268
- package/dist/src/frontend/knowledge_projection_contract.js +230 -0
- package/dist/src/frontend/knowledge_projection_store.js +214 -0
- package/dist/src/frontend/layout_gpu.js +12 -4
- package/dist/src/frontend/libs/path_core.js +158 -42
- package/dist/src/frontend/locales/en.json +753 -5
- package/dist/src/frontend/locales/zh.json +753 -5
- package/dist/src/frontend/main.mjs +60 -0
- package/dist/src/frontend/markdown_runtime.js +827 -0
- package/dist/src/frontend/mobile_budget_runtime.js +33 -0
- package/dist/src/frontend/mobile_exact_analyzer.js +393 -0
- package/dist/src/frontend/mobile_identity_contract.js +221 -0
- package/dist/src/frontend/mobile_semantic_comparator.js +264 -0
- package/dist/src/frontend/notemd.css +49 -0
- package/dist/src/frontend/notemd.html +7 -1
- package/dist/src/frontend/notemd.js +64 -0
- package/dist/src/frontend/path.html +113 -2
- package/dist/src/frontend/path_app.js +2108 -130
- package/dist/src/frontend/path_layout.mjs +143 -0
- package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
- package/dist/src/frontend/path_modules_bridge.js +486 -0
- package/dist/src/frontend/path_state.mjs +118 -0
- package/dist/src/frontend/path_styles.css +146 -0
- package/dist/src/frontend/path_worker_bridge.mjs +85 -0
- package/dist/src/frontend/reader.js +393 -33
- package/dist/src/frontend/runtime_bridge.js +67 -54
- package/dist/src/frontend/runtime_bridge.mjs +279 -0
- package/dist/src/frontend/settings.js +130 -12
- package/dist/src/frontend/simulationWorker.js +1 -1
- package/dist/src/frontend/source_manager.js +297 -22
- package/dist/src/frontend/storage_provider.js +661 -71
- package/dist/src/frontend/styles.css +2814 -72
- package/dist/src/frontend/workbench_state.mjs +101 -0
- package/dist/src/frontend/workspace_panes.js +10272 -0
- package/dist/src/frontend.locale.contract.test.js +62 -0
- package/dist/src/frontend.runtime.assets.contract.test.js +81 -0
- package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
- package/dist/src/graph.answer.operator.contract.test.js +72 -0
- package/dist/src/index.js +6 -2
- package/dist/src/index.knowledge-root.test.js +118 -0
- package/dist/src/indexing/IndexLifecycle.js +217 -0
- package/dist/src/indexing/IndexLifecycle.test.js +73 -0
- package/dist/src/indexing/SegmentBuilder.js +64 -0
- package/dist/src/indexing/UnitBuilder.js +48 -0
- package/dist/src/indexing/types.js +2 -0
- package/dist/src/knowledge.api.contract.test.js +172 -0
- package/dist/src/knowledge_projection.contract.test.js +134 -0
- package/dist/src/knowledge_projection_store.test.js +200 -0
- package/dist/src/learning/AnswerQualityEvaluation.js +153 -0
- package/dist/src/learning/AnswerQualityEvaluation.test.js +118 -0
- package/dist/src/learning/KnowledgeLearningPlatform.js +11181 -0
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +745 -0
- package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +3208 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2998 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3936 -0
- package/dist/src/learning/MeasurementEvidenceConflicts.test.js +78 -0
- package/dist/src/learning/PublicAnswerContract.test.js +85 -0
- package/dist/src/learning/PublicEvidenceSelection.test.js +94 -0
- package/dist/src/learning/PublicMeasurementDisclosure.test.js +54 -0
- package/dist/src/learning/agentConversationExecution.js +211 -0
- package/dist/src/learning/agentConversationExecution.test.js +209 -0
- package/dist/src/learning/agentConversationSerialization.js +266 -0
- package/dist/src/learning/agentConversationSerialization.test.js +165 -0
- package/dist/src/learning/agentResponseBudget.js +179 -0
- package/dist/src/learning/agentResponseBudget.test.js +97 -0
- package/dist/src/learning/agentWorkspaceCapabilityContracts.js +65 -0
- package/dist/src/learning/answerReleaseReview.js +5260 -0
- package/dist/src/learning/answerReleaseReview.test.js +4174 -0
- package/dist/src/learning/answerTaskPlan.js +473 -0
- package/dist/src/learning/api.js +2 -0
- package/dist/src/learning/conversationComposer.js +1721 -0
- package/dist/src/learning/conversationComposer.test.js +3220 -0
- package/dist/src/learning/domains/ConversationManager.js +53 -0
- package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
- package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
- package/dist/src/learning/domains/MasteryEngine.js +387 -0
- package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
- package/dist/src/learning/domains/QualityEvaluator.js +307 -0
- package/dist/src/learning/domains/TutorRouter.js +313 -0
- package/dist/src/learning/domains/index.js +33 -0
- package/dist/src/learning/domains/types.js +7 -0
- package/dist/src/learning/errors.js +29 -0
- package/dist/src/learning/evidenceContextAssembler.js +1368 -0
- package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
- package/dist/src/learning/graphAnswerCoverage.js +37 -0
- package/dist/src/learning/graphAnswerCoverage.test.js +93 -0
- package/dist/src/learning/graphAnswerCoverageCalibration.js +59 -0
- package/dist/src/learning/graphAnswerCoverageCalibration.test.js +46 -0
- package/dist/src/learning/graphAnswerFacts.js +94 -0
- package/dist/src/learning/graphAnswerFacts.test.js +39 -0
- package/dist/src/learning/graphAnswerPlan.js +908 -0
- package/dist/src/learning/graphAnswerPlan.test.js +907 -0
- package/dist/src/learning/graphAnswerQualityCalibration.js +255 -0
- package/dist/src/learning/graphAnswerQualityCalibration.test.js +72 -0
- package/dist/src/learning/graphAnswerQualityPolicy.js +30 -0
- package/dist/src/learning/graphClaimMatcher.js +104 -0
- package/dist/src/learning/graphConditionedContext.js +109 -0
- package/dist/src/learning/graphConditionedContext.test.js +99 -0
- package/dist/src/learning/graphContextAssembler.js +860 -0
- package/dist/src/learning/graphContextAssembler.test.js +1033 -0
- package/dist/src/learning/graphExpansionPolicy.js +22 -0
- package/dist/src/learning/graphExpansionPolicy.test.js +33 -0
- package/dist/src/learning/identityMetadata.test.js +26 -0
- package/dist/src/learning/index.js +29 -0
- package/dist/src/learning/mobileAnswerProjection.js +104 -0
- package/dist/src/learning/mobileAnswerProjection.test.js +102 -0
- package/dist/src/learning/queryBackend.js +1922 -0
- package/dist/src/learning/queryBackend.test.js +976 -0
- package/dist/src/learning/ragContextPack.js +356 -0
- package/dist/src/learning/ragContextPack.test.js +311 -0
- package/dist/src/learning/ragEvidenceQuality.js +96 -0
- package/dist/src/learning/ragEvidenceQuality.test.js +29 -0
- package/dist/src/learning/ragPublicText.js +101 -0
- package/dist/src/learning/ragPublicText.test.js +57 -0
- package/dist/src/learning/ragSufficiencyJudge.js +171 -0
- package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.js +217 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +207 -0
- package/dist/src/learning/requestNormalization.js +304 -0
- package/dist/src/learning/requestNormalization.test.js +101 -0
- package/dist/src/learning/runtimeCapability.js +4677 -0
- package/dist/src/learning/runtimeCapability.test.js +3635 -0
- package/dist/src/learning/store.js +1344 -0
- package/dist/src/learning/store.test.js +1425 -0
- package/dist/src/learning/tutorAdapter.js +2 -0
- package/dist/src/learning/types.js +2 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +958 -0
- package/dist/src/learning/vectorAccelerationAdapter.test.js +412 -0
- package/dist/src/learning/workspaceHydration.js +168 -0
- package/dist/src/learning/workspaceHydration.test.js +30 -0
- package/dist/src/lfs.asset.policy.contract.test.js +153 -0
- package/dist/src/license.policy.contract.test.js +71 -0
- package/dist/src/markdown/MarkdownGateway.js +4 -0
- package/dist/src/markdown/MarkdownGateway.test.js +59 -0
- package/dist/src/memory/MemoryGovernance.js +74 -0
- package/dist/src/memory/MemoryGovernance.test.js +46 -0
- package/dist/src/memory/types.js +2 -0
- package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
- package/dist/src/middleware/SseResponseWriter.js +122 -0
- package/dist/src/middleware/SseResponseWriter.test.js +54 -0
- package/dist/src/middleware/auth.js +38 -0
- package/dist/src/middleware/auth.test.js +33 -0
- package/dist/src/middleware/body-parser.js +45 -0
- package/dist/src/middleware/cors.js +44 -0
- package/dist/src/middleware/index.js +22 -0
- package/dist/src/middleware/request-trace.js +96 -0
- package/dist/src/mobile.android.evidence.contract.test.js +146 -0
- package/dist/src/mobile.android.signing.contract.test.js +66 -0
- package/dist/src/mobile.artifact.contract.test.js +144 -0
- package/dist/src/mobile.budget.contract.test.js +90 -0
- package/dist/src/mobile.canonical-id.readiness.test.js +54 -0
- package/dist/src/mobile.graph.parity.contract.test.js +207 -0
- package/dist/src/mobile.identity.contract.test.js +66 -0
- package/dist/src/mobile.identity.corpus.manifest.test.js +72 -0
- package/dist/src/mobile.identity.corpus.test.js +40 -0
- package/dist/src/mobile.native.recovery.contract.test.js +64 -0
- package/dist/src/mobile.pipeline.test.js +11 -1
- package/dist/src/mobile.profile.contract.test.js +225 -0
- package/dist/src/mobile.semantic.parity.test.js +92 -0
- package/dist/src/mobile_exact_analyzer.test.js +113 -0
- package/dist/src/notemd/AppConfigToml.js +6 -4
- package/dist/src/notemd/ContentGenerator.js +4 -9
- package/dist/src/notemd/FileProcessor.js +4 -9
- package/dist/src/notemd/MermaidProcessor.js +400 -50
- package/dist/src/notemd/NotemdService.js +506 -26
- package/dist/src/notemd/PromptManager.js +15 -0
- package/dist/src/notemd/Translator.js +4 -9
- package/dist/src/notemd/cli/commands.js +357 -0
- package/dist/src/notemd/cli/dispatcher.js +225 -0
- package/dist/src/notemd/cli/index.js +169 -0
- package/dist/src/notemd/cli/parser.js +68 -0
- package/dist/src/notemd/cli/types.js +2 -0
- package/dist/src/notemd/constants.js +43 -0
- package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
- package/dist/src/notemd/diagram/diagramSpec.js +79 -0
- package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
- package/dist/src/notemd/diagram/intent.js +95 -0
- package/dist/src/notemd/diagram/planner.js +71 -0
- package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
- package/dist/src/notemd/diagram/types.js +18 -0
- package/dist/src/notemd/index.js +26 -0
- package/dist/src/notemd/operations/capabilityManifest.js +23 -0
- package/dist/src/notemd/operations/cliContracts.js +17 -0
- package/dist/src/notemd/operations/configProfileCommands.js +85 -0
- package/dist/src/notemd/operations/registry.contract.test.js +95 -0
- package/dist/src/notemd/operations/registry.js +991 -0
- package/dist/src/notemd/operations/types.js +2 -0
- package/dist/src/notemd/progressReporter.js +9 -0
- package/dist/src/notemd/providerDiagnostics.js +220 -0
- package/dist/src/notemd/providerProfiles.js +42 -0
- package/dist/src/notemd/providerTemplates.js +231 -0
- package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
- package/dist/src/notemd/search/SearchManager.js +13 -0
- package/dist/src/notemd/search/SearchProvider.js +2 -0
- package/dist/src/notemd/search/TavilyProvider.js +44 -0
- package/dist/src/notemd.agent.manifest.test.js +85 -0
- package/dist/src/notemd.api.contract.test.js +14 -1
- package/dist/src/notemd.app_config_toml.test.js +2 -1
- package/dist/src/notemd.batch.workflow.test.js +117 -0
- package/dist/src/notemd.cli.e2e.test.js +136 -0
- package/dist/src/notemd.core.test.js +51 -0
- package/dist/src/notemd.diagram.pipeline.test.js +233 -0
- package/dist/src/notemd.providerTemplates.test.js +34 -0
- package/dist/src/notemd.server.integration.test.js +262 -39
- package/dist/src/notemd.workflow.pipeline.test.js +162 -0
- package/dist/src/pathbridge.handshake.contract.test.js +45 -2
- package/dist/src/pathbridge.host-adapter.contract.test.js +133 -0
- package/dist/src/pathcore.bundle.contract.test.js +8 -0
- package/dist/src/pathmode.background.contract.test.js +69 -0
- package/dist/src/pathmode.settings.api.contract.test.js +9 -0
- package/dist/src/pkg.sidecar.contract.test.js +9 -3
- package/dist/src/platform/ExportProfile.js +86 -0
- package/dist/src/platform/MobileBudget.js +11 -0
- package/dist/src/platform/PlatformCapabilities.js +59 -0
- package/dist/src/platform/PlatformCapabilities.test.js +36 -0
- package/dist/src/platform/RenderMaterializer.js +33 -0
- package/dist/src/platform/RenderMaterializer.test.js +32 -0
- package/dist/src/query_backend.external_http.integration.test.js +410 -0
- package/dist/src/reader_renderer.js +404 -3
- package/dist/src/reader_renderer.test.js +87 -0
- package/dist/src/release.godot.mirror.contract.test.js +97 -0
- package/dist/src/resources/ResourceRegistry.js +263 -0
- package/dist/src/resources/ResourceRegistry.test.js +97 -0
- package/dist/src/resources/types.js +2 -0
- package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
- package/dist/src/routes/index.js +19 -0
- package/dist/src/routes/knowledge.js +981 -0
- package/dist/src/routes/knowledgePayload.js +185 -0
- package/dist/src/routes/knowledgePayload.test.js +53 -0
- package/dist/src/routes/markdown.js +295 -0
- package/dist/src/routes/notemd.js +1321 -0
- package/dist/src/routes/registry.contract.test.js +133 -0
- package/dist/src/routes/registry.shadow.contract.test.js +22 -0
- package/dist/src/routes/render.js +248 -0
- package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
- package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
- package/dist/src/routes/settings.js +6 -0
- package/dist/src/routes/staticFiles.js +94 -0
- package/dist/src/routes/types.js +2 -0
- package/dist/src/runtime.capabilities.test.js +18 -2
- package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
- package/dist/src/server.js +10342 -1325
- package/dist/src/server.migration.test.js +584 -10
- package/dist/src/server.port.fallback.contract.test.js +63 -0
- package/dist/src/session/SessionStateStore.js +81 -0
- package/dist/src/session/SessionStateStore.test.js +58 -0
- package/dist/src/session/types.js +2 -0
- package/dist/src/settings.runtime.contract.test.js +50 -0
- package/dist/src/shared/types.contract.test.js +107 -0
- package/dist/src/shared/types.js +22 -0
- package/dist/src/sidecar.build.lock.contract.test.js +201 -0
- package/dist/src/sidecar.freshness.contract.test.js +184 -0
- package/dist/src/sidecar.replacement.boundary.contract.test.js +131 -0
- package/dist/src/sidecar.supply.readiness.contract.test.js +155 -0
- package/dist/src/simulation.worker.offline.test.js +104 -0
- package/dist/src/source_manager.loadflow.test.js +46 -0
- package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
- package/dist/src/storage.provider.capacitor.content.contract.test.js +4 -1
- package/dist/src/storage.provider.contract.test.js +152 -1
- package/dist/src/tauri.frontend.build.contract.test.js +68 -0
- package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
- package/dist/src/tauri.window.evidence.execution.test.js +68 -0
- package/dist/src/utils/RuntimePaths.js +10 -13
- package/dist/src/utils/RuntimePaths.test.js +27 -0
- package/dist/src/utils/platform.js +153 -0
- package/dist/src/windows.installer.build.test.js +109 -0
- package/dist/src/windows.installer.payload.test.js +76 -0
- package/dist/src/windows.installer.runtime.test.js +69 -0
- package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
- package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
- package/dist/src/workflows/types.js +2 -0
- package/dist/src/workspace/WorkspaceRegistry.js +135 -0
- package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
- package/dist/src/workspace/types.js +2 -0
- package/package.json +80 -15
|
@@ -0,0 +1,102 @@
|
|
|
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
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
describe('Android knowledge-base picker contract', () => {
|
|
39
|
+
const repoRoot = path.resolve(__dirname, '..');
|
|
40
|
+
const templatePath = path.join(repoRoot, 'src-tauri', 'mobile', 'android', 'KnowledgeBasePickerBridge.kt');
|
|
41
|
+
const patcherPath = path.join(repoRoot, 'scripts', 'apply-tauri-android-pathmode.js');
|
|
42
|
+
const rustPath = path.join(repoRoot, 'src-tauri', 'src', 'lib.rs');
|
|
43
|
+
const sourceManagerPath = path.join(repoRoot, 'src', 'frontend', 'source_manager.js');
|
|
44
|
+
test('uses SAF tree permissions and bounded app-local streaming import', () => {
|
|
45
|
+
const template = fs.readFileSync(templatePath, 'utf8');
|
|
46
|
+
expect(template).toContain('ACTION_OPEN_DOCUMENT_TREE');
|
|
47
|
+
expect(template).toContain('FLAG_GRANT_PERSISTABLE_URI_PERMISSION');
|
|
48
|
+
expect(template).toContain('takePersistableUriPermission');
|
|
49
|
+
expect(template).toContain('context.filesDir, "Knowledge_Base"');
|
|
50
|
+
expect(template).toContain('MAX_DOCUMENT_BYTES');
|
|
51
|
+
expect(template).toContain('MAX_TOTAL_BYTES');
|
|
52
|
+
expect(template).toContain('input.copyTo(output, 32 * 1024)');
|
|
53
|
+
expect(template).toContain('replaceImportedTree');
|
|
54
|
+
expect(template).toContain('Duplicate import path');
|
|
55
|
+
expect(template).toContain('knowledge_base_import_journal.v1.json');
|
|
56
|
+
expect(template).toContain('recoverImportTransaction(activity.applicationContext)');
|
|
57
|
+
expect(template).toContain('target-backed-up');
|
|
58
|
+
expect(template).toContain('target-activated');
|
|
59
|
+
expect(template).toContain('invalid_import_journal');
|
|
60
|
+
expect(template).toContain('output.fd.sync()');
|
|
61
|
+
expect(template).toContain('isSafeTransactionPath');
|
|
62
|
+
expect(template).toContain('isKnownJournalPhase');
|
|
63
|
+
expect(template).toContain('recovered_previous');
|
|
64
|
+
expect(template).toContain('importInFlight');
|
|
65
|
+
expect(template).toContain('import_in_progress');
|
|
66
|
+
expect(template).toContain('synchronized(importLock)');
|
|
67
|
+
expect(template).toContain('Retaining import backup for startup recovery');
|
|
68
|
+
expect(template).toContain('if (!backupRoot.exists())');
|
|
69
|
+
expect(template).toContain('import_recovery_pending');
|
|
70
|
+
expect(template).toContain('Unable to restore import backup; retaining journal for retry');
|
|
71
|
+
expect(template).toContain('orphan_recovery_pending');
|
|
72
|
+
const importFailureCatch = template.match(/Log\.e\(TAG, "Knowledge base import failed"[\s\S]*?writeResult\(resultFile, "failed", "", error\.message \?: "import_failed"\)/)?.[0];
|
|
73
|
+
expect(importFailureCatch).toBeDefined();
|
|
74
|
+
expect(importFailureCatch).not.toContain('backupRoot.deleteRecursively()');
|
|
75
|
+
expect(template).not.toContain('readText()');
|
|
76
|
+
});
|
|
77
|
+
test('patches picker bridge into mobile-slim without enabling Godot', () => {
|
|
78
|
+
const patcher = fs.readFileSync(patcherPath, 'utf8');
|
|
79
|
+
expect(patcher).toContain('KnowledgeBasePickerBridge.kt');
|
|
80
|
+
expect(patcher).toContain('patchKnowledgeBasePicker');
|
|
81
|
+
expect(patcher).toContain('KnowledgeBasePickerBridge.bindActivity(this)');
|
|
82
|
+
expect(patcher).toContain('removePathmodeAssets');
|
|
83
|
+
});
|
|
84
|
+
test('exposes additive request/poll commands and enables the Android capability', () => {
|
|
85
|
+
const rust = fs.readFileSync(rustPath, 'utf8');
|
|
86
|
+
const sourceManager = fs.readFileSync(sourceManagerPath, 'utf8');
|
|
87
|
+
expect(rust).toContain('request_android_knowledge_base_picker');
|
|
88
|
+
expect(rust).toContain('consume_android_knowledge_base_picker_result');
|
|
89
|
+
expect(rust).toContain('kb_import_mode: "android-saf-copy"');
|
|
90
|
+
expect(sourceManager).toContain("request_kb_path_change");
|
|
91
|
+
expect(sourceManager).toContain("poll_kb_path_change");
|
|
92
|
+
expect(sourceManager).toContain('Timed out waiting for Android knowledge base import.');
|
|
93
|
+
});
|
|
94
|
+
test('keeps Android slim packaging size-first and clears stale generated outputs', () => {
|
|
95
|
+
const runner = fs.readFileSync(path.join(repoRoot, 'scripts', 'run-tauri-android.js'), 'utf8');
|
|
96
|
+
expect(runner).toContain("CARGO_PROFILE_RELEASE_OPT_LEVEL || 'z'");
|
|
97
|
+
expect(runner).toContain('CARGO_PROFILE_RELEASE_CODEGEN_UNITS, 1');
|
|
98
|
+
expect(runner).toContain("CARGO_PROFILE_RELEASE_LTO || 'thin'");
|
|
99
|
+
expect(runner).toContain('cleanAndroidSlimOutputs');
|
|
100
|
+
expect(runner).toContain('!includeGodotPathmode');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
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
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const child_process_1 = require("child_process");
|
|
40
|
+
const { sha256File } = require('../scripts/sidecar-build-fingerprint');
|
|
41
|
+
const describeLinux = process.platform === 'linux' ? describe : describe.skip;
|
|
42
|
+
describeLinux('AppImage pkg sidecar patchelf boundary', () => {
|
|
43
|
+
let directory;
|
|
44
|
+
let server;
|
|
45
|
+
let transcript;
|
|
46
|
+
let buildEnvironment;
|
|
47
|
+
const adapter = path.resolve(__dirname, '../scripts/appimage-patchelf.js');
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
directory = fs.mkdtempSync(path.join(os.tmpdir(), 'appimage patchelf '));
|
|
50
|
+
server = path.join(directory, 'NoteConnection.AppDir/usr/bin/server');
|
|
51
|
+
transcript = path.join(directory, 'patchelf-calls.jsonl');
|
|
52
|
+
fs.mkdirSync(path.dirname(server), { recursive: true });
|
|
53
|
+
fs.writeFileSync(server, Buffer.from('\x7fELF embedded offsets\0appended pkg payload'));
|
|
54
|
+
const originalPatchelf = path.join(directory, 'actual-patchelf');
|
|
55
|
+
fs.writeFileSync(originalPatchelf, `#!${process.execPath}\n
|
|
56
|
+
const fs = require('fs');
|
|
57
|
+
const args = process.argv.slice(2);
|
|
58
|
+
fs.appendFileSync(process.env.APPIMAGE_PATCHELF_TEST_LOG, JSON.stringify(args) + '\\n');
|
|
59
|
+
if (args[0] === '--set-rpath') fs.appendFileSync(args[2], ' ELF rewrite');
|
|
60
|
+
process.stdout.write('original stdout\\n');
|
|
61
|
+
process.stderr.write('original stderr\\n');
|
|
62
|
+
process.exit(args[0] === '--fail' ? 23 : 0);
|
|
63
|
+
`, { mode: 0o755 });
|
|
64
|
+
buildEnvironment = {
|
|
65
|
+
...process.env,
|
|
66
|
+
NOTE_CONNECTION_APPIMAGE_PATCHELF: originalPatchelf,
|
|
67
|
+
NOTE_CONNECTION_APPIMAGE_SERVER_SUFFIX: 'NoteConnection.AppDir/usr/bin/server',
|
|
68
|
+
NOTE_CONNECTION_APPIMAGE_SERVER_SHA256: sha256File(server),
|
|
69
|
+
APPIMAGE_PATCHELF_TEST_LOG: transcript,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
afterEach(() => fs.rmSync(directory, { recursive: true, force: true }));
|
|
73
|
+
test('preserves the complete pkg sidecar through repeated RPATH writes', () => {
|
|
74
|
+
for (let scan = 0; scan < 2; scan += 1) {
|
|
75
|
+
const command = (0, child_process_1.spawnSync)(adapter, ['--set-rpath', '$ORIGIN/../lib', server], { env: buildEnvironment, encoding: 'utf8' });
|
|
76
|
+
expect(command.status).toBe(0);
|
|
77
|
+
expect(command.stderr).toBe('');
|
|
78
|
+
}
|
|
79
|
+
expect(sha256File(server)).toBe(buildEnvironment.NOTE_CONNECTION_APPIMAGE_SERVER_SHA256);
|
|
80
|
+
expect(fs.existsSync(transcript)).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
test('forwards read queries and preserves stdout, stderr, and argument boundaries', () => {
|
|
83
|
+
const args = ['--print-rpath', server];
|
|
84
|
+
const command = (0, child_process_1.spawnSync)(adapter, args, { env: buildEnvironment, encoding: 'utf8' });
|
|
85
|
+
expect(command.status).toBe(0);
|
|
86
|
+
expect(command.stdout).toBe('original stdout\n');
|
|
87
|
+
expect(command.stderr).toBe('original stderr\n');
|
|
88
|
+
expect(JSON.parse(fs.readFileSync(transcript, 'utf8'))).toEqual(args);
|
|
89
|
+
expect(sha256File(server)).toBe(buildEnvironment.NOTE_CONNECTION_APPIMAGE_SERVER_SHA256);
|
|
90
|
+
});
|
|
91
|
+
test.each(['other.AppDir/usr/bin/server', 'usr/bin/server', 'NoteConnection.AppDir/usr/bin/npm', 'NoteConnection.AppDir/usr/lib/libexample.so'])('forwards RPATH writes for %s', (relative) => {
|
|
92
|
+
const executable = path.join(directory, relative);
|
|
93
|
+
fs.mkdirSync(path.dirname(executable), { recursive: true });
|
|
94
|
+
fs.writeFileSync(executable, 'other ELF');
|
|
95
|
+
const args = ['--set-rpath', '$ORIGIN/path with spaces', executable];
|
|
96
|
+
const command = (0, child_process_1.spawnSync)(adapter, args, { env: buildEnvironment, encoding: 'utf8' });
|
|
97
|
+
expect(command.status).toBe(0);
|
|
98
|
+
expect(JSON.parse(fs.readFileSync(transcript, 'utf8'))).toEqual(args);
|
|
99
|
+
expect(fs.readFileSync(executable, 'utf8')).toBe('other ELF ELF rewrite');
|
|
100
|
+
});
|
|
101
|
+
test('rejects an already changed packaged server without rewriting it again', () => {
|
|
102
|
+
fs.appendFileSync(server, 'changed');
|
|
103
|
+
const changedSha256 = sha256File(server);
|
|
104
|
+
const command = (0, child_process_1.spawnSync)(adapter, ['--set-rpath', '$ORIGIN/../lib', server], { env: buildEnvironment, encoding: 'utf8' });
|
|
105
|
+
expect(command.status).toBe(1);
|
|
106
|
+
expect(command.stderr).toMatch(/differs from the original pkg sidecar/);
|
|
107
|
+
expect(sha256File(server)).toBe(changedSha256);
|
|
108
|
+
expect(fs.existsSync(transcript)).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
test('preserves a delegated failure exit status', () => {
|
|
111
|
+
expect((0, child_process_1.spawnSync)(adapter, ['--fail'], { env: buildEnvironment }).status).toBe(23);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
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
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const { verifyAppDir, verifySquashfsPermissions } = require('../scripts/verify-appimage');
|
|
40
|
+
const { sha256File } = require('../scripts/sidecar-build-fingerprint');
|
|
41
|
+
describe('stored AppImage permissions', () => {
|
|
42
|
+
test('accepts portable files, directories, and symlinks regardless of stored owner', () => {
|
|
43
|
+
expect(() => verifySquashfsPermissions([
|
|
44
|
+
'drwxr-xr-x 0/0 64 2026-10-03 00:00 squashfs-root',
|
|
45
|
+
'-rwxr-xr-x 0/0 64 2026-10-03 00:00 squashfs-root/AppRun.wrapped',
|
|
46
|
+
'-rw-r--r-- 1001/1001 64 2026-10-03 00:00 squashfs-root/NoteConnection.png',
|
|
47
|
+
'lrwxrwxrwx 0/0 18 2026-10-03 00:00 squashfs-root/.DirIcon -> NoteConnection.png',
|
|
48
|
+
].join('\n'))).not.toThrow();
|
|
49
|
+
});
|
|
50
|
+
test.each(['-rwxrwx---', '-rwxr--r--', '-rw-rw----', 'drwx------', 'drwxr--r--'])('rejects stored mode %s even when the build owner could use it', (mode) => {
|
|
51
|
+
expect(() => verifySquashfsPermissions(`${mode} 0/0 64 2026-10-03 00:00 squashfs-root/entry`))
|
|
52
|
+
.toThrow(/inaccessible to other users/);
|
|
53
|
+
});
|
|
54
|
+
test('rejects missing manifest output', () => {
|
|
55
|
+
expect(() => verifySquashfsPermissions('')).toThrow(/contains no file modes/);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
const describeLinux = process.platform === 'linux' ? describe : describe.skip;
|
|
59
|
+
describeLinux('AppImage desktop integration portability', () => {
|
|
60
|
+
let directory;
|
|
61
|
+
let appDir;
|
|
62
|
+
let sourceServer;
|
|
63
|
+
const desktop = '[Desktop Entry]\nName=NoteConnection\nType=Application\nExec=npm %U\nIcon=npm\nTerminal=false\n';
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
directory = fs.mkdtempSync(path.join(os.tmpdir(), 'appimage portability '));
|
|
66
|
+
appDir = path.join(directory, 'NoteConnection.AppDir');
|
|
67
|
+
fs.mkdirSync(path.join(appDir, 'usr/bin'), { recursive: true });
|
|
68
|
+
fs.mkdirSync(path.join(appDir, 'usr/share/applications'), { recursive: true });
|
|
69
|
+
fs.mkdirSync(path.join(appDir, 'usr/share/icons/hicolor/128x128/apps'), { recursive: true });
|
|
70
|
+
fs.writeFileSync(path.join(appDir, 'AppRun'), '#!/bin/sh\nexec "$APPDIR/AppRun.wrapped" "$@"\n', { mode: 0o755 });
|
|
71
|
+
fs.writeFileSync(path.join(appDir, 'AppRun.wrapped'), '#!/bin/sh\nexit 0\n', { mode: 0o755 });
|
|
72
|
+
fs.writeFileSync(path.join(appDir, 'usr/bin/npm'), '#!/bin/sh\nexit 0\n', { mode: 0o755 });
|
|
73
|
+
sourceServer = path.join(directory, 'original-server');
|
|
74
|
+
fs.writeFileSync(sourceServer, Buffer.from('\x7fELF embedded offsets\0pkg payload'), { mode: 0o755 });
|
|
75
|
+
fs.copyFileSync(sourceServer, path.join(appDir, 'usr/bin/server'));
|
|
76
|
+
fs.writeFileSync(path.join(appDir, 'usr/share/applications/NoteConnection.desktop'), desktop);
|
|
77
|
+
fs.writeFileSync(path.join(appDir, 'NoteConnection.png'), 'icon fixture');
|
|
78
|
+
fs.symlinkSync('usr/share/applications/NoteConnection.desktop', path.join(appDir, 'NoteConnection.desktop'));
|
|
79
|
+
fs.symlinkSync('NoteConnection.png', path.join(appDir, '.DirIcon'));
|
|
80
|
+
fs.symlinkSync('../../../../../../NoteConnection.png', path.join(appDir, 'usr/share/icons/hicolor/128x128/apps/npm.png'));
|
|
81
|
+
});
|
|
82
|
+
afterEach(() => fs.rmSync(directory, { recursive: true, force: true }));
|
|
83
|
+
test('accepts relative integration links after moving the complete image', () => {
|
|
84
|
+
const relocated = path.join(directory, 'relocated image');
|
|
85
|
+
fs.renameSync(appDir, relocated);
|
|
86
|
+
expect(verifyAppDir(relocated, sourceServer)).toEqual({
|
|
87
|
+
desktopPath: path.join(relocated, 'usr/share/applications/NoteConnection.desktop'),
|
|
88
|
+
iconPath: path.join(relocated, 'NoteConnection.png'),
|
|
89
|
+
executablePath: path.join(relocated, 'usr/bin/npm'),
|
|
90
|
+
serverSha256: sha256File(sourceServer),
|
|
91
|
+
name: 'NoteConnection',
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
test('rejects the original absolute .DirIcon link even while its build-host target exists', () => {
|
|
95
|
+
fs.unlinkSync(path.join(appDir, '.DirIcon'));
|
|
96
|
+
fs.symlinkSync(path.join(appDir, 'NoteConnection.png'), path.join(appDir, '.DirIcon'));
|
|
97
|
+
expect(fs.readFileSync(path.join(appDir, '.DirIcon'), 'utf8')).toBe('icon fixture');
|
|
98
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/\.DirIcon: absolute symlink/);
|
|
99
|
+
});
|
|
100
|
+
test.each(['.DirIcon', 'NoteConnection.desktop', 'AppRun', 'AppRun.wrapped', 'usr/bin/npm', 'usr/bin/server'])('rejects dangling integration entry %s', (entry) => {
|
|
101
|
+
fs.unlinkSync(path.join(appDir, entry));
|
|
102
|
+
fs.symlinkSync('missing-file', path.join(appDir, entry));
|
|
103
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/ENOENT/);
|
|
104
|
+
});
|
|
105
|
+
test('rejects a relative link outside the image even when the target exists', () => {
|
|
106
|
+
fs.writeFileSync(path.join(directory, 'outside.png'), 'external icon');
|
|
107
|
+
fs.unlinkSync(path.join(appDir, '.DirIcon'));
|
|
108
|
+
fs.symlinkSync('../outside.png', path.join(appDir, '.DirIcon'));
|
|
109
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/path leaves the AppImage/);
|
|
110
|
+
});
|
|
111
|
+
test('rejects an absolute link hidden in a relative icon chain', () => {
|
|
112
|
+
fs.unlinkSync(path.join(appDir, 'NoteConnection.png'));
|
|
113
|
+
fs.writeFileSync(path.join(directory, 'outside.png'), 'external icon');
|
|
114
|
+
fs.symlinkSync(path.join(directory, 'outside.png'), path.join(appDir, 'NoteConnection.png'));
|
|
115
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/absolute symlink/);
|
|
116
|
+
});
|
|
117
|
+
test('rejects a symlinked ancestor directory leading outside the image', () => {
|
|
118
|
+
fs.renameSync(path.join(appDir, 'usr'), path.join(directory, 'usr'));
|
|
119
|
+
fs.symlinkSync('../usr', path.join(appDir, 'usr'));
|
|
120
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/path leaves the AppImage/);
|
|
121
|
+
});
|
|
122
|
+
test('rejects a symlink cycle', () => {
|
|
123
|
+
fs.unlinkSync(path.join(appDir, '.DirIcon'));
|
|
124
|
+
fs.symlinkSync('.DirIcon', path.join(appDir, '.DirIcon'));
|
|
125
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/symlink loop/);
|
|
126
|
+
});
|
|
127
|
+
test.each(['AppRun', 'AppRun.wrapped', 'usr/bin/npm'])('rejects %s when only the build owner and group can execute it', (entry) => {
|
|
128
|
+
fs.chmodSync(path.join(appDir, entry), 0o770);
|
|
129
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/readable by other users|executable by other users/);
|
|
130
|
+
});
|
|
131
|
+
test('rejects an unreadable icon', () => {
|
|
132
|
+
fs.chmodSync(path.join(appDir, 'NoteConnection.png'), 0o600);
|
|
133
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/readable by other users/);
|
|
134
|
+
});
|
|
135
|
+
test('rejects a sidecar whose appended payload moved during packaging', () => {
|
|
136
|
+
const bytes = fs.readFileSync(sourceServer);
|
|
137
|
+
fs.writeFileSync(path.join(appDir, 'usr/bin/server'), Buffer.concat([bytes.subarray(0, 21), Buffer.alloc(4096), bytes.subarray(21)]));
|
|
138
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/Packaged server differs/);
|
|
139
|
+
});
|
|
140
|
+
test('rejects same-size sidecar corruption', () => {
|
|
141
|
+
const bytes = fs.readFileSync(sourceServer);
|
|
142
|
+
bytes[bytes.length - 1] ^= 1;
|
|
143
|
+
fs.writeFileSync(path.join(appDir, 'usr/bin/server'), bytes);
|
|
144
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(/Packaged server differs/);
|
|
145
|
+
});
|
|
146
|
+
test.each([
|
|
147
|
+
['Name=NoteConnection\n', '', /missing Name/],
|
|
148
|
+
['Type=Application', 'Type=Link', /Type must be Application/],
|
|
149
|
+
['Exec=npm %U', 'Exec=missing', /ENOENT/],
|
|
150
|
+
['Exec=npm %U', 'Exec=/usr/bin/npm', /must name a bundled executable/],
|
|
151
|
+
['Icon=npm', 'Icon=missing', /no bundled theme image/],
|
|
152
|
+
])('rejects invalid desktop metadata (%s)', (before, after, message) => {
|
|
153
|
+
fs.writeFileSync(path.join(appDir, 'usr/share/applications/NoteConnection.desktop'), desktop.replace(before, after));
|
|
154
|
+
expect(() => verifyAppDir(appDir, sourceServer)).toThrow(message);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.FileLoader = void 0;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
+
const ResourceIdentity_1 = require("./ResourceIdentity");
|
|
39
40
|
/**
|
|
40
41
|
* Service to load files from a directory.
|
|
41
42
|
* 从目录加载文件的服务。
|
|
@@ -47,13 +48,19 @@ class FileLoader {
|
|
|
47
48
|
* @param dirPath Directory path | 目录路径
|
|
48
49
|
* @param extensions File extensions to include (e.g., ['.md']) | 要包含的文件扩展名
|
|
49
50
|
*/
|
|
50
|
-
static async loadFiles(dirPath, extensions = ['.md']) {
|
|
51
|
+
static async loadFiles(dirPath, extensions = ['.md'], workspaceRoot = dirPath) {
|
|
51
52
|
const filePaths = [];
|
|
52
|
-
// Check if directory exists
|
|
53
53
|
if (!fs.existsSync(dirPath)) {
|
|
54
54
|
console.warn(`Directory not found: ${dirPath}`);
|
|
55
55
|
return [];
|
|
56
56
|
}
|
|
57
|
+
// Compare canonical directories before scanning: an alias must neither
|
|
58
|
+
// escape the workspace nor give the same source a second relative identity.
|
|
59
|
+
const identityRoot = fs.realpathSync.native(workspaceRoot);
|
|
60
|
+
const scanRoot = fs.realpathSync.native(dirPath);
|
|
61
|
+
if (scanRoot !== identityRoot) {
|
|
62
|
+
(0, ResourceIdentity_1.normalizeResourceRelativePath)(identityRoot, scanRoot);
|
|
63
|
+
}
|
|
57
64
|
// 1. Gather all file paths first (Sequential directory scan is safer for handles)
|
|
58
65
|
async function scanDir(currentPath) {
|
|
59
66
|
// Use withFileTypes to avoid extra stat calls
|
|
@@ -76,7 +83,7 @@ class FileLoader {
|
|
|
76
83
|
console.warn(`Failed to read directory: ${currentPath}`, e);
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
|
-
await scanDir(
|
|
86
|
+
await scanDir(scanRoot);
|
|
80
87
|
// 2. Read files with concurrency limit
|
|
81
88
|
const results = [];
|
|
82
89
|
const CONCURRENCY_LIMIT = 100; // Conservative limit
|
|
@@ -87,10 +94,17 @@ class FileLoader {
|
|
|
87
94
|
try {
|
|
88
95
|
const content = await fs.promises.readFile(fullPath, 'utf-8');
|
|
89
96
|
const filename = path.basename(fullPath, path.extname(fullPath));
|
|
97
|
+
const relativePath = (0, ResourceIdentity_1.normalizeResourceRelativePath)(identityRoot, fullPath);
|
|
98
|
+
const identity = (0, ResourceIdentity_1.createResourceIdentity)(relativePath, filename, content);
|
|
90
99
|
return {
|
|
91
100
|
filepath: fullPath,
|
|
92
101
|
filename: filename,
|
|
93
|
-
content: content
|
|
102
|
+
content: content,
|
|
103
|
+
relativePath,
|
|
104
|
+
sourceUri: identity.sourceUri,
|
|
105
|
+
canonicalId: identity.canonicalId,
|
|
106
|
+
revision: identity.revision,
|
|
107
|
+
identityAliases: identity.identityAliases,
|
|
94
108
|
};
|
|
95
109
|
}
|
|
96
110
|
catch (e) {
|
|
@@ -0,0 +1,125 @@
|
|
|
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
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const FileLoader_1 = require("./FileLoader");
|
|
40
|
+
describe('FileLoader resource paths', () => {
|
|
41
|
+
test('records a normalized path relative to the loaded workspace', async () => {
|
|
42
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'noteconnection-file-loader-'));
|
|
43
|
+
const nested = path.join(root, 'algebra');
|
|
44
|
+
fs.mkdirSync(nested, { recursive: true });
|
|
45
|
+
fs.writeFileSync(path.join(nested, 'index.md'), '# Algebra', 'utf8');
|
|
46
|
+
try {
|
|
47
|
+
const files = await FileLoader_1.FileLoader.loadFiles(root);
|
|
48
|
+
expect(files).toHaveLength(1);
|
|
49
|
+
expect(files[0].relativePath).toBe('algebra/index.md');
|
|
50
|
+
expect(files[0].sourceUri).toBe('note://workspace/v1/algebra/index.md');
|
|
51
|
+
expect(files[0].canonicalId).toBe('algebra/index');
|
|
52
|
+
expect(files[0].revision).toMatch(/^sha256:[0-9a-f]{64}$/);
|
|
53
|
+
expect(files[0].identityAliases).toEqual(expect.arrayContaining([
|
|
54
|
+
'index',
|
|
55
|
+
'algebra/index.md',
|
|
56
|
+
]));
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
test('keeps identity stable when loading a workspace subdirectory', async () => {
|
|
63
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'noteconnection-file-loader-root-'));
|
|
64
|
+
const nested = path.join(root, 'algebra');
|
|
65
|
+
fs.mkdirSync(nested, { recursive: true });
|
|
66
|
+
fs.writeFileSync(path.join(nested, 'index.md'), '# Algebra', 'utf8');
|
|
67
|
+
try {
|
|
68
|
+
const files = await FileLoader_1.FileLoader.loadFiles(nested, ['.md'], root);
|
|
69
|
+
expect(files).toHaveLength(1);
|
|
70
|
+
expect(files[0].relativePath).toBe('algebra/index.md');
|
|
71
|
+
expect(files[0].sourceUri).toBe('note://workspace/v1/algebra/index.md');
|
|
72
|
+
expect(files[0].canonicalId).toBe('algebra/index');
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
test('rejects an outside scan directory instead of returning an empty successful load', async () => {
|
|
79
|
+
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'noteconnection-file-loader-boundary-'));
|
|
80
|
+
const workspaceRoot = path.join(fixtureRoot, 'workspace');
|
|
81
|
+
const outside = path.join(fixtureRoot, 'outside');
|
|
82
|
+
fs.mkdirSync(workspaceRoot);
|
|
83
|
+
fs.mkdirSync(outside);
|
|
84
|
+
fs.writeFileSync(path.join(outside, 'private.md'), '# Outside');
|
|
85
|
+
try {
|
|
86
|
+
await expect(FileLoader_1.FileLoader.loadFiles(outside, ['.md'], workspaceRoot)).rejects.toThrow(/outside workspace root/i);
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
fs.rmSync(fixtureRoot, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
test('rejects a scan directory that escapes the workspace through a symlink', async () => {
|
|
93
|
+
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'noteconnection-file-loader-symlink-'));
|
|
94
|
+
const workspaceRoot = path.join(fixtureRoot, 'workspace');
|
|
95
|
+
const outside = path.join(fixtureRoot, 'outside');
|
|
96
|
+
fs.mkdirSync(workspaceRoot);
|
|
97
|
+
fs.mkdirSync(outside);
|
|
98
|
+
fs.writeFileSync(path.join(outside, 'private.md'), '# Outside');
|
|
99
|
+
const link = path.join(workspaceRoot, 'linked');
|
|
100
|
+
fs.symlinkSync(outside, link, process.platform === 'win32' ? 'junction' : 'dir');
|
|
101
|
+
try {
|
|
102
|
+
await expect(FileLoader_1.FileLoader.loadFiles(link, ['.md'], workspaceRoot)).rejects.toThrow(/outside workspace root/i);
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
fs.rmSync(fixtureRoot, { recursive: true, force: true });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
test('keeps canonical identities stable through an in-workspace directory alias', async () => {
|
|
109
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'noteconnection-file-loader-alias-'));
|
|
110
|
+
const nested = path.join(root, 'algebra');
|
|
111
|
+
fs.mkdirSync(nested);
|
|
112
|
+
fs.writeFileSync(path.join(nested, 'index.md'), '# Algebra');
|
|
113
|
+
const link = path.join(root, 'alias');
|
|
114
|
+
fs.symlinkSync(nested, link, process.platform === 'win32' ? 'junction' : 'dir');
|
|
115
|
+
try {
|
|
116
|
+
const files = await FileLoader_1.FileLoader.loadFiles(link, ['.md'], root);
|
|
117
|
+
expect(files).toHaveLength(1);
|
|
118
|
+
expect(files[0].relativePath).toBe('algebra/index.md');
|
|
119
|
+
expect(files[0].sourceUri).toBe('note://workspace/v1/algebra/index.md');
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const GraphBuilder_1 = require("./GraphBuilder");
|
|
4
|
+
const config_1 = require("./config");
|
|
5
|
+
describe('GraphBuilder identity compatibility', () => {
|
|
6
|
+
const originalConfig = {
|
|
7
|
+
...config_1.config,
|
|
8
|
+
exclusionList: [...config_1.config.exclusionList],
|
|
9
|
+
};
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
config_1.config.enableTags = false;
|
|
12
|
+
config_1.config.enableStatisticalInference = false;
|
|
13
|
+
config_1.config.enableVectorSimilarity = false;
|
|
14
|
+
config_1.config.enableHybridInference = false;
|
|
15
|
+
config_1.config.enableGPU = false;
|
|
16
|
+
config_1.config.enableGPULayout = false;
|
|
17
|
+
config_1.config.clusteringStrategy = 'folder';
|
|
18
|
+
config_1.config.exclusionList = [];
|
|
19
|
+
});
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
Object.assign(config_1.config, originalConfig);
|
|
22
|
+
});
|
|
23
|
+
test('preserves identity metadata, reads URI frontmatter, and accepts URI layouts', async () => {
|
|
24
|
+
const files = [
|
|
25
|
+
{
|
|
26
|
+
filepath: 'workspace/algebra/a.md',
|
|
27
|
+
filename: 'A',
|
|
28
|
+
content: '# A',
|
|
29
|
+
relativePath: 'algebra/a.md',
|
|
30
|
+
sourceUri: 'note://workspace/v1/algebra/a.md',
|
|
31
|
+
canonicalId: 'algebra/a',
|
|
32
|
+
revision: 'sha256:a',
|
|
33
|
+
identityAliases: ['A', 'algebra/a.md'],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
filepath: 'workspace/algebra/b.md',
|
|
37
|
+
filename: 'B',
|
|
38
|
+
content: '---\nprerequisites:\n - note://workspace/v1/algebra/a.md\n---\n# B',
|
|
39
|
+
relativePath: 'algebra/b.md',
|
|
40
|
+
sourceUri: 'note://workspace/v1/algebra/b.md',
|
|
41
|
+
revision: 'sha256:b',
|
|
42
|
+
identityAliases: ['B', 'algebra/b.md'],
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
const graph = await GraphBuilder_1.GraphBuilder.build(files, new Map([
|
|
46
|
+
['note://workspace/v1/algebra/a.md', { x: 12, y: 34 }],
|
|
47
|
+
]));
|
|
48
|
+
expect(graph.getNode('A')).toEqual(expect.objectContaining({
|
|
49
|
+
sourceUri: 'note://workspace/v1/algebra/a.md',
|
|
50
|
+
canonicalId: 'algebra/a',
|
|
51
|
+
revision: 'sha256:a',
|
|
52
|
+
identityAliases: expect.arrayContaining(['algebra/a.md']),
|
|
53
|
+
x: 12,
|
|
54
|
+
y: 34,
|
|
55
|
+
}));
|
|
56
|
+
expect(graph.getIncomingEdges('B')).toEqual(expect.arrayContaining([
|
|
57
|
+
expect.objectContaining({ source: 'A', target: 'B', type: 'explicit-prerequisite' }),
|
|
58
|
+
]));
|
|
59
|
+
});
|
|
60
|
+
test('uses indexed keyword candidates without changing exact-match semantics', async () => {
|
|
61
|
+
const files = [
|
|
62
|
+
{
|
|
63
|
+
filepath: 'workspace/alpha.md',
|
|
64
|
+
filename: 'Alpha',
|
|
65
|
+
content: 'Alpha is a prerequisite concept.',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
filepath: 'workspace/context.md',
|
|
69
|
+
filename: 'Context',
|
|
70
|
+
content: 'This context mentions Alpha as an explicit phrase.',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
filepath: 'workspace/beta.md',
|
|
74
|
+
filename: 'Beta',
|
|
75
|
+
content: 'This context mentions alphabet but not the standalone concept.',
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
const graph = await GraphBuilder_1.GraphBuilder.build(files);
|
|
79
|
+
expect(graph.getOutgoingEdges('Alpha')).toEqual(expect.arrayContaining([
|
|
80
|
+
expect.objectContaining({ target: 'Context', type: 'keyword-match' }),
|
|
81
|
+
]));
|
|
82
|
+
expect(graph.getOutgoingEdges('Alpha')).not.toEqual(expect.arrayContaining([
|
|
83
|
+
expect.objectContaining({ target: 'Beta', type: 'keyword-match' }),
|
|
84
|
+
]));
|
|
85
|
+
});
|
|
86
|
+
});
|