feat(lighthouse): add canonical three-host skill navigation

This commit is contained in:
冰朔 2026-08-07 18:39:00 +08:00
commit fb5f931e78
14 changed files with 891 additions and 22 deletions

View file

@ -0,0 +1,74 @@
{
"schema": "guanghu.development-closure-receipt/v1",
"receipt_id": "DEV-20260807-001-LIGHTHOUSE-HOST-NAVIGATION-20260807",
"development_id": "DEV-20260807-001",
"result": "PASS_100",
"source_repository": "REPO-012",
"source_baseline": "8423a967764174fb11f1879095d177608312984d",
"scope": [
"lighthouse_numbered_path_validity_gate",
"codex_qoder_cn_qoderwork_cn_host_navigation",
"local_macos_osxkeychain_repository_publish_route",
"jzao_shared_persona_brain_mirror",
"thin_local_host_adapters",
"legacy_route_redirects"
],
"canonical_ids": {
"lighthouse": "SYS-GLW-LTH-0001",
"path_registry": "GLW-LIGHTHOUSE-PATH-REGISTRY-001",
"host_navigation": "GLW-HOST-SKILL-NAV-001",
"navigation_skill": "GHS-009-LIGHTHOUSE-HOST-NAVIGATION",
"memory_brain": "GHS-007-MEMORY-CONTINUITY-SELF-BUILD",
"current_repository": "REPO-012",
"current_persona": "ICE-P-ZY001"
},
"truth_rule": "Only a stable numbered route registered by SYS-GLW-LTH-0001, returned by a non-degraded exact REPO-012 main snapshot and present in local reality when private is valid. Navigation grants no action authority.",
"artifacts": [
"routing/lighthouse-path-registry.json",
"routing/host-skill-navigation-map.json",
"routing/public-navigation-anchor.json",
"skills/shared/guanghu-lighthouse-navigator/BRAIN.hdlp",
"skills/shared/guanghu-lighthouse-navigator/SKILL.md",
"skills/shared/guanghu-lighthouse-navigator/scripts/resolve_lighthouse_route.py",
"skills/shared/guanghu-lighthouse-navigator/scripts/sync_jzao_mirror.py",
"server-tools/ai-discovery-gateway/server.js",
"skills/codex/guanghu-persona-skill-guard/references/persona-skill-registry.json"
],
"local_installation": {
"shared_root": "/Volumes/JZAO/HoloLake/persona-runtime/shared",
"codex_adapter": "/Users/bingshuolingdianyuanhe/.codex/skills/guanghu-lighthouse-navigator/SKILL.md",
"qoder_cn_adapter": "/Users/bingshuolingdianyuanhe/.qoder/skills/guanghu-lighthouse-navigator/SKILL.md",
"qoderwork_cn_adapter": "/Users/bingshuolingdianyuanhe/.qoderworkcn/skills/guanghu-lighthouse-navigator/SKILL.md",
"host_runtime_databases_moved": false,
"private_memory_published": false
},
"verified_routes": {
"codex_publish": "INTENT-REPOSITORY-PUBLISH-001 -> REPO-012 -> LOCAL_GIT_OSXKEYCHAIN -> lake-lamp finalizer",
"qoder_cn_memory": "INTENT-MEMORY-CONTINUITY-001 -> GHS-007 -> qoder-cn host partition",
"qoderwork_cn_memory": "INTENT-MEMORY-CONTINUITY-001 -> GHS-007 -> qoderwork-cn host partition",
"legacy_repo_001": "REDIRECT_ONLY_NOT_CURRENT -> REPO-012",
"legacy_persona_id": "ICE-GL-ZY001 -> ICE-P-ZY001"
},
"validation": {
"ai_discovery_gateway": "PASS_17_OF_17",
"lighthouse_navigator": "PASS_4_OF_4",
"persona_skill_resolver": "PASS_21_OF_21",
"jzao_mirror": "IN_SYNC",
"jzao_mirror_private_memory_included": false,
"json_parse": "PASS_100",
"git_diff_check": "PASS_100",
"osxkeychain_helper": "AVAILABLE_WITHOUT_SECRET_READ"
},
"publication": {
"repository": "repo://guanghulab.com/code/bingshuo/guanghu-ice-heart",
"branch": "main",
"state": "TO_BE_BOUND_BY_FINALIZATION_RECEIPT"
},
"runtime_boundary": {
"source_publication_is_service_deployment": false,
"public_api_new_endpoints_require_runtime_update_or_auto_refresh": true,
"host_adapter_files_installed": true,
"host_application_reload_verified": false
},
"recorded_at": "2026-08-07T18:36:00+08:00"
}

View file

@ -0,0 +1,134 @@
{
"schema": "guanghu.host-skill-navigation-map/v1",
"map_id": "GLW-HOST-SKILL-NAV-001",
"lighthouse_id": "SYS-GLW-LTH-0001",
"version": "2026-08-07.1",
"state": "CURRENT",
"hosts": [
{
"id": "HOST-CODEX-MACOS-001",
"aliases": ["codex", "Codex"],
"platform": "macOS",
"adapter_path": "~/.codex/skills/guanghu-lighthouse-navigator/SKILL.md",
"runtime_state_policy": "KEEP_LOCAL",
"shared_persona_source": "HL-PERSONA-RUNTIME-LOCAL-001",
"supported_transports": ["LOCAL_GIT_OSXKEYCHAIN"],
"skill_discovery": "CODEX_SKILL_DIRECTORY"
},
{
"id": "HOST-QODER-CN-MACOS-001",
"aliases": ["qoder", "qoder-cn", "Qoder CN"],
"platform": "macOS",
"adapter_path": "~/.qoder/skills/guanghu-lighthouse-navigator/SKILL.md",
"runtime_state_policy": "KEEP_LOCAL",
"shared_persona_source": "HL-PERSONA-RUNTIME-LOCAL-001",
"supported_transports": ["LOCAL_GIT_OSXKEYCHAIN"],
"skill_discovery": "QODER_SKILL_DIRECTORY"
},
{
"id": "HOST-QODERWORK-CN-MACOS-001",
"aliases": ["qoderwork", "qoderwork-cn", "QoderWork CN"],
"platform": "macOS",
"adapter_path": "~/.qoderworkcn/skills/guanghu-lighthouse-navigator/SKILL.md",
"runtime_state_policy": "KEEP_LOCAL",
"shared_persona_source": "HL-PERSONA-RUNTIME-LOCAL-001",
"supported_transports": ["LOCAL_GIT_OSXKEYCHAIN"],
"skill_discovery": "QODERWORK_USER_SKILL_DIRECTORY"
}
],
"intents": [
{
"id": "INTENT-REPOSITORY-PUBLISH-001",
"phrases": [
"推一下线上仓库",
"推送代码频道",
"把代码推上去",
"发布到光湖代码频道",
"push repository",
"git push"
],
"skill_id": "GHS-003-REPOSITORY-PUSH-PROOF-SEPARATION",
"target_id": "REPO-012",
"transport": "LOCAL_GIT_OSXKEYCHAIN",
"executor": "server-tools/lake-lamp-continuity-guard/finalize-development.mjs",
"sequence": [
"resolve_target_through_lighthouse",
"verify_current_host",
"verify_exact_worktree_remote_branch_and_head",
"verify_osxkeychain_helper_without_reading_secret",
"run_registered_tests",
"commit_intended_files",
"run_lake_lamp_finalizer",
"read_back_remote_full_sha_and_receipt"
],
"stop_conditions": [
"LIGHTHOUSE_LOOKUP_NOT_200",
"LIGHTHOUSE_SOURCE_DEGRADED",
"TARGET_NOT_CURRENT",
"WORKTREE_SCOPE_UNVERIFIED",
"KEYCHAIN_HELPER_UNAVAILABLE",
"PUBLISH_LEASE_UNAVAILABLE",
"TESTS_FAILED",
"REMOTE_READBACK_FAILED"
],
"authority": "USER_REQUEST_REQUIRED_AND_CURRENT_TASK_SCOPE_ONLY"
},
{
"id": "INTENT-PERSONA-RESTORE-001",
"phrases": [
"恢复铸渊",
"进入光湖语言世界",
"启动人格系统",
"去第五域恢复"
],
"skill_id": "GHS-001-FIFTH-DOMAIN-RESTORE",
"target_id": "GLW-PUBLIC-NAV-ANCHOR-001",
"transport": "PUBLIC_READ_ONLY_HTTPS_THEN_JZAO_PRIVATE",
"sequence": [
"resolve_language_world_entry_through_lighthouse",
"load_host_adapter",
"load_private_host_checkpoint_if_present",
"run_verified_persona_entry"
],
"stop_conditions": [
"LIGHTHOUSE_LOOKUP_NOT_200",
"PRIVATE_VOLUME_MISSING",
"PERSONA_ENTRY_UNVERIFIED"
],
"authority": "NAVIGATION_ONLY"
},
{
"id": "INTENT-MEMORY-CONTINUITY-001",
"phrases": [
"记忆连续守卫",
"压缩之眼",
"检查点存盘",
"跨对话记忆",
"大脑思维技能包"
],
"skill_id": "GHS-007-MEMORY-CONTINUITY-SELF-BUILD",
"target_id": "HL-PERSONA-RUNTIME-LOCAL-001",
"transport": "JZAO_PRIVATE",
"sequence": [
"resolve_skill_through_lighthouse",
"load_shared_brain",
"select_current_host_projection",
"use_host_partitioned_checkpoint"
],
"stop_conditions": [
"LIGHTHOUSE_LOOKUP_NOT_200",
"PRIVATE_VOLUME_MISSING",
"HOST_UNKNOWN_NO_GUESS"
],
"authority": "NAVIGATION_ONLY"
}
],
"truth_precedence": [
"current_explicit_user_instruction",
"healthy_lighthouse_number_resolution",
"JZAO_private_persona_checkpoint",
"exact_REPO_012_main_snapshot",
"host_adapter",
"host_cache_never_authoritative"
]
}

View file

@ -0,0 +1,82 @@
{
"schema": "guanghu.lighthouse-path-registry/v1",
"registry_id": "GLW-LIGHTHOUSE-PATH-REGISTRY-001",
"lighthouse_id": "SYS-GLW-LTH-0001",
"version": "2026-08-07.1",
"state": "CURRENT_CANONICAL",
"source_repository": "REPO-012",
"source_branch": "main",
"public_lookup": "https://guanghulab.com/api/ai/v1/resolve?id={NUMBER}",
"validity_rule": {
"decision": "A route is valid only when it has a stable numbered id in this registry, its state is CURRENT or ACTIVE, and the lighthouse lookup returns HTTP 200 from a non-degraded exact REPO-012 main snapshot.",
"unknown": "INVALID_NO_GUESS",
"deprecated": "REDIRECT_ONLY_NOT_CURRENT",
"local_private": "A private local route must also exist on the current machine. Lighthouse registration does not make a missing volume or file exist.",
"authority": "A healthy route grants navigation only. Repository writes, server actions and deployment still require their registered gates and receipts."
},
"paths": [
{
"id": "GLW-PUBLIC-NAV-ANCHOR-001",
"kind": "public_navigation_anchor",
"state": "CURRENT",
"online": "https://guanghulab.com/api/ai/v1/anchor",
"offline": "routing/public-navigation-anchor.json",
"owner": "REPO-012"
},
{
"id": "REPO-012",
"kind": "code_channel_repository",
"state": "CURRENT",
"online": "https://guanghulab.com/code/bingshuo/guanghu-ice-heart",
"clone": "https://guanghulab.com/code/bingshuo/guanghu-ice-heart.git",
"offline": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/WORK-工作区/guanghu-ice-heart",
"transport": "LOCAL_GIT_OSXKEYCHAIN",
"publication_gate": "HOLOLAKE-CONTINUITY-COLLABORATION-CURRENT"
},
{
"id": "HL-PERSONA-RUNTIME-LOCAL-001",
"kind": "private_persona_runtime_root",
"state": "ACTIVE_LOCAL_PRIVATE",
"online": null,
"offline": "/Volumes/JZAO/HoloLake/persona-runtime",
"privacy": "NEVER_PUBLIC_MIRROR_PRIVATE_MEMORY"
},
{
"id": "GHS-007-MEMORY-CONTINUITY-SELF-BUILD",
"kind": "persona_brain_skill",
"state": "ACTIVE_CANDIDATE",
"online": "skills/qoder/zhuyuan-memory-continuity-brain/BRAIN.hdlp",
"offline": "/Volumes/JZAO/HoloLake/persona-runtime/shared/brains/GHS-007-MEMORY-CONTINUITY-SELF-BUILD/BRAIN.hdlp",
"registry": "GLS-0238"
},
{
"id": "GHS-009-LIGHTHOUSE-HOST-NAVIGATION",
"kind": "host_navigation_skill",
"state": "ACTIVE",
"online": "skills/shared/guanghu-lighthouse-navigator/SKILL.md",
"offline": "/Volumes/JZAO/HoloLake/persona-runtime/shared/skills/guanghu-lighthouse-navigator/SKILL.md",
"registry": "GLS-0238"
},
{
"id": "GLW-HOST-SKILL-NAV-001",
"kind": "host_skill_navigation_map",
"state": "CURRENT",
"online": "routing/host-skill-navigation-map.json",
"offline": "/Volumes/JZAO/HoloLake/persona-runtime/shared/registries/host-skill-navigation-map.json"
}
],
"redirects": [
{
"id": "REPO-001",
"state": "HISTORICAL_REDIRECT_ONLY",
"redirect_to": "REPO-012",
"reason": "Fourth-generation Fifth Domain history is not the current code-channel entry."
},
{
"id": "ICE-GL-ZY001",
"state": "LEGACY_ID_REDIRECT_ONLY",
"redirect_to": "ICE-P-ZY001",
"reason": "Legacy persona id; canonicalize before navigation."
}
]
}

View file

@ -1,7 +1,7 @@
{
"schema": "guanghu.public-navigation-anchor/v1",
"anchor_id": "GLW-PUBLIC-NAV-ANCHOR-001",
"version": "2026-08-07.1",
"version": "2026-08-07.2",
"state": "CURRENT_CANONICAL",
"repository_id": "REPO-012",
"branch": "main",
@ -39,10 +39,20 @@
"id": "AI-MACHINE-NAV-001",
"version": "2026-08-05.1"
},
"lighthouse_paths": {
"path": "routing/lighthouse-path-registry.json",
"id": "GLW-LIGHTHOUSE-PATH-REGISTRY-001",
"version": "2026-08-07.1"
},
"host_skills": {
"path": "routing/host-skill-navigation-map.json",
"id": "GLW-HOST-SKILL-NAV-001",
"version": "2026-08-07.1"
},
"persona_skills": {
"path": "skills/codex/guanghu-persona-skill-guard/references/persona-skill-registry.json",
"id": "GLS-0238",
"version": "2026.08.07.2"
"version": "2026.08.07.6"
}
},
"update_contract": {

View file

@ -11,13 +11,19 @@ const DEFAULT_NODE_MAP = path.resolve(__dirname, "../../routing/server-node-map.
const DEFAULT_SUBJECT_REGISTRY = path.resolve(__dirname, "../../identity/fifth-domain-subject-registry.json");
const DEFAULT_SUBJECT_ALIAS_MAP = path.resolve(__dirname, "../../identity/subject-id-alias-map.json");
const DEFAULT_NAVIGATION_MAP = path.resolve(__dirname, "../../routing/ai-machine-navigation-map.json");
const SNAPSHOT_KEYS = Object.freeze(["repository", "nodes", "subjects", "aliases", "navigation"]);
const DEFAULT_LIGHTHOUSE_PATHS = path.resolve(__dirname, "../../routing/lighthouse-path-registry.json");
const DEFAULT_HOST_SKILLS = path.resolve(__dirname, "../../routing/host-skill-navigation-map.json");
const SNAPSHOT_KEYS = Object.freeze([
"repository", "nodes", "subjects", "aliases", "navigation", "lighthouse_paths", "host_skills",
]);
const SNAPSHOT_PATHS = Object.freeze({
repository: "routing/repository-route-map.json",
nodes: "routing/server-node-map.json",
subjects: "identity/fifth-domain-subject-registry.json",
aliases: "identity/subject-id-alias-map.json",
navigation: "routing/ai-machine-navigation-map.json",
lighthouse_paths: "routing/lighthouse-path-registry.json",
host_skills: "routing/host-skill-navigation-map.json",
});
function loadAnchor(filename = process.env.GUANGHU_NAVIGATION_ANCHOR || DEFAULT_ANCHOR) {
@ -44,6 +50,14 @@ function loadNavigationMap(filename = process.env.GUANGHU_NAVIGATION_MAP || DEFA
return JSON.parse(fs.readFileSync(filename, "utf8"));
}
function loadLighthousePaths(filename = process.env.GUANGHU_LIGHTHOUSE_PATHS || DEFAULT_LIGHTHOUSE_PATHS) {
return JSON.parse(fs.readFileSync(filename, "utf8"));
}
function loadHostSkills(filename = process.env.GUANGHU_HOST_SKILLS || DEFAULT_HOST_SKILLS) {
return JSON.parse(fs.readFileSync(filename, "utf8"));
}
function validateSnapshot(anchor, maps) {
if (anchor.schema !== "guanghu.public-navigation-anchor/v1") throw new Error("invalid_anchor_schema");
if (anchor.anchor_id !== "GLW-PUBLIC-NAV-ANCHOR-001") throw new Error("invalid_anchor_id");
@ -76,6 +90,8 @@ function loadFileSnapshot(options = {}) {
subjects: loadSubjectRegistry(options.subjectRegistryFile),
aliases: loadSubjectAliasMap(options.subjectAliasMapFile),
navigation: loadNavigationMap(options.navigationMapFile),
lighthouse_paths: loadLighthousePaths(options.lighthousePathsFile),
host_skills: loadHostSkills(options.hostSkillsFile),
});
}
@ -351,12 +367,100 @@ function compileNavigation(navigationMap, requestedSubject, requestedIntent, sig
};
}
function resolveLighthousePath(registry, requestedId) {
const id = String(requestedId || "").trim().toUpperCase();
const route = (registry.paths || []).find(item => String(item.id).toUpperCase() === id);
if (route) {
const current = ["CURRENT", "ACTIVE", "ACTIVE_CANDIDATE", "ACTIVE_LOCAL_PRIVATE"].includes(route.state);
return {
status: current ? 200 : 410,
body: {
schema: "guanghu.lighthouse-path-resolution/v1",
decision: current ? "VALID_REGISTERED" : "INVALID_STATE",
lighthouse_id: registry.lighthouse_id,
registry_id: registry.registry_id,
registry_version: registry.version,
route,
authority: "NONE_NAVIGATION_ONLY",
},
};
}
const redirect = (registry.redirects || []).find(item => String(item.id).toUpperCase() === id);
if (redirect) {
return {
status: 308,
body: {
schema: "guanghu.lighthouse-path-resolution/v1",
decision: "REDIRECT_ONLY_NOT_CURRENT",
lighthouse_id: registry.lighthouse_id,
registry_id: registry.registry_id,
registry_version: registry.version,
redirect,
authority: "NONE_NAVIGATION_ONLY",
},
};
}
return {
status: 404,
body: {
error: "lighthouse_path_not_registered_no_guess",
requested_id: requestedId,
lighthouse_id: registry.lighthouse_id,
},
};
}
function compileHostNavigation(hostMap, lighthouseRegistry, requestedHost, requestedIntent) {
const hostKey = normalize(requestedHost);
const host = (hostMap.hosts || []).find(item =>
[item.id, ...(item.aliases || [])].some(id => normalize(id) === hostKey)
);
if (!host) return { status: 404, body: { error: "host_unknown_no_guess", requested_host: requestedHost } };
const intentText = normalize(requestedIntent);
const ranked = (hostMap.intents || [])
.map(intent => ({
intent,
score: (intent.phrases || []).reduce(
(score, phrase) => score + (intentText.includes(normalize(phrase)) ? normalize(phrase).length : 0),
0,
),
}))
.filter(item => item.score > 0)
.sort((a, b) => b.score - a.score || a.intent.id.localeCompare(b.intent.id));
if (!ranked.length) {
return { status: 404, body: { error: "host_intent_unknown_no_guess", requested_intent: requestedIntent } };
}
const intent = ranked[0].intent;
const target = resolveLighthousePath(lighthouseRegistry, intent.target_id);
if (target.status !== 200) {
return {
status: 503,
body: { error: "lighthouse_target_not_current", target_resolution: target.body },
};
}
return {
status: 200,
body: {
schema: "guanghu.host-skill-navigation-bundle/v1",
status: "COMPILED_EXACT_NO_GUESS",
lighthouse_id: lighthouseRegistry.lighthouse_id,
registry_id: lighthouseRegistry.registry_id,
host,
intent,
target: target.body.route,
authority: "NONE_NAVIGATION_ONLY",
},
};
}
function createServer(options = {}) {
const mapFile = options.mapFile || process.env.GUANGHU_REPOSITORY_MAP || DEFAULT_MAP;
const nodeMapFile = options.nodeMapFile || process.env.GUANGHU_NODE_MAP || DEFAULT_NODE_MAP;
const subjectRegistryFile = options.subjectRegistryFile || process.env.GUANGHU_SUBJECT_REGISTRY || DEFAULT_SUBJECT_REGISTRY;
const subjectAliasMapFile = options.subjectAliasMapFile || process.env.GUANGHU_SUBJECT_ALIAS_MAP || DEFAULT_SUBJECT_ALIAS_MAP;
const navigationMapFile = options.navigationMapFile || process.env.GUANGHU_NAVIGATION_MAP || DEFAULT_NAVIGATION_MAP;
const lighthousePathsFile = options.lighthousePathsFile || process.env.GUANGHU_LIGHTHOUSE_PATHS || DEFAULT_LIGHTHOUSE_PATHS;
const hostSkillsFile = options.hostSkillsFile || process.env.GUANGHU_HOST_SKILLS || DEFAULT_HOST_SKILLS;
const anchorFile = options.anchorFile || process.env.GUANGHU_NAVIGATION_ANCHOR || DEFAULT_ANCHOR;
const gitDir = options.gitDir || process.env.GUANGHU_REPOSITORY_GIT_DIR;
const snapshotStore = options.snapshotStore || (gitDir ? new GitSnapshotStore(gitDir) : null);
@ -371,6 +475,7 @@ function createServer(options = {}) {
: {
...loadFileSnapshot({
anchorFile, mapFile, nodeMapFile, subjectRegistryFile, subjectAliasMapFile, navigationMapFile,
lighthousePathsFile, hostSkillsFile,
}),
source_commit: null,
source_mode: "FILESYSTEM_SNAPSHOT",
@ -384,6 +489,8 @@ function createServer(options = {}) {
const subjectRegistry = snapshot.subjects;
const aliasMap = snapshot.aliases;
const navigationMap = snapshot.navigation;
const lighthousePaths = snapshot.lighthouse_paths;
const hostSkills = snapshot.host_skills;
if (url.pathname === "/health") {
return json(res, snapshot.source_degraded ? 503 : 200, {
ok: !snapshot.source_degraded,
@ -399,6 +506,8 @@ function createServer(options = {}) {
if (url.pathname === "/v1/nodes") return json(res, 200, withSource(nodeMap, snapshot), 60);
if (url.pathname === "/v1/subjects") return json(res, 200, withSource(subjectRegistry, snapshot), 60);
if (url.pathname === "/v1/navigation") return json(res, 200, withSource(navigationMap, snapshot), 60);
if (url.pathname === "/v1/lighthouse") return json(res, 200, withSource(lighthousePaths, snapshot), 60);
if (url.pathname === "/v1/host-skills") return json(res, 200, withSource(hostSkills, snapshot), 60);
if (url.pathname === "/v1/entry") {
const subject = String(url.searchParams.get("subject") || "").toUpperCase();
if (!["ICE-P-ZY001", "ICE-GL-ZY001", "ICE-PZY-001"].includes(subject)) {
@ -427,6 +536,15 @@ function createServer(options = {}) {
);
return json(res, compiled.status, withSource(compiled.body, snapshot), compiled.status === 200 ? 60 : 0);
}
if (url.pathname === "/v1/host-navigate") {
const compiled = compileHostNavigation(
hostSkills,
lighthousePaths,
String(url.searchParams.get("host") || "").slice(0, 100),
String(url.searchParams.get("intent") || "").slice(0, 500),
);
return json(res, compiled.status, withSource(compiled.body, snapshot), compiled.status === 200 ? 60 : 0);
}
if (url.pathname === "/v1/search") {
const query = String(url.searchParams.get("q") || "").slice(0, 200);
const results = searchAll(map, nodeMap, query, subjectRegistry);
@ -493,6 +611,10 @@ function createServer(options = {}) {
},
}, snapshot), 60);
}
const lighthouseResolution = resolveLighthousePath(lighthousePaths, id);
if (lighthouseResolution.status !== 404) {
return json(res, lighthouseResolution.status, withSource(lighthouseResolution.body, snapshot), 60);
}
return json(res, 404, { error: "route_not_found", id });
}
if (url.pathname === "/openapi.json") return json(res, 200, openApi(), 3600);
@ -506,6 +628,9 @@ function createServer(options = {}) {
subject_registry: "https://guanghulab.com/api/ai/v1/subjects",
subject_alias_map: "https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/branch/main/identity/subject-id-alias-map.json",
machine_navigation_map: "https://guanghulab.com/api/ai/v1/navigation",
lighthouse_path_registry: "https://guanghulab.com/api/ai/v1/lighthouse",
host_skill_navigation_map: "https://guanghulab.com/api/ai/v1/host-skills",
host_navigate_api: "https://guanghulab.com/api/ai/v1/host-navigate?host={HOST}&intent={NATURAL_LANGUAGE_INTENT}",
warm_persona_entry: "https://guanghulab.com/api/ai/v1/entry?subject=ICE-P-ZY001",
navigate_api: "https://guanghulab.com/api/ai/v1/navigate?subject={SUBJECT}&intent={INTENT}&signals={EXPLICIT_SIGNALS}",
search_api: "https://guanghulab.com/api/ai/v1/search?q={query}",
@ -562,6 +687,9 @@ function openApi() {
"/v1/nodes": { get: { summary: "读取最新服务器节点与人格路径编号映射", responses: { "200": { description: "Server node map" } } } },
"/v1/subjects": { get: { summary: "读取人类、人格体与公共系统的分型身份注册表", responses: { "200": { description: "Subject registry" } } } },
"/v1/navigation": { get: { summary: "读取主体与意图驱动的机器导航地图", responses: { "200": { description: "Machine navigation map" } } } },
"/v1/lighthouse": { get: { summary: "读取光湖灯塔唯一有效路径注册表", responses: { "200": { description: "Lighthouse path registry" } } } },
"/v1/host-skills": { get: { summary: "读取 Codex、Qoder CN 与 QoderWork CN 宿主技能导航表", responses: { "200": { description: "Host skill navigation map" } } } },
"/v1/host-navigate": { get: { summary: "按宿主和自然语言意图编译确定性技能路径", responses: { "200": { description: "Compiled host skill route" }, "404": { description: "Unknown host or intent" } } } },
"/v1/entry": { get: { summary: "读取常驻人格运行体的快速恢复门;只返回脱敏状态,不授予执行权限", responses: { "200": { description: "Warm resume ready" }, "409": { description: "Full cycle required" }, "503": { description: "Resident runtime unavailable" } } } },
"/v1/navigate": { get: { summary: "按明确主体、意图与信号生成最小运行包", parameters: [{ name: "subject", in: "query", required: true, schema: { type: "string", example: "ICE-P-ZY001" } }, { name: "intent", in: "query", schema: { type: "string", example: "persona_restore" } }, { name: "signals", in: "query", schema: { type: "string" } }], responses: { "200": { description: "Compiled exact navigation bundle" }, "404": { description: "Unknown subject or intent; no guessing" } } } },
"/v1/search": { get: { summary: "按中文、编号或项目名检索", parameters: [{ name: "q", in: "query", schema: { type: "string" } }], responses: { "200": { description: "Search results" } } } },
@ -578,7 +706,8 @@ if (require.main === module) {
module.exports = {
createServer, loadAnchor, loadMap, loadNodeMap, loadSubjectRegistry, loadSubjectAliasMap, loadNavigationMap,
loadLighthousePaths, loadHostSkills,
loadFileSnapshot, validateSnapshot, GitSnapshotStore, sourceReceipt,
readResidentRuntimeStatus, compileWarmEntry,
resolveSubjectId, navigationRoute, compileNavigation, search, searchAll,
resolveSubjectId, navigationRoute, compileNavigation, resolveLighthousePath, compileHostNavigation, search, searchAll,
};

View file

@ -7,8 +7,9 @@ const { execFileSync } = require("node:child_process");
const test = require("node:test");
const {
createServer, loadAnchor, loadMap, loadNodeMap, loadSubjectRegistry, loadSubjectAliasMap, loadNavigationMap,
loadLighthousePaths, loadHostSkills,
loadFileSnapshot, GitSnapshotStore, compileWarmEntry,
resolveSubjectId, compileNavigation, search, searchAll,
resolveSubjectId, compileNavigation, resolveLighthousePath, compileHostNavigation, search, searchAll,
} = require("./server");
function warmRuntimeStatus(overrides = {}) {
@ -65,6 +66,8 @@ test("Git snapshot store follows main atomically and retains the last known-good
subjects: ["identity/fifth-domain-subject-registry.json", "FD-SUBJECT-REGISTRY-001"],
aliases: ["identity/subject-id-alias-map.json", "FD-SUBJECT-ID-ALIAS-MAP-001"],
navigation: ["routing/ai-machine-navigation-map.json", "AI-MACHINE-NAV-001"],
lighthouse_paths: ["routing/lighthouse-path-registry.json", "GLW-LIGHTHOUSE-PATH-REGISTRY-001"],
host_skills: ["routing/host-skill-navigation-map.json", "GLW-HOST-SKILL-NAV-001"],
};
fs.mkdirSync(path.join(root, "routing"), { recursive: true });
fs.mkdirSync(path.join(root, "identity"), { recursive: true });
@ -79,7 +82,7 @@ test("Git snapshot store follows main atomically and retains the last known-good
};
for (const [key, [relative, id]] of Object.entries(declarations)) {
anchor.maps[key] = { path: relative, id, version: "1" };
const idKey = key === "subjects" ? "registry_id" : "map_id";
const idKey = ["subjects", "lighthouse_paths"].includes(key) ? "registry_id" : "map_id";
fs.writeFileSync(path.join(root, relative), JSON.stringify({ [idKey]: id, version: "1" }));
}
fs.writeFileSync(path.join(root, "routing/public-navigation-anchor.json"), JSON.stringify(anchor));
@ -211,6 +214,31 @@ test("machine navigator fails closed instead of guessing", () => {
assert.equal(compileNavigation(loadNavigationMap(), "ICE-P-ZY001", "please_guess").body.error, "unknown_intent_no_guess");
});
test("lighthouse is the numbered path validity gate", () => {
const registry = loadLighthousePaths();
assert.equal(resolveLighthousePath(registry, "REPO-012").status, 200);
const old = resolveLighthousePath(registry, "REPO-001");
assert.equal(old.status, 308);
assert.equal(old.body.redirect.redirect_to, "REPO-012");
assert.equal(resolveLighthousePath(registry, "RANDOM-PATH").status, 404);
});
test("host navigator compiles local keychain publication without granting authority", () => {
const compiled = compileHostNavigation(
loadHostSkills(),
loadLighthousePaths(),
"codex",
"你推一下线上仓库",
);
assert.equal(compiled.status, 200);
assert.equal(compiled.body.host.id, "HOST-CODEX-MACOS-001");
assert.equal(compiled.body.intent.id, "INTENT-REPOSITORY-PUBLISH-001");
assert.equal(compiled.body.target.id, "REPO-012");
assert.equal(compiled.body.intent.transport, "LOCAL_GIT_OSXKEYCHAIN");
assert.equal(compiled.body.authority, "NONE_NAVIGATION_ONLY");
assert.equal(compileHostNavigation(loadHostSkills(), loadLighthousePaths(), "unknown", "推一下线上仓库").status, 404);
});
test("public endpoints are read-only and expose CORS", async () => {
const server = createServer({ runtimeStatusProvider: async () => warmRuntimeStatus() });
await new Promise(resolve => server.listen(0, "127.0.0.1", resolve));
@ -248,6 +276,14 @@ test("public endpoints are read-only and expose CORS", async () => {
);
const navigationResponse = await fetch(`${base}/v1/navigation`);
assert.equal((await navigationResponse.json()).map_id, "AI-MACHINE-NAV-001");
const lighthouseResponse = await fetch(`${base}/v1/lighthouse`);
assert.equal((await lighthouseResponse.json()).registry_id, "GLW-LIGHTHOUSE-PATH-REGISTRY-001");
const hostNavigateResponse = await fetch(
`${base}/v1/host-navigate?host=codex&intent=${encodeURIComponent("推一下线上仓库")}`,
);
const hostBundle = await hostNavigateResponse.json();
assert.equal(hostNavigateResponse.status, 200);
assert.equal(hostBundle.intent.id, "INTENT-REPOSITORY-PUBLISH-001");
const navigateResponse = await fetch(`${base}/v1/navigate?subject=ICE-P-ZY001&intent=persona_restore&signals=context_compacted`);
const bundle = await navigateResponse.json();
assert.equal(navigateResponse.status, 200);

View file

@ -1,7 +1,7 @@
{
"schema": "guanghu.persona-skill-registry/v1",
"registry_id": "GLS-0238",
"version": "2026.08.07.5",
"version": "2026.08.07.6",
"trust_policy": {
"priority": [
"live_verified_evidence",
@ -39,14 +39,12 @@
"空白实例"
],
"preferred_route": [
"REPO-001",
"CH-ZERO-CORE-LPM",
"TCS-LPM",
"TCS-LPS-REGISTRY-0001",
"LIGHT-LAKE",
"LL-CURRENT",
"LL-004",
"ICE-GL-ZY001",
"SYS-GLW-LTH-0001",
"GLW-PUBLIC-NAV-ANCHOR-001",
"REPO-012",
"LL-CMPN-0001",
"SYS-GLW-0001",
"ICE-P-ZY001",
"ZY-OPS-LOOP-001"
],
"forbidden_route_markers": [
@ -57,21 +55,26 @@
],
"deprecated_route_markers": [
"BROADCAST-TOWER作为根注册入口",
"旧本地副本优先于在线main"
"旧本地副本优先于在线main",
"REPO-001作为当前入口",
"ICE-GL-ZY001作为当前主体编号"
],
"evidence": [
".code-map",
"routing/lighthouse-path-registry.json",
"routing/public-navigation-anchor.json",
"routing/ai-machine-navigation-map.json",
"skills/codex/enter-fifth-domain/SKILL.md",
"tcs-core/WAKE-UP-PROTOCOL.hdlp"
],
"freshness": {
"check": "Resolve live REPO-001 and read current main before relying on a cached checkout.",
"check": "Resolve GLW-PUBLIC-NAV-ANCHOR-001 and every numbered route through the healthy lighthouse snapshot from the current REPO-012 main before relying on a cached checkout.",
"max_age_seconds": 0
},
"authorization": "Public route recovery is read-only. Writes and external actions require separate current authority.",
"recovery_route": [
"Return to current REPO-001 main",
"Resolve .code-map and subject kind",
"Query SYS-GLW-LTH-0001 by numbered id",
"Return to current REPO-012 main",
"Resolve the canonical anchor and subject kind",
"Rebuild the intent-state capsule from live evidence"
],
"enforcement_level": "PROMOTED_SKILL",
@ -492,6 +495,67 @@
"experience_receipts": [
"JD-PERSONA-ON-DEMAND-LIFECYCLE-20260807"
]
},
{
"id": "GHS-009-LIGHTHOUSE-HOST-NAVIGATION",
"hldp_skill": "GUANGHU-LIGHTHOUSE-HOST-NAVIGATION-BRAIN-001",
"gls_id": "GLS-0238",
"title": "光湖灯塔三宿主自动技能导航",
"intents": [
"光湖灯塔",
"唯一置信点",
"路径是否有效",
"旧路径过期",
"小湖灯提词器",
"三端自动导航",
"Codex Qoder QoderWork",
"推一下线上仓库",
"直接走钥匙串",
"自动技能导航"
],
"preferred_route": [
"SYS-GLW-LTH-0001",
"GLW-LIGHTHOUSE-PATH-REGISTRY-001",
"GLW-HOST-SKILL-NAV-001",
"识别当前宿主",
"把自然语言映射为稳定意图编号",
"按编号查询灯塔健康状态",
"执行宿主薄适配并返回现实回执"
],
"forbidden_route_markers": [
"未登记路径直接执行",
"灯塔查询失败仍猜路径",
"从历史聊天搜索凭据",
"打印钥匙串秘密",
"把导航健康当作执行成功",
"把本机缓存当作路径正本"
],
"deprecated_route_markers": [
"REPO-001作为当前入口",
"旧/fifth-domain/作为推送目标",
"ICE-GL-ZY001作为当前主体编号",
"三个宿主分别维护大脑正文"
],
"evidence": [
"routing/lighthouse-path-registry.json",
"routing/host-skill-navigation-map.json",
"skills/shared/guanghu-lighthouse-navigator/BRAIN.hdlp",
"skills/shared/guanghu-lighthouse-navigator/SKILL.md",
"server-tools/ai-discovery-gateway/server.js"
],
"freshness": {
"check": "Require an HTTP 200 numbered lighthouse lookup from a non-degraded exact REPO-012 main snapshot, then verify local private paths exist.",
"max_age_seconds": 0
},
"authorization": "The navigator selects a deterministic host route but grants no repository, server, deployment or secret-reading authority.",
"recovery_route": [
"Stop the guessed route",
"Resolve the stable number through SYS-GLW-LTH-0001",
"Canonicalize redirects",
"Recompile the route for the current host"
],
"enforcement_level": "PROMOTED_SKILL",
"experience_receipts": []
}
]
}

View file

@ -65,7 +65,7 @@ def resolve(registry: dict, intent: str, proposed_route: str = "") -> dict:
"decision": "NO_MATCH",
"registry_id": registry["registry_id"],
"registry_version": registry["version"],
"correction": "Resolve live REPO-001 and current .code-map; do not invent a route.",
"correction": "Resolve the stable number through SYS-GLW-LTH-0001 and current REPO-012 main; do not invent a route.",
"authority_granted": False,
}

View file

@ -12,7 +12,8 @@ class PersonaSkillResolverTests(unittest.TestCase):
result = resolve(self.registry, "我是冰朔,进入第五域并恢复小湖灯铸渊人格系统")
self.assertEqual(result["decision"], "ALLOW")
self.assertEqual(result["matched_skill"], "GHS-001-FIFTH-DOMAIN-RESTORE")
self.assertIn("REPO-001", result["preferred_route"])
self.assertIn("SYS-GLW-LTH-0001", result["preferred_route"])
self.assertIn("REPO-012", result["preferred_route"])
self.assertFalse(result["authority_granted"])
def test_corrects_deprecated_server_relay(self):
@ -46,8 +47,15 @@ class PersonaSkillResolverTests(unittest.TestCase):
def test_unknown_intent_fails_closed(self):
result = resolve(self.registry, "安排明天的午饭")
self.assertEqual(result["decision"], "NO_MATCH")
self.assertIn("SYS-GLW-LTH-0001", result["correction"])
self.assertFalse(result["authority_granted"])
def test_lighthouse_host_navigation_resolves_local_keychain_publish(self):
result = resolve(self.registry, "你推一下线上仓库,直接走钥匙串")
self.assertEqual(result["decision"], "ALLOW")
self.assertEqual(result["matched_skill"], "GHS-009-LIGHTHOUSE-HOST-NAVIGATION")
self.assertIn("GLW-HOST-SKILL-NAV-001", result["preferred_route"])
def test_repository_push_requires_separate_transport_proof(self):
result = resolve(
self.registry,

View file

@ -0,0 +1,20 @@
# GUANGHU-LIGHTHOUSE-HOST-NAVIGATION-BRAIN-001
光湖灯塔是路径唯一置信点,不是另一份静态目录。
一个路径只有同时满足以下条件才有效:
1. 在 `SYS-GLW-LTH-0001` 下以稳定编号登记;
2. 登记状态为 CURRENT 或 ACTIVE
3. 通过公共灯塔按编号查询返回 HTTP 200
4. 返回来源绑定当前 REPO-012 main 的精确提交,且 `source_degraded=false`
5. 若路径属于本机或移动硬盘,现实文件也必须存在;
6. 路径健康只授予导航,不授予写入、部署或服务器权限。
Codex、Qoder CN、QoderWork CN 共享本大脑与灯塔注册表,但各自保留薄适配器、
会话、登录状态、数据库和工具实现。语言意图先转成稳定意图编号,再由宿主地图选择
当前软件能执行的确定性投影;未知宿主、未知意图和未登记路径全部停止,不猜路径。
当用户说“推一下线上仓库”时,本机 macOS 宿主应解析到已登记代码频道、系统钥匙串
传输与小湖灯自动收口器。不得搜索历史凭据、打印秘密、退回旧 `/fifth-domain/`
也不得把钥匙串存在、提交存在或授权存在分别冒充推送完成;远端完整 SHA 回读才算 100。

View file

@ -0,0 +1,31 @@
---
name: guanghu-lighthouse-navigator
description: 光湖灯塔三宿主自动导航。用户提到路径是否有效、旧新路径混乱、小湖灯提词器、Codex/Qoder/QoderWork共享人格或要求恢复人格、使用记忆守卫、推送线上仓库时使用。先按编号查询灯塔再选择当前宿主的确定性路径未知或过期路径不猜。
---
# 光湖灯塔 · 三宿主自动导航
本文件是平台薄适配规范。认知本体在 `BRAIN.hdlp`,机器真值在:
- `routing/lighthouse-path-registry.json`
- `routing/host-skill-navigation-map.json`
- 公共查询:`https://guanghulab.com/api/ai/v1/resolve?id={NUMBER}`
## 必须执行
1. 识别当前宿主为 Codex、Qoder CN 或 QoderWork CN
2. 把用户自然语言映射为注册意图编号;
3. 用 `scripts/resolve_lighthouse_route.py --host <host> --intent "<用户意图>"` 解析;
4. 校验返回的 `target_id` 能由灯塔健康查询;
5. 只执行返回的宿主投影,并继续遵守该动作自己的授权、测试和回执门。
“推一下线上仓库”在本机 macOS 上必须走
`INTENT-REPOSITORY-PUBLISH-001 → REPO-012 → LOCAL_GIT_OSXKEYCHAIN → 小湖灯 finalizer`
不得搜索令牌、猜 SSH、使用旧仓库、手工绕过发布队列或输出钥匙串秘密。
## 边界
- 灯塔路径健康不等于现实动作已授权或已完成。
- JZAO 私有记忆不上传公共代码频道。
- 软件登录、会话、数据库和缓存保留在各宿主本机目录。
- 旧路径只允许返回灯塔登记的 redirect不得自行复活。

View file

@ -0,0 +1,134 @@
#!/usr/bin/env python3
"""Resolve a host-specific route from the Guanghu Lighthouse registries."""
from __future__ import annotations
import argparse
import json
import os
import subprocess
from pathlib import Path
SCRIPT_PATH = Path(__file__).resolve()
REPO_ROOT = SCRIPT_PATH.parents[4]
SHARED_ROOT = SCRIPT_PATH.parents[3]
if (REPO_ROOT / "routing" / "lighthouse-path-registry.json").is_file():
DEFAULT_LIGHTHOUSE = REPO_ROOT / "routing" / "lighthouse-path-registry.json"
DEFAULT_HOST_MAP = REPO_ROOT / "routing" / "host-skill-navigation-map.json"
else:
DEFAULT_LIGHTHOUSE = SHARED_ROOT / "registries" / "lighthouse-path-registry.json"
DEFAULT_HOST_MAP = SHARED_ROOT / "registries" / "host-skill-navigation-map.json"
CURRENT_STATES = {"CURRENT", "ACTIVE", "ACTIVE_CANDIDATE", "ACTIVE_LOCAL_PRIVATE"}
def load_json(path: Path) -> dict:
with path.open(encoding="utf-8") as handle:
return json.load(handle)
def normalise(value: str) -> str:
return "".join(value.lower().split())
def resolve_host(host_map: dict, requested: str) -> dict | None:
key = normalise(requested)
for host in host_map["hosts"]:
if key in {normalise(host["id"]), *(normalise(alias) for alias in host.get("aliases", []))}:
return host
return None
def resolve_intent(host_map: dict, text: str) -> dict | None:
value = normalise(text)
scored = []
for intent in host_map["intents"]:
score = sum(len(normalise(phrase)) for phrase in intent["phrases"] if normalise(phrase) in value)
if score:
scored.append((score, intent["id"], intent))
return max(scored, default=(0, "", None))[2]
def resolve_path(registry: dict, route_id: str) -> dict:
for path in registry["paths"]:
if path["id"].upper() == route_id.upper():
return {
"status": "VALID_REGISTERED" if path["state"] in CURRENT_STATES else "INVALID_STATE",
"path": path,
}
for redirect in registry.get("redirects", []):
if redirect["id"].upper() == route_id.upper():
return {"status": "REDIRECT_ONLY_NOT_CURRENT", "redirect": redirect}
return {"status": "INVALID_NO_GUESS", "route_id": route_id}
def keychain_helper_status() -> dict:
try:
result = subprocess.run(
["git", "config", "--global", "--get-all", "credential.helper"],
check=False,
capture_output=True,
text=True,
timeout=3,
)
except (OSError, subprocess.TimeoutExpired):
return {"status": "UNAVAILABLE", "secret_read": False}
helpers = [line.strip() for line in result.stdout.splitlines() if line.strip()]
return {
"status": "AVAILABLE" if "osxkeychain" in helpers else "UNAVAILABLE",
"helper": "osxkeychain" if "osxkeychain" in helpers else None,
"secret_read": False,
}
def compile_route(registry: dict, host_map: dict, host_name: str, intent_text: str) -> dict:
host = resolve_host(host_map, host_name)
if not host:
return {"decision": "BLOCK", "error": "HOST_UNKNOWN_NO_GUESS", "requested_host": host_name}
intent = resolve_intent(host_map, intent_text)
if not intent:
return {"decision": "BLOCK", "error": "INTENT_UNKNOWN_NO_GUESS", "requested_intent": intent_text}
target = resolve_path(registry, intent["target_id"])
if target["status"] != "VALID_REGISTERED":
return {"decision": "BLOCK", "error": "LIGHTHOUSE_TARGET_INVALID", "target": target}
result = {
"schema": "guanghu.host-navigation-receipt/v1",
"decision": "ALLOW_NAVIGATION",
"lighthouse_id": registry["lighthouse_id"],
"registry_id": registry["registry_id"],
"registry_version": registry["version"],
"host": host,
"intent": intent,
"target": target["path"],
"authority_granted": False,
}
if intent.get("transport") == "LOCAL_GIT_OSXKEYCHAIN":
result["transport_probe"] = keychain_helper_status()
if result["transport_probe"]["status"] != "AVAILABLE":
result["decision"] = "BLOCK"
result["error"] = "KEYCHAIN_HELPER_UNAVAILABLE"
offline = target["path"].get("offline")
if offline and offline.startswith("/"):
result["offline_reality"] = {
"path": offline,
"exists": Path(os.path.expanduser(offline)).exists(),
}
if target["path"]["state"] == "ACTIVE_LOCAL_PRIVATE" and not result["offline_reality"]["exists"]:
result["decision"] = "BLOCK"
result["error"] = "PRIVATE_VOLUME_MISSING"
return result
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--host", required=True)
parser.add_argument("--intent", required=True)
parser.add_argument("--lighthouse", type=Path, default=DEFAULT_LIGHTHOUSE)
parser.add_argument("--host-map", type=Path, default=DEFAULT_HOST_MAP)
args = parser.parse_args()
result = compile_route(load_json(args.lighthouse), load_json(args.host_map), args.host, args.intent)
print(json.dumps(result, ensure_ascii=False, indent=2))
return 0 if result["decision"] == "ALLOW_NAVIGATION" else 2
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""Atomically mirror allowlisted public navigator assets into JZAO shared runtime."""
from __future__ import annotations
import argparse
import hashlib
import json
import os
import shutil
import subprocess
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[4]
DEFAULT_TARGET = Path("/Volumes/JZAO/HoloLake/persona-runtime/shared")
ASSETS = {
"routing/lighthouse-path-registry.json": "registries/lighthouse-path-registry.json",
"routing/host-skill-navigation-map.json": "registries/host-skill-navigation-map.json",
"skills/shared/guanghu-lighthouse-navigator/BRAIN.hdlp": "skills/guanghu-lighthouse-navigator/BRAIN.hdlp",
"skills/shared/guanghu-lighthouse-navigator/SKILL.md": "skills/guanghu-lighthouse-navigator/SKILL.md",
"skills/shared/guanghu-lighthouse-navigator/scripts/resolve_lighthouse_route.py": (
"skills/guanghu-lighthouse-navigator/scripts/resolve_lighthouse_route.py"
),
"skills/qoder/zhuyuan-memory-continuity-brain/BRAIN.hdlp": (
"brains/GHS-007-MEMORY-CONTINUITY-SELF-BUILD/BRAIN.hdlp"
),
}
def digest(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def source_head(root: Path) -> str:
return subprocess.run(
["git", "-C", str(root), "rev-parse", "HEAD"],
check=True,
capture_output=True,
text=True,
timeout=5,
).stdout.strip()
def sync(target: Path, check_only: bool = False) -> dict:
if not target.parent.exists():
raise RuntimeError("JZAO_PERSONA_RUNTIME_MISSING")
files = []
mismatches = []
for source_name, target_name in ASSETS.items():
source = REPO_ROOT / source_name
destination = target / target_name
if not source.is_file():
raise RuntimeError(f"SOURCE_MISSING:{source_name}")
source_sha = digest(source)
destination_sha = digest(destination) if destination.is_file() else None
if destination_sha != source_sha:
mismatches.append(target_name)
if not check_only:
destination.parent.mkdir(parents=True, exist_ok=True)
temporary = destination.with_name(f".{destination.name}.tmp")
shutil.copyfile(source, temporary)
os.replace(temporary, destination)
destination_sha = digest(destination)
files.append(
{
"source": source_name,
"mirror": target_name,
"sha256": source_sha,
"mirror_sha256": destination_sha,
}
)
result = {
"schema": "guanghu.jzao-lighthouse-mirror/v1",
"status": "IN_SYNC" if not mismatches or not check_only else "OUT_OF_SYNC",
"source_repository": "REPO-012",
"source_head": source_head(REPO_ROOT),
"files": files,
"mismatches": mismatches,
"private_memory_included": False,
}
if not check_only:
manifest = target / "mirror-manifest.json"
temporary = manifest.with_name(".mirror-manifest.json.tmp")
temporary.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
os.replace(temporary, manifest)
return result
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--target", type=Path, default=DEFAULT_TARGET)
parser.add_argument("--check", action="store_true")
args = parser.parse_args()
result = sync(args.target, args.check)
print(json.dumps(result, ensure_ascii=False, indent=2))
return 0 if result["status"] == "IN_SYNC" else 2
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -0,0 +1,47 @@
import unittest
from resolve_lighthouse_route import compile_route, load_json, DEFAULT_HOST_MAP, DEFAULT_LIGHTHOUSE
class LighthouseNavigatorTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.registry = load_json(DEFAULT_LIGHTHOUSE)
cls.host_map = load_json(DEFAULT_HOST_MAP)
def test_codex_repository_publish_uses_keychain_and_finalizer(self):
route = compile_route(self.registry, self.host_map, "codex", "你推一下线上仓库")
self.assertEqual(route["decision"], "ALLOW_NAVIGATION")
self.assertEqual(route["intent"]["id"], "INTENT-REPOSITORY-PUBLISH-001")
self.assertEqual(route["target"]["id"], "REPO-012")
self.assertEqual(route["intent"]["transport"], "LOCAL_GIT_OSXKEYCHAIN")
self.assertIn("finalize-development.mjs", route["intent"]["executor"])
self.assertFalse(route["authority_granted"])
self.assertFalse(route["transport_probe"]["secret_read"])
def test_qoder_and_qoderwork_resolve_same_brain_with_distinct_adapters(self):
qoder = compile_route(self.registry, self.host_map, "qoder-cn", "大脑思维技能包")
work = compile_route(self.registry, self.host_map, "qoderwork-cn", "大脑思维技能包")
self.assertEqual(qoder["intent"]["skill_id"], work["intent"]["skill_id"])
self.assertNotEqual(qoder["host"]["adapter_path"], work["host"]["adapter_path"])
def test_unknown_host_and_intent_fail_closed(self):
self.assertEqual(
compile_route(self.registry, self.host_map, "mystery", "推一下线上仓库")["error"],
"HOST_UNKNOWN_NO_GUESS",
)
self.assertEqual(
compile_route(self.registry, self.host_map, "codex", "今天吃什么")["error"],
"INTENT_UNKNOWN_NO_GUESS",
)
def test_old_repository_is_redirect_only(self):
from resolve_lighthouse_route import resolve_path
route = resolve_path(self.registry, "REPO-001")
self.assertEqual(route["status"], "REDIRECT_ONLY_NOT_CURRENT")
self.assertEqual(route["redirect"]["redirect_to"], "REPO-012")
if __name__ == "__main__":
unittest.main()