noteconnection 1.8.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/README.md +257 -1803
- package/dist/src/agent_workspace.contract.parity.test.js +105 -421
- package/dist/src/agent_workspace.frontend.test.js +410 -11
- 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/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 +265 -2
- 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 +44 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +61 -0
- package/dist/src/foundation.release.evidence.contract.test.js +127 -9
- package/dist/src/foundation.sqlite.runtime.contract.test.js +6 -0
- package/dist/src/frontend/README.md +257 -1803
- package/dist/src/frontend/agent_workspace.js +665 -7
- package/dist/src/frontend/index.html +31 -2
- package/dist/src/frontend/knowledge_projection_contract.js +230 -0
- package/dist/src/frontend/knowledge_projection_store.js +214 -0
- package/dist/src/frontend/libs/path_core.js +158 -42
- package/dist/src/frontend/locales/en.json +32 -0
- package/dist/src/frontend/locales/zh.json +32 -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/path.html +6 -2
- package/dist/src/frontend/simulationWorker.js +1 -1
- package/dist/src/frontend/source_manager.js +110 -4
- package/dist/src/frontend/storage_provider.js +661 -71
- package/dist/src/frontend/styles.css +107 -13
- package/dist/src/frontend/workspace_panes.js +111 -7
- package/dist/src/frontend.runtime.assets.contract.test.js +81 -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 +22 -0
- package/dist/src/indexing/IndexLifecycle.test.js +24 -0
- package/dist/src/knowledge.api.contract.test.js +4 -2
- 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 +4687 -3892
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +418 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +243 -6
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +25 -1
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +13 -5
- 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 +1191 -250
- package/dist/src/learning/answerReleaseReview.test.js +1293 -7
- package/dist/src/learning/answerTaskPlan.js +473 -0
- package/dist/src/learning/conversationComposer.js +627 -386
- package/dist/src/learning/conversationComposer.test.js +1403 -0
- package/dist/src/learning/evidenceContextAssembler.js +312 -120
- 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 +3 -13
- package/dist/src/learning/graphContextAssembler.test.js +2 -2
- 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 +1 -0
- package/dist/src/learning/mobileAnswerProjection.js +104 -0
- package/dist/src/learning/mobileAnswerProjection.test.js +102 -0
- package/dist/src/learning/queryBackend.js +34 -10
- package/dist/src/learning/queryBackend.test.js +21 -0
- package/dist/src/learning/ragContextPack.js +115 -16
- package/dist/src/learning/ragContextPack.test.js +151 -0
- package/dist/src/learning/ragEvidenceQuality.js +96 -0
- package/dist/src/learning/ragEvidenceQuality.test.js +29 -0
- package/dist/src/learning/ragPublicText.js +67 -4
- package/dist/src/learning/ragPublicText.test.js +57 -0
- package/dist/src/learning/ragSufficiencyJudge.js +11 -1
- package/dist/src/learning/ragSufficiencyProviderJudge.js +16 -26
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +51 -0
- package/dist/src/learning/requestNormalization.js +106 -0
- package/dist/src/learning/requestNormalization.test.js +101 -0
- package/dist/src/learning/store.js +116 -12
- package/dist/src/learning/store.test.js +299 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +22 -6
- package/dist/src/learning/vectorAccelerationAdapter.test.js +30 -0
- package/dist/src/learning/workspaceHydration.js +168 -0
- package/dist/src/learning/workspaceHydration.test.js +30 -0
- package/dist/src/license.policy.contract.test.js +9 -4
- package/dist/src/markdown/MarkdownGateway.js +4 -0
- package/dist/src/markdown/MarkdownGateway.test.js +59 -0
- package/dist/src/middleware/SseResponseWriter.js +122 -0
- package/dist/src/middleware/SseResponseWriter.test.js +54 -0
- package/dist/src/middleware/auth.js +28 -7
- package/dist/src/middleware/auth.test.js +33 -0
- package/dist/src/middleware/index.js +2 -1
- 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/ContentGenerator.js +4 -9
- package/dist/src/notemd/FileProcessor.js +4 -9
- package/dist/src/notemd/NotemdService.js +12 -17
- package/dist/src/notemd/Translator.js +4 -9
- package/dist/src/notemd/progressReporter.js +9 -0
- package/dist/src/notemd.server.integration.test.js +119 -4
- package/dist/src/notemd.workflow.pipeline.test.js +1 -1
- package/dist/src/pathbridge.handshake.contract.test.js +29 -0
- package/dist/src/pathbridge.host-adapter.contract.test.js +133 -0
- package/dist/src/pathcore.bundle.contract.test.js +8 -0
- package/dist/src/platform/ExportProfile.js +28 -0
- package/dist/src/platform/MobileBudget.js +11 -0
- package/dist/src/platform/PlatformCapabilities.js +14 -0
- package/dist/src/platform/PlatformCapabilities.test.js +6 -0
- package/dist/src/query_backend.external_http.integration.test.js +2 -2
- package/dist/src/release.godot.mirror.contract.test.js +28 -4
- package/dist/src/resources/ResourceRegistry.js +40 -0
- package/dist/src/resources/ResourceRegistry.test.js +36 -0
- package/dist/src/routes/index.js +0 -4
- package/dist/src/routes/knowledge.js +46 -33
- package/dist/src/routes/knowledgePayload.js +185 -0
- package/dist/src/routes/knowledgePayload.test.js +53 -0
- package/dist/src/routes/markdown.js +8 -0
- package/dist/src/routes/notemd.js +990 -234
- package/dist/src/routes/registry.contract.test.js +5 -2
- package/dist/src/routes/registry.shadow.contract.test.js +22 -0
- package/dist/src/routes/render.js +14 -51
- package/dist/src/runtime.capabilities.test.js +18 -2
- package/dist/src/server.js +566 -1090
- package/dist/src/server.migration.test.js +417 -15
- 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 +6 -3
- package/dist/src/sidecar.supply.readiness.contract.test.js +11 -0
- package/dist/src/simulation.worker.offline.test.js +104 -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 +8 -0
- package/dist/src/tauri.window.evidence.execution.test.js +68 -0
- package/dist/src/utils/RuntimePaths.js +6 -0
- package/dist/src/utils/RuntimePaths.test.js +27 -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/workspace/WorkspaceRegistry.js +13 -0
- package/package.json +32 -10
- package/dist/src/routes/data.js +0 -267
- package/dist/src/routes/diagnostics.js +0 -51
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PathBridge = exports.BRIDGE_INBOUND_SCHEMA_LIMITS = exports.BRIDGE_INBOUND_LIMITS = exports.BRIDGE_BACKPRESSURE_LIMITS = void 0;
|
|
3
|
+
exports.PathBridge = exports.BRIDGE_INBOUND_SCHEMA_LIMITS = exports.BRIDGE_INBOUND_LIMITS = exports.BRIDGE_BACKPRESSURE_LIMITS = exports.PATH_BRIDGE_CAPABILITIES = exports.PATH_BRIDGE_PROTOCOL_VERSION = void 0;
|
|
4
4
|
exports.resolveBridgeInboundSchemaPolicy = resolveBridgeInboundSchemaPolicy;
|
|
5
5
|
exports.resolveBridgeInboundLimitConfig = resolveBridgeInboundLimitConfig;
|
|
6
6
|
exports.parseBridgeInboundEnvelope = parseBridgeInboundEnvelope;
|
|
@@ -8,10 +8,21 @@ exports.computeBridgePathFingerprint = computeBridgePathFingerprint;
|
|
|
8
8
|
exports.buildBridgePathTransportSummary = buildBridgePathTransportSummary;
|
|
9
9
|
exports.validateBridgePathPayload = validateBridgePathPayload;
|
|
10
10
|
const ws_1 = require("ws");
|
|
11
|
+
/** Versioned, host-neutral contract shared by Web, Tauri, Capacitor, and Godot. */
|
|
12
|
+
exports.PATH_BRIDGE_PROTOCOL_VERSION = '2.0';
|
|
13
|
+
exports.PATH_BRIDGE_CAPABILITIES = Object.freeze([
|
|
14
|
+
'path.transport',
|
|
15
|
+
'knowledge.analyze',
|
|
16
|
+
'knowledge.query',
|
|
17
|
+
'knowledge.readEvidence',
|
|
18
|
+
'knowledge.exportBundle',
|
|
19
|
+
'request.cancel',
|
|
20
|
+
]);
|
|
11
21
|
const PATH_REQUEST_TIMEOUT_MS = 3000;
|
|
12
22
|
const PATH_PRODUCER_GRACE_MS = 30000;
|
|
13
23
|
const MERMAID_RENDER_TIMEOUT_MS = 12000;
|
|
14
24
|
const UNAUTHORIZED_CLIENT_TIMEOUT_MS = 5000;
|
|
25
|
+
const DEFAULT_HOST_OPERATION_TIMEOUT_MS = 15000;
|
|
15
26
|
const BYTES_PER_MIB = 1024 * 1024;
|
|
16
27
|
const DEFAULT_INBOUND_MESSAGE_LIMIT_MIB = 128;
|
|
17
28
|
const LARGE_GRAPH_INBOUND_MESSAGE_LIMIT_MIB = 256;
|
|
@@ -131,6 +142,12 @@ const PATH_MUTATION_TYPES = new Set([
|
|
|
131
142
|
const KNOWN_BRIDGE_MESSAGE_TYPES = new Set([
|
|
132
143
|
'authenticate',
|
|
133
144
|
'identify',
|
|
145
|
+
'capabilities',
|
|
146
|
+
'analyze',
|
|
147
|
+
'query',
|
|
148
|
+
'readEvidence',
|
|
149
|
+
'exportBundle',
|
|
150
|
+
'cancel',
|
|
134
151
|
'requestPath',
|
|
135
152
|
'pathResult',
|
|
136
153
|
'pathStatus',
|
|
@@ -247,6 +264,74 @@ function validateRequestPathPayload(payload) {
|
|
|
247
264
|
}
|
|
248
265
|
return null;
|
|
249
266
|
}
|
|
267
|
+
const BRIDGE_CORRELATION_ID_MAX_LENGTH = 128;
|
|
268
|
+
const BRIDGE_CAPABILITY_MAX_COUNT = 32;
|
|
269
|
+
function validateCorrelationId(value, field) {
|
|
270
|
+
if (value === undefined) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
if (!isNonEmptyString(value)) {
|
|
274
|
+
return `${field} must be a non-empty string when provided.`;
|
|
275
|
+
}
|
|
276
|
+
if (value.trim().length > BRIDGE_CORRELATION_ID_MAX_LENGTH) {
|
|
277
|
+
return `${field} must be at most ${BRIDGE_CORRELATION_ID_MAX_LENGTH} characters.`;
|
|
278
|
+
}
|
|
279
|
+
if (/[\u0000-\u001f\u007f]/.test(value)) {
|
|
280
|
+
return `${field} must not contain control characters.`;
|
|
281
|
+
}
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
function validateCapabilitiesPayload(payload) {
|
|
285
|
+
if (payload.protocolVersion !== undefined && !isNonEmptyString(payload.protocolVersion)) {
|
|
286
|
+
return 'capabilities payload.protocolVersion must be a non-empty string when provided.';
|
|
287
|
+
}
|
|
288
|
+
if (payload.client !== undefined && !isNonEmptyString(payload.client)) {
|
|
289
|
+
return 'capabilities payload.client must be a non-empty string when provided.';
|
|
290
|
+
}
|
|
291
|
+
if (!Array.isArray(payload.capabilities)) {
|
|
292
|
+
return 'capabilities payload.capabilities must be an array.';
|
|
293
|
+
}
|
|
294
|
+
if (payload.capabilities.length > BRIDGE_CAPABILITY_MAX_COUNT) {
|
|
295
|
+
return `capabilities payload.capabilities must contain at most ${BRIDGE_CAPABILITY_MAX_COUNT} entries.`;
|
|
296
|
+
}
|
|
297
|
+
if (payload.capabilities.some((capability) => !isNonEmptyString(capability))) {
|
|
298
|
+
return 'capabilities payload.capabilities must contain only non-empty strings.';
|
|
299
|
+
}
|
|
300
|
+
if (payload.maxPayloadBytes !== undefined && !isFiniteNumberValue(payload.maxPayloadBytes)) {
|
|
301
|
+
return 'capabilities payload.maxPayloadBytes must be a finite number when provided.';
|
|
302
|
+
}
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
function validateAnalysisRequestPayload(type, payload) {
|
|
306
|
+
if (!isRecord(payload)) {
|
|
307
|
+
return `${type} payload must be an object.`;
|
|
308
|
+
}
|
|
309
|
+
const requestIdError = validateCorrelationId(payload.requestId, `${type} payload.requestId`);
|
|
310
|
+
if (requestIdError) {
|
|
311
|
+
return requestIdError;
|
|
312
|
+
}
|
|
313
|
+
if (type !== 'cancel' && !isNonEmptyString(payload.requestId)) {
|
|
314
|
+
return `${type} payload.requestId must be a non-empty string.`;
|
|
315
|
+
}
|
|
316
|
+
if (payload.workspaceId !== undefined && !isNonEmptyString(payload.workspaceId)) {
|
|
317
|
+
return `${type} payload.workspaceId must be a non-empty string when provided.`;
|
|
318
|
+
}
|
|
319
|
+
if (payload.sourceUri !== undefined && !isNonEmptyString(payload.sourceUri)) {
|
|
320
|
+
return `${type} payload.sourceUri must be a non-empty string when provided.`;
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
function identifyPayloadCapabilitiesInvalid(payload) {
|
|
325
|
+
if (payload.capabilities === undefined) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
return validateCapabilitiesPayload({
|
|
329
|
+
protocolVersion: payload.protocolVersion,
|
|
330
|
+
client: payload.client ?? payload.tag,
|
|
331
|
+
capabilities: payload.capabilities,
|
|
332
|
+
maxPayloadBytes: payload.maxPayloadBytes,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
250
335
|
function validatePathStatusPayload(payload) {
|
|
251
336
|
if (payload.level !== undefined && !isValidBridgeStatusLevel(payload.level)) {
|
|
252
337
|
return 'pathStatus payload.level must be one of info/success/warning/error when provided.';
|
|
@@ -485,8 +570,22 @@ function validateKnownEnvelopePayload(type, payload, policy) {
|
|
|
485
570
|
if (client !== undefined && typeof client !== 'string') {
|
|
486
571
|
return `${type} client/tag must be a string when provided.`;
|
|
487
572
|
}
|
|
573
|
+
if (identifyPayloadCapabilitiesInvalid(payload)) {
|
|
574
|
+
return identifyPayloadCapabilitiesInvalid(payload);
|
|
575
|
+
}
|
|
488
576
|
}
|
|
489
577
|
return null;
|
|
578
|
+
case 'capabilities':
|
|
579
|
+
if (!isRecord(payload)) {
|
|
580
|
+
return 'capabilities payload must be an object.';
|
|
581
|
+
}
|
|
582
|
+
return validateCapabilitiesPayload(payload);
|
|
583
|
+
case 'analyze':
|
|
584
|
+
case 'query':
|
|
585
|
+
case 'readEvidence':
|
|
586
|
+
case 'exportBundle':
|
|
587
|
+
case 'cancel':
|
|
588
|
+
return validateAnalysisRequestPayload(type, payload);
|
|
490
589
|
case 'requestPath':
|
|
491
590
|
if (payload !== undefined && !isRecord(payload)) {
|
|
492
591
|
return 'requestPath payload must be an object when provided.';
|
|
@@ -593,6 +692,9 @@ function parseBridgeInboundEnvelope(data, policy = BRIDGE_INBOUND_SCHEMA_POLICY)
|
|
|
593
692
|
payload: data.payload,
|
|
594
693
|
token: data.token,
|
|
595
694
|
client: data.client,
|
|
695
|
+
version: data.version,
|
|
696
|
+
requestId: data.requestId,
|
|
697
|
+
correlationId: data.correlationId,
|
|
596
698
|
};
|
|
597
699
|
if (envelope.token !== undefined && typeof envelope.token !== 'string') {
|
|
598
700
|
return {
|
|
@@ -606,6 +708,18 @@ function parseBridgeInboundEnvelope(data, policy = BRIDGE_INBOUND_SCHEMA_POLICY)
|
|
|
606
708
|
reason: 'Bridge message client must be a string when provided.',
|
|
607
709
|
};
|
|
608
710
|
}
|
|
711
|
+
const versionError = validateCorrelationId(envelope.version, 'Bridge message version');
|
|
712
|
+
if (versionError) {
|
|
713
|
+
return { ok: false, reason: versionError };
|
|
714
|
+
}
|
|
715
|
+
const requestIdError = validateCorrelationId(envelope.requestId, 'Bridge message requestId');
|
|
716
|
+
if (requestIdError) {
|
|
717
|
+
return { ok: false, reason: requestIdError };
|
|
718
|
+
}
|
|
719
|
+
const correlationIdError = validateCorrelationId(envelope.correlationId, 'Bridge message correlationId');
|
|
720
|
+
if (correlationIdError) {
|
|
721
|
+
return { ok: false, reason: correlationIdError };
|
|
722
|
+
}
|
|
609
723
|
const isKnownType = KNOWN_BRIDGE_MESSAGE_TYPES.has(type);
|
|
610
724
|
if (!isKnownType && policy.rejectUnknownTypes) {
|
|
611
725
|
return {
|
|
@@ -828,6 +942,7 @@ class PathBridge {
|
|
|
828
942
|
this.currentPath = null;
|
|
829
943
|
this.pendingPathRequests = new Map();
|
|
830
944
|
this.pendingMermaidRenderRequests = new Map();
|
|
945
|
+
this.pendingHostOperations = new Map();
|
|
831
946
|
this.unauthorizedClientTimers = new Map();
|
|
832
947
|
this.outboundQueueState = new Map();
|
|
833
948
|
this.nextMermaidRenderRequestId = 1;
|
|
@@ -840,6 +955,11 @@ class PathBridge {
|
|
|
840
955
|
: 9876;
|
|
841
956
|
this.host = resolvedOptions.host || '127.0.0.1';
|
|
842
957
|
this.authToken = typeof resolvedOptions.authToken === 'string' ? resolvedOptions.authToken.trim() : '';
|
|
958
|
+
this.hostAdapter = resolvedOptions.hostAdapter || null;
|
|
959
|
+
this.hostOperationTimeoutMs = Number.isFinite(Number(resolvedOptions.hostOperationTimeoutMs)) &&
|
|
960
|
+
Number(resolvedOptions.hostOperationTimeoutMs) > 0
|
|
961
|
+
? Math.floor(Number(resolvedOptions.hostOperationTimeoutMs))
|
|
962
|
+
: DEFAULT_HOST_OPERATION_TIMEOUT_MS;
|
|
843
963
|
this.wss = new ws_1.WebSocketServer({
|
|
844
964
|
port: this.port,
|
|
845
965
|
host: this.host,
|
|
@@ -918,6 +1038,7 @@ class PathBridge {
|
|
|
918
1038
|
const wasProducer = !!meta && this.isPathProducerTag(meta.tag);
|
|
919
1039
|
this.clearUnauthorizedDisconnect(ws);
|
|
920
1040
|
this.clearPendingPathRequest(ws);
|
|
1041
|
+
this.cancelHostOperationsForClient(ws, 'client_disconnected');
|
|
921
1042
|
this.clearOutboundQueueState(ws);
|
|
922
1043
|
this.clients.delete(ws);
|
|
923
1044
|
this.clientMeta.delete(ws);
|
|
@@ -1187,7 +1308,11 @@ class PathBridge {
|
|
|
1187
1308
|
}
|
|
1188
1309
|
let serialized = '';
|
|
1189
1310
|
try {
|
|
1190
|
-
serialized = JSON.stringify({
|
|
1311
|
+
serialized = JSON.stringify({
|
|
1312
|
+
type,
|
|
1313
|
+
payload,
|
|
1314
|
+
version: exports.PATH_BRIDGE_PROTOCOL_VERSION,
|
|
1315
|
+
});
|
|
1191
1316
|
}
|
|
1192
1317
|
catch (error) {
|
|
1193
1318
|
const meta = this.clientMeta.get(client);
|
|
@@ -1221,6 +1346,15 @@ class PathBridge {
|
|
|
1221
1346
|
sendStatus(client, payload) {
|
|
1222
1347
|
this.sendMessage(client, 'pathStatus', payload);
|
|
1223
1348
|
}
|
|
1349
|
+
sendCapabilities(client) {
|
|
1350
|
+
this.sendMessage(client, 'capabilities', {
|
|
1351
|
+
protocolVersion: exports.PATH_BRIDGE_PROTOCOL_VERSION,
|
|
1352
|
+
capabilities: [...exports.PATH_BRIDGE_CAPABILITIES],
|
|
1353
|
+
maxPayloadBytes: MAX_INBOUND_MESSAGE_BYTES,
|
|
1354
|
+
hostAdapter: Boolean(this.hostAdapter),
|
|
1355
|
+
hostOperationTimeoutMs: this.hostOperationTimeoutMs,
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1224
1358
|
notifyPendingPathRequests(payload) {
|
|
1225
1359
|
const pendingClients = Array.from(this.pendingPathRequests.keys());
|
|
1226
1360
|
pendingClients.forEach((client) => this.sendStatus(client, payload));
|
|
@@ -1239,6 +1373,17 @@ class PathBridge {
|
|
|
1239
1373
|
clearAllPendingPathRequests() {
|
|
1240
1374
|
Array.from(this.pendingPathRequests.keys()).forEach((client) => this.clearPendingPathRequest(client));
|
|
1241
1375
|
}
|
|
1376
|
+
cancelHostOperationsForClient(client, reason) {
|
|
1377
|
+
Array.from(this.pendingHostOperations.entries()).forEach(([requestId, pending]) => {
|
|
1378
|
+
if (pending.client !== client) {
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
clearTimeout(pending.timer);
|
|
1382
|
+
pending.controller.abort(reason);
|
|
1383
|
+
this.pendingHostOperations.delete(requestId);
|
|
1384
|
+
this.hostAdapter?.cancel?.(requestId);
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1242
1387
|
invalidateCurrentPath(reason) {
|
|
1243
1388
|
if (!this.currentPath) {
|
|
1244
1389
|
return;
|
|
@@ -1451,6 +1596,101 @@ class PathBridge {
|
|
|
1451
1596
|
}
|
|
1452
1597
|
this.broadcast('pathStatus', status);
|
|
1453
1598
|
}
|
|
1599
|
+
sendHostOperationResult(client, operationType, requestId, correlationId, result, error, cancelled = false) {
|
|
1600
|
+
this.sendMessage(client, 'operationResult', {
|
|
1601
|
+
type: operationType,
|
|
1602
|
+
requestId,
|
|
1603
|
+
correlationId,
|
|
1604
|
+
ok: !error && !cancelled,
|
|
1605
|
+
cancelled,
|
|
1606
|
+
result: error || cancelled ? undefined : result,
|
|
1607
|
+
error: error || (cancelled ? 'operation_cancelled' : undefined),
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1610
|
+
executeHostOperation(type, payloadLike, envelope, sender) {
|
|
1611
|
+
if (!this.hostAdapter || !isRecord(payloadLike)) {
|
|
1612
|
+
this.broadcast(type, payloadLike || {});
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
const requestId = typeof payloadLike.requestId === 'string' ? payloadLike.requestId.trim() : '';
|
|
1616
|
+
if (!requestId) {
|
|
1617
|
+
this.sendHostOperationResult(sender, type, '', '', undefined, 'request_id_required');
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
if (this.pendingHostOperations.has(requestId)) {
|
|
1621
|
+
this.sendHostOperationResult(sender, type, requestId, requestId, undefined, 'request_in_flight');
|
|
1622
|
+
return;
|
|
1623
|
+
}
|
|
1624
|
+
const controller = new AbortController();
|
|
1625
|
+
const correlationId = typeof envelope.correlationId === 'string' && envelope.correlationId.trim()
|
|
1626
|
+
? envelope.correlationId.trim()
|
|
1627
|
+
: requestId;
|
|
1628
|
+
const timer = setTimeout(() => {
|
|
1629
|
+
const pending = this.pendingHostOperations.get(requestId);
|
|
1630
|
+
if (!pending) {
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1633
|
+
this.pendingHostOperations.delete(requestId);
|
|
1634
|
+
pending.controller.abort();
|
|
1635
|
+
this.hostAdapter?.cancel?.(requestId);
|
|
1636
|
+
this.sendHostOperationResult(sender, type, requestId, correlationId, undefined, 'operation_timeout');
|
|
1637
|
+
}, this.hostOperationTimeoutMs);
|
|
1638
|
+
const pending = { client: sender, controller, timer };
|
|
1639
|
+
this.pendingHostOperations.set(requestId, pending);
|
|
1640
|
+
const clientTag = this.clientMeta.get(sender)?.tag || 'unknown';
|
|
1641
|
+
Promise.resolve()
|
|
1642
|
+
.then(() => this.hostAdapter.execute({
|
|
1643
|
+
type,
|
|
1644
|
+
requestId,
|
|
1645
|
+
correlationId,
|
|
1646
|
+
payload: payloadLike,
|
|
1647
|
+
clientTag,
|
|
1648
|
+
signal: controller.signal,
|
|
1649
|
+
}))
|
|
1650
|
+
.then((result) => {
|
|
1651
|
+
if (this.pendingHostOperations.get(requestId) !== pending) {
|
|
1652
|
+
return;
|
|
1653
|
+
}
|
|
1654
|
+
this.pendingHostOperations.delete(requestId);
|
|
1655
|
+
clearTimeout(timer);
|
|
1656
|
+
this.sendHostOperationResult(sender, type, requestId, correlationId, result);
|
|
1657
|
+
})
|
|
1658
|
+
.catch((error) => {
|
|
1659
|
+
if (this.pendingHostOperations.get(requestId) !== pending) {
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
this.pendingHostOperations.delete(requestId);
|
|
1663
|
+
clearTimeout(timer);
|
|
1664
|
+
const message = controller.signal.aborted ? 'operation_cancelled' : String(error?.message || error);
|
|
1665
|
+
this.sendHostOperationResult(sender, type, requestId, correlationId, undefined, message, controller.signal.aborted);
|
|
1666
|
+
});
|
|
1667
|
+
}
|
|
1668
|
+
cancelHostOperation(payloadLike, sender) {
|
|
1669
|
+
if (!this.hostAdapter) {
|
|
1670
|
+
// Preserve the pre-adapter relay contract for legacy clients,
|
|
1671
|
+
// including cancellation frames without a request ID.
|
|
1672
|
+
this.broadcast('cancel', payloadLike || {});
|
|
1673
|
+
return;
|
|
1674
|
+
}
|
|
1675
|
+
const payload = isRecord(payloadLike) ? payloadLike : {};
|
|
1676
|
+
const requestId = typeof payload.requestId === 'string' ? payload.requestId.trim() : '';
|
|
1677
|
+
if (!requestId) {
|
|
1678
|
+
this.sendHostOperationResult(sender, 'cancel', '', '', undefined, 'request_id_required');
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
const pending = this.pendingHostOperations.get(requestId);
|
|
1682
|
+
if (pending) {
|
|
1683
|
+
clearTimeout(pending.timer);
|
|
1684
|
+
pending.controller.abort();
|
|
1685
|
+
this.pendingHostOperations.delete(requestId);
|
|
1686
|
+
this.hostAdapter?.cancel?.(requestId);
|
|
1687
|
+
this.sendHostOperationResult(sender, 'cancel', requestId, requestId, undefined, undefined, true);
|
|
1688
|
+
}
|
|
1689
|
+
else {
|
|
1690
|
+
this.sendHostOperationResult(sender, 'cancel', requestId, requestId, undefined, 'operation_not_found');
|
|
1691
|
+
}
|
|
1692
|
+
this.broadcast('cancel', payloadLike || {});
|
|
1693
|
+
}
|
|
1454
1694
|
handleMessage(envelope, sender) {
|
|
1455
1695
|
const { type, payload, client } = envelope;
|
|
1456
1696
|
console.log(`[PathBridge] Received: ${type}`);
|
|
@@ -1461,8 +1701,25 @@ class PathBridge {
|
|
|
1461
1701
|
const identifyPayload = isRecord(payload) ? payload : {};
|
|
1462
1702
|
const requestedTag = identifyPayload.client ?? identifyPayload.tag ?? client ?? 'unknown';
|
|
1463
1703
|
this.setClientTag(sender, String(requestedTag));
|
|
1704
|
+
this.sendCapabilities(sender);
|
|
1464
1705
|
break;
|
|
1465
1706
|
}
|
|
1707
|
+
case 'capabilities':
|
|
1708
|
+
// Capability advertisements are relayed so a Web/Tauri client
|
|
1709
|
+
// can negotiate the same contract with Godot or a mobile peer.
|
|
1710
|
+
this.broadcast('capabilities', payload || {});
|
|
1711
|
+
break;
|
|
1712
|
+
case 'analyze':
|
|
1713
|
+
case 'query':
|
|
1714
|
+
case 'readEvidence':
|
|
1715
|
+
case 'exportBundle':
|
|
1716
|
+
// The optional host adapter owns domain execution while the
|
|
1717
|
+
// bridge retains correlation, timeout, and cancellation policy.
|
|
1718
|
+
this.executeHostOperation(type, payload, envelope, sender);
|
|
1719
|
+
break;
|
|
1720
|
+
case 'cancel':
|
|
1721
|
+
this.cancelHostOperation(payload, sender);
|
|
1722
|
+
break;
|
|
1466
1723
|
case 'requestPath':
|
|
1467
1724
|
this.handlePathRequest(sender);
|
|
1468
1725
|
break;
|
|
@@ -1599,6 +1856,12 @@ class PathBridge {
|
|
|
1599
1856
|
}
|
|
1600
1857
|
close() {
|
|
1601
1858
|
this.clearAllPendingPathRequests();
|
|
1859
|
+
Array.from(this.pendingHostOperations.entries()).forEach(([requestId, pending]) => {
|
|
1860
|
+
clearTimeout(pending.timer);
|
|
1861
|
+
pending.controller.abort();
|
|
1862
|
+
this.hostAdapter?.cancel?.(requestId);
|
|
1863
|
+
});
|
|
1864
|
+
this.pendingHostOperations.clear();
|
|
1602
1865
|
Array.from(this.pendingMermaidRenderRequests.values()).forEach((pendingRequest) => {
|
|
1603
1866
|
clearTimeout(pendingRequest.timer);
|
|
1604
1867
|
pendingRequest.reject(new Error('PathBridge is closing before Mermaid render completed.'));
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeResourceReference = normalizeResourceReference;
|
|
4
|
+
/**
|
|
5
|
+
* Shared, host-neutral reference normalization used by Graph and backend
|
|
6
|
+
* identity generation. It intentionally has no Node or platform dependency so
|
|
7
|
+
* the path-core bundle can execute in a browser VM and in Godot WebView.
|
|
8
|
+
*/
|
|
9
|
+
function normalizeResourceReference(reference) {
|
|
10
|
+
if (typeof reference !== 'string') {
|
|
11
|
+
throw new Error('Resource reference must be a string');
|
|
12
|
+
}
|
|
13
|
+
if (reference.includes('\0')) {
|
|
14
|
+
throw new Error('Resource reference must not contain NUL characters');
|
|
15
|
+
}
|
|
16
|
+
return reference.normalize('NFC').replace(/\\/g, '/').toLowerCase();
|
|
17
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
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
|
+
jest.mock('child_process', () => ({ ...jest.requireActual('child_process'), spawnSync: jest.fn() }));
|
|
41
|
+
const { prepareDesktopGodotPack } = require('../scripts/prepare-desktop-godot-pack');
|
|
42
|
+
const { resolveHostGodotBinaryName } = require('../scripts/tauri-sidecar-utils');
|
|
43
|
+
const runtime = require('../config/godot-desktop-runtime.json');
|
|
44
|
+
const spawn = child_process_1.spawnSync;
|
|
45
|
+
describe('desktop Godot resource package', () => {
|
|
46
|
+
let directory;
|
|
47
|
+
const write = (relative, content) => {
|
|
48
|
+
const file = path.join(directory, relative);
|
|
49
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
50
|
+
fs.writeFileSync(file, content);
|
|
51
|
+
};
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
directory = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'desktop-godot-pack-'));
|
|
54
|
+
write('path_mode/project.godot', `config_version=5\nconfig/features=PackedStringArray("${runtime.version}", "Forward+")\n`);
|
|
55
|
+
write('path_mode/export_presets.cfg', '[preset.0]\nname="Windows Desktop"\n');
|
|
56
|
+
write('path_mode/scenes/main.tscn', '[gd_scene format=3]\n');
|
|
57
|
+
write('path_mode/scripts/main.gd', 'extends Node\n');
|
|
58
|
+
write('path_mode/shaders/main.gdshader', 'shader_type spatial;\n');
|
|
59
|
+
write('path_mode/assets/background.exr', 'fixture');
|
|
60
|
+
write(`src-tauri/bin/${resolveHostGodotBinaryName()}`, 'engine fixture');
|
|
61
|
+
spawn.mockImplementation((_executable, args) => {
|
|
62
|
+
if (args.includes('--version'))
|
|
63
|
+
return { status: 0, stdout: `${runtime.version}.stable.official.fixture\n`, stderr: '' };
|
|
64
|
+
if (args.includes('--export-pack'))
|
|
65
|
+
fs.writeFileSync(args[args.length - 1], 'GDPC resource fixture');
|
|
66
|
+
return { status: 0, stdout: 'done\n', stderr: '' };
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
afterEach(() => {
|
|
70
|
+
jest.resetAllMocks();
|
|
71
|
+
fs.rmSync(directory, { recursive: true, force: true });
|
|
72
|
+
});
|
|
73
|
+
test('exports only runtime roots and binds the pack to source and engine bytes', () => {
|
|
74
|
+
write('path_mode/.godot/editor/state', 'private editor state');
|
|
75
|
+
write('path_mode/tmp/debug.gd', 'debug fixture');
|
|
76
|
+
const report = prepareDesktopGodotPack(directory);
|
|
77
|
+
expect(report.engineVersion).toBe(`${runtime.version}.stable.official.fixture`);
|
|
78
|
+
expect(report.pack.path).toBe('output/desktop/path_mode.pck');
|
|
79
|
+
expect(report.pack.sha256).toMatch(/^[a-f0-9]{64}$/);
|
|
80
|
+
expect(report.files.map((file) => file.path)).toEqual(expect.arrayContaining(['project.godot', 'scenes/main.tscn', 'assets/background.exr']));
|
|
81
|
+
expect(report.files.some((file) => /editor|tmp/.test(file.path))).toBe(false);
|
|
82
|
+
expect(fs.readdirSync(path.join(directory, 'output/desktop')).some(name => name.startsWith('.pathmode-'))).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
test('rejects an engine version that cannot consume the declared project', () => {
|
|
85
|
+
spawn.mockReturnValue({ status: 0, stdout: '4.3.stable.official.fixture\n', stderr: '' });
|
|
86
|
+
expect(() => prepareDesktopGodotPack(directory)).toThrow(/requires Godot/);
|
|
87
|
+
expect(spawn).toHaveBeenCalledTimes(1);
|
|
88
|
+
});
|
|
89
|
+
test('rejects SVG before invoking Godot import', () => {
|
|
90
|
+
write('path_mode/assets/unsupported.svg', '<svg/>');
|
|
91
|
+
expect(() => prepareDesktopGodotPack(directory)).toThrow(/cannot import SVG/);
|
|
92
|
+
expect(spawn.mock.calls.every(([, args]) => args.includes('--version'))).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
test('does not accept zero exit after a Godot script error or replace an earlier pack', () => {
|
|
95
|
+
write('output/desktop/path_mode.pck', 'GDPC previous pack');
|
|
96
|
+
spawn.mockImplementation((_executable, args) => args.includes('--version')
|
|
97
|
+
? { status: 0, stdout: `${runtime.version}.stable.official.fixture`, stderr: '' }
|
|
98
|
+
: { status: 0, stdout: '', stderr: '\u001b[31mSCRIPT ERROR: invalid exported script\u001b[0m\n' });
|
|
99
|
+
expect(() => prepareDesktopGodotPack(directory)).toThrow(/invalid exported script/);
|
|
100
|
+
expect(fs.readFileSync(path.join(directory, 'output/desktop/path_mode.pck'), 'utf8')).toBe('GDPC previous pack');
|
|
101
|
+
});
|
|
102
|
+
test('rejects successful export without a resource pack', () => {
|
|
103
|
+
spawn.mockImplementation((_executable, args) => ({ status: 0, stdout: args.includes('--version') ? `${runtime.version}.stable.official.fixture` : '', stderr: '' }));
|
|
104
|
+
expect(() => prepareDesktopGodotPack(directory)).toThrow(/ENOENT/);
|
|
105
|
+
});
|
|
106
|
+
test('rejects an invalid pack header', () => {
|
|
107
|
+
spawn.mockImplementation((_executable, args) => {
|
|
108
|
+
if (args.includes('--export-pack'))
|
|
109
|
+
fs.writeFileSync(args[args.length - 1], 'not a pack');
|
|
110
|
+
return { status: 0, stdout: args.includes('--version') ? `${runtime.version}.stable.official.fixture` : '', stderr: '' };
|
|
111
|
+
});
|
|
112
|
+
expect(() => prepareDesktopGodotPack(directory)).toThrow(/PCK resource pack/);
|
|
113
|
+
});
|
|
114
|
+
test('rejects source changes between staging and publication', () => {
|
|
115
|
+
spawn.mockImplementation((_executable, args) => {
|
|
116
|
+
if (args.includes('--export-pack')) {
|
|
117
|
+
fs.writeFileSync(args[args.length - 1], 'GDPC resource fixture');
|
|
118
|
+
write('path_mode/scripts/main.gd', 'extends Node\n# changed during export\n');
|
|
119
|
+
}
|
|
120
|
+
return { status: 0, stdout: args.includes('--version') ? `${runtime.version}.stable.official.fixture` : '', stderr: '' };
|
|
121
|
+
});
|
|
122
|
+
expect(() => prepareDesktopGodotPack(directory)).toThrow(/inputs changed/);
|
|
123
|
+
expect(fs.existsSync(path.join(directory, 'output/desktop/path_mode.pck'))).toBe(false);
|
|
124
|
+
});
|
|
125
|
+
test('rejects files added between staging and publication', () => {
|
|
126
|
+
spawn.mockImplementation((_executable, args) => {
|
|
127
|
+
if (args.includes('--export-pack')) {
|
|
128
|
+
fs.writeFileSync(args[args.length - 1], 'GDPC resource fixture');
|
|
129
|
+
write('path_mode/scripts/added.gd', 'extends Node\n');
|
|
130
|
+
}
|
|
131
|
+
return { status: 0, stdout: args.includes('--version') ? `${runtime.version}.stable.official.fixture` : '', stderr: '' };
|
|
132
|
+
});
|
|
133
|
+
expect(() => prepareDesktopGodotPack(directory)).toThrow(/inputs changed/);
|
|
134
|
+
expect(fs.existsSync(path.join(directory, 'output/desktop/path_mode.pck'))).toBe(false);
|
|
135
|
+
});
|
|
136
|
+
test('rejects a symlinked runtime root before importing external files', () => {
|
|
137
|
+
fs.renameSync(path.join(directory, 'path_mode/assets'), path.join(directory, 'external-assets'));
|
|
138
|
+
fs.symlinkSync(path.join(directory, 'external-assets'), path.join(directory, 'path_mode/assets'), process.platform === 'win32' ? 'junction' : 'dir');
|
|
139
|
+
expect(() => prepareDesktopGodotPack(directory)).toThrow(/must not be a symlink/);
|
|
140
|
+
expect(spawn.mock.calls.every(([, args]) => args.includes('--version'))).toBe(true);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
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 vm = __importStar(require("node:vm"));
|
|
37
|
+
const { waitForAcceptanceGraph } = require('../scripts/verify-desktop-runtime');
|
|
38
|
+
const graph = { nodes: [{ id: 'Alpha' }, { id: 'Beta' }], edges: [{ source: 'Alpha', target: 'Beta' }] };
|
|
39
|
+
test('waits past the build reload and returns one snapshot from the ready document', async () => {
|
|
40
|
+
const pages = [
|
|
41
|
+
vm.createContext({ performance: { timeOrigin: 100 }, graphData: graph }),
|
|
42
|
+
vm.createContext({ performance: { timeOrigin: 200 } }),
|
|
43
|
+
vm.createContext({ performance: { timeOrigin: 200 }, graphData: graph }),
|
|
44
|
+
];
|
|
45
|
+
const evaluate = jest.fn(async (expression) => {
|
|
46
|
+
const page = pages.shift();
|
|
47
|
+
if (!page)
|
|
48
|
+
throw new Error('Unexpected extra WebView read');
|
|
49
|
+
return vm.runInContext(expression, page);
|
|
50
|
+
});
|
|
51
|
+
await expect(waitForAcceptanceGraph({ evaluate }, 100)).resolves.toEqual({ nodes: ['Alpha', 'Beta'], edges: 1 });
|
|
52
|
+
expect(evaluate).toHaveBeenCalledTimes(3);
|
|
53
|
+
});
|
|
54
|
+
test('captures lexical graphData and its links before another CDP request can replace the document', async () => {
|
|
55
|
+
const page = vm.createContext({ performance: { timeOrigin: 200 } });
|
|
56
|
+
vm.runInContext(`const graphData = ${JSON.stringify({ nodes: graph.nodes, links: graph.edges })}`, page);
|
|
57
|
+
const evaluate = jest.fn(async (expression) => {
|
|
58
|
+
const snapshot = vm.runInContext(expression, page);
|
|
59
|
+
// Navigation destroys the document after this single serialized CDP response.
|
|
60
|
+
if (evaluate.mock.calls.length > 1)
|
|
61
|
+
throw new Error('Execution context was destroyed');
|
|
62
|
+
return snapshot;
|
|
63
|
+
});
|
|
64
|
+
await expect(waitForAcceptanceGraph({ evaluate }, 100)).resolves.toEqual({ nodes: ['Alpha', 'Beta'], edges: 1 });
|
|
65
|
+
expect(evaluate).toHaveBeenCalledTimes(1);
|
|
66
|
+
});
|
|
@@ -457,6 +457,16 @@ function buildKnowledgeRunReports(records) {
|
|
|
457
457
|
? knowledgeRun.scope
|
|
458
458
|
: {};
|
|
459
459
|
const answerReleaseReview = buildAnswerReleaseReviewSummary(knowledgeRun.answerReleaseReview ?? payload.answerReleaseReview);
|
|
460
|
+
const graphAnswerPlan = (knowledgeRun.graphAnswerPlan ?? payload.graphAnswerPlan);
|
|
461
|
+
const graphAnswerCoverage = (knowledgeRun.graphAnswerCoverage ?? payload.graphAnswerCoverage);
|
|
462
|
+
const answerTaskPlan = (knowledgeRun.answerTaskPlan
|
|
463
|
+
?? graphAnswerPlan?.answerTaskPlan
|
|
464
|
+
?? payload.answerTaskPlan);
|
|
465
|
+
const answerTaskCoverage = (knowledgeRun.answerTaskCoverage
|
|
466
|
+
?? payload.answerTaskCoverage);
|
|
467
|
+
const graphAnswerClaims = Array.isArray(graphAnswerPlan?.claims)
|
|
468
|
+
? graphAnswerPlan.claims.filter((claim) => Boolean(claim && typeof claim === 'object'))
|
|
469
|
+
: [];
|
|
460
470
|
const graphContext = payload.graphContext && typeof payload.graphContext === 'object'
|
|
461
471
|
? payload.graphContext
|
|
462
472
|
: {};
|
|
@@ -510,6 +520,40 @@ function buildKnowledgeRunReports(records) {
|
|
|
510
520
|
: null,
|
|
511
521
|
missingLookupCount,
|
|
512
522
|
},
|
|
523
|
+
...(graphAnswerPlan ? {
|
|
524
|
+
graphAnswerPlan: {
|
|
525
|
+
intent: String(graphAnswerPlan.intent || '').trim(),
|
|
526
|
+
depth: String(graphAnswerPlan.depth || '').trim(),
|
|
527
|
+
anchorAtomId: String(graphAnswerPlan.anchorAtomId || '').trim(),
|
|
528
|
+
claimCount: graphAnswerClaims.length,
|
|
529
|
+
requiredClaimCount: graphAnswerClaims.filter((claim) => claim.required === true).length,
|
|
530
|
+
requiredRoles: Array.isArray(graphAnswerPlan.requiredRoles)
|
|
531
|
+
? graphAnswerPlan.requiredRoles.map((role) => String(role || '').trim()).filter(Boolean)
|
|
532
|
+
: [],
|
|
533
|
+
coverageScore: normalizeOptionalScore(graphAnswerCoverage?.coverageScore),
|
|
534
|
+
missingRequiredClaimIds: Array.isArray(graphAnswerCoverage?.missingRequiredClaimIds)
|
|
535
|
+
? graphAnswerCoverage.missingRequiredClaimIds.map((claimId) => String(claimId || '').trim()).filter(Boolean)
|
|
536
|
+
: [],
|
|
537
|
+
},
|
|
538
|
+
} : {}),
|
|
539
|
+
...(answerTaskPlan ? {
|
|
540
|
+
answerTask: {
|
|
541
|
+
primarySubject: String(answerTaskPlan.primarySubject || '').trim(),
|
|
542
|
+
subtaskCount: Array.isArray(answerTaskPlan.subtasks)
|
|
543
|
+
? answerTaskPlan.subtasks.length
|
|
544
|
+
: 0,
|
|
545
|
+
requiredSubtaskCount: Array.isArray(answerTaskPlan.subtasks)
|
|
546
|
+
? answerTaskPlan.subtasks.filter((subtask) => Boolean(subtask && typeof subtask === 'object' && subtask.required === true)).length
|
|
547
|
+
: 0,
|
|
548
|
+
missingRequiredSubtaskIds: Array.isArray(answerTaskCoverage?.missingRequiredSubtaskIds)
|
|
549
|
+
? answerTaskCoverage.missingRequiredSubtaskIds.map((id) => String(id || '').trim()).filter(Boolean)
|
|
550
|
+
: [],
|
|
551
|
+
learningRouteNodeCount: Array.isArray(answerTaskPlan.learningRoute)
|
|
552
|
+
? answerTaskPlan.learningRoute.length
|
|
553
|
+
: 0,
|
|
554
|
+
coverageScore: normalizeOptionalScore(answerTaskCoverage?.coverageScore),
|
|
555
|
+
},
|
|
556
|
+
} : {}),
|
|
513
557
|
...(answerReleaseReview ? { answerReleaseReview } : {}),
|
|
514
558
|
};
|
|
515
559
|
});
|