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

@ -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);