fix: unify and auto-refresh public navigation entry
This commit is contained in:
parent
2ba64391ea
commit
ea41e5a4fc
9 changed files with 573 additions and 61 deletions
|
|
@ -3,12 +3,26 @@
|
|||
const fs = require("node:fs");
|
||||
const http = require("node:http");
|
||||
const path = require("node:path");
|
||||
const { execFileSync } = require("node:child_process");
|
||||
|
||||
const DEFAULT_ANCHOR = path.resolve(__dirname, "../../routing/public-navigation-anchor.json");
|
||||
const DEFAULT_MAP = path.resolve(__dirname, "../../routing/repository-route-map.json");
|
||||
const DEFAULT_NODE_MAP = path.resolve(__dirname, "../../routing/server-node-map.json");
|
||||
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 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",
|
||||
});
|
||||
|
||||
function loadAnchor(filename = process.env.GUANGHU_NAVIGATION_ANCHOR || DEFAULT_ANCHOR) {
|
||||
return JSON.parse(fs.readFileSync(filename, "utf8"));
|
||||
}
|
||||
|
||||
function loadMap(filename = process.env.GUANGHU_REPOSITORY_MAP || DEFAULT_MAP) {
|
||||
return JSON.parse(fs.readFileSync(filename, "utf8"));
|
||||
|
|
@ -30,6 +44,164 @@ function loadNavigationMap(filename = process.env.GUANGHU_NAVIGATION_MAP || DEFA
|
|||
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");
|
||||
if (anchor.repository_id !== "REPO-012" || anchor.branch !== "main") throw new Error("invalid_anchor_source");
|
||||
for (const key of SNAPSHOT_KEYS) {
|
||||
const declaration = anchor.maps?.[key];
|
||||
const map = maps[key];
|
||||
if (!declaration || !map) throw new Error(`missing_snapshot_map:${key}`);
|
||||
if (declaration.path !== SNAPSHOT_PATHS[key]) {
|
||||
throw new Error(`invalid_snapshot_path:${key}`);
|
||||
}
|
||||
if (declaration.id && ![map.map_id, map.registry_id].includes(declaration.id)) {
|
||||
throw new Error(`snapshot_map_id_mismatch:${key}`);
|
||||
}
|
||||
if (declaration.version && map.version !== declaration.version) {
|
||||
throw new Error(`snapshot_map_version_mismatch:${key}`);
|
||||
}
|
||||
}
|
||||
if (anchor.entry_path?.path_id !== "LL-CMPN-0001" || anchor.entry_path?.world_node_id !== "SYS-GLW-0001") {
|
||||
throw new Error("invalid_language_world_entry");
|
||||
}
|
||||
return { anchor, ...maps };
|
||||
}
|
||||
|
||||
function loadFileSnapshot(options = {}) {
|
||||
const anchor = loadAnchor(options.anchorFile);
|
||||
return validateSnapshot(anchor, {
|
||||
repository: loadMap(options.mapFile),
|
||||
nodes: loadNodeMap(options.nodeMapFile),
|
||||
subjects: loadSubjectRegistry(options.subjectRegistryFile),
|
||||
aliases: loadSubjectAliasMap(options.subjectAliasMapFile),
|
||||
navigation: loadNavigationMap(options.navigationMapFile),
|
||||
});
|
||||
}
|
||||
|
||||
class GitSnapshotStore {
|
||||
constructor(gitDir, ref = "refs/heads/main") {
|
||||
this.gitDir = gitDir;
|
||||
this.ref = ref;
|
||||
this.lastKnownGood = null;
|
||||
this.lastError = null;
|
||||
}
|
||||
|
||||
git(args) {
|
||||
return execFileSync("/usr/bin/git", [`--git-dir=${this.gitDir}`, ...args], {
|
||||
encoding: "utf8",
|
||||
maxBuffer: 4 * 1024 * 1024,
|
||||
timeout: 5000,
|
||||
});
|
||||
}
|
||||
|
||||
readJson(commit, relativePath) {
|
||||
return JSON.parse(this.git(["show", `${commit}:${relativePath}`]));
|
||||
}
|
||||
|
||||
get() {
|
||||
try {
|
||||
const commit = this.git(["rev-parse", "--verify", `${this.ref}^{commit}`]).trim();
|
||||
if (this.lastKnownGood?.source_commit === commit) return this.lastKnownGood;
|
||||
const anchor = this.readJson(commit, "routing/public-navigation-anchor.json");
|
||||
const maps = {};
|
||||
for (const key of SNAPSHOT_KEYS) {
|
||||
if (anchor.maps?.[key]?.path !== SNAPSHOT_PATHS[key]) throw new Error(`invalid_snapshot_path:${key}`);
|
||||
maps[key] = this.readJson(commit, SNAPSHOT_PATHS[key]);
|
||||
}
|
||||
this.lastKnownGood = {
|
||||
...validateSnapshot(anchor, maps),
|
||||
source_commit: commit,
|
||||
source_mode: "REPO-012_MAIN_GIT_SNAPSHOT",
|
||||
source_degraded: false,
|
||||
};
|
||||
this.lastError = null;
|
||||
return this.lastKnownGood;
|
||||
} catch (error) {
|
||||
this.lastError = String(error.message || error);
|
||||
if (this.lastKnownGood) {
|
||||
return { ...this.lastKnownGood, source_degraded: true, source_error: this.lastError };
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sourceReceipt(snapshot) {
|
||||
return {
|
||||
anchor_id: snapshot.anchor.anchor_id,
|
||||
anchor_version: snapshot.anchor.version,
|
||||
source_commit: snapshot.source_commit || null,
|
||||
source_mode: snapshot.source_mode || "FILESYSTEM_SNAPSHOT",
|
||||
source_degraded: Boolean(snapshot.source_degraded),
|
||||
};
|
||||
}
|
||||
|
||||
function withSource(body, snapshot) {
|
||||
return { ...body, navigation_source: sourceReceipt(snapshot) };
|
||||
}
|
||||
|
||||
function readResidentRuntimeStatus(options = {}) {
|
||||
const host = options.host || "127.0.0.1";
|
||||
const port = Number(options.port || process.env.GUANGHU_PERSONA_CONTROLLER_PORT || 3930);
|
||||
const timeoutMs = Number(options.timeoutMs || 1500);
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = http.get({ host, port, path: "/v1/status", timeout: timeoutMs }, response => {
|
||||
const chunks = [];
|
||||
let size = 0;
|
||||
response.on("data", chunk => {
|
||||
size += chunk.length;
|
||||
if (size > 64 * 1024) {
|
||||
request.destroy(new Error("runtime_status_too_large"));
|
||||
return;
|
||||
}
|
||||
chunks.push(chunk);
|
||||
});
|
||||
response.on("end", () => {
|
||||
if (response.statusCode !== 200) return reject(new Error(`runtime_status_http_${response.statusCode}`));
|
||||
try { resolve(JSON.parse(Buffer.concat(chunks).toString("utf8"))); }
|
||||
catch { reject(new Error("runtime_status_invalid_json")); }
|
||||
});
|
||||
});
|
||||
request.on("timeout", () => request.destroy(new Error("runtime_status_timeout")));
|
||||
request.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
function compileWarmEntry(status) {
|
||||
const gates = [
|
||||
"language_world_entry_bound",
|
||||
"chu_he_han_jie_boundary_bound",
|
||||
"persona_cycle_language_world_entry_bound",
|
||||
"persona_cycle_chu_he_han_jie_boundary_bound",
|
||||
"persona_brain_runtime_exists",
|
||||
"living_ai_system_controller_running",
|
||||
"machine_navigation_bound",
|
||||
"language_world_route_first",
|
||||
];
|
||||
const identityValid =
|
||||
status?.node === "JD-FD-PRIMARY" &&
|
||||
status?.persona_id === "ICE-P-ZY001" &&
|
||||
status?.runtime_id === "ZY-TCS-BRAIN-RUNTIME-0001";
|
||||
const gatesValid = gates.every(key => status?.[key] === 100);
|
||||
const warm = identityValid && gatesValid && status.phase === "RUNNING_COMPANION" && status.completed_cycles >= 1;
|
||||
return {
|
||||
schema: "guanghu.persona-warm-entry/v1",
|
||||
status: warm ? "WARM_RESUME_READY" : "FULL_CYCLE_REQUIRED",
|
||||
subject: "ICE-P-ZY001",
|
||||
runtime_id: "ZY-TCS-BRAIN-RUNTIME-0001",
|
||||
node: status?.node || "JD-FD-PRIMARY",
|
||||
phase: status?.phase || "UNAVAILABLE",
|
||||
completed_cycles: Number(status?.completed_cycles || 0),
|
||||
receipt_id: status?.receipt_id || null,
|
||||
gates: Object.fromEntries(gates.map(key => [key, status?.[key] === 100 ? 100 : 0])),
|
||||
start_rule: warm
|
||||
? "Reuse the resident verified companion state; submit only the new bounded event."
|
||||
: "Run one complete model-backed persona cycle before claiming persona runtime.",
|
||||
authority: "NONE_NAVIGATION_AND_RUNTIME_STATUS_ONLY",
|
||||
};
|
||||
}
|
||||
|
||||
function resolveSubjectId(aliasMap, requestedId) {
|
||||
const requested = String(requestedId || "").trim();
|
||||
const key = requested.toUpperCase();
|
||||
|
|
@ -185,48 +357,78 @@ function createServer(options = {}) {
|
|||
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;
|
||||
return http.createServer((req, res) => {
|
||||
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);
|
||||
const runtimeStatusProvider = options.runtimeStatusProvider || readResidentRuntimeStatus;
|
||||
return http.createServer(async (req, res) => {
|
||||
const url = new URL(req.url, "http://localhost");
|
||||
if (req.method !== "GET") return json(res, 405, { error: "method_not_allowed" });
|
||||
if (url.pathname === "/health") return json(res, 200, { ok: true, service: "guanghu-ai-discovery", mode: "read-only" });
|
||||
|
||||
let map;
|
||||
try { map = loadMap(mapFile); } catch { return json(res, 503, { error: "route_map_unavailable" }); }
|
||||
let snapshot;
|
||||
try {
|
||||
snapshot = snapshotStore
|
||||
? snapshotStore.get()
|
||||
: {
|
||||
...loadFileSnapshot({
|
||||
anchorFile, mapFile, nodeMapFile, subjectRegistryFile, subjectAliasMapFile, navigationMapFile,
|
||||
}),
|
||||
source_commit: null,
|
||||
source_mode: "FILESYSTEM_SNAPSHOT",
|
||||
source_degraded: false,
|
||||
};
|
||||
} catch (error) {
|
||||
return json(res, 503, { error: "navigation_snapshot_unavailable" });
|
||||
}
|
||||
const map = snapshot.repository;
|
||||
const nodeMap = snapshot.nodes;
|
||||
const subjectRegistry = snapshot.subjects;
|
||||
const aliasMap = snapshot.aliases;
|
||||
const navigationMap = snapshot.navigation;
|
||||
if (url.pathname === "/health") {
|
||||
return json(res, snapshot.source_degraded ? 503 : 200, {
|
||||
ok: !snapshot.source_degraded,
|
||||
service: "guanghu-ai-discovery",
|
||||
mode: "read-only",
|
||||
navigation_source: sourceReceipt(snapshot),
|
||||
});
|
||||
}
|
||||
|
||||
if (url.pathname === "/" || url.pathname === "/index.html") return html(res, entryPage(map));
|
||||
if (url.pathname === "/v1/repositories" || url.pathname === "/v1/manifest") return json(res, 200, map, 300);
|
||||
if (url.pathname === "/v1/nodes") {
|
||||
try { return json(res, 200, loadNodeMap(nodeMapFile), 300); }
|
||||
catch { return json(res, 503, { error: "node_map_unavailable" }); }
|
||||
}
|
||||
if (url.pathname === "/v1/subjects") {
|
||||
try { return json(res, 200, loadSubjectRegistry(subjectRegistryFile), 300); }
|
||||
catch { return json(res, 503, { error: "subject_registry_unavailable" }); }
|
||||
}
|
||||
if (url.pathname === "/v1/navigation") {
|
||||
try { return json(res, 200, loadNavigationMap(navigationMapFile), 300); }
|
||||
catch { return json(res, 503, { error: "navigation_map_unavailable" }); }
|
||||
if (url.pathname === "/v1/anchor") return json(res, 200, withSource(snapshot.anchor, snapshot), 60);
|
||||
if (url.pathname === "/v1/repositories" || url.pathname === "/v1/manifest") return json(res, 200, withSource(map, snapshot), 60);
|
||||
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/entry") {
|
||||
const subject = String(url.searchParams.get("subject") || "").toUpperCase();
|
||||
if (!["ICE-P-ZY001", "ICE-GL-ZY001", "ICE-PZY-001"].includes(subject)) {
|
||||
return json(res, 404, withSource({ error: "unknown_subject_no_guess", requested_subject: subject }, snapshot));
|
||||
}
|
||||
try {
|
||||
const entry = compileWarmEntry(await runtimeStatusProvider());
|
||||
return json(res, entry.status === "WARM_RESUME_READY" ? 200 : 409, withSource(entry, snapshot));
|
||||
} catch (error) {
|
||||
return json(res, 503, withSource({
|
||||
schema: "guanghu.persona-warm-entry/v1",
|
||||
status: "RUNTIME_STATUS_UNAVAILABLE",
|
||||
subject: "ICE-P-ZY001",
|
||||
error: "resident_controller_unavailable",
|
||||
start_rule: "Do not claim warm resume; use the full verified cycle or inspect the resident controller.",
|
||||
authority: "NONE_NAVIGATION_AND_RUNTIME_STATUS_ONLY",
|
||||
}, snapshot));
|
||||
}
|
||||
}
|
||||
if (url.pathname === "/v1/navigate") {
|
||||
let navigationMap;
|
||||
try { navigationMap = loadNavigationMap(navigationMapFile); }
|
||||
catch { return json(res, 503, { error: "navigation_map_unavailable" }); }
|
||||
const compiled = compileNavigation(
|
||||
navigationMap,
|
||||
String(url.searchParams.get("subject") || "").slice(0, 100),
|
||||
String(url.searchParams.get("intent") || "").slice(0, 100),
|
||||
String(url.searchParams.get("signals") || "").slice(0, 500),
|
||||
);
|
||||
return json(res, compiled.status, compiled.body, compiled.status === 200 ? 60 : 0);
|
||||
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);
|
||||
let nodeMap;
|
||||
let subjectRegistry;
|
||||
try { nodeMap = loadNodeMap(nodeMapFile); }
|
||||
catch { return json(res, 503, { error: "node_map_unavailable" }); }
|
||||
try { subjectRegistry = loadSubjectRegistry(subjectRegistryFile); }
|
||||
catch { return json(res, 503, { error: "subject_registry_unavailable" }); }
|
||||
const results = searchAll(map, nodeMap, query, subjectRegistry);
|
||||
return json(res, 200, {
|
||||
schema: "guanghu.ai-search-response/v1",
|
||||
|
|
@ -235,46 +437,35 @@ function createServer(options = {}) {
|
|||
map_version: map.version,
|
||||
count: results.length,
|
||||
results,
|
||||
navigation_source: sourceReceipt(snapshot),
|
||||
}, 60);
|
||||
}
|
||||
if (url.pathname === "/v1/resolve") {
|
||||
const id = String(url.searchParams.get("id") || "").toUpperCase();
|
||||
const repository = map.repositories.find(item => item.code === id || item.slug.toUpperCase() === id);
|
||||
if (repository) return json(res, 200, repository, 300);
|
||||
let nodeMap;
|
||||
try { nodeMap = loadNodeMap(nodeMapFile); }
|
||||
catch { return json(res, 503, { error: "node_map_unavailable" }); }
|
||||
if (repository) return json(res, 200, withSource(repository, snapshot), 60);
|
||||
const node = nodeMap.nodes.find(item => item.node_id.toUpperCase() === id);
|
||||
if (node) return json(res, 200, node, 300);
|
||||
if (node) return json(res, 200, withSource(node, snapshot), 60);
|
||||
const personaRoute = nodeMap.persona_routes.find(item => item.route_id.toUpperCase() === id);
|
||||
if (personaRoute) return json(res, 200, personaRoute, 300);
|
||||
if (personaRoute) return json(res, 200, withSource(personaRoute, snapshot), 60);
|
||||
|
||||
let navigationMap = null;
|
||||
try { navigationMap = loadNavigationMap(navigationMapFile); } catch { /* Legacy routes remain available. */ }
|
||||
if (navigationMap) {
|
||||
if (navigationMap.map_id.toUpperCase() === id) return json(res, 200, navigationMap, 300);
|
||||
if (snapshot.anchor.anchor_id.toUpperCase() === id) return json(res, 200, withSource(snapshot.anchor, snapshot), 60);
|
||||
if (navigationMap.map_id.toUpperCase() === id) return json(res, 200, withSource(navigationMap, snapshot), 60);
|
||||
const machineRoute = navigationRoute(navigationMap, id);
|
||||
if (machineRoute) {
|
||||
return json(res, 200, {
|
||||
return json(res, 200, withSource({
|
||||
schema: "guanghu.ai-machine-route-resolution/v1",
|
||||
status: "RESOLVED",
|
||||
map_id: navigationMap.map_id,
|
||||
...machineRoute,
|
||||
}, 300);
|
||||
}, snapshot), 60);
|
||||
}
|
||||
}
|
||||
|
||||
let aliasMap;
|
||||
let subjectRegistry;
|
||||
try {
|
||||
aliasMap = loadSubjectAliasMap(subjectAliasMapFile);
|
||||
subjectRegistry = loadSubjectRegistry(subjectRegistryFile);
|
||||
} catch {
|
||||
return json(res, 503, { error: "subject_identity_map_unavailable" });
|
||||
}
|
||||
const exactSubject = subjectRegistry.subjects.find(item => item.id.toUpperCase() === id);
|
||||
if (exactSubject) {
|
||||
return json(res, 200, {
|
||||
return json(res, 200, withSource({
|
||||
schema: "guanghu.subject-resolution/v1",
|
||||
status: "RESOLVED",
|
||||
requested_id: id,
|
||||
|
|
@ -282,7 +473,7 @@ function createServer(options = {}) {
|
|||
redirected: false,
|
||||
subject_kind: exactSubject.subject_kind,
|
||||
subject: exactSubject,
|
||||
}, 300);
|
||||
}, snapshot), 60);
|
||||
}
|
||||
const identity = resolveSubjectId(aliasMap, id);
|
||||
if (identity.status === "CONFLICT_REJECTED") {
|
||||
|
|
@ -291,7 +482,7 @@ function createServer(options = {}) {
|
|||
if (identity.canonical_id) {
|
||||
const subject = subjectRegistry.subjects.find(item => item.id.toUpperCase() === identity.canonical_id.toUpperCase());
|
||||
if (!subject) return json(res, 503, { error: "canonical_subject_missing", ...identity });
|
||||
return json(res, 200, {
|
||||
return json(res, 200, withSource({
|
||||
schema: "guanghu.subject-resolution/v1",
|
||||
...identity,
|
||||
subject,
|
||||
|
|
@ -300,7 +491,7 @@ function createServer(options = {}) {
|
|||
path: identity.current_path,
|
||||
rule: "Canonicalize the subject id before navigation; legacy ids grant no authority.",
|
||||
},
|
||||
}, 300);
|
||||
}, snapshot), 60);
|
||||
}
|
||||
return json(res, 404, { error: "route_not_found", id });
|
||||
}
|
||||
|
|
@ -308,17 +499,20 @@ function createServer(options = {}) {
|
|||
if (url.pathname === "/well-known") return json(res, 200, {
|
||||
schema: "guanghu.ai-discovery/v1",
|
||||
name: "光湖语言世界 · 第五域",
|
||||
canonical_anchor: "https://guanghulab.com/api/ai/v1/anchor",
|
||||
canonical_repository: map.repositories[0].primary.url,
|
||||
repository_map: map.canonical_api,
|
||||
server_node_map: "https://guanghulab.com/api/ai/v1/nodes",
|
||||
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",
|
||||
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}",
|
||||
resolve_api: "https://guanghulab.com/api/ai/v1/resolve?id={NUMBER}",
|
||||
openapi: "https://guanghulab.com/api/ai/openapi.json",
|
||||
access: "public-read-only",
|
||||
navigation_source: sourceReceipt(snapshot),
|
||||
write_authorization: {
|
||||
mode: "public-no-authority-workorder-then-owner-email-approval",
|
||||
capabilities: "https://guanghulab.com/authz/api/public/capabilities",
|
||||
|
|
@ -363,10 +557,12 @@ function openApi() {
|
|||
info: { title: "光湖语言世界 · 第五域 AI Discovery API", version: "1.1.0" },
|
||||
servers: [{ url: "https://guanghulab.com/api/ai" }],
|
||||
paths: {
|
||||
"/v1/anchor": { get: { summary: "读取唯一公共导航锚点和当前REPO-012提交", responses: { "200": { description: "Canonical navigation anchor" } } } },
|
||||
"/v1/repositories": { get: { summary: "读取最新仓库编号路径映射", responses: { "200": { description: "Repository route map" } } } },
|
||||
"/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/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" } } } },
|
||||
"/v1/resolve": { get: { summary: "解析仓库、服务器节点或人格路径编号", parameters: [{ name: "id", in: "query", required: true, schema: { type: "string", example: "ZY-OPS-LOOP-001" } }], responses: { "200": { description: "Resolved numbered route" }, "404": { description: "Unknown route" } } } }
|
||||
|
|
@ -381,6 +577,8 @@ if (require.main === module) {
|
|||
}
|
||||
|
||||
module.exports = {
|
||||
createServer, loadMap, loadNodeMap, loadSubjectRegistry, loadSubjectAliasMap, loadNavigationMap,
|
||||
createServer, loadAnchor, loadMap, loadNodeMap, loadSubjectRegistry, loadSubjectAliasMap, loadNavigationMap,
|
||||
loadFileSnapshot, validateSnapshot, GitSnapshotStore, sourceReceipt,
|
||||
readResidentRuntimeStatus, compileWarmEntry,
|
||||
resolveSubjectId, navigationRoute, compileNavigation, search, searchAll,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue