backup: preserve pre-native-foundation runtime work
This commit is contained in:
parent
a4cba27d3c
commit
71dbcd62ec
23 changed files with 3647 additions and 196 deletions
|
|
@ -172,9 +172,14 @@
|
|||
"decide_authorization_request",
|
||||
"set_external_ai_gateway_exposure",
|
||||
"get_conversation",
|
||||
"list_conversations",
|
||||
"create_conversation",
|
||||
"delete_conversation",
|
||||
"send_message",
|
||||
"upsert_model_provider",
|
||||
"run_execution_limb_training_drill"
|
||||
"run_execution_limb_training_drill",
|
||||
"resolve_number_coordinate",
|
||||
"preview_hldp_tool_program"
|
||||
],
|
||||
"direct_field_aliases": {
|
||||
"perform_code_repo_login": [
|
||||
|
|
@ -1993,6 +1998,61 @@
|
|||
"admission": "VERIFIED_HUMAN_ROUTE",
|
||||
"effect": "STATE_CHANGE",
|
||||
"payload_schema": "hololake.numbered-ipc.payload/run_execution_limb_training_drill/v1"
|
||||
},
|
||||
{
|
||||
"operation_number": "HLP-NIPC-OP-0164",
|
||||
"alias": "list_conversations",
|
||||
"handler": "persona_language_channel::list_conversations",
|
||||
"channel_number": "HLP-NIPC-CH-0002",
|
||||
"module_number": "HLP-NIPC-MOD-0035",
|
||||
"target_number": "HLP-NIPC-TGT-0035",
|
||||
"admission": "VERIFIED_HUMAN_ROUTE",
|
||||
"effect": "READ_OR_STATUS",
|
||||
"payload_schema": "hololake.numbered-ipc.payload/list_conversations/v1"
|
||||
},
|
||||
{
|
||||
"operation_number": "HLP-NIPC-OP-0165",
|
||||
"alias": "create_conversation",
|
||||
"handler": "persona_language_channel::create_conversation",
|
||||
"channel_number": "HLP-NIPC-CH-0002",
|
||||
"module_number": "HLP-NIPC-MOD-0035",
|
||||
"target_number": "HLP-NIPC-TGT-0035",
|
||||
"admission": "VERIFIED_HUMAN_ROUTE",
|
||||
"effect": "STATE_CHANGE",
|
||||
"payload_schema": "hololake.numbered-ipc.payload/create_conversation/v1"
|
||||
},
|
||||
{
|
||||
"operation_number": "HLP-NIPC-OP-0166",
|
||||
"alias": "delete_conversation",
|
||||
"handler": "persona_language_channel::delete_conversation",
|
||||
"channel_number": "HLP-NIPC-CH-0002",
|
||||
"module_number": "HLP-NIPC-MOD-0035",
|
||||
"target_number": "HLP-NIPC-TGT-0035",
|
||||
"admission": "VERIFIED_HUMAN_ROUTE",
|
||||
"effect": "STATE_CHANGE",
|
||||
"payload_schema": "hololake.numbered-ipc.payload/delete_conversation/v1"
|
||||
},
|
||||
{
|
||||
"operation_number": "HLP-NIPC-OP-0167",
|
||||
"alias": "resolve_number_coordinate",
|
||||
"handler": "number_database::resolve_number_coordinate",
|
||||
"channel_number": "HLP-NIPC-CH-0001",
|
||||
"module_number": "HLP-NIPC-MOD-0018",
|
||||
"target_number": "HLP-NIPC-TGT-0018",
|
||||
"admission": "PREAUTH_SYSTEM_ROUTE",
|
||||
"effect": "READ_OR_STATUS",
|
||||
"payload_schema": "hololake.numbered-ipc.payload/resolve_number_coordinate/v1"
|
||||
},
|
||||
{
|
||||
"operation_number": "HLP-NIPC-OP-0168",
|
||||
"alias": "preview_hldp_tool_program",
|
||||
"handler": "persona_language_channel::preview_hldp_tool_program",
|
||||
"channel_number": "HLP-NIPC-CH-0002",
|
||||
"module_number": "HLP-NIPC-MOD-0035",
|
||||
"target_number": "HLP-NIPC-TGT-0035",
|
||||
"admission": "VERIFIED_HUMAN_ROUTE",
|
||||
"effect": "READ_OR_STATUS",
|
||||
"payload_schema": "hololake.numbered-ipc.payload/preview_hldp_tool_program/v1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
},
|
||||
{
|
||||
"recordId": "HLP-NUMBERED-IPC-ROOT-001",
|
||||
"sha256": "facab9ecdcfce0e8e676585275c0cd9bbf502c2496ca96a9600e019896e51ef0"
|
||||
"sha256": "d029c7d2ceadc372955cea52654d8b0d8687d50d3327e2e36f1cf3b78252c815"
|
||||
},
|
||||
{
|
||||
"recordId": "HLP-NBROKER-ROOT-001",
|
||||
|
|
@ -73,14 +73,791 @@
|
|||
"everyAcceptedCallHasEvidenceClass": true,
|
||||
"everyProtocolReferenceHasNumberCoordinate": true,
|
||||
"referenceOnlyNodesNeverExecutable": true,
|
||||
"oneModuleOneRuntimeRootPath": true,
|
||||
"unresolvedNumberReferenceCount": 0,
|
||||
"mismatchedCoordinate": "FAIL_CLOSED"
|
||||
},
|
||||
"coordinateCount": 273,
|
||||
"routeCount": 170,
|
||||
"coordinateCount": 324,
|
||||
"moduleNodeCount": 46,
|
||||
"routeCount": 175,
|
||||
"identityNodeCount": 4,
|
||||
"protocolNodeCount": 99,
|
||||
"referenceOnlyNodeCount": 16,
|
||||
"moduleNodes": [
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0001",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0001",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0001",
|
||||
"HLP-NBROKER-OP-0004"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0001"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0002",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0002",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0002"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0002"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0003",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0003",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0003"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0003"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0004",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0004",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 4,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0005",
|
||||
"HLP-NBROKER-OP-0006",
|
||||
"HLP-NBROKER-OP-0007",
|
||||
"HLP-NBROKER-OP-0011"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0004"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0005",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0005",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0008",
|
||||
"HLP-NBROKER-OP-0009"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0005"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0006",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0006",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0010"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0006"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0007",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0007",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 3,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0012",
|
||||
"HLP-NBROKER-OP-0013",
|
||||
"HLP-NBROKER-OP-0014"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0007"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0008",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0008",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 3,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0015",
|
||||
"HLP-NBROKER-OP-0016",
|
||||
"HLP-NBROKER-OP-0017"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0008"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0009",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0009",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0018",
|
||||
"HLP-NBROKER-OP-0019"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0009"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0010",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0010",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 3,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0020",
|
||||
"HLP-NBROKER-OP-0021",
|
||||
"HLP-NBROKER-OP-0022"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0010"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NBROKER-MOD-0011",
|
||||
"moduleNumber": "HLP-NBROKER-MOD-0011",
|
||||
"transport": "DIRECT_LOCAL_NUMBERED_BROKER",
|
||||
"operationCount": 3,
|
||||
"operationNumbers": [
|
||||
"HLP-NBROKER-OP-0023",
|
||||
"HLP-NBROKER-OP-0024",
|
||||
"HLP-NBROKER-OP-0025"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NBROKER-MOD-0011"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0001",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0001",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0001"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0001"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0002",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0002",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 5,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0002",
|
||||
"HLP-NIPC-OP-0003",
|
||||
"HLP-NIPC-OP-0004",
|
||||
"HLP-NIPC-OP-0005",
|
||||
"HLP-NIPC-OP-0006"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0002"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0003",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0003",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 5,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0007",
|
||||
"HLP-NIPC-OP-0008",
|
||||
"HLP-NIPC-OP-0009",
|
||||
"HLP-NIPC-OP-0010",
|
||||
"HLP-NIPC-OP-0011"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0003"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0004",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0004",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0012"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0004"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0005",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0005",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0013"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0005"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0006",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0006",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 3,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0014",
|
||||
"HLP-NIPC-OP-0015",
|
||||
"HLP-NIPC-OP-0016"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0006"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0007",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0007",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 3,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0017",
|
||||
"HLP-NIPC-OP-0018",
|
||||
"HLP-NIPC-OP-0019"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0007"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0008",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0008",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 4,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0020",
|
||||
"HLP-NIPC-OP-0021",
|
||||
"HLP-NIPC-OP-0022",
|
||||
"HLP-NIPC-OP-0023"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0008"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0009",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0009",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 4,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0024",
|
||||
"HLP-NIPC-OP-0025",
|
||||
"HLP-NIPC-OP-0026",
|
||||
"HLP-NIPC-OP-0027"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0009"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0010",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0010",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 10,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0028",
|
||||
"HLP-NIPC-OP-0029",
|
||||
"HLP-NIPC-OP-0030",
|
||||
"HLP-NIPC-OP-0031",
|
||||
"HLP-NIPC-OP-0032",
|
||||
"HLP-NIPC-OP-0033",
|
||||
"HLP-NIPC-OP-0034",
|
||||
"HLP-NIPC-OP-0035",
|
||||
"HLP-NIPC-OP-0036",
|
||||
"HLP-NIPC-OP-0037"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0010"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0011",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0011",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 5,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0038",
|
||||
"HLP-NIPC-OP-0039",
|
||||
"HLP-NIPC-OP-0040",
|
||||
"HLP-NIPC-OP-0041",
|
||||
"HLP-NIPC-OP-0042"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0011"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0012",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0012",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 3,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0043",
|
||||
"HLP-NIPC-OP-0044",
|
||||
"HLP-NIPC-OP-0045"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0012"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0013",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0013",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0046"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0013"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0014",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0014",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0047"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0014"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0015",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0015",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 7,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0048",
|
||||
"HLP-NIPC-OP-0049",
|
||||
"HLP-NIPC-OP-0050",
|
||||
"HLP-NIPC-OP-0051",
|
||||
"HLP-NIPC-OP-0052",
|
||||
"HLP-NIPC-OP-0053",
|
||||
"HLP-NIPC-OP-0055"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0015"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0016",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0016",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0054"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0016"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0017",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0017",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0056",
|
||||
"HLP-NIPC-OP-0057"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0017"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0018",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0018",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0058",
|
||||
"HLP-NIPC-OP-0167"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0018"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0019",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0019",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 4,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0059",
|
||||
"HLP-NIPC-OP-0060",
|
||||
"HLP-NIPC-OP-0061",
|
||||
"HLP-NIPC-OP-0062"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0019"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0020",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0020",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 9,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0063",
|
||||
"HLP-NIPC-OP-0064",
|
||||
"HLP-NIPC-OP-0065",
|
||||
"HLP-NIPC-OP-0066",
|
||||
"HLP-NIPC-OP-0067",
|
||||
"HLP-NIPC-OP-0068",
|
||||
"HLP-NIPC-OP-0069",
|
||||
"HLP-NIPC-OP-0070",
|
||||
"HLP-NIPC-OP-0071"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0020"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0021",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0021",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0072",
|
||||
"HLP-NIPC-OP-0073"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0021"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0022",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0022",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 3,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0074",
|
||||
"HLP-NIPC-OP-0075",
|
||||
"HLP-NIPC-OP-0076"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0022"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0023",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0023",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 8,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0077",
|
||||
"HLP-NIPC-OP-0078",
|
||||
"HLP-NIPC-OP-0079",
|
||||
"HLP-NIPC-OP-0080",
|
||||
"HLP-NIPC-OP-0081",
|
||||
"HLP-NIPC-OP-0082",
|
||||
"HLP-NIPC-OP-0083",
|
||||
"HLP-NIPC-OP-0084"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0023"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0025",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0025",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 30,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0103",
|
||||
"HLP-NIPC-OP-0104",
|
||||
"HLP-NIPC-OP-0105",
|
||||
"HLP-NIPC-OP-0106",
|
||||
"HLP-NIPC-OP-0107",
|
||||
"HLP-NIPC-OP-0108",
|
||||
"HLP-NIPC-OP-0109",
|
||||
"HLP-NIPC-OP-0110",
|
||||
"HLP-NIPC-OP-0111",
|
||||
"HLP-NIPC-OP-0112",
|
||||
"HLP-NIPC-OP-0113",
|
||||
"HLP-NIPC-OP-0114",
|
||||
"HLP-NIPC-OP-0115",
|
||||
"HLP-NIPC-OP-0116",
|
||||
"HLP-NIPC-OP-0117",
|
||||
"HLP-NIPC-OP-0118",
|
||||
"HLP-NIPC-OP-0119",
|
||||
"HLP-NIPC-OP-0120",
|
||||
"HLP-NIPC-OP-0121",
|
||||
"HLP-NIPC-OP-0122",
|
||||
"HLP-NIPC-OP-0123",
|
||||
"HLP-NIPC-OP-0124",
|
||||
"HLP-NIPC-OP-0125",
|
||||
"HLP-NIPC-OP-0126",
|
||||
"HLP-NIPC-OP-0127",
|
||||
"HLP-NIPC-OP-0128",
|
||||
"HLP-NIPC-OP-0129",
|
||||
"HLP-NIPC-OP-0130",
|
||||
"HLP-NIPC-OP-0131",
|
||||
"HLP-NIPC-OP-0132"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0025"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0026",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0026",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0133",
|
||||
"HLP-NIPC-OP-0134"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0026"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0027",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0027",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0135",
|
||||
"HLP-NIPC-OP-0136"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0027"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0028",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0028",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0137",
|
||||
"HLP-NIPC-OP-0138"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0028"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0029",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0029",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0139",
|
||||
"HLP-NIPC-OP-0140"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0029"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0030",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0030",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 6,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0141",
|
||||
"HLP-NIPC-OP-0142",
|
||||
"HLP-NIPC-OP-0143",
|
||||
"HLP-NIPC-OP-0144",
|
||||
"HLP-NIPC-OP-0145",
|
||||
"HLP-NIPC-OP-0146"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0030"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0031",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0031",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 1,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0147"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0031"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0032",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0032",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0148",
|
||||
"HLP-NIPC-OP-0149"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0032"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0033",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0033",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 6,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0150",
|
||||
"HLP-NIPC-OP-0151",
|
||||
"HLP-NIPC-OP-0152",
|
||||
"HLP-NIPC-OP-0153",
|
||||
"HLP-NIPC-OP-0154",
|
||||
"HLP-NIPC-OP-0155"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0033"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0034",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0034",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0156",
|
||||
"HLP-NIPC-OP-0157"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0034"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0035",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0035",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 8,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0158",
|
||||
"HLP-NIPC-OP-0159",
|
||||
"HLP-NIPC-OP-0160",
|
||||
"HLP-NIPC-OP-0161",
|
||||
"HLP-NIPC-OP-0164",
|
||||
"HLP-NIPC-OP-0165",
|
||||
"HLP-NIPC-OP-0166",
|
||||
"HLP-NIPC-OP-0168"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0035"
|
||||
},
|
||||
{
|
||||
"nodeKind": "EXECUTION_MODULE",
|
||||
"nodeNumber": "HLP-NIPC-MOD-0036",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0036",
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"operationCount": 2,
|
||||
"operationNumbers": [
|
||||
"HLP-NIPC-OP-0162",
|
||||
"HLP-NIPC-OP-0163"
|
||||
],
|
||||
"schedulingPolicy": "ONE_MODULE_ONE_NUMBER_PATH_SERIAL",
|
||||
"executionState": "RUNTIME_NUMBER_DATABASE_INDEXED",
|
||||
"evidence": "UNIFIED_NUMBER_ROUTE_MEMBERSHIP",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0036"
|
||||
}
|
||||
],
|
||||
"identityNodes": [
|
||||
{
|
||||
"nodeKind": "IDENTITY_NAMESPACE",
|
||||
|
|
@ -1680,6 +2457,20 @@
|
|||
"evidence": "HASH_CHAINED_NUMBERED_IPC_RECEIPT",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/TAURI/HLP-NIPC-CH-0001/HLP-NIPC-MOD-0018/HLP-NIPC-OP-0058/HLP-NIPC-TGT-0018"
|
||||
},
|
||||
{
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0001",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0018",
|
||||
"operationNumber": "HLP-NIPC-OP-0167",
|
||||
"targetNumber": "HLP-NIPC-TGT-0018",
|
||||
"alias": "resolve_number_coordinate",
|
||||
"admission": "PREAUTH_SYSTEM_ROUTE",
|
||||
"effect": "READ_OR_STATUS",
|
||||
"evidence": "HASH_CHAINED_NUMBERED_IPC_RECEIPT",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/TAURI/HLP-NIPC-CH-0001/HLP-NIPC-MOD-0018/HLP-NIPC-OP-0167/HLP-NIPC-TGT-0018"
|
||||
},
|
||||
{
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
|
|
@ -3080,6 +3871,62 @@
|
|||
"evidence": "HASH_CHAINED_NUMBERED_IPC_RECEIPT",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/TAURI/HLP-NIPC-CH-0002/HLP-NIPC-MOD-0035/HLP-NIPC-OP-0161/HLP-NIPC-TGT-0035"
|
||||
},
|
||||
{
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0002",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0035",
|
||||
"operationNumber": "HLP-NIPC-OP-0164",
|
||||
"targetNumber": "HLP-NIPC-TGT-0035",
|
||||
"alias": "list_conversations",
|
||||
"admission": "VERIFIED_HUMAN_ROUTE",
|
||||
"effect": "READ_OR_STATUS",
|
||||
"evidence": "HASH_CHAINED_NUMBERED_IPC_RECEIPT",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/TAURI/HLP-NIPC-CH-0002/HLP-NIPC-MOD-0035/HLP-NIPC-OP-0164/HLP-NIPC-TGT-0035"
|
||||
},
|
||||
{
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0002",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0035",
|
||||
"operationNumber": "HLP-NIPC-OP-0165",
|
||||
"targetNumber": "HLP-NIPC-TGT-0035",
|
||||
"alias": "create_conversation",
|
||||
"admission": "VERIFIED_HUMAN_ROUTE",
|
||||
"effect": "STATE_CHANGE",
|
||||
"evidence": "HASH_CHAINED_NUMBERED_IPC_RECEIPT",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/TAURI/HLP-NIPC-CH-0002/HLP-NIPC-MOD-0035/HLP-NIPC-OP-0165/HLP-NIPC-TGT-0035"
|
||||
},
|
||||
{
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0002",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0035",
|
||||
"operationNumber": "HLP-NIPC-OP-0166",
|
||||
"targetNumber": "HLP-NIPC-TGT-0035",
|
||||
"alias": "delete_conversation",
|
||||
"admission": "VERIFIED_HUMAN_ROUTE",
|
||||
"effect": "STATE_CHANGE",
|
||||
"evidence": "HASH_CHAINED_NUMBERED_IPC_RECEIPT",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/TAURI/HLP-NIPC-CH-0002/HLP-NIPC-MOD-0035/HLP-NIPC-OP-0166/HLP-NIPC-TGT-0035"
|
||||
},
|
||||
{
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0002",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0035",
|
||||
"operationNumber": "HLP-NIPC-OP-0168",
|
||||
"targetNumber": "HLP-NIPC-TGT-0035",
|
||||
"alias": "preview_hldp_tool_program",
|
||||
"admission": "VERIFIED_HUMAN_ROUTE",
|
||||
"effect": "READ_OR_STATUS",
|
||||
"evidence": "HASH_CHAINED_NUMBERED_IPC_RECEIPT",
|
||||
"path": "HLP-NUMBER-WORLD-ROOT-001/TAURI/HLP-NIPC-CH-0002/HLP-NIPC-MOD-0035/HLP-NIPC-OP-0168/HLP-NIPC-TGT-0035"
|
||||
},
|
||||
{
|
||||
"transport": "TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
|
|
|
|||
|
|
@ -66,6 +66,29 @@ export function compileUnifiedNumberTree() {
|
|||
if (routes.length !== uniquePaths.size || routes.length !== uniqueOperations.size) {
|
||||
throw new Error('HOLOLAKE_UNIFIED_NUMBER_TREE_DUPLICATE_COORDINATE')
|
||||
}
|
||||
const moduleRoutes = new Map()
|
||||
for (const route of routes) {
|
||||
const existing = moduleRoutes.get(route.moduleNumber) ?? []
|
||||
existing.push(route)
|
||||
moduleRoutes.set(route.moduleNumber, existing)
|
||||
}
|
||||
const moduleNodes = [...moduleRoutes.entries()].map(([moduleNumber, members]) => ({
|
||||
nodeKind: 'EXECUTION_MODULE',
|
||||
nodeNumber: moduleNumber,
|
||||
moduleNumber,
|
||||
transport: [...new Set(members.map((route) => route.transport))].join('+'),
|
||||
operationCount: members.length,
|
||||
operationNumbers: members.map((route) => route.operationNumber).sort((left, right) => left.localeCompare(right, 'en')),
|
||||
schedulingPolicy: 'ONE_MODULE_ONE_NUMBER_PATH_SERIAL',
|
||||
executionState: 'RUNTIME_NUMBER_DATABASE_INDEXED',
|
||||
evidence: 'UNIFIED_NUMBER_ROUTE_MEMBERSHIP',
|
||||
path: `HLP-NUMBER-WORLD-ROOT-001/MODULE/${moduleNumber}`,
|
||||
})).sort((left, right) => left.path.localeCompare(right.path, 'en'))
|
||||
if (new Set(moduleNodes.map((node) => node.moduleNumber)).size !== moduleNodes.length
|
||||
|| new Set(moduleNodes.map((node) => node.path)).size !== moduleNodes.length
|
||||
|| moduleNodes.some((node) => node.operationCount === 0)) {
|
||||
throw new Error('HOLOLAKE_UNIFIED_NUMBER_TREE_MODULE_ROOT_COLLISION')
|
||||
}
|
||||
const identityNodes = identity.value.namespaces.map((namespace) => ({
|
||||
nodeKind: 'IDENTITY_NAMESPACE',
|
||||
nodeNumber: `HLP-IDENTITY-NS-${namespace.id}`,
|
||||
|
|
@ -99,7 +122,7 @@ export function compileUnifiedNumberTree() {
|
|||
path: `HLP-NUMBER-WORLD-ROOT-001/GLS/REFERENCE/${reference.node_number}`,
|
||||
})),
|
||||
].sort((left, right) => left.path.localeCompare(right.path, 'en'))
|
||||
const allPaths = [...routes.map((route) => route.path), ...identityNodes.map((node) => node.path), ...protocolNodes.map((node) => node.path)]
|
||||
const allPaths = [...moduleNodes.map((node) => node.path), ...routes.map((route) => route.path), ...identityNodes.map((node) => node.path), ...protocolNodes.map((node) => node.path)]
|
||||
if (new Set(allPaths).size !== allPaths.length
|
||||
|| gls.value.reconciliation.unresolved_number_reference_count !== 0
|
||||
|| gls.value.reconciliation.every_dependency_has_number_coordinate !== true
|
||||
|
|
@ -136,14 +159,17 @@ export function compileUnifiedNumberTree() {
|
|||
everyAcceptedCallHasEvidenceClass: true,
|
||||
everyProtocolReferenceHasNumberCoordinate: true,
|
||||
referenceOnlyNodesNeverExecutable: true,
|
||||
oneModuleOneRuntimeRootPath: true,
|
||||
unresolvedNumberReferenceCount: 0,
|
||||
mismatchedCoordinate: 'FAIL_CLOSED',
|
||||
},
|
||||
coordinateCount: routes.length + identityNodes.length + protocolNodes.length,
|
||||
coordinateCount: moduleNodes.length + routes.length + identityNodes.length + protocolNodes.length,
|
||||
moduleNodeCount: moduleNodes.length,
|
||||
routeCount: routes.length,
|
||||
identityNodeCount: identityNodes.length,
|
||||
protocolNodeCount: protocolNodes.length,
|
||||
referenceOnlyNodeCount: protocolNodes.filter((node) => node.nodeKind === 'GLS_REFERENCE_ONLY').length,
|
||||
moduleNodes,
|
||||
identityNodes,
|
||||
protocolNodes,
|
||||
routes,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ test('light lake exposes a first-class human conversation entrance', () => {
|
|||
assert.match(main, /<PersonaChannelBody/)
|
||||
assert.match(channel, /<textarea[\s\S]*?form\?\.requestSubmit\(\)/)
|
||||
assert.match(channel, /\{sending \? '正在回应…' : '发送'\}/)
|
||||
assert.match(channel, /markdownHtml\(item\.content\)/)
|
||||
assert.match(channel, /persona-message-markdown/)
|
||||
})
|
||||
|
||||
test('knowledge workspace keeps the chat visible and binds the exact active page', () => {
|
||||
|
|
@ -31,7 +33,8 @@ test('knowledge workspace keeps the chat visible and binds the exact active page
|
|||
|
||||
test('model configuration remains secondary to the conversation surface', () => {
|
||||
assert.match(channel, /const \[settingsOpen, setSettingsOpen\] = useState\(false\)/)
|
||||
assert.match(channel, /直接输入消息开始对话;知识引用、模型设置和运行回执按需展开/)
|
||||
assert.match(channel, /ZERO CORE · LANGUAGE PERSONA CHANNEL/)
|
||||
assert.match(channel, /persona-chat-status/)
|
||||
assert.match(channel, /\{settingsOpen && <aside className="persona-chat-settings">/)
|
||||
assert.match(channel, /API 密钥 · 只进钥匙串/)
|
||||
})
|
||||
|
|
@ -42,4 +45,7 @@ test('the chosen model route survives restart and prefers explicit user configur
|
|||
assert.match(channel, /item\.source === 'EXPLICIT_USER_CONFIG'/)
|
||||
assert.match(channel, /rememberProvider\(nextProviderId\)/)
|
||||
assert.match(channel, /onChange=\{\(event\) => selectProvider\(event\.target\.value\)\}/)
|
||||
assert.match(channel, /selectedProvider\?\.source === 'EXPLICIT_USER_CONFIG'/)
|
||||
assert.match(channel, /providerId: existingProviderId/)
|
||||
assert.match(channel, /setModel\(saved\?\.selectedModel \|\| configModel\.trim\(\)\)/)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import test from 'node:test'
|
||||
|
||||
const frontend = readFileSync(new URL('../src/modules/persona-channel-body/index.tsx', import.meta.url), 'utf8')
|
||||
const main = readFileSync(new URL('../src/main.tsx', import.meta.url), 'utf8')
|
||||
const runtime = readFileSync(new URL('../src-tauri/src/persona_language_channel.rs', import.meta.url), 'utf8')
|
||||
const routes = JSON.parse(readFileSync(new URL('../contracts/numbered-ipc-registry.json', import.meta.url), 'utf8'))
|
||||
|
||||
test('human conversations are real numbered entities with create switch and delete controls', () => {
|
||||
for (const alias of ['list_conversations', 'create_conversation', 'delete_conversation']) {
|
||||
assert.match(frontend, new RegExp(`invoke<[^>]+>\\('${alias}'`))
|
||||
assert.ok(routes.operations.some((route) => route.alias === alias && route.module_number === 'HLP-NIPC-MOD-0035'))
|
||||
}
|
||||
assert.match(frontend, /conversationId,\s*providerId/)
|
||||
assert.match(frontend, /setConversationId\(item\.conversationId\)/)
|
||||
assert.match(frontend, /删除对话/)
|
||||
assert.match(main, /setPersonaNewConversationRequest\(\(value\) => value \+ 1\)/)
|
||||
assert.match(main, /newConversationRequest=\{personaNewConversationRequest\}/)
|
||||
})
|
||||
|
||||
test('legacy history migrates without loss and deletion preserves the local receipt chain', () => {
|
||||
assert.match(runtime, /ALTER TABLE messages ADD COLUMN conversation_id/)
|
||||
assert.match(runtime, /migrate_legacy_conversations/)
|
||||
assert.match(runtime, /HLP-CONV-LEGACY-/)
|
||||
assert.match(runtime, /SOFT_DELETE_TOMBSTONE_MESSAGES_RETAINED_FOR_LOCAL_RECEIPT_CHAIN/)
|
||||
assert.match(runtime, /legacy_messages_migrate_into_one_numbered_conversation_without_loss/)
|
||||
assert.match(runtime, /conversations_are_isolated_and_delete_keeps_local_receipt_history/)
|
||||
})
|
||||
|
||||
test('model receives machine environment facts instead of a hard-coded unknown response', () => {
|
||||
assert.match(runtime, /\[ZERO_CORE_CHANNEL_RUNTIME\]/)
|
||||
assert.match(runtime, /human_anchor=\{human_name\} · \{human_id\}/)
|
||||
assert.match(runtime, /知识库工具仍然可用/)
|
||||
assert.match(runtime, /hololake_search_knowledge/)
|
||||
assert.match(runtime, /hololake_read_knowledge_document/)
|
||||
assert.doesNotMatch(runtime, /没有证据就明确说不知道/)
|
||||
assert.match(runtime, /REGISTERED_AGE_PERSONA_BRAIN_DRIVES_REPLACEABLE_MODEL_AND_CODEX_LIMBS/)
|
||||
})
|
||||
|
||||
test('persona tool forge compiles typed HLDP through its own numbered preview route', () => {
|
||||
assert.match(frontend, /preview_hldp_tool_program/)
|
||||
assert.match(frontend, /HLDP NATIVE TOOL FORGE/)
|
||||
assert.match(frontend, /确定性 GIR/)
|
||||
assert.ok(routes.operations.some((route) => route.alias === 'preview_hldp_tool_program'
|
||||
&& route.operation_number === 'HLP-NIPC-OP-0168'
|
||||
&& route.module_number === 'HLP-NIPC-MOD-0035'))
|
||||
assert.match(runtime, /compile_hldp_program\(input\)/)
|
||||
})
|
||||
|
|
@ -22,6 +22,7 @@ test('release center records every shipped HoloLake line from 0.4.0 through curr
|
|||
|
||||
test('one engine exposes Guanghu and standard workbench projections with a human default', async () => {
|
||||
const source = await read('src/main.tsx')
|
||||
const styles = await read('src/styles.css')
|
||||
assert.match(source, /type PresentationMode = 'guanghu' \| 'workbench'/)
|
||||
assert.match(source, /type AudienceLayer = 'human' \| 'execution'/)
|
||||
assert.match(source, /hololake-presentation-mode/)
|
||||
|
|
@ -33,6 +34,12 @@ test('one engine exposes Guanghu and standard workbench projections with a human
|
|||
assert.match(source, /renderWorkbenchHuman()/)
|
||||
assert.match(source, /renderExecutionProjection\(\)/)
|
||||
assert.match(source, /人格体结构化执行界面/)
|
||||
assert.match(source, /presentationMode !== 'workbench' \|\| view !== 'persona'/)
|
||||
assert.match(source, /void refreshPersonaBodyModule\(\)/)
|
||||
assert.match(source, /<PersonaChannelBody onBack=\{\(\) => \{ setView\('overview'\); setWorldStage\(toolReturnStage\) \}\}/)
|
||||
assert.match(styles, /\.standard-workbench\s*\{[^}]*display:\s*grid;[^}]*grid-template-columns:\s*52px 244px minmax\(0, 1fr\);/s)
|
||||
assert.match(styles, /@media \(max-width: 640px\)\s*\{[^}]*\.standard-workbench\s*\{[^}]*grid-template-columns:\s*46px minmax\(0, 1fr\);/s)
|
||||
assert.ok(styles.indexOf('.workbench-sidebar { display: none; }') > styles.indexOf('@media (max-width: 640px)'))
|
||||
})
|
||||
|
||||
test('main domain routes to the public release center instead of a descriptive popup', async () => {
|
||||
|
|
@ -45,7 +52,8 @@ test('main domain routes to the public release center instead of a descriptive p
|
|||
|
||||
test('public language persona copy is formal and keeps a visible human composer', async () => {
|
||||
const source = await read('src/modules/persona-channel-body/index.tsx')
|
||||
assert.match(source, /<h1>\{embedded \? '对话与知识协作' : '语言人格频道'\}<\/h1>/)
|
||||
assert.match(source, /<h1>\{conversation\?\.title \|\| \(embedded \? '对话与知识协作' : '语言人格频道'\)\}<\/h1>/)
|
||||
assert.match(source, /冰朔 · ICE-GL∞/)
|
||||
assert.match(source, /输入消息;需要知识时可直接提问。/)
|
||||
assert.match(source, /<textarea/)
|
||||
assert.match(source, /send_message/)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ test('number verification is an unknown star abyss and the world stays veiled un
|
|||
assert.match(styles, /\.starlake-scene\.world-veiled \.domains/)
|
||||
assert.match(styles, /\.starlake-scene\.world-veiled \.masthead/)
|
||||
assert.match(styles, /\.starlake-scene \.star-abyss-entry\s*\{/)
|
||||
assert.match(styles, /\.starlake-scene \.world-channel-return\s*\{[^}]*pointer-events:\s*auto;/s)
|
||||
assert.match(styles, /left:50%/)
|
||||
assert.match(styles, /@keyframes sl-domain-rise/)
|
||||
assert.match(styles, /@keyframes sl-abyss-open/)
|
||||
|
|
|
|||
|
|
@ -8,18 +8,23 @@ test('identity, webview and direct broker numbers compile into one unique eviden
|
|||
assert.deepEqual(generated, compileUnifiedNumberTree())
|
||||
assert.equal(generated.schema, 'hololake.unified-number-coordinate-tree/v2')
|
||||
assert.equal(generated.recordId, 'HLP-UNIFIED-NUMBER-TREE-001')
|
||||
assert.equal(generated.coordinateCount, 273)
|
||||
assert.equal(generated.routeCount, 170)
|
||||
assert.equal(generated.coordinateCount, 324)
|
||||
assert.equal(generated.moduleNodeCount, 46)
|
||||
assert.equal(generated.routeCount, 175)
|
||||
assert.equal(generated.identityNodeCount, 4)
|
||||
assert.equal(generated.protocolNodeCount, 99)
|
||||
assert.equal(generated.referenceOnlyNodeCount, 16)
|
||||
assert.equal(new Set(generated.routes.map((route) => route.path)).size, 170)
|
||||
assert.equal(new Set([...generated.identityNodes, ...generated.protocolNodes, ...generated.routes].map((node) => node.path)).size, 273)
|
||||
assert.equal(new Set(generated.moduleNodes.map((node) => node.path)).size, 46)
|
||||
assert.equal(new Set(generated.routes.map((route) => route.path)).size, 175)
|
||||
assert.equal(new Set([...generated.moduleNodes, ...generated.identityNodes, ...generated.protocolNodes, ...generated.routes].map((node) => node.path)).size, 324)
|
||||
assert.equal(generated.invariants.everyPhysicalCallHasNumberedRoute, true)
|
||||
assert.equal(generated.invariants.everyAcceptedCallHasEvidenceClass, true)
|
||||
assert.equal(generated.invariants.everyProtocolReferenceHasNumberCoordinate, true)
|
||||
assert.equal(generated.invariants.referenceOnlyNodesNeverExecutable, true)
|
||||
assert.equal(generated.invariants.oneModuleOneRuntimeRootPath, true)
|
||||
assert.equal(generated.invariants.unresolvedNumberReferenceCount, 0)
|
||||
assert.ok(generated.protocolNodes.filter((node) => node.nodeKind === 'GLS_REFERENCE_ONLY').every((node) => node.executionState === 'REFERENCE_ONLY_NOT_EXECUTABLE'))
|
||||
assert.ok(generated.routes.every((route) => route.admission && route.evidence))
|
||||
assert.ok(generated.moduleNodes.every((node) => node.path === `${generated.rootNumber}/MODULE/${node.moduleNumber}`))
|
||||
assert.ok(generated.moduleNodes.every((node) => node.schedulingPolicy === 'ONE_MODULE_ONE_NUMBER_PATH_SERIAL'))
|
||||
})
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ url = "2"
|
|||
reqwest = { version = "0.13.2", default-features = false, features = ["cookies", "form", "json", "rustls", "stream"] }
|
||||
rust_xlsxwriter = "=0.64.2"
|
||||
zip = { version = "=0.6.6", default-features = false, features = ["deflate"] }
|
||||
tokio = { version = "1", features = ["io-util", "process", "time"] }
|
||||
tokio = { version = "1", features = ["io-util", "process", "sync", "time"] }
|
||||
futures-util = "0.3"
|
||||
minisign-verify = "0.2.5"
|
||||
qrcode = { version = "0.14", default-features = false, features = ["svg"] }
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ mod code_repo_login;
|
|||
mod direct_local_broker;
|
||||
mod direct_local_session;
|
||||
mod dynamic_capability_routing;
|
||||
mod execution_limb_training;
|
||||
mod enterprise_work_channel;
|
||||
mod execution_limb_training;
|
||||
mod external_ai_gateway;
|
||||
mod glp_envelope;
|
||||
mod gls_bootstrap_compiler;
|
||||
|
|
@ -23,6 +23,7 @@ mod mobile_sync;
|
|||
mod module_package_runtime;
|
||||
mod native_composition;
|
||||
mod number_coordinate_tree;
|
||||
mod number_database;
|
||||
mod numbered_ipc;
|
||||
mod numbered_ipc_dispatch;
|
||||
mod numbered_language_input;
|
||||
|
|
@ -64,7 +65,8 @@ pub fn run() {
|
|||
.plugin(tauri_plugin_dialog::init())
|
||||
.manage(numbered_ipc::NumberedIpcState::default())
|
||||
.manage(mobile_sync::MobileSyncState::default())
|
||||
.invoke_handler(tauri::generate_handler![numbered_ipc::numbered_ipc,]) .setup(|app| {
|
||||
.invoke_handler(tauri::generate_handler![numbered_ipc::numbered_ipc,])
|
||||
.setup(|app| {
|
||||
// GLS 是 HoloLake 产品内核,不是开发机旁路服务。合同、依赖闭包、
|
||||
// 自举编译器或回执账本任一不可用时,产品启动失败关闭。
|
||||
gls_protocol_kernel::start_on_application_open(app.handle())?;
|
||||
|
|
@ -73,6 +75,7 @@ pub fn run() {
|
|||
module_package_runtime::start_on_application_open(app.handle())?;
|
||||
online_marketplace::start_on_application_open(app.handle())?;
|
||||
number_coordinate_tree::start_on_application_open()?;
|
||||
number_database::start_on_application_open(app.handle())?;
|
||||
numbered_language_input::validate_contract()?;
|
||||
numbered_ipc::start_on_application_open(app.handle())?;
|
||||
human_authorization::start_on_application_open()?;
|
||||
|
|
|
|||
|
|
@ -1620,7 +1620,6 @@ mod tests {
|
|||
assert!(is_sha256(&digest));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn bundled_web_novel_family_uses_one_signed_lifecycle_and_exact_numbers() {
|
||||
let expected = [
|
||||
|
|
|
|||
|
|
@ -11,16 +11,33 @@ struct NumberTree {
|
|||
state: String,
|
||||
root_number: String,
|
||||
coordinate_count: usize,
|
||||
module_node_count: usize,
|
||||
route_count: usize,
|
||||
identity_node_count: usize,
|
||||
protocol_node_count: usize,
|
||||
reference_only_node_count: usize,
|
||||
module_nodes: Vec<ModuleNode>,
|
||||
identity_nodes: Vec<IdentityNode>,
|
||||
protocol_nodes: Vec<ProtocolNode>,
|
||||
routes: Vec<NumberRoute>,
|
||||
invariants: NumberTreeInvariants,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ModuleNode {
|
||||
node_kind: String,
|
||||
node_number: String,
|
||||
module_number: String,
|
||||
transport: String,
|
||||
operation_count: usize,
|
||||
operation_numbers: Vec<String>,
|
||||
scheduling_policy: String,
|
||||
execution_state: String,
|
||||
evidence: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct IdentityNode {
|
||||
|
|
@ -73,6 +90,7 @@ struct NumberTreeInvariants {
|
|||
every_accepted_call_has_evidence_class: bool,
|
||||
every_protocol_reference_has_number_coordinate: bool,
|
||||
reference_only_nodes_never_executable: bool,
|
||||
one_module_one_runtime_root_path: bool,
|
||||
unresolved_number_reference_count: usize,
|
||||
mismatched_coordinate: String,
|
||||
}
|
||||
|
|
@ -88,8 +106,10 @@ fn validate_tree() -> Result<(), String> {
|
|||
|| tree.record_id != "HLP-UNIFIED-NUMBER-TREE-001"
|
||||
|| tree.state != "MACHINE_COMPILED_STARTUP_ENFORCED"
|
||||
|| tree.root_number != "HLP-NUMBER-WORLD-ROOT-001"
|
||||
|| tree.coordinate_count != 273
|
||||
|| tree.route_count != 170
|
||||
|| tree.coordinate_count != 324
|
||||
|| tree.module_node_count != 46
|
||||
|| tree.module_nodes.len() != tree.module_node_count
|
||||
|| tree.route_count != 175
|
||||
|| tree.routes.len() != tree.route_count
|
||||
|| tree.identity_node_count != 4
|
||||
|| tree.identity_nodes.len() != tree.identity_node_count
|
||||
|
|
@ -97,7 +117,10 @@ fn validate_tree() -> Result<(), String> {
|
|||
|| tree.protocol_nodes.len() != tree.protocol_node_count
|
||||
|| tree.reference_only_node_count != 16
|
||||
|| tree.coordinate_count
|
||||
!= tree.route_count + tree.identity_node_count + tree.protocol_node_count
|
||||
!= tree.module_node_count
|
||||
+ tree.route_count
|
||||
+ tree.identity_node_count
|
||||
+ tree.protocol_node_count
|
||||
|| !tree.invariants.number_is_stable_coordinate_not_authority
|
||||
|| !tree.invariants.path_is_unique_navigation
|
||||
|| !tree.invariants.admission_is_separate_from_identity
|
||||
|
|
@ -107,6 +130,7 @@ fn validate_tree() -> Result<(), String> {
|
|||
.invariants
|
||||
.every_protocol_reference_has_number_coordinate
|
||||
|| !tree.invariants.reference_only_nodes_never_executable
|
||||
|| !tree.invariants.one_module_one_runtime_root_path
|
||||
|| tree.invariants.unresolved_number_reference_count != 0
|
||||
|| tree.invariants.mismatched_coordinate != "FAIL_CLOSED"
|
||||
{
|
||||
|
|
@ -116,6 +140,27 @@ fn validate_tree() -> Result<(), String> {
|
|||
let mut coordinates = HashSet::new();
|
||||
let mut node_numbers = HashSet::new();
|
||||
let mut protocol_ids = HashSet::new();
|
||||
let mut module_numbers = HashSet::new();
|
||||
for node in &tree.module_nodes {
|
||||
if node.node_kind != "EXECUTION_MODULE"
|
||||
|| node.node_number != node.module_number
|
||||
|| node.module_number.is_empty()
|
||||
|| node.transport.is_empty()
|
||||
|| node.operation_count == 0
|
||||
|| node.operation_numbers.len() != node.operation_count
|
||||
|| node.scheduling_policy != "ONE_MODULE_ONE_NUMBER_PATH_SERIAL"
|
||||
|| node.execution_state != "RUNTIME_NUMBER_DATABASE_INDEXED"
|
||||
|| node.evidence != "UNIFIED_NUMBER_ROUTE_MEMBERSHIP"
|
||||
|| node.path != format!("HLP-NUMBER-WORLD-ROOT-001/MODULE/{}", node.module_number)
|
||||
|| !paths.insert(node.path.as_str())
|
||||
|| !node_numbers.insert(node.node_number.as_str())
|
||||
|| !module_numbers.insert(node.module_number.as_str())
|
||||
|| node.operation_numbers.iter().collect::<HashSet<_>>().len()
|
||||
!= node.operation_numbers.len()
|
||||
{
|
||||
return Err("HOLOLAKE_UNIFIED_NUMBER_TREE_MODULE_NODE_INVALID".into());
|
||||
}
|
||||
}
|
||||
for node in &tree.identity_nodes {
|
||||
if node.node_kind != "IDENTITY_NAMESPACE"
|
||||
|| !node.node_number.starts_with("HLP-IDENTITY-NS-")
|
||||
|
|
@ -183,6 +228,7 @@ fn validate_tree() -> Result<(), String> {
|
|||
|| route.admission.is_empty()
|
||||
|| !matches!(route.effect.as_str(), "READ_OR_STATUS" | "STATE_CHANGE")
|
||||
|| route.evidence.is_empty()
|
||||
|| !module_numbers.contains(route.module_number.as_str())
|
||||
|| !route.path.starts_with("HLP-NUMBER-WORLD-ROOT-001/")
|
||||
|| !paths.insert(route.path.as_str())
|
||||
|| !coordinates.insert(coordinate)
|
||||
|
|
@ -190,6 +236,22 @@ fn validate_tree() -> Result<(), String> {
|
|||
return Err("HOLOLAKE_UNIFIED_NUMBER_TREE_ROUTE_INVALID".into());
|
||||
}
|
||||
}
|
||||
for node in &tree.module_nodes {
|
||||
let observed = tree
|
||||
.routes
|
||||
.iter()
|
||||
.filter(|route| route.module_number == node.module_number)
|
||||
.map(|route| route.operation_number.as_str())
|
||||
.collect::<HashSet<_>>();
|
||||
let declared = node
|
||||
.operation_numbers
|
||||
.iter()
|
||||
.map(String::as_str)
|
||||
.collect::<HashSet<_>>();
|
||||
if observed != declared {
|
||||
return Err("HOLOLAKE_UNIFIED_NUMBER_TREE_MODULE_MEMBERSHIP_INVALID".into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,691 @@
|
|||
//! 光湖编号数据库。
|
||||
//!
|
||||
//! 编号树是唯一正本;本数据库是由该正本事务化生成的运行时索引,不接受手工登记。
|
||||
//! 它把“编号 → 唯一模块根路径 → 操作叶片 → 证据 → 调度规则”变成所有执行入口
|
||||
//! 都能查询的机器事实。树哈希变化时数据库整体重建,未知或错配坐标一律失败关闭。
|
||||
|
||||
use ring::digest::{digest, SHA256};
|
||||
use rusqlite::{params, Connection, OptionalExtension, TransactionBehavior};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tauri::{AppHandle, Manager};
|
||||
|
||||
const TREE: &str = include_str!("../../generated/unified-number-coordinate-tree.json");
|
||||
const DATABASE_ID: &str = "HLP-NUMBER-DATABASE-0001";
|
||||
const DATABASE_SCHEMA: &str = "hololake.number-database/v1";
|
||||
const DATABASE_STATE: &str = "READY_RUNTIME_REMINDER_INDEX";
|
||||
const SCHEDULING_POLICY: &str = "ONE_MODULE_ONE_NUMBER_PATH_SERIAL";
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct NumberTree {
|
||||
schema: String,
|
||||
record_id: String,
|
||||
state: String,
|
||||
root_number: String,
|
||||
coordinate_count: usize,
|
||||
module_node_count: usize,
|
||||
route_count: usize,
|
||||
identity_node_count: usize,
|
||||
protocol_node_count: usize,
|
||||
sources: Vec<NumberSource>,
|
||||
module_nodes: Vec<ModuleNode>,
|
||||
routes: Vec<NumberRoute>,
|
||||
identity_nodes: Vec<IdentityNode>,
|
||||
protocol_nodes: Vec<ProtocolNode>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct NumberSource {
|
||||
record_id: String,
|
||||
sha256: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ModuleNode {
|
||||
module_number: String,
|
||||
transport: String,
|
||||
operation_count: usize,
|
||||
operation_numbers: Vec<String>,
|
||||
scheduling_policy: String,
|
||||
execution_state: String,
|
||||
evidence: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct NumberRoute {
|
||||
transport: String,
|
||||
protocol_version: String,
|
||||
caller_number: String,
|
||||
channel_number: String,
|
||||
module_number: String,
|
||||
operation_number: String,
|
||||
target_number: String,
|
||||
alias: String,
|
||||
admission: String,
|
||||
effect: String,
|
||||
evidence: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct IdentityNode {
|
||||
node_number: String,
|
||||
namespace_id: String,
|
||||
subject_kind: String,
|
||||
domain_scope: String,
|
||||
admission: String,
|
||||
execution_state: String,
|
||||
evidence: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ProtocolNode {
|
||||
node_number: String,
|
||||
protocol_id: String,
|
||||
source_state: String,
|
||||
execution_state: String,
|
||||
evidence: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RuntimeRouteResolution {
|
||||
pub database_id: &'static str,
|
||||
pub source_tree_record_id: String,
|
||||
pub source_tree_sha256: String,
|
||||
pub transport: String,
|
||||
pub protocol_version: String,
|
||||
pub caller_number: String,
|
||||
pub channel_number: String,
|
||||
pub module_number: String,
|
||||
pub operation_number: String,
|
||||
pub target_number: String,
|
||||
pub alias: String,
|
||||
pub module_root_path: String,
|
||||
pub route_path: String,
|
||||
pub admission: String,
|
||||
pub effect: String,
|
||||
pub evidence: String,
|
||||
pub scheduling_policy: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct NumberCoordinateReminder {
|
||||
pub schema: &'static str,
|
||||
pub database_id: &'static str,
|
||||
pub database_state: &'static str,
|
||||
pub query: String,
|
||||
pub coordinate_kind: String,
|
||||
pub canonical_number: String,
|
||||
pub path: String,
|
||||
pub module_root_path: Option<String>,
|
||||
pub route_path: Option<String>,
|
||||
pub scheduling_policy: Option<String>,
|
||||
pub evidence: String,
|
||||
pub related_operation_numbers: Vec<String>,
|
||||
pub source_tree_record_id: String,
|
||||
pub source_tree_sha256: String,
|
||||
pub reminder: &'static str,
|
||||
}
|
||||
|
||||
fn sha256_hex(bytes: &[u8]) -> String {
|
||||
digest(&SHA256, bytes)
|
||||
.as_ref()
|
||||
.iter()
|
||||
.map(|byte| format!("{byte:02x}"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn tree_sha256() -> String {
|
||||
sha256_hex(TREE.as_bytes())
|
||||
}
|
||||
|
||||
fn load_tree() -> Result<NumberTree, String> {
|
||||
let tree: NumberTree = serde_json::from_str(TREE)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_TREE_INVALID: {error}"))?;
|
||||
if tree.schema != "hololake.unified-number-coordinate-tree/v2"
|
||||
|| tree.record_id != "HLP-UNIFIED-NUMBER-TREE-001"
|
||||
|| tree.state != "MACHINE_COMPILED_STARTUP_ENFORCED"
|
||||
|| tree.root_number != "HLP-NUMBER-WORLD-ROOT-001"
|
||||
|| tree.coordinate_count
|
||||
!= tree.module_node_count
|
||||
+ tree.route_count
|
||||
+ tree.identity_node_count
|
||||
+ tree.protocol_node_count
|
||||
|| tree.module_nodes.len() != tree.module_node_count
|
||||
|| tree.routes.len() != tree.route_count
|
||||
|| tree.identity_nodes.len() != tree.identity_node_count
|
||||
|| tree.protocol_nodes.len() != tree.protocol_node_count
|
||||
{
|
||||
return Err("HOLOLAKE_NUMBER_DATABASE_TREE_BOUNDARY_INVALID".into());
|
||||
}
|
||||
Ok(tree)
|
||||
}
|
||||
|
||||
fn database_path(app: &AppHandle) -> Result<PathBuf, String> {
|
||||
let root = app
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_HOME_FAILED: {error}"))?
|
||||
.join("guanghu-number-world-v1");
|
||||
fs::create_dir_all(&root)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_HOME_CREATE_FAILED: {error}"))?;
|
||||
Ok(root.join("number-coordinates.sqlite3"))
|
||||
}
|
||||
|
||||
fn open_database(path: &Path) -> Result<Connection, String> {
|
||||
let connection = Connection::open(path)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_OPEN_FAILED: {error}"))?;
|
||||
connection
|
||||
.execute_batch(
|
||||
"PRAGMA journal_mode=WAL;
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA busy_timeout=5000;
|
||||
CREATE TABLE IF NOT EXISTS metadata(
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS module_paths(
|
||||
module_number TEXT PRIMARY KEY,
|
||||
transport TEXT NOT NULL,
|
||||
module_root_path TEXT NOT NULL UNIQUE,
|
||||
scheduling_policy TEXT NOT NULL,
|
||||
operation_count INTEGER NOT NULL,
|
||||
operation_numbers_json TEXT NOT NULL,
|
||||
execution_state TEXT NOT NULL,
|
||||
evidence TEXT NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS route_coordinates(
|
||||
operation_number TEXT PRIMARY KEY,
|
||||
alias TEXT NOT NULL UNIQUE,
|
||||
transport TEXT NOT NULL,
|
||||
protocol_version TEXT NOT NULL,
|
||||
caller_number TEXT NOT NULL,
|
||||
channel_number TEXT NOT NULL,
|
||||
module_number TEXT NOT NULL REFERENCES module_paths(module_number),
|
||||
target_number TEXT NOT NULL,
|
||||
module_root_path TEXT NOT NULL,
|
||||
route_path TEXT NOT NULL UNIQUE,
|
||||
admission TEXT NOT NULL,
|
||||
effect TEXT NOT NULL,
|
||||
evidence TEXT NOT NULL,
|
||||
UNIQUE(transport,protocol_version,caller_number,channel_number,module_number,operation_number,target_number)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS identity_coordinates(
|
||||
node_number TEXT PRIMARY KEY,
|
||||
namespace_id TEXT NOT NULL UNIQUE,
|
||||
subject_kind TEXT NOT NULL,
|
||||
domain_scope TEXT NOT NULL,
|
||||
admission TEXT NOT NULL,
|
||||
execution_state TEXT NOT NULL,
|
||||
evidence TEXT NOT NULL,
|
||||
path TEXT NOT NULL UNIQUE
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS protocol_coordinates(
|
||||
node_number TEXT PRIMARY KEY,
|
||||
protocol_id TEXT NOT NULL UNIQUE,
|
||||
source_state TEXT NOT NULL,
|
||||
execution_state TEXT NOT NULL,
|
||||
evidence TEXT NOT NULL,
|
||||
path TEXT NOT NULL UNIQUE
|
||||
);",
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_SCHEMA_FAILED: {error}"))?;
|
||||
Ok(connection)
|
||||
}
|
||||
|
||||
fn put_metadata(
|
||||
transaction: &rusqlite::Transaction<'_>,
|
||||
key: &str,
|
||||
value: impl AsRef<str>,
|
||||
) -> Result<(), String> {
|
||||
transaction
|
||||
.execute(
|
||||
"INSERT INTO metadata(key,value) VALUES(?1,?2)",
|
||||
params![key, value.as_ref()],
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_METADATA_WRITE_FAILED: {error}"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn materialize_at(path: &Path) -> Result<(), String> {
|
||||
let tree = load_tree()?;
|
||||
let source_sha256 = tree_sha256();
|
||||
let mut connection = open_database(path)?;
|
||||
let transaction = connection
|
||||
.transaction_with_behavior(TransactionBehavior::Immediate)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_REBUILD_FAILED: {error}"))?;
|
||||
transaction
|
||||
.execute_batch(
|
||||
"DELETE FROM route_coordinates;
|
||||
DELETE FROM module_paths;
|
||||
DELETE FROM identity_coordinates;
|
||||
DELETE FROM protocol_coordinates;
|
||||
DELETE FROM metadata;",
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_REBUILD_FAILED: {error}"))?;
|
||||
|
||||
for module in &tree.module_nodes {
|
||||
if module.scheduling_policy != SCHEDULING_POLICY
|
||||
|| module.path != format!("{}/MODULE/{}", tree.root_number, module.module_number)
|
||||
|| module.operation_count != module.operation_numbers.len()
|
||||
{
|
||||
return Err("HOLOLAKE_NUMBER_DATABASE_MODULE_ROOT_INVALID".into());
|
||||
}
|
||||
transaction
|
||||
.execute(
|
||||
"INSERT INTO module_paths(module_number,transport,module_root_path,scheduling_policy,operation_count,operation_numbers_json,execution_state,evidence)
|
||||
VALUES(?1,?2,?3,?4,?5,?6,?7,?8)",
|
||||
params![
|
||||
module.module_number,
|
||||
module.transport,
|
||||
module.path,
|
||||
module.scheduling_policy,
|
||||
module.operation_count as i64,
|
||||
serde_json::to_string(&module.operation_numbers).map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_MODULE_OPERATIONS_INVALID: {error}"))?,
|
||||
module.execution_state,
|
||||
module.evidence,
|
||||
],
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_MODULE_WRITE_FAILED: {error}"))?;
|
||||
}
|
||||
for route in &tree.routes {
|
||||
let module_root_path: String = transaction
|
||||
.query_row(
|
||||
"SELECT module_root_path FROM module_paths WHERE module_number=?1",
|
||||
params![route.module_number],
|
||||
|row| row.get(0),
|
||||
)
|
||||
.map_err(|error| {
|
||||
format!("HOLOLAKE_NUMBER_DATABASE_MODULE_RESOLUTION_FAILED: {error}")
|
||||
})?;
|
||||
transaction
|
||||
.execute(
|
||||
"INSERT INTO route_coordinates(operation_number,alias,transport,protocol_version,caller_number,channel_number,module_number,target_number,module_root_path,route_path,admission,effect,evidence)
|
||||
VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13)",
|
||||
params![route.operation_number,route.alias,route.transport,route.protocol_version,route.caller_number,route.channel_number,route.module_number,route.target_number,module_root_path,route.path,route.admission,route.effect,route.evidence],
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_ROUTE_WRITE_FAILED: {error}"))?;
|
||||
}
|
||||
for node in &tree.identity_nodes {
|
||||
transaction
|
||||
.execute(
|
||||
"INSERT INTO identity_coordinates(node_number,namespace_id,subject_kind,domain_scope,admission,execution_state,evidence,path)
|
||||
VALUES(?1,?2,?3,?4,?5,?6,?7,?8)",
|
||||
params![node.node_number,node.namespace_id,node.subject_kind,node.domain_scope,node.admission,node.execution_state,node.evidence,node.path],
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_IDENTITY_WRITE_FAILED: {error}"))?;
|
||||
}
|
||||
for node in &tree.protocol_nodes {
|
||||
transaction
|
||||
.execute(
|
||||
"INSERT INTO protocol_coordinates(node_number,protocol_id,source_state,execution_state,evidence,path)
|
||||
VALUES(?1,?2,?3,?4,?5,?6)",
|
||||
params![node.node_number,node.protocol_id,node.source_state,node.execution_state,node.evidence,node.path],
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_PROTOCOL_WRITE_FAILED: {error}"))?;
|
||||
}
|
||||
|
||||
put_metadata(&transaction, "database_id", DATABASE_ID)?;
|
||||
put_metadata(&transaction, "database_schema", DATABASE_SCHEMA)?;
|
||||
put_metadata(&transaction, "database_state", DATABASE_STATE)?;
|
||||
put_metadata(&transaction, "source_tree_record_id", &tree.record_id)?;
|
||||
put_metadata(&transaction, "source_tree_sha256", &source_sha256)?;
|
||||
put_metadata(&transaction, "root_number", &tree.root_number)?;
|
||||
put_metadata(
|
||||
&transaction,
|
||||
"coordinate_count",
|
||||
tree.coordinate_count.to_string(),
|
||||
)?;
|
||||
put_metadata(
|
||||
&transaction,
|
||||
"module_node_count",
|
||||
tree.module_node_count.to_string(),
|
||||
)?;
|
||||
put_metadata(&transaction, "route_count", tree.route_count.to_string())?;
|
||||
put_metadata(
|
||||
&transaction,
|
||||
"identity_node_count",
|
||||
tree.identity_node_count.to_string(),
|
||||
)?;
|
||||
put_metadata(
|
||||
&transaction,
|
||||
"protocol_node_count",
|
||||
tree.protocol_node_count.to_string(),
|
||||
)?;
|
||||
put_metadata(
|
||||
&transaction,
|
||||
"source_records_json",
|
||||
serde_json::to_string(
|
||||
&tree
|
||||
.sources
|
||||
.iter()
|
||||
.map(|source| (&source.record_id, &source.sha256))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_SOURCE_RECORD_INVALID: {error}"))?,
|
||||
)?;
|
||||
transaction
|
||||
.commit()
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_REBUILD_COMMIT_FAILED: {error}"))?;
|
||||
verify_at(path)
|
||||
}
|
||||
|
||||
fn metadata(connection: &Connection, key: &str) -> Result<String, String> {
|
||||
connection
|
||||
.query_row(
|
||||
"SELECT value FROM metadata WHERE key=?1",
|
||||
params![key],
|
||||
|row| row.get(0),
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_METADATA_READ_FAILED: {error}"))
|
||||
}
|
||||
|
||||
fn table_count(connection: &Connection, table: &str) -> Result<usize, String> {
|
||||
let query = match table {
|
||||
"module_paths" => "SELECT COUNT(*) FROM module_paths",
|
||||
"route_coordinates" => "SELECT COUNT(*) FROM route_coordinates",
|
||||
"identity_coordinates" => "SELECT COUNT(*) FROM identity_coordinates",
|
||||
"protocol_coordinates" => "SELECT COUNT(*) FROM protocol_coordinates",
|
||||
_ => return Err("HOLOLAKE_NUMBER_DATABASE_TABLE_UNKNOWN".into()),
|
||||
};
|
||||
connection
|
||||
.query_row(query, [], |row| row.get::<_, i64>(0))
|
||||
.map(|count| count as usize)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_COUNT_FAILED: {error}"))
|
||||
}
|
||||
|
||||
fn verify_at(path: &Path) -> Result<(), String> {
|
||||
let tree = load_tree()?;
|
||||
let connection = open_database(path)?;
|
||||
if metadata(&connection, "database_id")? != DATABASE_ID
|
||||
|| metadata(&connection, "database_schema")? != DATABASE_SCHEMA
|
||||
|| metadata(&connection, "database_state")? != DATABASE_STATE
|
||||
|| metadata(&connection, "source_tree_record_id")? != tree.record_id
|
||||
|| metadata(&connection, "source_tree_sha256")? != tree_sha256()
|
||||
|| table_count(&connection, "module_paths")? != tree.module_node_count
|
||||
|| table_count(&connection, "route_coordinates")? != tree.route_count
|
||||
|| table_count(&connection, "identity_coordinates")? != tree.identity_node_count
|
||||
|| table_count(&connection, "protocol_coordinates")? != tree.protocol_node_count
|
||||
{
|
||||
return Err("HOLOLAKE_NUMBER_DATABASE_VERIFY_FAILED".into());
|
||||
}
|
||||
let mismatched_modules: i64 = connection
|
||||
.query_row(
|
||||
"SELECT COUNT(*) FROM module_paths m
|
||||
WHERE m.scheduling_policy != ?1
|
||||
OR m.operation_count != (SELECT COUNT(*) FROM route_coordinates r WHERE r.module_number=m.module_number)
|
||||
OR m.module_root_path != ?2 || '/MODULE/' || m.module_number",
|
||||
params![SCHEDULING_POLICY, tree.root_number],
|
||||
|row| row.get(0),
|
||||
)
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_MODULE_VERIFY_FAILED: {error}"))?;
|
||||
if mismatched_modules != 0 {
|
||||
return Err("HOLOLAKE_NUMBER_DATABASE_MODULE_VERIFY_FAILED".into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn start_on_application_open(app: &AppHandle) -> Result<(), String> {
|
||||
materialize_at(&database_path(app)?)
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_runtime_route(
|
||||
app: &AppHandle,
|
||||
transport: &str,
|
||||
protocol_version: &str,
|
||||
caller_number: &str,
|
||||
channel_number: &str,
|
||||
module_number: &str,
|
||||
operation_number: &str,
|
||||
target_number: &str,
|
||||
) -> Result<RuntimeRouteResolution, String> {
|
||||
let connection = open_database(&database_path(app)?)?;
|
||||
let source_tree_record_id = metadata(&connection, "source_tree_record_id")?;
|
||||
let source_tree_sha256 = metadata(&connection, "source_tree_sha256")?;
|
||||
connection
|
||||
.query_row(
|
||||
"SELECT r.transport,r.protocol_version,r.caller_number,r.channel_number,r.module_number,
|
||||
r.operation_number,r.target_number,r.alias,r.module_root_path,r.route_path,
|
||||
r.admission,r.effect,r.evidence,m.scheduling_policy
|
||||
FROM route_coordinates r JOIN module_paths m ON m.module_number=r.module_number
|
||||
WHERE r.transport=?1 AND r.protocol_version=?2 AND r.caller_number=?3
|
||||
AND r.channel_number=?4 AND r.module_number=?5 AND r.operation_number=?6
|
||||
AND r.target_number=?7",
|
||||
params![transport,protocol_version,caller_number,channel_number,module_number,operation_number,target_number],
|
||||
|row| {
|
||||
Ok(RuntimeRouteResolution {
|
||||
database_id: DATABASE_ID,
|
||||
source_tree_record_id: source_tree_record_id.clone(),
|
||||
source_tree_sha256: source_tree_sha256.clone(),
|
||||
transport: row.get(0)?,
|
||||
protocol_version: row.get(1)?,
|
||||
caller_number: row.get(2)?,
|
||||
channel_number: row.get(3)?,
|
||||
module_number: row.get(4)?,
|
||||
operation_number: row.get(5)?,
|
||||
target_number: row.get(6)?,
|
||||
alias: row.get(7)?,
|
||||
module_root_path: row.get(8)?,
|
||||
route_path: row.get(9)?,
|
||||
admission: row.get(10)?,
|
||||
effect: row.get(11)?,
|
||||
evidence: row.get(12)?,
|
||||
scheduling_policy: row.get(13)?,
|
||||
})
|
||||
},
|
||||
)
|
||||
.optional()
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_ROUTE_READ_FAILED: {error}"))?
|
||||
.ok_or_else(|| "HOLOLAKE_NUMBER_DATABASE_ROUTE_COORDINATE_MISMATCH".to_string())
|
||||
}
|
||||
|
||||
fn validate_query(number: &str) -> Result<&str, String> {
|
||||
let number = number.trim();
|
||||
if number.is_empty()
|
||||
|| number.len() > 160
|
||||
|| number
|
||||
.chars()
|
||||
.any(|character| character.is_control() || character.is_whitespace())
|
||||
{
|
||||
return Err("HOLOLAKE_NUMBER_DATABASE_QUERY_INVALID".into());
|
||||
}
|
||||
Ok(number)
|
||||
}
|
||||
|
||||
fn resolve_number_coordinate_at(
|
||||
path: &Path,
|
||||
number: &str,
|
||||
) -> Result<NumberCoordinateReminder, String> {
|
||||
let number = validate_query(number)?;
|
||||
let connection = open_database(path)?;
|
||||
let source_tree_record_id = metadata(&connection, "source_tree_record_id")?;
|
||||
let source_tree_sha256 = metadata(&connection, "source_tree_sha256")?;
|
||||
|
||||
if let Some((module_number, module_root_path, policy, evidence, operations_json)) = connection
|
||||
.query_row(
|
||||
"SELECT module_number,module_root_path,scheduling_policy,evidence,operation_numbers_json
|
||||
FROM module_paths WHERE module_number=?1",
|
||||
params![number],
|
||||
|row| Ok((row.get::<_, String>(0)?,row.get::<_, String>(1)?,row.get::<_, String>(2)?,row.get::<_, String>(3)?,row.get::<_, String>(4)?)),
|
||||
)
|
||||
.optional()
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_MODULE_READ_FAILED: {error}"))?
|
||||
{
|
||||
return Ok(NumberCoordinateReminder {
|
||||
schema: "hololake.number-coordinate-reminder/v1",
|
||||
database_id: DATABASE_ID,
|
||||
database_state: DATABASE_STATE,
|
||||
query: number.into(),
|
||||
coordinate_kind: "EXECUTION_MODULE".into(),
|
||||
canonical_number: module_number,
|
||||
path: module_root_path.clone(),
|
||||
module_root_path: Some(module_root_path),
|
||||
route_path: None,
|
||||
scheduling_policy: Some(policy),
|
||||
evidence,
|
||||
related_operation_numbers: serde_json::from_str(&operations_json).map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_MODULE_OPERATIONS_INVALID: {error}"))?,
|
||||
source_tree_record_id,
|
||||
source_tree_sha256,
|
||||
reminder: "有则按唯一编号路径进入;无则明确未知,不猜路径。",
|
||||
});
|
||||
}
|
||||
|
||||
if let Some((operation_number, module_root_path, route_path, evidence, policy)) = connection
|
||||
.query_row(
|
||||
"SELECT r.operation_number,r.module_root_path,r.route_path,r.evidence,m.scheduling_policy
|
||||
FROM route_coordinates r JOIN module_paths m ON m.module_number=r.module_number
|
||||
WHERE r.operation_number=?1 OR r.alias=?1",
|
||||
params![number],
|
||||
|row| Ok((row.get::<_, String>(0)?,row.get::<_, String>(1)?,row.get::<_, String>(2)?,row.get::<_, String>(3)?,row.get::<_, String>(4)?)),
|
||||
)
|
||||
.optional()
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_ROUTE_READ_FAILED: {error}"))?
|
||||
{
|
||||
return Ok(NumberCoordinateReminder {
|
||||
schema: "hololake.number-coordinate-reminder/v1",
|
||||
database_id: DATABASE_ID,
|
||||
database_state: DATABASE_STATE,
|
||||
query: number.into(),
|
||||
coordinate_kind: "OPERATION_ROUTE".into(),
|
||||
canonical_number: operation_number.clone(),
|
||||
path: route_path.clone(),
|
||||
module_root_path: Some(module_root_path),
|
||||
route_path: Some(route_path),
|
||||
scheduling_policy: Some(policy),
|
||||
evidence,
|
||||
related_operation_numbers: vec![operation_number],
|
||||
source_tree_record_id,
|
||||
source_tree_sha256,
|
||||
reminder: "先回到模块唯一根路径,再进入当前操作叶片。",
|
||||
});
|
||||
}
|
||||
|
||||
if let Some((node_number, path, evidence)) = connection
|
||||
.query_row(
|
||||
"SELECT node_number,path,evidence FROM identity_coordinates WHERE node_number=?1 OR namespace_id=?1",
|
||||
params![number],
|
||||
|row| Ok((row.get::<_, String>(0)?,row.get::<_, String>(1)?,row.get::<_, String>(2)?)),
|
||||
)
|
||||
.optional()
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_IDENTITY_READ_FAILED: {error}"))?
|
||||
{
|
||||
return Ok(NumberCoordinateReminder {
|
||||
schema: "hololake.number-coordinate-reminder/v1", database_id: DATABASE_ID,
|
||||
database_state: DATABASE_STATE, query: number.into(), coordinate_kind: "IDENTITY_NAMESPACE".into(),
|
||||
canonical_number: node_number, path, module_root_path: None, route_path: None,
|
||||
scheduling_policy: None, evidence, related_operation_numbers: vec![],
|
||||
source_tree_record_id, source_tree_sha256,
|
||||
reminder: "身份编号只定位权威登记路径,不自行授予身份或执行权。",
|
||||
});
|
||||
}
|
||||
|
||||
if let Some((node_number, path, evidence)) = connection
|
||||
.query_row(
|
||||
"SELECT node_number,path,evidence FROM protocol_coordinates WHERE node_number=?1 OR protocol_id=?1",
|
||||
params![number],
|
||||
|row| Ok((row.get::<_, String>(0)?,row.get::<_, String>(1)?,row.get::<_, String>(2)?)),
|
||||
)
|
||||
.optional()
|
||||
.map_err(|error| format!("HOLOLAKE_NUMBER_DATABASE_PROTOCOL_READ_FAILED: {error}"))?
|
||||
{
|
||||
return Ok(NumberCoordinateReminder {
|
||||
schema: "hololake.number-coordinate-reminder/v1", database_id: DATABASE_ID,
|
||||
database_state: DATABASE_STATE, query: number.into(), coordinate_kind: "GLS_PROTOCOL".into(),
|
||||
canonical_number: node_number, path, module_root_path: None, route_path: None,
|
||||
scheduling_policy: None, evidence, related_operation_numbers: vec![],
|
||||
source_tree_record_id, source_tree_sha256,
|
||||
reminder: "协议编号先定位来源与执行状态;引用节点不得冒充可执行协议。",
|
||||
});
|
||||
}
|
||||
Err("HOLOLAKE_NUMBER_DATABASE_COORDINATE_UNKNOWN".into())
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_number_coordinate(
|
||||
app: &AppHandle,
|
||||
input: Value,
|
||||
) -> Result<NumberCoordinateReminder, String> {
|
||||
let number = input
|
||||
.get("number")
|
||||
.and_then(Value::as_str)
|
||||
.ok_or_else(|| "HOLOLAKE_NUMBER_DATABASE_NUMBER_REQUIRED".to_string())?;
|
||||
resolve_number_coordinate_at(&database_path(app)?, number)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn tree_materializes_into_a_verified_runtime_number_database() {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
let path = directory.path().join("numbers.sqlite3");
|
||||
materialize_at(&path).unwrap();
|
||||
let connection = open_database(&path).unwrap();
|
||||
assert_eq!(metadata(&connection, "database_id").unwrap(), DATABASE_ID);
|
||||
assert_eq!(table_count(&connection, "module_paths").unwrap(), 46);
|
||||
assert_eq!(table_count(&connection, "route_coordinates").unwrap(), 175);
|
||||
assert_eq!(table_count(&connection, "identity_coordinates").unwrap(), 4);
|
||||
assert_eq!(
|
||||
table_count(&connection, "protocol_coordinates").unwrap(),
|
||||
99
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_persona_conversation_operation_resolves_to_one_module_root() {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
let path = directory.path().join("numbers.sqlite3");
|
||||
materialize_at(&path).unwrap();
|
||||
for operation in [
|
||||
"HLP-NIPC-OP-0158",
|
||||
"HLP-NIPC-OP-0159",
|
||||
"HLP-NIPC-OP-0160",
|
||||
"HLP-NIPC-OP-0161",
|
||||
"HLP-NIPC-OP-0164",
|
||||
"HLP-NIPC-OP-0165",
|
||||
"HLP-NIPC-OP-0166",
|
||||
"HLP-NIPC-OP-0168",
|
||||
] {
|
||||
let reminder = resolve_number_coordinate_at(&path, operation).unwrap();
|
||||
assert_eq!(
|
||||
reminder.module_root_path.as_deref(),
|
||||
Some("HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0035")
|
||||
);
|
||||
assert_eq!(
|
||||
reminder.scheduling_policy.as_deref(),
|
||||
Some(SCHEDULING_POLICY)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reminder_resolves_module_alias_and_protocol_but_unknowns_fail_closed() {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
let path = directory.path().join("numbers.sqlite3");
|
||||
materialize_at(&path).unwrap();
|
||||
let module = resolve_number_coordinate_at(&path, "HLP-NIPC-MOD-0035").unwrap();
|
||||
assert_eq!(module.coordinate_kind, "EXECUTION_MODULE");
|
||||
assert_eq!(module.related_operation_numbers.len(), 8);
|
||||
let alias = resolve_number_coordinate_at(&path, "create_conversation").unwrap();
|
||||
assert_eq!(alias.canonical_number, "HLP-NIPC-OP-0165");
|
||||
let protocol = resolve_number_coordinate_at(&path, "GLS-0001").unwrap();
|
||||
assert_eq!(protocol.coordinate_kind, "GLS_PROTOCOL");
|
||||
assert_eq!(
|
||||
resolve_number_coordinate_at(&path, "UNKNOWN-999").unwrap_err(),
|
||||
"HOLOLAKE_NUMBER_DATABASE_COORDINATE_UNKNOWN"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ use serde_json::{Map, Value};
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use tauri::{AppHandle, Manager, State};
|
||||
use uuid::Uuid;
|
||||
|
|
@ -164,6 +164,7 @@ pub struct NumberedIpcState {
|
|||
signing_key: hmac::Key,
|
||||
grants: Mutex<HashMap<String, GrantRecord>>,
|
||||
ledger: Mutex<()>,
|
||||
module_paths: Mutex<HashMap<String, Arc<tokio::sync::Mutex<()>>>>,
|
||||
}
|
||||
|
||||
impl Default for NumberedIpcState {
|
||||
|
|
@ -177,10 +178,25 @@ impl Default for NumberedIpcState {
|
|||
signing_key: hmac::Key::new(hmac::HMAC_SHA256, &secret),
|
||||
grants: Mutex::new(HashMap::new()),
|
||||
ledger: Mutex::new(()),
|
||||
module_paths: Mutex::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn module_path_lock(
|
||||
state: &NumberedIpcState,
|
||||
module_root_path: &str,
|
||||
) -> Result<Arc<tokio::sync::Mutex<()>>, String> {
|
||||
let mut paths = state
|
||||
.module_paths
|
||||
.lock()
|
||||
.map_err(|_| "HOLOLAKE_NUMBERED_IPC_MODULE_PATH_LOCK_POISONED".to_string())?;
|
||||
Ok(paths
|
||||
.entry(module_root_path.to_string())
|
||||
.or_insert_with(|| Arc::new(tokio::sync::Mutex::new(())))
|
||||
.clone())
|
||||
}
|
||||
|
||||
fn default_ttl_ms() -> u64 {
|
||||
10_000
|
||||
}
|
||||
|
|
@ -763,6 +779,52 @@ pub async fn numbered_ipc(
|
|||
)
|
||||
}
|
||||
};
|
||||
let runtime_route = match crate::number_database::resolve_runtime_route(
|
||||
&app,
|
||||
"TAURI_WEBVIEW_NUMBERED_IPC",
|
||||
&request.envelope.coordinate.protocol_version,
|
||||
&request.envelope.coordinate.caller_number,
|
||||
&request.envelope.coordinate.channel_number,
|
||||
&request.envelope.coordinate.module_number,
|
||||
&request.envelope.coordinate.operation_number,
|
||||
&request.envelope.coordinate.target_number,
|
||||
) {
|
||||
Ok(runtime_route)
|
||||
if runtime_route.alias == route.alias
|
||||
&& runtime_route.admission == route.admission
|
||||
&& runtime_route.effect == route.effect =>
|
||||
{
|
||||
runtime_route
|
||||
}
|
||||
Ok(_) => {
|
||||
return response(
|
||||
&app,
|
||||
&state,
|
||||
"NUMBER_DATABASE_REJECTED",
|
||||
"DENY",
|
||||
&operation_number,
|
||||
&digest,
|
||||
None,
|
||||
None,
|
||||
Some("HOLOLAKE_NUMBER_DATABASE_REGISTRY_MISMATCH".into()),
|
||||
now,
|
||||
)
|
||||
}
|
||||
Err(error) => {
|
||||
return response(
|
||||
&app,
|
||||
&state,
|
||||
"NUMBER_DATABASE_REJECTED",
|
||||
"DENY",
|
||||
&operation_number,
|
||||
&digest,
|
||||
None,
|
||||
None,
|
||||
Some(error),
|
||||
now,
|
||||
)
|
||||
}
|
||||
};
|
||||
let authority_binding = match enforce_admission(&app, route) {
|
||||
Ok(binding) => binding,
|
||||
Err(error) => {
|
||||
|
|
@ -873,6 +935,8 @@ pub async fn numbered_ipc(
|
|||
)
|
||||
}
|
||||
};
|
||||
let module_lock = module_path_lock(&state, &runtime_route.module_root_path)?;
|
||||
let _module_path_guard = module_lock.lock().await;
|
||||
match crate::numbered_ipc_dispatch::dispatch(
|
||||
app.clone(),
|
||||
&route.handler,
|
||||
|
|
@ -934,10 +998,23 @@ mod tests {
|
|||
#[test]
|
||||
fn registry_is_closed_and_contains_every_migrated_command() {
|
||||
let registry = load_registry().unwrap();
|
||||
assert_eq!(registry.operations.len(), 145);
|
||||
assert_eq!(registry.operations.len(), 150);
|
||||
assert!(!registry.runtime.legacy_direct_commands_allowed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_module_root_reuses_one_runtime_execution_lane() {
|
||||
let state = NumberedIpcState::default();
|
||||
let first =
|
||||
module_path_lock(&state, "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0035").unwrap();
|
||||
let second =
|
||||
module_path_lock(&state, "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0035").unwrap();
|
||||
let other =
|
||||
module_path_lock(&state, "HLP-NUMBER-WORLD-ROOT-001/MODULE/HLP-NIPC-MOD-0018").unwrap();
|
||||
assert!(Arc::ptr_eq(&first, &second));
|
||||
assert!(!Arc::ptr_eq(&first, &other));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn route_coordinates_cannot_be_mixed() {
|
||||
let registry = load_registry().unwrap();
|
||||
|
|
|
|||
|
|
@ -392,21 +392,37 @@ pub(crate) async fn dispatch(
|
|||
"persona_language_channel::discover_model_providers" => {
|
||||
json(crate::persona_language_channel::discover_model_providers(app).await?)
|
||||
}
|
||||
"persona_language_channel::upsert_model_provider" => {
|
||||
json(crate::persona_language_channel::upsert_model_provider(app, input(&payload)?).await?)
|
||||
}
|
||||
"persona_language_channel::upsert_model_provider" => json(
|
||||
crate::persona_language_channel::upsert_model_provider(app, input(&payload)?).await?,
|
||||
),
|
||||
"persona_language_channel::get_conversation" => {
|
||||
json(crate::persona_language_channel::get_conversation(app, input(&payload)?).await?)
|
||||
}
|
||||
"persona_language_channel::list_conversations" => {
|
||||
json(crate::persona_language_channel::list_conversations(app, input(&payload)?).await?)
|
||||
}
|
||||
"persona_language_channel::create_conversation" => {
|
||||
json(crate::persona_language_channel::create_conversation(app, input(&payload)?).await?)
|
||||
}
|
||||
"persona_language_channel::delete_conversation" => {
|
||||
json(crate::persona_language_channel::delete_conversation(app, input(&payload)?).await?)
|
||||
}
|
||||
"persona_language_channel::send_message" => {
|
||||
json(crate::persona_language_channel::send_message(app, input(&payload)?).await?)
|
||||
}
|
||||
"persona_language_channel::preview_hldp_tool_program" => json(
|
||||
crate::persona_language_channel::preview_hldp_tool_program(input(&payload)?).await?,
|
||||
),
|
||||
"execution_limb_training::get_execution_limb_snapshot" => {
|
||||
json(crate::execution_limb_training::get_execution_limb_snapshot(app).await?)
|
||||
}
|
||||
"execution_limb_training::run_execution_limb_training_drill" => {
|
||||
json(crate::execution_limb_training::run_execution_limb_training_drill(app, input(&payload)?).await?)
|
||||
}
|
||||
"execution_limb_training::run_execution_limb_training_drill" => json(
|
||||
crate::execution_limb_training::run_execution_limb_training_drill(
|
||||
app,
|
||||
input(&payload)?,
|
||||
)
|
||||
.await?,
|
||||
),
|
||||
"persona_time_authority::issue_persona_time_ticket" => json(
|
||||
crate::persona_time_authority::issue_persona_time_ticket(app, input(&payload)?).await?,
|
||||
),
|
||||
|
|
@ -562,6 +578,12 @@ pub(crate) async fn dispatch(
|
|||
"zero_core_numbering::get_zero_core_numbering_kernel" => {
|
||||
json(crate::zero_core_numbering::get_zero_core_numbering_kernel().await?)
|
||||
}
|
||||
"number_database::resolve_number_coordinate" => {
|
||||
json(crate::number_database::resolve_number_coordinate(
|
||||
&app,
|
||||
payload.get("input").cloned().unwrap_or(Value::Null),
|
||||
)?)
|
||||
}
|
||||
"zero_point::zero_point_bind" => json(
|
||||
crate::zero_point::zero_point_bind(
|
||||
app.state::<crate::zero_point::ZeroPointState>(),
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ pub struct PersonaChannelBodySnapshot {
|
|||
pub history_mutation_allowed: bool,
|
||||
}
|
||||
|
||||
|
||||
/// 语言频道读取已注册人格体摘要的共用入口(2026-08-20 正向合并:自语言人格频道线移植)。
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub(crate) fn require_registered_persona(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -667,6 +667,7 @@ function HoloLakeApp() {
|
|||
const [surface, setSurface] = useState<'world' | 'traditional'>(() => window.localStorage.getItem('hololake-surface') === 'traditional' ? 'traditional' : 'world')
|
||||
const [traditionalFinish, setTraditionalFinish] = useState<FinishId>(() => (window.localStorage.getItem('hololake-finish') as FinishId) || 'aurora')
|
||||
const [view, setView] = useState<ViewId>('overview')
|
||||
const [personaNewConversationRequest, setPersonaNewConversationRequest] = useState(0)
|
||||
const [presentationMode, setPresentationMode] = useState<PresentationMode>(() => (window.localStorage.getItem('hololake-presentation-mode') as PresentationMode) || 'guanghu')
|
||||
const [audienceLayer, setAudienceLayer] = useState<AudienceLayer>(() => (window.localStorage.getItem('hololake-audience-layer') as AudienceLayer) || 'human')
|
||||
const choosePresentationMode = (next: PresentationMode) => {
|
||||
|
|
@ -1275,6 +1276,10 @@ function HoloLakeApp() {
|
|||
return module
|
||||
} catch (error) { setPersonaBodyMessage(humanError(error, 'system')); return null }
|
||||
}
|
||||
useEffect(() => {
|
||||
if (!repoLogin || presentationMode !== 'workbench' || view !== 'persona') return
|
||||
void refreshPersonaBodyModule()
|
||||
}, [repoLogin?.username, repoLogin?.domain, presentationMode, view])
|
||||
const openPersonaBody = () => { openWorldTool('persona'); void refreshPersonaBodyModule() }
|
||||
const activatePersonaBodyModule = async () => {
|
||||
setPersonaBodyBusy(true)
|
||||
|
|
@ -1881,7 +1886,7 @@ function HoloLakeApp() {
|
|||
const renderPersonaBody = () => (
|
||||
<section className="full-workbench persona-channel-body-world">
|
||||
{personaBodyModule?.installedState === 'ACTIVE'
|
||||
? <Suspense fallback={<div className="workbench-empty"><p>正在读取人格频道本体……</p></div>}><PersonaChannelBody onBack={() => setWorldStage(toolReturnStage)}/></Suspense>
|
||||
? <Suspense fallback={<div className="workbench-empty"><p>正在读取人格频道本体……</p></div>}><PersonaChannelBody onBack={() => { setView('overview'); setWorldStage(toolReturnStage) }} newConversationRequest={personaNewConversationRequest}/></Suspense>
|
||||
: <div className="workbench-empty">
|
||||
<span>生</span><h2>启用人格频道本体</h2>
|
||||
<p>模块保存可逆试用、明确语言合约、真实轨迹语言链和最小化成长投影。登记人格体不等于人格绑定;宿主也不能借此自行签发人格许可证。</p>
|
||||
|
|
@ -2237,7 +2242,7 @@ function HoloLakeApp() {
|
|||
</aside>
|
||||
<aside className="workbench-sidebar">
|
||||
<header><div><b>HoloLake</b><span>标准工作台</span></div><button type="button" title="返回光湖工作台" onClick={() => choosePresentationMode('guanghu')}>切换</button></header>
|
||||
<button className="workbench-new-channel" type="button" onClick={() => { setView('persona'); chooseAudienceLayer('human') }}><Icon name="plus"/>新建对话</button>
|
||||
<button className="workbench-new-channel" type="button" onClick={() => { setView('persona'); chooseAudienceLayer('human'); setPersonaNewConversationRequest((value) => value + 1) }}><Icon name="plus"/>新建对话</button>
|
||||
<nav aria-label="HoloLake 功能栏目">{workbenchViews.map((item) => <button className={view === item ? 'active' : ''} type="button" key={item} onClick={() => setView(item)}><Icon name={item}/><span>{viewLabels[item]}</span></button>)}</nav>
|
||||
<section className="workbench-scope"><span>当前工作区</span><b>{domainDisplayName(repoLogin.domain)}</b><small>{repoLogin.username}</small></section>
|
||||
</aside>
|
||||
|
|
|
|||
|
|
@ -1160,6 +1160,46 @@ const ROUTES = {
|
|||
"moduleNumber": "HLP-NIPC-MOD-0036",
|
||||
"operationNumber": "HLP-NIPC-OP-0163",
|
||||
"targetNumber": "HLP-NIPC-TGT-0036"
|
||||
},
|
||||
"list_conversations": {
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0002",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0035",
|
||||
"operationNumber": "HLP-NIPC-OP-0164",
|
||||
"targetNumber": "HLP-NIPC-TGT-0035"
|
||||
},
|
||||
"create_conversation": {
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0002",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0035",
|
||||
"operationNumber": "HLP-NIPC-OP-0165",
|
||||
"targetNumber": "HLP-NIPC-TGT-0035"
|
||||
},
|
||||
"delete_conversation": {
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0002",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0035",
|
||||
"operationNumber": "HLP-NIPC-OP-0166",
|
||||
"targetNumber": "HLP-NIPC-TGT-0035"
|
||||
},
|
||||
"resolve_number_coordinate": {
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0001",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0018",
|
||||
"operationNumber": "HLP-NIPC-OP-0167",
|
||||
"targetNumber": "HLP-NIPC-TGT-0018"
|
||||
},
|
||||
"preview_hldp_tool_program": {
|
||||
"protocolVersion": "HLP-NIPC-v1",
|
||||
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
|
||||
"channelNumber": "HLP-NIPC-CH-0002",
|
||||
"moduleNumber": "HLP-NIPC-MOD-0035",
|
||||
"operationNumber": "HLP-NIPC-OP-0168",
|
||||
"targetNumber": "HLP-NIPC-TGT-0035"
|
||||
}
|
||||
} as const
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { numberedInvoke as invoke } from '../numbered-ipc'
|
||||
import { markdownHtml } from '../knowledge-render'
|
||||
import { listen, type UnlistenFn } from '@tauri-apps/api/event'
|
||||
import { type FormEvent, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import './styles.css'
|
||||
|
||||
|
|
@ -15,14 +17,64 @@ interface ModelProvider { providerId: string; label: string; kind: string; state
|
|||
interface ProviderDiscovery { state: string; providers: ModelProvider[]; secretPolicy: string }
|
||||
interface ToolReceipt { source: string; path: string; contentSha256: string }
|
||||
interface PersonaMessage { messageId: string; eventId: string; personaId: string; role: 'human' | 'persona'; content: string; providerId: string; model: string; createdAtUnixMs: number; stateVersion: number; receiptHash: string; toolReceipts: ToolReceipt[] }
|
||||
interface ConversationSnapshot { personaId: string; messages: PersonaMessage[]; stateVersion: number; lastReceiptHash: string }
|
||||
interface ConversationSnapshot { personaId: string; conversationId: string; title: string; messages: PersonaMessage[]; stateVersion: number; lastReceiptHash: string }
|
||||
interface ConversationSummary { conversationId: string; personaId: string; title: string; updatedAtUnixMs: number; messageCount: number; lastMessagePreview: string }
|
||||
interface ConversationListSnapshot { personaId: string; conversations: ConversationSummary[]; deletionPolicy: string }
|
||||
interface LimbSnapshot { state: string; limbId: string; executableState: string; executableVersion?: string; trainingCycleCount: number; validatedMemoryCount: number; ledgerIntegrity: string; lastTraining?: { state: string; lessonId: string; summary: string; receiptHash: string } }
|
||||
interface DrillReceipt { state: string; summary: string; receiptHash: string; snapshot: LimbSnapshot }
|
||||
interface AgentProgress {
|
||||
requestId: string
|
||||
conversationId: string
|
||||
stage: string
|
||||
label: string
|
||||
state: 'RUNNING' | 'DONE' | 'FAILED'
|
||||
detail?: string
|
||||
completed: number
|
||||
total?: number
|
||||
occurredAtUnixMs: number
|
||||
}
|
||||
interface GirPreview {
|
||||
schema: string
|
||||
programId: string
|
||||
sourceSha256: string
|
||||
permissions: string[]
|
||||
actionGraph: Array<{ ordinal: number; id: string; kind: string; permission: string }>
|
||||
unresolvedNaturalLanguage: string[]
|
||||
unresolvedPermissions: string[]
|
||||
girSha256: string
|
||||
}
|
||||
|
||||
const PROVIDER_SELECTION_KEY = 'hololake-persona-provider-id'
|
||||
const DEFAULT_HLDP_TOOL = JSON.stringify({
|
||||
schema: 'hololake.hldp-native-program/v1',
|
||||
programId: 'HLP-TOOL-KNOWLEDGE-READ-0001',
|
||||
version: '0.1.0',
|
||||
subjectId: 'ICE-P-ZY001',
|
||||
targetId: 'HOLOLAKE-KNOWLEDGE-LOCAL',
|
||||
scope: 'CURRENT_ACCOUNT_KNOWLEDGE',
|
||||
permissions: ['KNOWLEDGE_READ', 'RECEIPT_WRITE'],
|
||||
resources: { cpuUnits: 1, memoryBytes: 16777216, storageBytes: 0, networkAllowed: false },
|
||||
actions: [
|
||||
{ id: 'validate-input', kind: 'VALIDATE', dependsOn: [], inputDigest: '0'.repeat(64), permission: 'KNOWLEDGE_READ' },
|
||||
{ id: 'read-document', kind: 'READ', dependsOn: ['validate-input'], inputDigest: '0'.repeat(64), permission: 'KNOWLEDGE_READ' },
|
||||
{ id: 'write-receipt', kind: 'WRITE_RECEIPT', dependsOn: ['read-document'], inputDigest: '0'.repeat(64), permission: 'RECEIPT_WRITE' },
|
||||
],
|
||||
timeoutMs: 30000,
|
||||
stopAction: 'STOP',
|
||||
cleanupAction: 'CLEANUP',
|
||||
rollbackAction: 'ROLLBACK',
|
||||
receiptKinds: ['COMPILE', 'READ', 'TERMINAL'],
|
||||
}, null, 2)
|
||||
|
||||
function errorText(error: unknown) {
|
||||
return String(error).replace(/^Error:\s*/, '').replace(/^HOLOLAKE_/, '')
|
||||
const raw = String(error).replace(/^Error:\s*/, '')
|
||||
if (raw.includes('MODEL_SELECTION_REQUIRED')) return '请选择模型;百炼 Token Plan 可使用 qwen3.8-max。'
|
||||
if (raw.includes('MODEL_HTTP_401') || raw.includes('MODEL_HTTP_403')) return '模型平台拒绝了凭据,请重新保存 API 密钥。'
|
||||
if (raw.includes('MODEL_REQUEST_FAILED') || raw.includes('MODEL_CLIENT_FAILED')) return '没有连接到模型平台,请检查网络与接口地址。'
|
||||
if (raw.includes('TOOL_ROUND_LIMIT')) return '工具调用达到本轮上限,已安全停止。'
|
||||
if (raw.includes('GLC_') || raw.includes('HLDP_PREVIEW')) return 'HLDP 程序没有通过严格类型检查,请检查字段、权限、依赖和摘要。'
|
||||
if (raw.includes('KNOWLEDGE')) return '知识库工具没有完成这一步,失败结果已保留。'
|
||||
return '本轮没有完成。技术详情已保存在本机运行回执中。'
|
||||
}
|
||||
|
||||
function shortHash(value: string) {
|
||||
|
|
@ -39,10 +91,12 @@ function rememberProvider(providerId: string) {
|
|||
}
|
||||
|
||||
// 本页登记生命周期,不创建人格绑定。
|
||||
export function PersonaChannelBody({ onBack, knowledgeFocus, embedded = false }: { onBack?: () => void; knowledgeFocus?: KnowledgeFocus | null; embedded?: boolean }) {
|
||||
export function PersonaChannelBody({ onBack, knowledgeFocus, embedded = false, newConversationRequest = 0 }: { onBack?: () => void; knowledgeFocus?: KnowledgeFocus | null; embedded?: boolean; newConversationRequest?: number }) {
|
||||
const [body, setBody] = useState<PersonaBodySnapshot | null>(null)
|
||||
const [discovery, setDiscovery] = useState<ProviderDiscovery | null>(null)
|
||||
const [conversation, setConversation] = useState<ConversationSnapshot | null>(null)
|
||||
const [conversations, setConversations] = useState<ConversationSummary[]>([])
|
||||
const [conversationId, setConversationId] = useState('')
|
||||
const [personaId, setPersonaId] = useState('')
|
||||
const [providerId, setProviderId] = useState(() => localStorage.getItem(PROVIDER_SELECTION_KEY) || '')
|
||||
const [model, setModel] = useState('')
|
||||
|
|
@ -51,14 +105,21 @@ export function PersonaChannelBody({ onBack, knowledgeFocus, embedded = false }:
|
|||
const [loading, setLoading] = useState(true)
|
||||
const [sending, setSending] = useState(false)
|
||||
const [settingsOpen, setSettingsOpen] = useState(false)
|
||||
const [forgeOpen, setForgeOpen] = useState(false)
|
||||
const [personaName, setPersonaName] = useState('铸渊 · 本机频道')
|
||||
const [configLabel, setConfigLabel] = useState('我的模型接口')
|
||||
const [configBaseUrl, setConfigBaseUrl] = useState('https://api.openai.com/v1')
|
||||
const [configModel, setConfigModel] = useState('')
|
||||
const [configLabel, setConfigLabel] = useState('百炼 Token Plan')
|
||||
const [configBaseUrl, setConfigBaseUrl] = useState('https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1')
|
||||
const [configModel, setConfigModel] = useState('qwen3.8-max')
|
||||
const [configKey, setConfigKey] = useState('')
|
||||
const [activity, setActivity] = useState<AgentProgress[]>([])
|
||||
const [hldpProgram, setHldpProgram] = useState(DEFAULT_HLDP_TOOL)
|
||||
const [girPreview, setGirPreview] = useState<GirPreview | null>(null)
|
||||
const [forgeBusy, setForgeBusy] = useState(false)
|
||||
const [limb, setLimb] = useState<LimbSnapshot | null>(null)
|
||||
const [limbBusy, setLimbBusy] = useState(false)
|
||||
const ledgerRef = useRef<HTMLDivElement>(null)
|
||||
const activeRequestRef = useRef('')
|
||||
const handledNewConversationRequest = useRef(0)
|
||||
|
||||
const selectedProvider = useMemo(() => discovery?.providers.find((item) => item.providerId === providerId), [discovery, providerId])
|
||||
const selectedPersona = useMemo(() => body?.personas.find((item) => item.personaId === personaId), [body, personaId])
|
||||
|
|
@ -90,24 +151,88 @@ export function PersonaChannelBody({ onBack, knowledgeFocus, embedded = false }:
|
|||
setPersonaId((current) => current && next.personas.some((item) => item.personaId === current) ? current : (next.personas[0]?.personaId || ''))
|
||||
}
|
||||
|
||||
const refreshConversations = async (targetPersonaId: string, preferredId = '') => {
|
||||
const snapshot = await invoke<ConversationListSnapshot>('list_conversations', { input: { personaId: targetPersonaId, conversationId: null } })
|
||||
setConversations(snapshot.conversations)
|
||||
const nextId = snapshot.conversations.some((item) => item.conversationId === preferredId)
|
||||
? preferredId
|
||||
: snapshot.conversations[0]?.conversationId || ''
|
||||
setConversationId(nextId)
|
||||
if (!nextId) setConversation(null)
|
||||
return snapshot
|
||||
}
|
||||
|
||||
const createConversation = async () => {
|
||||
if (!personaId) return
|
||||
setLoading(true)
|
||||
try {
|
||||
const created = await invoke<ConversationSnapshot>('create_conversation', { input: { personaId, title: null } })
|
||||
setConversation(created)
|
||||
await refreshConversations(personaId, created.conversationId)
|
||||
setNotice('新对话已建立;它拥有独立历史和回执坐标。')
|
||||
} catch (error) { setNotice(errorText(error)) }
|
||||
finally { setLoading(false) }
|
||||
}
|
||||
|
||||
const deleteConversation = async (target: ConversationSummary) => {
|
||||
if (!window.confirm(`删除对话“${target.title}”?它会从列表移除,本机回执链保留不可冒充的删除墓碑。`)) return
|
||||
setLoading(true)
|
||||
try {
|
||||
const snapshot = await invoke<ConversationListSnapshot>('delete_conversation', { input: { personaId, conversationId: target.conversationId } })
|
||||
setConversations(snapshot.conversations)
|
||||
const nextId = snapshot.conversations[0]?.conversationId || ''
|
||||
setConversationId(nextId)
|
||||
if (!nextId) setConversation(null)
|
||||
setNotice('对话已从活动列表删除;本机审计回执链保留删除墓碑。')
|
||||
} catch (error) { setNotice(errorText(error)) }
|
||||
finally { setLoading(false) }
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([refreshBody(), refreshProviders(), invoke<LimbSnapshot>('get_execution_limb_snapshot').then(setLimb)])
|
||||
.catch((error) => setNotice(errorText(error)))
|
||||
.finally(() => setLoading(false))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let unlisten: UnlistenFn | undefined
|
||||
void listen<AgentProgress>('hololake://persona-agent-progress', ({ payload }) => {
|
||||
if (!payload || payload.requestId !== activeRequestRef.current) return
|
||||
setActivity((current) => {
|
||||
const index = current.findIndex((item) => item.stage === payload.stage)
|
||||
if (index < 0) return [...current, payload]
|
||||
const next = [...current]
|
||||
next[index] = payload
|
||||
return next
|
||||
})
|
||||
}).then((dispose) => { unlisten = dispose })
|
||||
return () => unlisten?.()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const nextModel = selectedProvider?.selectedModel || selectedProvider?.models[0] || ''
|
||||
setModel(nextModel)
|
||||
}, [selectedProvider])
|
||||
|
||||
useEffect(() => {
|
||||
if (!personaId) { setConversation(null); return }
|
||||
invoke<ConversationSnapshot>('get_conversation', { input: { personaId } })
|
||||
.then(setConversation)
|
||||
if (!personaId) { setConversation(null); setConversations([]); setConversationId(''); return }
|
||||
refreshConversations(personaId, conversationId)
|
||||
.catch((error) => setNotice(errorText(error)))
|
||||
}, [personaId])
|
||||
|
||||
useEffect(() => {
|
||||
if (!personaId || !conversationId) { setConversation(null); return }
|
||||
invoke<ConversationSnapshot>('get_conversation', { input: { personaId, conversationId } })
|
||||
.then(setConversation)
|
||||
.catch((error) => setNotice(errorText(error)))
|
||||
}, [personaId, conversationId])
|
||||
|
||||
useEffect(() => {
|
||||
if (!newConversationRequest || newConversationRequest === handledNewConversationRequest.current || !personaId) return
|
||||
handledNewConversationRequest.current = newConversationRequest
|
||||
void createConversation()
|
||||
}, [newConversationRequest, personaId])
|
||||
|
||||
useEffect(() => {
|
||||
ledgerRef.current?.scrollTo({ top: ledgerRef.current.scrollHeight, behavior: 'smooth' })
|
||||
}, [conversation?.messages.length])
|
||||
|
|
@ -127,23 +252,58 @@ export function PersonaChannelBody({ onBack, knowledgeFocus, embedded = false }:
|
|||
|
||||
const send = async (event: FormEvent) => {
|
||||
event.preventDefault()
|
||||
if (!draft.trim() || !personaId || !providerId) return
|
||||
if (!draft.trim() || !personaId || !conversationId || !providerId) return
|
||||
const content = draft.trim()
|
||||
const requestId = `HLP_AGENT_${crypto.randomUUID().replaceAll('-', '')}`
|
||||
activeRequestRef.current = requestId
|
||||
setDraft('')
|
||||
setSending(true)
|
||||
setNotice('正在生成回复并读取当前知识上下文……')
|
||||
setNotice('')
|
||||
setActivity([{
|
||||
requestId,
|
||||
conversationId,
|
||||
stage: 'MESSAGE_PERSISTED',
|
||||
label: '正在把消息写入频道',
|
||||
state: 'RUNNING',
|
||||
completed: 0,
|
||||
total: 1,
|
||||
occurredAtUnixMs: Date.now(),
|
||||
}])
|
||||
setConversation((current) => current ? {
|
||||
...current,
|
||||
messages: [...current.messages, {
|
||||
messageId: `optimistic-${requestId}`,
|
||||
eventId: requestId,
|
||||
personaId,
|
||||
role: 'human',
|
||||
content,
|
||||
providerId,
|
||||
model,
|
||||
createdAtUnixMs: Date.now(),
|
||||
stateVersion: current.stateVersion + 1,
|
||||
receiptHash: '',
|
||||
toolReceipts: [],
|
||||
}],
|
||||
} : current)
|
||||
try {
|
||||
const next = await invoke<ConversationSnapshot>('send_message', { input: {
|
||||
personaId,
|
||||
conversationId,
|
||||
providerId,
|
||||
model: model || null,
|
||||
content: draft.trim(),
|
||||
content,
|
||||
useKnowledge: true,
|
||||
activeKnowledgeSource: knowledgeFocus?.source || null,
|
||||
activeKnowledgePath: knowledgeFocus?.path || null,
|
||||
requestId,
|
||||
} })
|
||||
setConversation(next)
|
||||
setDraft('')
|
||||
setNotice(next.messages.at(-1)?.toolReceipts.length ? '回复已写入频道;当前知识页已形成可核验引用。' : '回复已写入频道;本轮没有匹配到知识页。')
|
||||
} catch (error) { setNotice(errorText(error)) }
|
||||
await refreshConversations(personaId, next.conversationId)
|
||||
setNotice(next.messages.at(-1)?.toolReceipts.length ? '已完成,并附上本轮实际读取的知识来源。' : '已完成。')
|
||||
} catch (error) {
|
||||
setNotice(errorText(error))
|
||||
void invoke<ConversationSnapshot>('get_conversation', { input: { personaId, conversationId } }).then(setConversation)
|
||||
}
|
||||
finally { setSending(false) }
|
||||
}
|
||||
|
||||
|
|
@ -151,8 +311,11 @@ export function PersonaChannelBody({ onBack, knowledgeFocus, embedded = false }:
|
|||
event.preventDefault()
|
||||
setLoading(true)
|
||||
try {
|
||||
const existingProviderId = selectedProvider?.source === 'EXPLICIT_USER_CONFIG'
|
||||
? selectedProvider.providerId
|
||||
: null
|
||||
const next = await invoke<ProviderDiscovery>('upsert_model_provider', { input: {
|
||||
providerId: null,
|
||||
providerId: existingProviderId,
|
||||
label: configLabel.trim(),
|
||||
kind: 'OPENAI_COMPATIBLE',
|
||||
baseUrl: configBaseUrl.trim(),
|
||||
|
|
@ -160,8 +323,10 @@ export function PersonaChannelBody({ onBack, knowledgeFocus, embedded = false }:
|
|||
apiKey: configKey || null,
|
||||
} })
|
||||
setDiscovery(next)
|
||||
const created = next.providers.find((item) => item.label === configLabel.trim())
|
||||
selectProvider(created?.providerId || next.providers.find((item) => item.state === 'AVAILABLE')?.providerId || '')
|
||||
const saved = (existingProviderId && next.providers.find((item) => item.providerId === existingProviderId))
|
||||
|| next.providers.find((item) => item.label === configLabel.trim())
|
||||
selectProvider(saved?.providerId || next.providers.find((item) => item.state === 'AVAILABLE')?.providerId || '')
|
||||
setModel(saved?.selectedModel || configModel.trim())
|
||||
setConfigKey('')
|
||||
setSettingsOpen(false)
|
||||
setNotice('模型入口已保存并验证;密钥只进入系统钥匙串。')
|
||||
|
|
@ -180,19 +345,42 @@ export function PersonaChannelBody({ onBack, knowledgeFocus, embedded = false }:
|
|||
finally { setLimbBusy(false) }
|
||||
}
|
||||
|
||||
const compileHldpPreview = async () => {
|
||||
setForgeBusy(true)
|
||||
setGirPreview(null)
|
||||
try {
|
||||
const program = JSON.parse(hldpProgram) as Record<string, unknown>
|
||||
const result = await invoke<GirPreview>('preview_hldp_tool_program', { input: program })
|
||||
setGirPreview(result)
|
||||
setNotice('HLDP 已编译为确定性 GIR 预览;本步没有执行工具,也没有取得新权限。')
|
||||
} catch (error) {
|
||||
setNotice(errorText(error))
|
||||
} finally {
|
||||
setForgeBusy(false)
|
||||
}
|
||||
}
|
||||
|
||||
const personaLabel = selectedPersona?.state === 'IMMUTABLE_ACTIVE'
|
||||
? `${selectedPersona.displayName} · ${selectedPersona.personaId}`
|
||||
: `未绑定人格体 · ${selectedPersona?.personaId || '等待登记'}`
|
||||
const modelLabel = selectedProvider
|
||||
? `${selectedProvider.label}${model ? ` · ${model}` : ''}`
|
||||
: '尚未接入模型'
|
||||
|
||||
if (loading && !body) return <section className={`persona-chat-world${embedded ? ' is-embedded' : ''}`}><div className="persona-chat-loading">正在打开语言频道……</div></section>
|
||||
|
||||
return <section className={`persona-chat-world${embedded ? ' is-embedded' : ''}`}>
|
||||
<header className="persona-chat-header">
|
||||
<div>
|
||||
{!embedded && onBack && <button type="button" onClick={onBack}>← 返回光之湖</button>}
|
||||
<span>LANGUAGE PERSONA CHANNEL</span>
|
||||
<h1>{embedded ? '对话与知识协作' : '语言人格频道'}</h1>
|
||||
<p>{knowledgeFocus ? <>当前知识页:<b>{knowledgeFocus.title}</b></> : '直接输入消息开始对话;知识引用、模型设置和运行回执按需展开。'}</p>
|
||||
<span>ZERO CORE · LANGUAGE PERSONA CHANNEL</span>
|
||||
<h1>{conversation?.title || (embedded ? '对话与知识协作' : '语言人格频道')}</h1>
|
||||
<p>{personaLabel} <span className="persona-header-divider">/</span> 冰朔 · ICE-GL∞</p>
|
||||
</div>
|
||||
<div className="persona-chat-status">
|
||||
<i className={providerId ? 'ready' : ''}/>
|
||||
<span>{selectedProvider ? `${selectedProvider.label} · ${selectedProvider.state}` : '尚无可用模型'}</span>
|
||||
<span title={modelLabel}>{modelLabel}</span>
|
||||
<button type="button" onClick={() => setForgeOpen((value) => !value)}>{forgeOpen ? '收起 HLDP' : 'HLDP 工具'}</button>
|
||||
<button type="button" onClick={() => setSettingsOpen((value) => !value)}>{settingsOpen ? '收起设置' : '设置'}</button>
|
||||
</div>
|
||||
</header>
|
||||
|
|
@ -201,21 +389,47 @@ export function PersonaChannelBody({ onBack, knowledgeFocus, embedded = false }:
|
|||
<div><span>建立本机对话入口</span><h2>设置频道显示名称</h2><p>该名称用于当前设备上的频道列表,不会更改模型配置或系统权限。</p></div>
|
||||
<input value={personaName} maxLength={80} aria-label="频道显示名称" onChange={(event) => setPersonaName(event.target.value)}/>
|
||||
<button disabled={loading || !personaName.trim()}>进入对话</button>
|
||||
</form> : <>
|
||||
</form> : <div className="persona-chat-body">
|
||||
<aside className="persona-conversation-rail" aria-label="对话列表">
|
||||
<header><div><span>CONVERSATIONS</span><b>对话</b></div><button type="button" onClick={() => void createConversation()} disabled={loading}>+ 新建</button></header>
|
||||
<div>{conversations.map((item) => <article className={item.conversationId === conversationId ? 'active' : ''} key={item.conversationId}>
|
||||
<button type="button" onClick={() => setConversationId(item.conversationId)}><b>{item.title}</b><span>{item.messageCount ? `${item.messageCount} 条消息` : '空对话'}</span><small>{item.lastMessagePreview || '等待第一句话'}</small></button>
|
||||
<button className="persona-conversation-delete" type="button" title="删除对话" aria-label={`删除对话 ${item.title}`} onClick={() => void deleteConversation(item)}>×</button>
|
||||
</article>)}</div>
|
||||
{!conversations.length && <p>还没有对话。新建后,每条历史会拥有独立坐标。</p>}
|
||||
</aside>
|
||||
<main className="persona-chat-main">
|
||||
<div className="persona-chat-ledger" ref={ledgerRef} aria-live="polite">
|
||||
{conversation?.messages.length ? conversation.messages.map((item) => <article className={`persona-chat-message is-${item.role}`} key={item.messageId}>
|
||||
<header><b>{item.role === 'human' ? '人类' : selectedPersona?.displayName || '人格体'}</b><span>{localTime(item.createdAtUnixMs)} · v{item.stateVersion}</span></header>
|
||||
<p>{item.content}</p>
|
||||
<header><b>{item.role === 'human' ? '冰朔 · ICE-GL∞' : personaLabel}</b><span>{localTime(item.createdAtUnixMs)}</span></header>
|
||||
{item.role === 'persona'
|
||||
? <div className="persona-message-markdown" dangerouslySetInnerHTML={{ __html: markdownHtml(item.content) }}/>
|
||||
: <p>{item.content}</p>}
|
||||
{item.toolReceipts.length > 0 && <div className="persona-knowledge-receipts">{item.toolReceipts.map((receipt) => <span key={`${item.messageId}-${receipt.path}`} title={receipt.contentSha256}>引用知识 · {receipt.path} · {shortHash(receipt.contentSha256)}</span>)}</div>}
|
||||
<footer><span>{item.model || item.providerId}</span><span title={item.receiptHash}>回执 {shortHash(item.receiptHash)}</span></footer>
|
||||
</article>) : <div className="persona-chat-empty"><span>频道已就绪</span><h2>{knowledgeFocus ? '询问当前知识页' : '开始新对话'}</h2><p>{knowledgeFocus ? '回复会附带知识路径与内容指纹,便于核验引用来源。' : '输入“@知识 关键词”可检索本地知识库。'}</p></div>}
|
||||
{item.role === 'persona' && <footer><span>{selectedProvider?.label || '模型入口'} · {item.model || model || '自动路由'}</span><span title={item.receiptHash}>已写入频道</span></footer>}
|
||||
</article>) : <div className="persona-chat-empty"><span>{conversation ? '频道已就绪' : '尚未选择对话'}</span><h2>{conversation ? (knowledgeFocus ? '询问当前知识页' : '开始新对话') : '先建立一个对话'}</h2><p>{conversation ? (knowledgeFocus ? '回复会附带知识路径与内容指纹,便于核验引用来源。' : '输入“@知识 关键词”可检索本地知识库。') : '每个对话拥有独立历史坐标;删除只从活动列表移除并保留本机审计墓碑。'}</p>{!conversation && <button type="button" onClick={() => void createConversation()}>新建对话</button>}</div>}
|
||||
</div>
|
||||
{(sending || activity.length > 0) && <div className="persona-agent-activity" aria-live="polite">
|
||||
{activity.map((item) => <div className={`is-${item.state.toLowerCase()}`} key={item.stage}>
|
||||
<i/><span>{item.label}</span>{item.detail && <small>{item.detail}</small>}
|
||||
</div>)}
|
||||
</div>}
|
||||
<form className="persona-chat-composer" onSubmit={(event) => void send(event)}>
|
||||
{knowledgeFocus && <div className="persona-knowledge-focus"><span>当前知识</span><b>{knowledgeFocus.title}</b><small>{knowledgeFocus.path}</small></div>}
|
||||
<textarea autoFocus={!embedded} value={draft} maxLength={64000} placeholder={knowledgeFocus ? `输入关于《${knowledgeFocus.title}》的问题` : '输入消息;需要知识时可直接提问。'} onChange={(event) => setDraft(event.target.value)} onKeyDown={(event) => { if (event.key === 'Enter' && !event.shiftKey && !event.nativeEvent.isComposing) { event.preventDefault(); event.currentTarget.form?.requestSubmit() } }}/>
|
||||
<div><span>Enter 发送 · Shift+Enter 换行 · 每次回复保存事件和回执</span><button disabled={sending || !draft.trim() || !providerId}>{sending ? '正在回应…' : '发送'}</button></div>
|
||||
<textarea disabled={!conversationId} autoFocus={!embedded} value={draft} maxLength={64000} placeholder={conversationId ? (knowledgeFocus ? `输入关于《${knowledgeFocus.title}》的问题` : '输入消息;需要知识时可直接提问。') : '请先新建或选择对话'} onChange={(event) => setDraft(event.target.value)} onKeyDown={(event) => { if (event.key === 'Enter' && !event.shiftKey && !event.nativeEvent.isComposing) { event.preventDefault(); event.currentTarget.form?.requestSubmit() } }}/>
|
||||
<div><span>Enter 发送 · Shift+Enter 换行 · 每次回复保存事件和回执</span><button disabled={sending || !draft.trim() || !providerId || !conversationId}>{sending ? '正在回应…' : '发送'}</button></div>
|
||||
</form>
|
||||
</>}
|
||||
</main>
|
||||
</div>}
|
||||
|
||||
{forgeOpen && <aside className="persona-hldp-forge">
|
||||
<header><div><span>HLDP NATIVE TOOL FORGE</span><h2>人格体原生工具面板</h2><p>类型化 HLDP-NP → 确定性 GIR。预检不会执行代码、访问终端或取得权限。</p></div><button type="button" onClick={() => setForgeOpen(false)}>关闭</button></header>
|
||||
<div className="persona-hldp-forge-body">
|
||||
<label><span>HLDP-NP 程序</span><textarea spellCheck={false} value={hldpProgram} onChange={(event) => setHldpProgram(event.target.value)}/></label>
|
||||
<section><span>GIR 编译回执</span>{girPreview ? <><b>{girPreview.programId}</b><small>GIR · {shortHash(girPreview.girSha256)}</small><small>源码 · {shortHash(girPreview.sourceSha256)}</small><ol>{girPreview.actionGraph.map((action) => <li key={action.id}>{action.ordinal + 1}. {action.kind} · {action.id} · {action.permission}</li>)}</ol></> : <p>尚未编译。输入必须是严格类型化结构;自然语言不会被偷偷执行。</p>}</section>
|
||||
</div>
|
||||
<footer><span>下一执行门:授权测试 → 沙箱 → Terminal 回执(本面板当前只开放确定性编译预检)</span><button type="button" disabled={forgeBusy} onClick={() => void compileHldpPreview()}>{forgeBusy ? '正在编译…' : '编译 GIR 预览'}</button></footer>
|
||||
</aside>}
|
||||
|
||||
{settingsOpen && <aside className="persona-chat-settings">
|
||||
<header><div><span>ADVANCED SETTINGS</span><h2>模型与执行证据</h2></div><button type="button" onClick={() => void refreshProviders()}>重新发现</button></header>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,13 @@
|
|||
.persona-chat-onboarding>div { grid-column: 1/-1; }.persona-chat-onboarding span { color: var(--accent-light); font-size: 11px; letter-spacing: .12em; }.persona-chat-onboarding h2 { margin: 7px 0; }.persona-chat-onboarding p { margin: 0; color: var(--content-secondary); line-height: 1.6; }
|
||||
.persona-chat-onboarding input,.persona-provider-selectors select,.persona-provider-selectors input,.persona-provider-form input { min-width: 0; border: 1px solid color-mix(in srgb,var(--content-primary) 14%,transparent); border-radius: 12px; padding: 11px 12px; background: color-mix(in srgb,var(--surface-depth) 86%,transparent); color: var(--content-primary); font: inherit; }
|
||||
.persona-chat-onboarding button,.persona-chat-composer button,.persona-provider-form button,.persona-limb-strip button { border: 0; border-radius: 12px; padding: 11px 17px; background: var(--accent-light); color: var(--surface-depth); font-weight: 700; cursor: pointer; }
|
||||
.persona-chat-body { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: minmax(190px,240px) minmax(0,1fr); gap: 12px; }
|
||||
.persona-conversation-rail { min-height: 0; display: flex; flex-direction: column; gap: 10px; padding: 12px; border-radius: 18px; background: color-mix(in srgb,var(--surface-depth) 62%,transparent); border: 1px solid color-mix(in srgb,var(--content-primary) 9%,transparent); }
|
||||
.persona-conversation-rail>header { display: flex; align-items: center; justify-content: space-between; gap: 8px; }.persona-conversation-rail>header>div { display: grid; gap: 2px; }.persona-conversation-rail>header span { color: var(--content-muted); font-size: 9px; letter-spacing: .12em; }.persona-conversation-rail>header b { font-size: 14px; }.persona-conversation-rail>header button { border: 0; border-radius: 9px; padding: 7px 9px; background: color-mix(in srgb,var(--accent-light) 12%,transparent); color: var(--accent-light); cursor: pointer; }
|
||||
.persona-conversation-rail>div { min-height: 0; overflow: auto; display: grid; align-content: start; gap: 6px; }.persona-conversation-rail article { position: relative; border-radius: 12px; border: 1px solid transparent; background: color-mix(in srgb,var(--panel-bg) 60%,transparent); }.persona-conversation-rail article.active { border-color: color-mix(in srgb,var(--accent-light) 36%,transparent); background: color-mix(in srgb,var(--accent-light) 9%,var(--panel-bg)); }
|
||||
.persona-conversation-rail article>button:first-child { width: 100%; display: grid; gap: 3px; padding: 10px 28px 10px 10px; text-align: left; border: 0; background: transparent; color: var(--content-primary); cursor: pointer; }.persona-conversation-rail article b,.persona-conversation-rail article small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }.persona-conversation-rail article span,.persona-conversation-rail article small,.persona-conversation-rail>p { color: var(--content-muted); font-size: 10px; }.persona-conversation-rail>p { line-height: 1.55; }
|
||||
.persona-conversation-delete { position: absolute; top: 7px; right: 7px; width: 22px; height: 22px; border: 0; border-radius: 50%; background: transparent; color: var(--content-muted); cursor: pointer; }.persona-conversation-delete:hover { background: color-mix(in srgb,#f16f75 15%,transparent); color: #f16f75; }
|
||||
.persona-chat-main { min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 10px; }.persona-chat-empty button { margin-top: 14px; border: 0; border-radius: 11px; padding: 9px 13px; background: var(--accent-light); color: var(--surface-depth); font-weight: 700; cursor: pointer; }
|
||||
.persona-chat-ledger { flex: 1 1 auto; min-height: 250px; display: flex; flex-direction: column; gap: 12px; overflow: auto; padding: 20px; border-radius: 20px; background: color-mix(in srgb,var(--surface-depth) 55%,transparent); border: 1px solid color-mix(in srgb,var(--content-primary) 9%,transparent); }
|
||||
.persona-chat-world.is-embedded .persona-chat-ledger { min-height: 190px; padding: 13px; }
|
||||
.persona-chat-empty { margin: auto; text-align: center; max-width: 560px; color: var(--content-secondary); }.persona-chat-empty>span { color: var(--accent-light); font-size: 11px; letter-spacing: .13em; }.persona-chat-empty h2 { color: var(--content-primary); margin: 7px 0; }.persona-chat-empty p { margin: 0; line-height: 1.6; }
|
||||
|
|
@ -35,4 +42,104 @@
|
|||
.persona-provider-form { display: grid; grid-template-columns: .8fr 1.5fr .8fr 1fr auto; gap: 8px; }
|
||||
.persona-limb-strip { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 13px; border-radius: 13px; background: color-mix(in srgb,var(--surface-depth) 68%,transparent); }.persona-limb-strip>div { display: grid; gap: 3px; }.persona-limb-strip span,.persona-limb-strip small { color: var(--content-muted); font-size: 10px; }.persona-limb-strip b { font-size: 13px; }
|
||||
.persona-chat-notice { margin: 0; color: var(--accent-light); font-size: 12px; }
|
||||
@media (max-width: 900px) { .persona-chat-header { flex-direction: column; }.persona-chat-status { width: 100%; }.persona-chat-status span { flex: 1; max-width: none; }.persona-provider-selectors,.persona-provider-form { grid-template-columns: 1fr; }.persona-chat-message { width: 94%; } }
|
||||
@media (max-width: 900px) { .persona-chat-header { flex-direction: column; }.persona-chat-status { width: 100%; }.persona-chat-status span { flex: 1; max-width: none; }.persona-chat-body { grid-template-columns: 1fr; }.persona-conversation-rail { min-height: auto; max-height: 180px; }.persona-provider-selectors,.persona-provider-form { grid-template-columns: 1fr; }.persona-chat-message { width: 94%; } }
|
||||
|
||||
/* HLP-AGENT-WORKBENCH-20260820
|
||||
紧凑工作台覆盖层:保留旧主题资产,不再用巨型标题、卡片墙和裸错误承载Agent。 */
|
||||
.persona-chat-world {
|
||||
--agent-line: color-mix(in srgb,var(--content-primary) 10%,transparent);
|
||||
--agent-panel: color-mix(in srgb,var(--panel-bg) 88%,transparent);
|
||||
position: relative;
|
||||
gap: 10px;
|
||||
padding: 14px clamp(14px,2.4vw,28px) 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.persona-chat-world.is-embedded { padding: 0; }
|
||||
.persona-chat-header { min-height: 54px; align-items: center; padding: 0 2px 9px; border-bottom: 1px solid var(--agent-line); }
|
||||
.persona-chat-header span { font-size: 9px; }
|
||||
.persona-chat-header h1,.persona-chat-world.is-embedded .persona-chat-header h1 { margin: 3px 0 1px; font-size: 20px; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.persona-chat-header p { font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.persona-chat-header p .persona-header-divider { display: inline; letter-spacing: 0; opacity: .45; }
|
||||
.persona-chat-status { min-width: 0; flex: 0 1 440px; justify-content: flex-end; padding: 0; border: 0; border-radius: 0; background: transparent; }
|
||||
.persona-chat-status span { max-width: 340px; font-size: 11px; }
|
||||
.persona-chat-status button { padding: 6px 9px; border: 1px solid var(--agent-line); border-radius: 8px; }
|
||||
.persona-chat-body { grid-template-columns: 226px minmax(0,1fr); gap: 10px; }
|
||||
.persona-conversation-rail { gap: 8px; padding: 9px 8px; border: 0; border-right: 1px solid var(--agent-line); border-radius: 0; background: color-mix(in srgb,var(--surface-depth) 44%,transparent); }
|
||||
.persona-conversation-rail>header { padding: 0 4px 4px; }
|
||||
.persona-conversation-rail>header button { padding: 6px 8px; border-radius: 8px; }
|
||||
.persona-conversation-rail>div { gap: 3px; }
|
||||
.persona-conversation-rail article { border: 0; border-left: 2px solid transparent; border-radius: 8px; background: transparent; }
|
||||
.persona-conversation-rail article:hover { background: color-mix(in srgb,var(--content-primary) 4%,transparent); }
|
||||
.persona-conversation-rail article.active { border-color: var(--accent-light); background: color-mix(in srgb,var(--accent-light) 7%,transparent); }
|
||||
.persona-conversation-rail article>button:first-child { padding: 9px 27px 9px 10px; }
|
||||
.persona-conversation-delete { top: 6px; right: 4px; }
|
||||
.persona-chat-main { gap: 0; }
|
||||
.persona-chat-ledger,.persona-chat-world.is-embedded .persona-chat-ledger { min-height: 180px; gap: 18px; padding: 18px max(18px,calc((100% - 920px)/2)); border: 0; border-radius: 0; background: transparent; }
|
||||
.persona-chat-message { width: min(88%,760px); padding: 0 4px; border: 0; border-radius: 0; background: transparent; box-shadow: none; }
|
||||
.persona-chat-message.is-persona { align-self: flex-start; }
|
||||
.persona-chat-message.is-human { align-self: flex-end; width: min(76%,680px); padding: 12px 14px; border: 1px solid color-mix(in srgb,var(--accent-light) 16%,transparent); border-radius: 15px 15px 5px 15px; background: color-mix(in srgb,var(--accent-light) 10%,var(--panel-bg)); }
|
||||
.persona-chat-message header b { font-size: 11px; }
|
||||
.persona-chat-message header span,.persona-chat-message footer { font-size: 9px; }
|
||||
.persona-chat-message p { margin: 7px 0; font-size: 14px; line-height: 1.7; overflow-wrap: anywhere; }
|
||||
.persona-chat-message.is-persona p { font-size: 14.5px; }
|
||||
.persona-message-markdown { margin: 7px 0; font-size: 14.5px; line-height: 1.72; overflow-wrap: anywhere; }
|
||||
.persona-message-markdown :where(p,ul,ol,blockquote,pre) { margin: 0 0 11px; }
|
||||
.persona-message-markdown :where(ul,ol) { padding-left: 22px; }
|
||||
.persona-message-markdown li { margin: 4px 0; }
|
||||
.persona-message-markdown :where(h1,h2,h3,h4) { margin: 16px 0 8px; color: var(--content-primary); font-size: 15.5px; line-height: 1.4; }
|
||||
.persona-message-markdown code:not(pre code) { padding: 2px 5px; border-radius: 5px; background: color-mix(in srgb,var(--content-primary) 7%,transparent); font: .88em/1.5 ui-monospace,SFMono-Regular,Menlo,monospace; }
|
||||
.persona-message-markdown pre { overflow: auto; padding: 12px; border: 1px solid var(--agent-line); border-radius: 9px; background: color-mix(in srgb,var(--panel-bg) 80%,#000); font: 12.5px/1.65 ui-monospace,SFMono-Regular,Menlo,monospace; }
|
||||
.persona-message-markdown a { color: var(--accent-light); text-underline-offset: 3px; }
|
||||
.persona-message-markdown > :last-child { margin-bottom: 0; }
|
||||
.persona-chat-message footer { margin-top: 9px; padding-top: 7px; border-top: 1px solid var(--agent-line); }
|
||||
.persona-knowledge-receipts span { border-left: 2px solid color-mix(in srgb,var(--accent-light) 48%,transparent); border-radius: 0; background: color-mix(in srgb,var(--accent-light) 6%,transparent); }
|
||||
.persona-agent-activity { display: flex; flex-wrap: wrap; gap: 5px 13px; padding: 8px max(18px,calc((100% - 920px)/2)); border-top: 1px solid var(--agent-line); color: var(--content-secondary); }
|
||||
.persona-agent-activity>div { min-width: 0; display: flex; align-items: center; gap: 6px; font-size: 10px; }
|
||||
.persona-agent-activity i { width: 6px; height: 6px; flex: 0 0 auto; border-radius: 50%; background: var(--content-muted); }
|
||||
.persona-agent-activity .is-running i { background: var(--accent-light); box-shadow: 0 0 9px color-mix(in srgb,var(--accent-light) 62%,transparent); animation: persona-agent-pulse 1.15s ease-in-out infinite; }
|
||||
.persona-agent-activity .is-done i { background: #85d9bb; }
|
||||
.persona-agent-activity .is-failed i { background: #f18a8f; }
|
||||
.persona-agent-activity small { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--content-muted); }
|
||||
@keyframes persona-agent-pulse { 50% { opacity: .35; transform: scale(.78); } }
|
||||
.persona-chat-composer { gap: 7px; padding: 10px max(18px,calc((100% - 920px)/2)) 0; border-top: 1px solid var(--agent-line); background: color-mix(in srgb,var(--surface-depth) 44%,transparent); }
|
||||
.persona-chat-composer textarea,.persona-chat-world.is-embedded .persona-chat-composer textarea { min-height: 72px; max-height: 210px; padding: 12px 13px; border-radius: 12px; background: var(--agent-panel); box-shadow: none; outline: none; }
|
||||
.persona-chat-composer textarea:focus { border-color: color-mix(in srgb,var(--accent-light) 44%,transparent); box-shadow: 0 0 0 3px color-mix(in srgb,var(--accent-light) 7%,transparent); }
|
||||
.persona-chat-composer>div:last-child { font-size: 10px; }
|
||||
.persona-knowledge-focus { padding: 6px 8px; border: 0; border-left: 2px solid var(--accent-light); border-radius: 0; background: color-mix(in srgb,var(--accent-light) 5%,transparent); }
|
||||
.persona-chat-settings { position: absolute; z-index: 12; top: 64px; right: clamp(14px,2.4vw,28px); width: min(760px,calc(100% - 36px)); max-height: calc(100% - 80px); overflow: auto; padding: 16px; border-radius: 13px; background: color-mix(in srgb,var(--panel-bg) 97%,#020713); box-shadow: 0 24px 70px rgba(0,0,0,.42); }
|
||||
.persona-hldp-forge { position:absolute; z-index:13; inset:64px clamp(14px,2.4vw,28px) 18px auto; width:min(880px,calc(100% - 36px)); display:flex; flex-direction:column; gap:12px; padding:16px; border:1px solid var(--agent-line); border-radius:13px; background:color-mix(in srgb,var(--panel-bg) 98%,#020713); box-shadow:0 24px 70px rgba(0,0,0,.46); }
|
||||
.persona-hldp-forge>header,.persona-hldp-forge>footer { display:flex; align-items:flex-start; justify-content:space-between; gap:18px; }
|
||||
.persona-hldp-forge>header span,.persona-hldp-forge label>span,.persona-hldp-forge section>span { color:var(--content-muted); font-size:9px; letter-spacing:.12em; }
|
||||
.persona-hldp-forge h2 { margin:4px 0; font-size:18px; }
|
||||
.persona-hldp-forge p { margin:0; color:var(--content-secondary); font-size:11px; line-height:1.55; }
|
||||
.persona-hldp-forge>header button { border:0; background:transparent; color:var(--content-secondary); cursor:pointer; }
|
||||
.persona-hldp-forge-body { min-height:0; flex:1; display:grid; grid-template-columns:minmax(0,1.25fr) minmax(250px,.75fr); gap:12px; }
|
||||
.persona-hldp-forge label { min-height:0; display:flex; flex-direction:column; gap:6px; }
|
||||
.persona-hldp-forge textarea { min-height:0; flex:1; resize:none; padding:12px; border:1px solid var(--agent-line); border-radius:9px; background:color-mix(in srgb,var(--surface-depth) 84%,transparent); color:var(--content-primary); font:11px/1.55 ui-monospace,SFMono-Regular,Menlo,monospace; outline:none; }
|
||||
.persona-hldp-forge section { min-height:0; overflow:auto; display:flex; flex-direction:column; gap:7px; padding:12px; border-left:1px solid var(--agent-line); }
|
||||
.persona-hldp-forge section b { font-size:13px; }
|
||||
.persona-hldp-forge section small { color:var(--content-secondary); font:10px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace; }
|
||||
.persona-hldp-forge ol { margin:5px 0 0; padding-left:17px; color:var(--content-secondary); font:10px/1.7 ui-monospace,SFMono-Regular,Menlo,monospace; }
|
||||
.persona-hldp-forge>footer { align-items:center; padding-top:11px; border-top:1px solid var(--agent-line); }
|
||||
.persona-hldp-forge>footer span { color:var(--content-muted); font-size:10px; }
|
||||
.persona-hldp-forge>footer button { border:0; border-radius:9px; padding:9px 15px; background:var(--accent-light); color:var(--surface-depth); font-weight:760; cursor:pointer; }
|
||||
.persona-hldp-forge>footer button:disabled { opacity:.45; cursor:default; }
|
||||
.persona-chat-settings h2 { font-size: 18px; }
|
||||
.persona-provider-form { grid-template-columns: .8fr 1.4fr .8fr 1fr auto; }
|
||||
.persona-chat-notice { position: absolute; z-index: 14; left: 50%; bottom: 112px; transform: translateX(-50%); max-width: min(640px,84%); padding: 7px 11px; border: 1px solid var(--agent-line); border-radius: 9px; background: color-mix(in srgb,var(--panel-bg) 96%,transparent); color: var(--content-secondary); box-shadow: 0 10px 30px rgba(0,0,0,.25); }
|
||||
@media (max-width:900px) {
|
||||
.persona-chat-header { flex-direction: row; align-items: flex-start; }
|
||||
.persona-chat-status { width: auto; flex: 0 1 50%; }
|
||||
.persona-chat-status span { max-width: 180px; }
|
||||
.persona-chat-body { grid-template-columns: 176px minmax(0,1fr); }
|
||||
.persona-conversation-rail { max-height: none; }
|
||||
.persona-provider-form { grid-template-columns: 1fr; }
|
||||
}
|
||||
@media (max-width:680px) {
|
||||
.persona-chat-header p,.persona-chat-status span { display: none; }
|
||||
.persona-chat-body { grid-template-columns:1fr; }
|
||||
.persona-conversation-rail { max-height:132px; border-right:0; border-bottom:1px solid var(--agent-line); }
|
||||
.persona-chat-message.is-human { width:90%; }
|
||||
.persona-hldp-forge-body { grid-template-columns:1fr; }
|
||||
.persona-hldp-forge section { border-left:0; border-top:1px solid var(--agent-line); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@
|
|||
@keyframes sl-abyss-open { 0%{opacity:1;transform:translate(-50%,-50%) scale(1)} 54%{opacity:.9;transform:translate(-50%,-50%) scale(1.45);filter:brightness(1.4)} 100%{opacity:0;transform:translate(-50%,-50%) scale(3.2);filter:blur(16px) brightness(1.9)} }
|
||||
@keyframes sl-abyss-copy-away { to{opacity:0;transform:translateY(8px)} }
|
||||
.starlake-scene .world-channel-return { position:absolute; z-index:9; left:50%; top:44%; transform:translate(-50%,-50%); display:grid; justify-items:center; gap:4px;
|
||||
padding:12px 18px; border:0; color:inherit; background:radial-gradient(ellipse,rgba(247,235,200,.08),transparent 72%); cursor:pointer; font-family:inherit; }
|
||||
padding:12px 18px; border:0; color:inherit; background:radial-gradient(ellipse,rgba(247,235,200,.08),transparent 72%); pointer-events:auto; cursor:pointer; font-family:inherit; }
|
||||
.starlake-scene .world-channel-return b { color:#f7ebc8; font-size:13px; font-weight:760; letter-spacing:.18em; }
|
||||
.starlake-scene .world-channel-return small { color:rgba(196,206,228,.58); font-size:9px; font-weight:650; letter-spacing:.1em; }
|
||||
.starlake-scene .era-foot { position:absolute; left:50%; bottom:21px; transform:translateX(-50%); color:rgba(180,192,220,.34);
|
||||
|
|
|
|||
|
|
@ -971,6 +971,7 @@ svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-lineca
|
|||
|
||||
|
||||
/* ==== 标准工作台 · 公告与版本 · 执行层投影(实例1移植 2026-08-20 正向合并) ==== */
|
||||
.standard-workbench { width: 100vw; height: 100vh; display: grid; grid-template-columns: 52px 244px minmax(0, 1fr); overflow: hidden; color: var(--content-primary); background: var(--surface-depth); }
|
||||
.workbench-empty, .empty-state { display: grid; place-content: center; justify-items: center; color: var(--content-muted); text-align: center; }
|
||||
.workbench-empty { min-height: 0; padding: 40px; }
|
||||
.workbench-empty > span { color: var(--accent-light); font-family: "Songti SC", serif; font-size: 36px; }
|
||||
|
|
@ -1049,9 +1050,17 @@ svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-lineca
|
|||
.execution-fields dd { color: var(--content-secondary); }
|
||||
.release-fields { margin-top: 12px; border-top: 1px solid var(--panel-edge); }
|
||||
.release-fields > div { padding-left: 0; padding-right: 0; }
|
||||
.execution-projection { max-width: 1180px; margin: 0 auto; }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.standard-workbench { grid-template-columns: 48px 190px minmax(0, 1fr); }
|
||||
.workbench-topbar { grid-template-columns: minmax(120px, 1fr) auto; }
|
||||
.workbench-account { display: none; }
|
||||
.execution-section-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.standard-workbench { grid-template-columns: 46px minmax(0, 1fr); }
|
||||
.workbench-sidebar { display: none; }
|
||||
.workbench-topbar > div:first-child span { display: none; }
|
||||
.release-center-title, .execution-projection .page-title { align-items: flex-start; flex-direction: column; }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue