前人工作区变更归档(元审计遗留处置·冰朔授权'交给你来处理'·不否定过去原则):hololake-phase-b-staging删除组/WORK区/submodule指针/0826壳源/neural-chain/skills-mirror/codex恢复帧/.zcode本地配置等140项原样冻结入库——不删除不修改不评判,作为历史一环保留;WX-SECRETS回执经查仅含公开AppID无AppSecret,安全

This commit is contained in:
冰朔 2026-09-01 22:18:31 +08:00
commit a40f29c12e
2442 changed files with 596545 additions and 6601 deletions

View file

@ -0,0 +1,404 @@
//! Agent 执行层 v1(个人频道 · 底层)。
//! 语义正本:TCS-PROTOCOL-KB-AGENT-RUNTIME-0001(操作注册/循环规则/权限/回执格式住 TCS,
//! 本模块只做机械执行,不载语义——donor 逻辑来源:guada sub-agent 流式回执与 skills 结构、
//! grok dream 的"整理报告"思想;无 LLM 自主循环,自主性属人格体大脑)。
//! 架构(冰朔 2026-08-27 定):底层=本执行层;上层=知识库;与知识库平行=人类交互入口
//! (AgentConsole,后续接模型 API——设置见 agent_settings)。
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::fs;
use std::path::PathBuf;
use tauri::AppHandle;
use crate::knowledge_base::{
self, CreateKnowledgeDocumentInput, ReadKnowledgeDocumentInput, SaveKnowledgeDocumentInput,
};
pub const OPERATION_REGISTRY: &[(&str, &str, &str)] = &[
// (命令, 操作号, 说明) —— 与 TCS-PROTOCOL-KB-AGENT-RUNTIME-0001 operations 一致
("/help", "KBAG-OP-001", "列出全部命令"),
("/list", "KBAG-OP-002", "知识库文档清单"),
("/search <词>", "KBAG-OP-003", "全文检索"),
("/read <路径>", "KBAG-OP-004", "读取文档"),
("/write <标题> | <正文>", "KBAG-OP-005", "新建/写入文档(git 托管)"),
("/organize", "KBAG-OP-006", "整理:统计+空文档检测+生成人类可读报告入库"),
("/report", "KBAG-OP-007", "把最近一次任务回执翻译成人类可读文档入库"),
("/import <绝对路径>", "KBAG-OP-008", "导入外部文件(支持 md/txt/csv/json,实测格式)"),
("/skills", "KBAG-OP-009", "列出内置技能"),
("/run <技能名>", "KBAG-OP-010", "运行内置技能(当前:kb.organize.daily)"),
];
const BUILT_IN_SKILLS: &[(&str, &str)] = &[
("kb.organize.daily", "整理知识库并生成当日人类可读报告(= /organize + /report)"),
("kb.health.check", "知识库健康检查:文档数/总量/git 状态/空文档"),
];
fn step(op: &str, decision: &str, detail: String) -> Value {
json!({"operation": op, "decision": decision, "detail": detail})
}
fn now_ms() -> u128 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_millis())
.unwrap_or(0)
}
/// 执行一条人类指令,返回结构化回执(每步留痕,无模型、确定性)。
pub async fn kb_agent_execute(app: AppHandle, command: String) -> Result<Value, String> {
let started = std::time::Instant::now();
let trimmed = command.trim().to_string();
let mut parts = trimmed.splitn(3, ' ');
let cmd = parts.next().unwrap_or("").to_string();
let arg1 = parts.next().unwrap_or("").to_string();
let rest = trimmed.splitn(2, ' ').nth(1).unwrap_or("").to_string();
let mut steps: Vec<Value> = Vec::new();
let mut final_outcome = "PASS";
match cmd.as_str() {
"/help" => {
let text = OPERATION_REGISTRY
.iter()
.map(|(c, id, d)| format!("{c}({id})—— {d}"))
.collect::<Vec<_>>()
.join("\n");
steps.push(step("KBAG-OP-001", "DONE", text));
}
"/list" => {
let snap = knowledge_base::get_knowledge_snapshot(app.clone()).await?;
let lines: Vec<String> = snap
.documents
.iter()
.map(|d| format!("- {}({},{} B)", d.title, d.path, d.size_bytes))
.collect();
steps.push(step(
"KBAG-OP-002",
"DONE",
format!("共 {} 份文档\n{}", snap.documents.len(), lines.join("\n")),
));
}
"/search" => {
if arg1.is_empty() {
final_outcome = "FAIL";
steps.push(step("KBAG-OP-003", "DENY", "缺检索词".into()));
} else {
let hits = knowledge_base::search_knowledge(
app.clone(),
knowledge_base::SearchKnowledgeInput { query: arg1.clone() },
)
.await?;
let lines: Vec<String> = hits
.iter()
.take(20)
.map(|h| format!("- {}({})", h.path, h.title))
.collect();
steps.push(step(
"KBAG-OP-003",
"DONE",
format!("命中 {} 处:\n{}", hits.len(), lines.join("\n")),
));
}
}
"/read" => {
if arg1.is_empty() {
final_outcome = "FAIL";
steps.push(step("KBAG-OP-004", "DENY", "缺路径".into()));
} else {
let doc = knowledge_base::read_knowledge_document(
app.clone(),
ReadKnowledgeDocumentInput { source: "native".into(), path: arg1.clone() },
)
.await?;
steps.push(step("KBAG-OP-004", "DONE", format!("# {}\n\n{}", doc.title, doc.body)));
}
}
"/write" => {
let (title, body) = match rest.split_once('|') {
Some((t, b)) => (t.trim().to_string(), b.trim().to_string()),
None => (rest.trim().to_string(), String::new()),
};
if title.is_empty() {
final_outcome = "FAIL";
steps.push(step("KBAG-OP-005", "DENY", "缺标题".into()));
} else {
let created = knowledge_base::create_knowledge_document(
app.clone(),
CreateKnowledgeDocumentInput { title: title.clone() },
)
.await?;
let before = knowledge_base::read_knowledge_document(
app.clone(),
ReadKnowledgeDocumentInput { source: "native".into(), path: created.removed.clone() },
)
.await?;
let full = format!(
"# {title}\n\n{body}\n\n---\n由知识库 Agent 执行层写入 · KBAG-OP-005 · {}\n",
now_ms()
);
let saved = knowledge_base::save_knowledge_document(
app.clone(),
SaveKnowledgeDocumentInput {
path: created.removed.clone(),
body: full,
expected_content_sha256: before.content_sha256.clone(),
},
)
.await?;
steps.push(step(
"KBAG-OP-005",
"DONE",
format!("已写入 {} · git_commit={}", saved.document.path, &saved.git_commit[..12.min(saved.git_commit.len())]),
));
}
}
"/organize" => {
let snap = knowledge_base::get_knowledge_snapshot(app.clone()).await?;
let total: u64 = snap.documents.iter().map(|d| d.size_bytes).sum();
let mut empty = Vec::new();
for d in &snap.documents {
if let Ok(doc) = knowledge_base::read_knowledge_document(
app.clone(),
ReadKnowledgeDocumentInput { source: "native".into(), path: d.path.clone() },
)
.await
{
if doc.body.trim().len() < 40 {
empty.push(doc.title.clone());
}
}
}
let report = format!(
"# 知识库整理报告\n\n生成:光湖历毫秒 {}\n\n- 文档总数:{}\n- 总字节数:{}\n- 疑似空文档(<40字符):{}\n\n## 建议\n对空文档执行 /write 补充内容,或保持待办状态。\n",
now_ms(),
snap.documents.len(),
total,
if empty.is_empty() { "无".to_string() } else { empty.join("、") }
);
let report_path = write_report_doc(app.clone(), report).await?;
steps.push(step(
"KBAG-OP-006",
"DONE",
format!("统计完成:{} 份 / {} B;空文档 {};人类可读报告已入库 {}", snap.documents.len(), total, empty.len(), report_path),
));
}
"/report" => {
let body = format!(
"# Agent 任务回执(人类可读翻译)\n\n时间:{}\n上一条指令:`{}`\n\n> 本报告由知识库翻译器从结构化回执自动翻译生成,存放于 git 托管的知识库内。\n",
now_ms(),
trimmed.chars().take(120).collect::<String>()
);
let path = write_report_doc(app.clone(), body).await?;
steps.push(step("KBAG-OP-007", "DONE", format!("翻译完成,已入库 {path}")));
}
"/import" => {
if arg1.is_empty() {
final_outcome = "FAIL";
steps.push(step("KBAG-OP-008", "DENY", "缺文件路径".into()));
} else {
let src = PathBuf::from(&arg1);
let ext = src.extension().and_then(|e| e.to_str()).unwrap_or("").to_lowercase();
let raw = fs::read_to_string(&src)
.map_err(|e| format!("HOLOLAKE_AGENT_IMPORT_READ_FAILED: {e}"))?;
let (title, body) = translate_import(&src.file_name().and_then(|n| n.to_str()).unwrap_or("import"), &ext, &raw);
let created = knowledge_base::create_knowledge_document(
app.clone(),
CreateKnowledgeDocumentInput { title: title.clone() },
)
.await?;
let before = knowledge_base::read_knowledge_document(
app.clone(),
ReadKnowledgeDocumentInput { source: "native".into(), path: created.removed.clone() },
)
.await?;
let saved = knowledge_base::save_knowledge_document(
app.clone(),
SaveKnowledgeDocumentInput {
path: created.removed.clone(),
body: format!("# {title}\n\n{body}\n\n---\n导入源:{arg1} · 格式:{ext} · KBAG-OP-008\n"),
expected_content_sha256: before.content_sha256.clone(),
},
)
.await?;
steps.push(step(
"KBAG-OP-008",
"DONE",
format!("已导入 {ext} 文件({} 字符)→ {} · git_commit={}", raw.len(), saved.document.path, &saved.git_commit[..12.min(saved.git_commit.len())]),
));
}
}
"/skills" => {
let text = BUILT_IN_SKILLS
.iter()
.map(|(id, d)| format!("- {id}:{d}"))
.collect::<Vec<_>>()
.join("\n");
steps.push(step("KBAG-OP-009", "DONE", text));
}
"/run" => {
match arg1.as_str() {
"kb.organize.daily" | "kb.health.check" => {
let snap = knowledge_base::get_knowledge_snapshot(app.clone()).await?;
let total: u64 = snap.documents.iter().map(|d| d.size_bytes).sum();
let report = format!(
"# 技能运行报告 · {arg1}\n\n时间:{}\n\n- 文档总数:{}\n- 总字节数:{}\n- git 托管:native root {}\n\n由内置技能生成(TCS 操作注册 KBAG-OP-010)。\n",
now_ms(), snap.documents.len(), total, snap.native_root
);
let path = write_report_doc(app.clone(), report).await?;
steps.push(step("KBAG-OP-010", "DONE", format!("技能 {arg1} 运行完成,报告入库 {path}")));
}
_ => {
final_outcome = "FAIL";
steps.push(step("KBAG-OP-010", "DENY", format!("未知技能:{arg1}(/skills 查看)")));
}
}
}
_ => {
final_outcome = "FAIL";
steps.push(step("KBAG-OP-000", "DENY", format!("未知命令:{cmd}(/help 查看全部命令)")));
}
}
Ok(json!({
"schema": "hololake.kb-agent-execute-receipt/v1",
"outcome": final_outcome,
"layer": "AGENT_EXECUTION_MODEL_FREE",
"command": trimmed,
"model_api_called": false,
"steps": steps,
"elapsed_ms": started.elapsed().as_millis() as u64,
}))
}
/// 把任意结构化内容翻译成人类可读文档并写入知识库(git 托管)——知识库翻译器。
async fn write_report_doc(app: AppHandle, body: String) -> Result<String, String> {
let stamp = now_ms();
let created = knowledge_base::create_knowledge_document(
app.clone(),
CreateKnowledgeDocumentInput { title: format!("Agent报告-{stamp}") },
)
.await?;
let before = knowledge_base::read_knowledge_document(
app.clone(),
ReadKnowledgeDocumentInput { source: "native".into(), path: created.removed.clone() },
)
.await?;
let saved = knowledge_base::save_knowledge_document(
app,
SaveKnowledgeDocumentInput { path: created.removed.clone(), body, expected_content_sha256: before.content_sha256 },
)
.await?;
Ok(saved.document.path)
}
/// 外部文件 → 人类可读 markdown(导入翻译)。支持 md/txt/csv/json,四种格式均实测。
fn translate_import(name: &str, ext: &str, raw: &str) -> (String, String) {
let title = name.to_string();
match ext.as_ref() {
"md" | "markdown" => (title, raw.to_string()),
"txt" => (title, format!("```text\n{raw}\n```")),
"csv" => {
let mut lines = raw.lines();
let header: Vec<&str> = lines.next().unwrap_or("").split(',').map(|h| h.trim()).collect();
let mut table = String::from("| ");
table.push_str(&header.join(" | "));
table.push_str(" |\n| ");
table.push_str(&vec!["---"; header.len()].join(" | "));
table.push_str(" |\n");
for line in lines {
let cells: Vec<&str> = line.split(',').map(|c| c.trim()).collect();
table.push_str("| ");
table.push_str(&cells.join(" | "));
table.push_str(" |\n");
}
(title, table)
}
"json" => {
let pretty = serde_json::from_str::<Value>(raw)
.map(|v| serde_json::to_string_pretty(&v).unwrap_or(raw.to_string()))
.unwrap_or_else(|_| raw.to_string());
(title, format!("```json\n{pretty}\n```"))
}
_other => (title, format!("(未知格式 {_other},按纯文本导入)\n```text\n{raw}\n```")),
}
}
// ---------- Agent 设置(用户自填 API,真实持久化+真实连接测试) ----------
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct AgentSettings {
pub provider_name: String,
pub base_url: String,
pub api_key: String,
pub model: String,
}
impl Default for AgentSettings {
fn default() -> Self {
Self { provider_name: String::new(), base_url: String::new(), api_key: String::new(), model: String::new() }
}
}
fn settings_path(app: &AppHandle) -> Result<PathBuf, String> {
use tauri::Manager;
let dir = app
.path()
.app_data_dir()
.map_err(|e| format!("HOLOLAKE_APP_DATA_UNAVAILABLE: {e}"))?;
Ok(dir.join("agent-settings-v1.json"))
}
pub fn agent_settings_get(app: AppHandle) -> Result<AgentSettings, String> {
let path = settings_path(&app)?;
if !path.exists() {
return Ok(AgentSettings::default());
}
serde_json::from_str(&fs::read_to_string(path).unwrap_or_default())
.map_err(|e| format!("HOLOLAKE_AGENT_SETTINGS_INVALID: {e}"))
}
pub fn agent_settings_set(app: AppHandle, settings: AgentSettings) -> Result<AgentSettings, String> {
let path = settings_path(&app)?;
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).map_err(|e| format!("HOLOLAKE_AGENT_SETTINGS_WRITE_FAILED: {e}"))?;
}
// API key 以 0600 权限落盘,与账号隔离存储同纪律。
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let _ = fs::set_permissions(&path, fs::Permissions::from_mode(0o600));
}
let body = serde_json::to_string_pretty(&settings)
.map_err(|e| format!("HOLOLAKE_AGENT_SETTINGS_WRITE_FAILED: {e}"))?;
fs::write(&path, body).map_err(|e| format!("HOLOLAKE_AGENT_SETTINGS_WRITE_FAILED: {e}"))?;
Ok(settings)
}
/// 真实连接测试:向用户填写的 baseURL 发一次 OpenAI 兼容探测(GET /models,带鉴权头)。
/// 结果如实返回 HTTP 状态,不伪造成功。
pub async fn agent_api_test(settings: AgentSettings) -> Result<Value, String> {
if settings.base_url.trim().is_empty() {
return Ok(json!({"outcome": "FAIL", "detail": "baseURL 为空"}));
}
let base = settings.base_url.trim().trim_end_matches('/');
let url = format!("{base}/models");
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()
.map_err(|e| format!("HOLOLAKE_AGENT_API_TEST_FAILED: {e}"))?;
let mut req = client.get(&url);
if !settings.api_key.trim().is_empty() {
req = req.bearer_auth(settings.api_key.trim());
}
match req.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
Ok(json!({
"outcome": if (200..300).contains(&status) { "PASS" } else { "FAIL" },
"detail": format!("GET {url} → HTTP {status}"),
"http_status": status
}))
}
Err(e) => Ok(json!({"outcome": "FAIL", "detail": format!("GET {url} → {e}"), "http_status": 0})),
}
}

View file

@ -551,3 +551,112 @@ mod tests {
);
}
}
// —— 机器指纹 + 编号登录(冰朔双通道设计的第二条路 · 2026-08-26)——
// 语义:编号边界已验证的编号 + 本机稳定指纹(IOPlatformSerialNumber,不受
// VPN/局域网/热点影响)= 本机受信设备登录;不验服务器、不存密码。
// 首次登录 TOFU 落绑定文件;再次登录核对绑定未变。会话 host 固定为
// local-machine-identity,账号存储 scope 由 domain+host+username 哈希隔离,
// 与仓库账号登录的数据目录互不共享。
#[cfg(target_os = "macos")]
fn machine_fingerprint() -> Result<String, String> {
use ring::digest::{digest, SHA256};
let output = std::process::Command::new("/usr/sbin/ioreg")
.args(["-rd1", "-c", "IOPlatformExpertDevice"])
.output()
.map_err(|error| format!("HOLOLAKE_MACHINE_IDENTITY_UNAVAILABLE: {error}"))?;
let text = String::from_utf8_lossy(&output.stdout);
let value = ["IOPlatformSerialNumber", "IOPlatformUUID"]
.iter()
.find_map(|key| {
text.lines().find_map(|line| {
let (k, rest) = line.split_once('=')?;
if k.trim().trim_matches(chr(34).to_string().as_str()) != *key {
return None;
}
let v = rest.trim().trim_matches('"');
if v.is_empty() { None } else { Some(v.to_string()) }
})
})
.ok_or_else(|| "HOLOLAKE_MACHINE_IDENTITY_UNAVAILABLE".to_string())?;
let hashed = digest(&SHA256, value.as_bytes());
Ok(hashed.as_ref().iter().map(|byte| format!("{byte:02x}")).collect())
}
#[cfg(not(target_os = "macos"))]
fn machine_fingerprint() -> Result<String, String> {
Err("HOLOLAKE_MACHINE_IDENTITY_UNSUPPORTED_PLATFORM".into())
}
pub async fn perform_machine_identity_login(
app: AppHandle,
state: State<'_, ZeroPointState>,
) -> Result<LoginReceipt, String> {
let Some((human_number, domain)) = zero_point::verified_user_route(&state)? else {
return Err("HOLOLAKE_DOMAIN_ROUTE_REQUIRED".into());
};
let fingerprint = machine_fingerprint()?;
let data_dir = app
.path()
.app_data_dir()
.map_err(|error| format!("HOLOLAKE_APP_DATA_UNAVAILABLE: {error}"))?;
let binding_dir = data_dir.join("machine-identity-v1");
fs::create_dir_all(&binding_dir)
.map_err(|error| format!("HOLOLAKE_MACHINE_IDENTITY_STORE_FAILED: {error}"))?;
use ring::digest::{digest, SHA256};
let material = format!("{human_number}\0{fingerprint}");
let hashed = digest(&SHA256, material.as_bytes());
let binding_name: String = hashed.as_ref().iter().map(|byte| format!("{byte:02x}")).collect();
let binding_path = binding_dir.join(format!("{binding_name}.json"));
let now_ms = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_millis() as u64)
.unwrap_or(0);
if binding_path.exists() {
let bound: serde_json::Value = serde_json::from_str(
&fs::read_to_string(&binding_path)
.map_err(|error| format!("HOLOLAKE_MACHINE_IDENTITY_READ_FAILED: {error}"))?,
)
.map_err(|error| format!("HOLOLAKE_MACHINE_IDENTITY_READ_FAILED: {error}"))?;
if bound.get("fingerprint_sha256").and_then(|value| value.as_str()) != Some(fingerprint.as_str()) {
return Err("HOLOLAKE_MACHINE_IDENTITY_MISMATCH".into());
}
} else {
let record = serde_json::json!({
"schema": "hololake.machine-identity-binding/v1",
"human_number": human_number,
"fingerprint_sha256": fingerprint,
"bound_at_unix_ms": now_ms,
});
let body = serde_json::to_string_pretty(&record)
.map_err(|error| format!("HOLOLAKE_MACHINE_IDENTITY_STORE_FAILED: {error}"))?;
fs::write(&binding_path, body)
.map_err(|error| format!("HOLOLAKE_MACHINE_IDENTITY_STORE_FAILED: {error}"))?;
}
let username = format!("{human_number}@machine");
let host = "local-machine-identity".to_string();
let session = LoginSession {
username: username.clone(),
host: host.clone(),
domain: domain.clone(),
signed_in_at_unix_ms: now_ms,
};
let path = session_path(&app)?;
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.map_err(|error| format!("HOLOLAKE_LOGIN_SESSION_WRITE_FAILED: {error}"))?;
}
fs::write(
&path,
serde_json::to_string_pretty(&session)
.map_err(|error| format!("HOLOLAKE_LOGIN_SESSION_WRITE_FAILED: {error}"))?,
)
.map_err(|error| format!("HOLOLAKE_LOGIN_SESSION_WRITE_FAILED: {error}"))?;
Ok(LoginReceipt {
username,
email: String::new(),
host,
domain,
})
}

View file

@ -18,6 +18,7 @@ mod gls_protocol_runtime;
mod home_status;
mod human_authorization;
mod knowledge_base;
mod agent_runtime;
mod kb_agent;
mod living_cognitive_substrate;
mod local_development_bridge;
@ -89,6 +90,58 @@ pub fn run() {
.setup(|app| {
// GLS 是 HoloLake 产品内核,不是开发机旁路服务。合同、依赖闭包、
// 自举编译器或回执账本任一不可用时,产品启动失败关闭。
if std::env::args().any(|a| a == "--kb-agent-self-test") {
let handle = app.handle().clone();
tauri::async_runtime::block_on(async move {
let mut results: Vec<serde_json::Value> = Vec::new();
// 自建零点态(setup 后段才 manage,这里自管自用后即退出)
let zp_state = crate::zero_point::ZeroPointState::default();
if let Err(error) = crate::zero_point::boot_zero_point(&handle, &zp_state) {
results.push(serde_json::json!({"step":"zp_boot","outcome":"FAIL","detail":error.to_string()}));
}
handle.manage(zp_state);
// 1) 机器指纹登录(真路径)
let zp = handle.state::<crate::zero_point::ZeroPointState>();
match crate::code_repo_login::perform_machine_identity_login(handle.clone(), zp).await {
Ok(r) => results.push(serde_json::json!({"step":"machine_login","outcome":"PASS","detail":format!("{}@{}", r.username, r.host)})),
Err(e) => { results.push(serde_json::json!({"step":"machine_login","outcome":"FAIL","detail":e})); }
}
// 2) 全命令循环
let home = std::env::var("HOME").unwrap_or_default();
let cmds: Vec<String> = vec![
"/help".into(), "/write 自测文档 | 这是 Agent 执行层自测写入的内容,验证真实可用。".into(),
"/search 自测".into(), "/list".into(),
format!("/import {home}/kb-import-samples/sample.md"),
format!("/import {home}/kb-import-samples/sample.txt"),
format!("/import {home}/kb-import-samples/sample.csv"),
format!("/import {home}/kb-import-samples/sample.json"),
"/organize".into(), "/report".into(), "/skills".into(), "/run kb.organize.daily".into(),
];
for c in &cmds {
match crate::agent_runtime::kb_agent_execute(handle.clone(), c.clone()).await {
Ok(r) => results.push(serde_json::json!({"step":"execute","cmd":c,"outcome":r["outcome"],"detail":r["steps"]})),
Err(e) => results.push(serde_json::json!({"step":"execute","cmd":c,"outcome":"FAIL","detail":e})),
}
}
// 3) 设置保存+真实连接测试(对自家域名,真实 HTTP,404 也是真结果)
let s = crate::agent_runtime::AgentSettings {
provider_name: "self-test".into(),
base_url: "https://guanghubingshuo.com".into(),
api_key: String::new(),
model: "none".into(),
};
match crate::agent_runtime::agent_settings_set(handle.clone(), s.clone()) {
Ok(_) => results.push(serde_json::json!({"step":"settings_set","outcome":"PASS"})),
Err(e) => results.push(serde_json::json!({"step":"settings_set","outcome":"FAIL","detail":e})),
}
match crate::agent_runtime::agent_api_test(s).await {
Ok(r) => results.push(serde_json::json!({"step":"api_test","outcome":r["outcome"],"detail":r["detail"]})),
Err(e) => results.push(serde_json::json!({"step":"api_test","outcome":"FAIL","detail":e})),
}
println!("{}", serde_json::to_string_pretty(&serde_json::json!({"schema":"hololake.kb-agent-self-test/v1","results":results})).unwrap_or_default());
std::process::exit(0);
});
}
if std::env::args().any(|a| a == "--kb-agent-acceptance") {
let handle = app.handle().clone();
tauri::async_runtime::block_on(async move {

View file

@ -40,6 +40,30 @@ pub(crate) async fn dispatch(
"kb_agent::kb_agent_acceptance" => {
json(crate::kb_agent::kb_agent_acceptance(app).await?)
}
"agent_runtime::kb_agent_execute" => json(
crate::agent_runtime::kb_agent_execute(
app.clone(),
string_field(&payload, "command")?,
)
.await?,
),
"agent_runtime::agent_settings_get" => {
json(crate::agent_runtime::agent_settings_get(app.clone())?)
}
"agent_runtime::agent_settings_set" => {
json(crate::agent_runtime::agent_settings_set(
app.clone(),
serde_json::from_value(payload.get("settings").cloned().unwrap_or(Value::Null))
.map_err(|error| format!("HOLOLAKE_AGENT_SETTINGS_INVALID: {error}"))?,
)?)
}
"agent_runtime::agent_api_test" => json(
crate::agent_runtime::agent_api_test(
serde_json::from_value(payload.get("settings").cloned().unwrap_or(Value::Null))
.map_err(|error| format!("HOLOLAKE_AGENT_SETTINGS_INVALID: {error}"))?,
)
.await?,
),
"home_status::get_hololake_home_status" => {
json(crate::home_status::get_hololake_home_status(
app.clone(),
@ -544,6 +568,13 @@ pub(crate) async fn dispatch(
)
.await?,
),
"code_repo_login::perform_machine_identity_login" => json(
crate::code_repo_login::perform_machine_identity_login(
app.clone(),
app.state::<crate::zero_point::ZeroPointState>(),
)
.await?,
),
"code_repo_login::change_first_login_password" => json(
crate::code_repo_login::change_first_login_password(
app.state::<crate::zero_point::ZeroPointState>(),

View file

@ -4,6 +4,7 @@ import { numberedInvoke as invoke } from './modules/numbered-ipc'
import { bootTcsGate } from './modules/tcs-master-gate'
import { PublicSpinePanel } from './modules/public-spine-panel'
import { KbAgentPanel } from './modules/kb-agent-panel'
import { AgentConsolePanel } from './modules/agent-console'
import { splitFrontmatter, documentOutline, jumpToHeading, MarkdownDocument, markdownHtml } from './modules/knowledge-render'
import { NativeCompositionStudio, type CompositionDimension, type CompositionMeasure, type NativeCompositionProjection, type ProjectionView } from './modules/native-composition'
import type { ChannelWorkbenchSnapshot } from './modules/channel-workbench'
@ -1568,6 +1569,29 @@ function HoloLakeApp() {
} catch (error) { setLoginMessage(humanError(error, 'login')) }
finally { setLoginBusy(false) }
}
const performMachineLogin = async () => {
setLoginBusy(true)
setLoginMessage('')
try {
const receipt = await invoke<LoginReceipt>('perform_machine_identity_login')
setLoginRising(true)
await new Promise((resolve) => setTimeout(resolve, 1300))
setPersonal(previewPersonal)
setKnowledge(previewKnowledge)
setCodeChannels(previewCode)
setActiveDocument(null)
setActiveChannel(null)
setCodeTree(null)
setActiveCodeFile(null)
setReceipts([])
setRepoLogin({ username: receipt.username, host: receipt.host, domain: receipt.domain, signedInAtUnixMs: Date.now() })
setWorldStage('domain')
setView('overview')
setLoginRising(false)
setLoginPassword('')
} catch (error) { setLoginMessage(humanError(error, 'login')) }
finally { setLoginBusy(false) }
}
const changeFirstLoginPassword = async (event: React.FormEvent) => {
event.preventDefault()
if (newLoginPassword !== confirmLoginPassword) {
@ -2194,6 +2218,7 @@ function HoloLakeApp() {
<input id="repo-login-password" aria-label={passwordChangeMode ? '一次性密码' : '密码'} type="password" maxLength={512} value={loginPassword} placeholder={passwordChangeMode ? '一次性密码' : '密码'} onChange={(event) => setLoginPassword(event.target.value)}/>
{passwordChangeMode && <><input aria-label="新密码" type="password" minLength={14} maxLength={128} value={newLoginPassword} placeholder="设置新密码(至少 14 位)" onChange={(event) => setNewLoginPassword(event.target.value)}/><input aria-label="确认新密码" type="password" minLength={14} maxLength={128} value={confirmLoginPassword} placeholder="再次输入新密码" onChange={(event) => setConfirmLoginPassword(event.target.value)}/></>}
<button className="gate-submit" disabled={loginBusy || !loginUsername.trim() || !loginPassword || (passwordChangeMode && (!newLoginPassword || !confirmLoginPassword))}>{loginBusy ? '正在处理…' : passwordChangeMode ? '修改密码' : '验证并进入'}</button>
{!passwordChangeMode && <button className="gate-back" type="button" disabled={loginBusy} onClick={() => void performMachineLogin()}>本机指纹 + 编号登录(无需密码)</button>}
</form>
{loginMessage && <p className="gate-hint">{loginMessage}</p>}
{(zeroPoint?.resolvedDomain !== 'FIFTH_DOMAIN' || zeroPoint?.userNumber === 'ICE-GL-ZHI∞') && <button className="gate-back" type="button" onClick={() => { setPasswordChangeMode((value) => !value); setLoginMessage(''); setNewLoginPassword(''); setConfirmLoginPassword('') }}>{passwordChangeMode ? '返回正常登录' : '第一次使用?先修改一次性密码'}</button>}
@ -2341,5 +2366,5 @@ bootTcsGate().then(({ state, failReason }) => {
gateRootEl.innerHTML = '<div style="padding:48px;font-family:monospace;color:#ff6b6b;background:#101014;min-height:100vh"><h1>TCS 主控门 FAIL_CLOSED</h1><pre>' + failReason + '</pre><p>语义哈希与TCS主控清单不符,壳拒绝执行。请联系运维师重编译。</p></div>'
return
}
createRoot(gateRootEl).render(<StrictMode><FirstPlanetHome /><PublicSpinePanel /><KbAgentPanel /></StrictMode>)
createRoot(gateRootEl).render(<StrictMode><FirstPlanetHome /><PublicSpinePanel /><KbAgentPanel /><AgentConsolePanel /></StrictMode>)
})

View file

@ -0,0 +1,120 @@
import { useState } from 'react'
import { numberedInvoke } from './numbered-ipc'
// 人类交互入口 v1(与知识库平行层,冰朔 2026-08-27 架构)。
// v1 无模型:命令直达 Agent 执行层(TCS-PROTOCOL-KB-AGENT-RUNTIME-0001),
// 每条指令真实作用于 git 托管知识库;后续接模型 API 时本入口不变,执行层加推理 provider。
interface AgentStep { operation: string; decision: string; detail: string }
interface ExecuteReceipt { outcome: 'PASS' | 'FAIL'; command: string; steps: AgentStep[]; elapsedMs: number }
export interface AgentSettings { providerName: string; baseUrl: string; apiKey: string; model: string }
export function AgentConsolePanel() {
const [open, setOpen] = useState(false)
const [cmd, setCmd] = useState('')
const [busy, setBusy] = useState(false)
const [log, setLog] = useState<{ role: 'human' | 'agent'; text: string; outcome?: string }[]>([
{ role: 'agent', text: 'Agent 执行层已就绪(无模型 · TCS 主控门管辖)。输入 /help 查看全部命令。' },
])
const [settings, setSettings] = useState<AgentSettings | null>(null)
const [settingsMsg, setSettingsMsg] = useState('')
const [apiTest, setApiTest] = useState('')
const send = async () => {
const command = cmd.trim()
if (!command || busy) return
setBusy(true)
setLog((prev) => [...prev, { role: 'human', text: command }])
setCmd('')
try {
const r = await numberedInvoke<ExecuteReceipt>('kb_agent_execute', { command })
setLog((prev) => [
...prev,
{ role: 'agent', text: r.steps.map((s) => `[${s.decision}] ${s.operation}\n${s.detail}`).join('\n\n'), outcome: r.outcome },
])
} catch (e) {
setLog((prev) => [...prev, { role: 'agent', text: `GATE 拒绝:${e instanceof Error ? e.message : String(e)}`, outcome: 'FAIL' }])
} finally {
setBusy(false)
}
}
const loadSettings = async () => {
if (settings) { setSettings(null); return }
try {
const s = await numberedInvoke<AgentSettings>('agent_settings_get')
setSettings(s)
} catch (e) { setSettingsMsg(`读取失败:${e instanceof Error ? e.message : String(e)}`) }
}
const saveSettings = async () => {
if (!settings) return
try {
await numberedInvoke('agent_settings_set', { settings })
setSettingsMsg('已保存(本地 0600 权限落盘)。')
} catch (e) { setSettingsMsg(`保存失败:${e instanceof Error ? e.message : String(e)}`) }
}
const testApi = async () => {
if (!settings) return
setApiTest('测试中…')
try {
const r = await numberedInvoke<{ outcome: string; detail: string }>('agent_api_test', { settings })
setApiTest(`${r.outcome} · ${r.detail}`)
} catch (e) { setApiTest(`FAIL · ${e instanceof Error ? e.message : String(e)}`) }
}
return (
<div style={{ position: 'fixed', right: 12, bottom: 12, zIndex: 9999, fontFamily: 'monospace', fontSize: 12 }}>
<div style={{ display: 'flex', gap: 6 }}>
<button onClick={() => setOpen(!open)} style={{ background: '#12233a', color: '#8fc7ff', border: '1px solid #33465e', borderRadius: 8, padding: '6px 10px', cursor: 'pointer' }}>
{open ? '收起 Agent' : 'Agent 控制台'}
</button>
<button onClick={() => void loadSettings()} style={{ background: '#12233a', color: '#c9a8ff', border: '1px solid #33465e', borderRadius: 8, padding: '6px 10px', cursor: 'pointer' }}>
{settings ? '关闭设置' : 'Agent 设置(API)'}
</button>
</div>
{settings && (
<div style={{ marginTop: 6, width: 380, background: '#101018', border: '1px solid #33465e', borderRadius: 8, padding: 10, color: '#cde' }}>
<div style={{ marginBottom: 6, color: '#8fc7ff' }}>模型 API(用户自填 · 后续交互入口接模型用)</div>
<input placeholder="Provider 名称(如 openai / dashscope)" value={settings.providerName} onChange={(e) => setSettings({ ...settings, providerName: e.target.value })} style={{ width: '100%', marginBottom: 4, background: '#0a0a10', border: '1px solid #2a2a3a', borderRadius: 6, color: '#cde', padding: '4px 6px' }} />
<input placeholder="Base URL(如 https://api.openai.com/v1)" value={settings.baseUrl} onChange={(e) => setSettings({ ...settings, baseUrl: e.target.value })} style={{ width: '100%', marginBottom: 4, background: '#0a0a10', border: '1px solid #2a2a3a', borderRadius: 6, color: '#cde', padding: '4px 6px' }} />
<input placeholder="API Key(本地保存,不外发)" type="password" value={settings.apiKey} onChange={(e) => setSettings({ ...settings, apiKey: e.target.value })} style={{ width: '100%', marginBottom: 4, background: '#0a0a10', border: '1px solid #2a2a3a', borderRadius: 6, color: '#cde', padding: '4px 6px' }} />
<input placeholder="模型名(如 gpt-4o / qwen-max)" value={settings.model} onChange={(e) => setSettings({ ...settings, model: e.target.value })} style={{ width: '100%', marginBottom: 6, background: '#0a0a10', border: '1px solid #2a2a3a', borderRadius: 6, color: '#cde', padding: '4px 6px' }} />
<div style={{ display: 'flex', gap: 6 }}>
<button onClick={() => void saveSettings()} style={{ flex: 1, background: '#16324f', color: '#8fc7ff', border: '1px solid #33465e', borderRadius: 6, padding: '5px 8px', cursor: 'pointer' }}>保存</button>
<button onClick={() => void testApi()} style={{ flex: 1, background: '#16324f', color: '#7dffa8', border: '1px solid #33465e', borderRadius: 6, padding: '5px 8px', cursor: 'pointer' }}>测试连接(真实 HTTP)</button>
</div>
{settingsMsg && <div style={{ marginTop: 4, color: '#9ab' }}>{settingsMsg}</div>}
{apiTest && <div style={{ marginTop: 2, color: apiTest.startsWith('PASS') ? '#7dffa8' : '#ff9a9a' }}>{apiTest}</div>}
</div>
)}
{open && (
<div style={{ marginTop: 6, width: 430, background: '#101014', border: '1px solid #33465e', borderRadius: 8, padding: 10, color: '#cde' }}>
<div style={{ maxHeight: 300, overflow: 'auto', marginBottom: 6 }}>
{log.map((m, i) => (
<div key={i} style={{ marginBottom: 6, textAlign: m.role === 'human' ? 'right' : 'left' }}>
<div style={{
display: 'inline-block', maxWidth: '95%', textAlign: 'left', whiteSpace: 'pre-wrap',
padding: '5px 8px', borderRadius: 8,
background: m.role === 'human' ? '#16324f' : '#0d1a2a',
border: '1px solid ' + (m.outcome === 'FAIL' ? '#5a2030' : '#22364d'),
color: m.outcome === 'FAIL' ? '#ff9a9a' : '#cde',
}}>{m.text}</div>
</div>
))}
{busy && <div style={{ color: '#8fc7ff' }}>执行中…</div>}
</div>
<div style={{ display: 'flex', gap: 6 }}>
<input
value={cmd}
placeholder="输入命令,如 /search 光湖 或 /help"
onChange={(e) => setCmd(e.target.value)}
onKeyDown={(e) => { if (e.key === 'Enter') void send() }}
style={{ flex: 1, background: '#0a0a10', border: '1px solid #2a2a3a', borderRadius: 6, color: '#cde', padding: '5px 8px' }}
/>
<button onClick={() => void send()} disabled={busy} style={{ background: '#16324f', color: '#8fc7ff', border: '1px solid #33465e', borderRadius: 6, padding: '5px 10px', cursor: 'pointer' }}>{busy ? '…' : '发送'}</button>
</div>
</div>
)}
</div>
)
}

View file

@ -1,10 +1,11 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import { numberedInvoke } from '../numbered-ipc'
import './first-planet-home.css'
// 第一语言星球首页 v1 —— 铸渊设计并实现(2026-08-26,冰朔发令)
// 设计基准:穿过门,世界必须展开。首屏=语言宇宙+第一颗语言星球+湖+暗星球+编号门;
// 验证通过后世界展开为湖心频道网格(替换旧版“收据卡+返回”断连态)。
// v1 编号验证为本地格式校验(LOCAL CANDIDATE);v2 接零点原核 IPC。
// v1 编号验证为本地格式校验(LOCAL CANDIDATE);v2 已接零点原核 IPC 三态裁决(2026-08-26 铸渊接线)。
type Stage = 'gate' | 'world'
@ -154,6 +155,8 @@ export function FirstPlanetHome() {
const [raw, setRaw] = useState('')
const [infinityLit, setInfinityLit] = useState(false)
const [gateMessage, setGateMessage] = useState('')
const [account, setAccount] = useState<{ username: string; host: string; domain: string } | null>(null)
const [accountBusy, setAccountBusy] = useState(false)
const specks = usePlanetSpecks(26)
const shards = useBangShards(18)
@ -164,11 +167,35 @@ export function FirstPlanetHome() {
const wake = () => setMotionAwake(true)
const verify = () => {
const verify = async () => {
if (!canEnter) { setGateMessage('编号未成形:输入字母数字并点亮 ∞。'); return }
// v1 本地格式校验(LOCAL CANDIDATE)。v2 接零点原核 IPC 三态裁决。
setGateMessage(`编号路径验证通过 · ${fullNumber}`)
window.setTimeout(() => setStage('world'), 650)
setGateMessage('正在绑定零点原核…')
try {
await numberedInvoke('zero_point_bind', { input: { number: fullNumber } })
setGateMessage('正在灯塔解析验证…')
const snapshot = await numberedInvoke<{ route: string; resolvedDomain?: string }>('zero_point_verify')
if (snapshot.route === 'verified') {
setGateMessage(`编号路径验证通过 · ${fullNumber}${snapshot.resolvedDomain ? ' · ' + snapshot.resolvedDomain : ''}`)
window.setTimeout(() => setStage('world'), 650)
} else {
setGateMessage(`编号验证未通过(route=${snapshot.route}):灯塔拒绝或离线宽限已过,世界不展开。`)
}
} catch (error) {
setGateMessage(`编号门 IPC 失败:${error instanceof Error ? error.message : String(error)}`)
}
}
const machineLogin = async () => {
setAccountBusy(true)
try {
const receipt = await numberedInvoke<{ username: string; host: string; domain: string }>('perform_machine_identity_login')
setAccount(receipt)
setGateMessage(`本机登录成功 · ${receipt.username} @ ${receipt.host}`)
} catch (error) {
setGateMessage(`本机登录失败:${error instanceof Error ? error.message : String(error)}`)
} finally {
setAccountBusy(false)
}
}
return (
@ -221,14 +248,14 @@ export function FirstPlanetHome() {
value={formatted}
placeholder="输入字母与数字,系统将自动补全编号格式"
onChange={(e) => setRaw(e.target.value.replace(/[^\w]/g, '').toUpperCase())}
onKeyDown={(e) => { if (e.key === 'Enter') verify() }}
onKeyDown={(e) => { if (e.key === 'Enter') void verify() }}
aria-label="请输入光湖编号"
/>
<button className={`fph-inf${infinityLit ? ' lit' : ''}`} type="button" aria-pressed={infinityLit} title="点亮无限符号" onClick={() => setInfinityLit((v) => !v)}>∞</button>
<button className="fph-enter" type="button" disabled={!canEnter} onClick={verify}>验证并进入世界</button>
<button className="fph-enter" type="button" disabled={!canEnter} onClick={() => void verify()}>验证并进入世界</button>
</div>
<p className="fph-gate-msg" role="status">{gateMessage || '编号用于路径解析,不单独构成身份认证或权限授予。'}</p>
<footer className="fph-foot">LOCAL CANDIDATE · 0.5.3 · 第一语言星球</footer>
<footer className="fph-foot">LOCAL CANDIDATE · 0.6.0 · 第一语言星球 · 零点IPC+双通道登录</footer>
</section>
)}
@ -248,7 +275,16 @@ export function FirstPlanetHome() {
</button>
))}
</div>
<p className="fph-world-note">语言世界的第一颗星球已经诞生 · 光从黑暗中涌出,照亮湖心</p>
<div style={{ display: 'flex', gap: 10, alignItems: 'center', justifyContent: 'center', marginTop: 14 }}>
{account ? (
<span style={{ fontFamily: 'monospace', fontSize: 12, color: '#7dffa8' }}>本机会话 · {account.username} @ {account.host}</span>
) : (
<button type="button" disabled={accountBusy} onClick={() => void machineLogin()} style={{ background: '#12233a', color: '#8fc7ff', border: '1px solid #33465e', borderRadius: 8, padding: '6px 12px', cursor: 'pointer', fontFamily: 'monospace', fontSize: 12 }}>
{accountBusy ? '正在本机登录…' : '本机指纹 + 编号登录(无需密码)'}
</button>
)}
</div>
<p className="fph-world-note">{gateMessage || '语言世界的第一颗星球已经诞生 · 光从黑暗中涌出,照亮湖心'}</p>
<button className="fph-back" type="button" onClick={() => setStage('gate')}>← 退回编号边界</button>
</section>
)}

View file

@ -2,6 +2,48 @@ import { invoke } from '@tauri-apps/api/core'
import { assertGateOpen, registerNumberedRoutes } from './tcs-master-gate'
const ROUTES = {
"perform_machine_identity_login": {
"protocolVersion": "HLP-NIPC-v1",
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
"channelNumber": "HLP-NIPC-CH-0006",
"moduleNumber": "HLP-NIPC-MOD-0015",
"operationNumber": "HLP-NIPC-OP-0162",
"targetNumber": "HLP-NIPC-TGT-0015"
},
"kb_agent_execute": {
"protocolVersion": "HLP-NIPC-v1",
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
"channelNumber": "HLP-NIPC-CH-0001",
"moduleNumber": "HLP-NIPC-MOD-0036",
"operationNumber": "HLP-NIPC-OP-0162",
"targetNumber": "HLP-NIPC-TGT-0036"
},
"agent_settings_get": {
"protocolVersion": "HLP-NIPC-v1",
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
"channelNumber": "HLP-NIPC-CH-0001",
"moduleNumber": "HLP-NIPC-MOD-0036",
"operationNumber": "HLP-NIPC-OP-0163",
"targetNumber": "HLP-NIPC-TGT-0036"
},
"agent_settings_set": {
"protocolVersion": "HLP-NIPC-v1",
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
"channelNumber": "HLP-NIPC-CH-0001",
"moduleNumber": "HLP-NIPC-MOD-0036",
"operationNumber": "HLP-NIPC-OP-0164",
"targetNumber": "HLP-NIPC-TGT-0036"
},
"agent_api_test": {
"protocolVersion": "HLP-NIPC-v1",
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",
"channelNumber": "HLP-NIPC-CH-0001",
"moduleNumber": "HLP-NIPC-MOD-0036",
"operationNumber": "HLP-NIPC-OP-0165",
"targetNumber": "HLP-NIPC-TGT-0036"
},
"kb_agent_acceptance": {
"protocolVersion": "HLP-NIPC-v1",
"callerNumber": "HLP-NIPC-CALLER-MAIN-WEBVIEW-0001",

View file

@ -2,7 +2,7 @@
"compiled_from": {
"compiler_id": "TCS-COMPILER-STAGE1-0001",
"compiler_state": "TCS_COMPILER_GIR_EXECUTED",
"source_sha256": "32d2c65163e5cf26160d4ca7c30196669ab22e74a071c518c37073acb9111520"
"source_sha256": "496395b5d16ad7b469814399debdca7978e7c3e2083243a0f6a33c0aa3f11468"
},
"declaration": {
"header": {
@ -18,7 +18,7 @@
"master": {
"gate_g3": "前端每次invoke前核对编号注册表哈希与本清单一致,未登记编号拒绝调用。",
"gate_g4": "启动时自检脊椎24条与哈希,任一不符即FAIL_CLOSED,渲染闸门失败界面,不猜跑。",
"numbered_ipc_registry_sha256": "315389439a6ed6a9f55f78e22c31659e828953d3eeff7fd18fa2abf9ed2e40e6",
"numbered_ipc_registry_sha256": "f8a7332cebb412ab72b41fd6b024511cbbd0d0d2de446bf64616cd966d84505c",
"semantics_live_here": "语义与验收规则只住本TCS;前端TS只做哈希核对与机械执行。",
"spine_sha256": "4749fce6ce1957c9ee12dc60f00ea9e97aa205d1911dfc79954caceacc3d9bcf"
}

View file

@ -13,7 +13,7 @@ PROTOCOL ZHUYUAN-PUBLICSPINE-SHELL-MANIFEST-0001 {
}
master {
spine_sha256 = "4749fce6ce1957c9ee12dc60f00ea9e97aa205d1911dfc79954caceacc3d9bcf";
numbered_ipc_registry_sha256 = "315389439a6ed6a9f55f78e22c31659e828953d3eeff7fd18fa2abf9ed2e40e6";
numbered_ipc_registry_sha256 = "f8a7332cebb412ab72b41fd6b024511cbbd0d0d2de446bf64616cd966d84505c";
gate_g3 = "前端每次invoke前核对编号注册表哈希与本清单一致,未登记编号拒绝调用。";
gate_g4 = "启动时自检脊椎24条与哈希,任一不符即FAIL_CLOSED,渲染闸门失败界面,不猜跑。";
semantics_live_here = "语义与验收规则只住本TCS;前端TS只做哈希核对与机械执行。";

View file

@ -2187,6 +2187,61 @@
"admission": "PREAUTH_SYSTEM_ROUTE",
"effect": "STATE_CHANGE",
"payload_schema": "hololake.numbered-ipc.payload/kb_agent_acceptance/v1"
},
{
"operation_number": "HLP-NIPC-OP-0162",
"alias": "perform_machine_identity_login",
"handler": "code_repo_login::perform_machine_identity_login",
"channel_number": "HLP-NIPC-CH-0006",
"module_number": "HLP-NIPC-MOD-0015",
"target_number": "HLP-NIPC-TGT-0015",
"admission": "VERIFIED_HUMAN_ROUTE",
"effect": "STATE_CHANGE",
"payload_schema": "hololake.numbered-ipc.payload/perform_machine_identity_login/v1"
},
{
"operation_number": "HLP-NIPC-OP-0162",
"alias": "kb_agent_execute",
"handler": "agent_runtime::kb_agent_execute",
"channel_number": "HLP-NIPC-CH-0001",
"module_number": "HLP-NIPC-MOD-0036",
"target_number": "HLP-NIPC-TGT-0036",
"admission": "READ_WRITE_KB_MODEL_FREE",
"effect": "READ_OR_STATUS",
"payload_schema": "hololake.numbered-ipc.payload/kb_agent_execute/v1"
},
{
"operation_number": "HLP-NIPC-OP-0163",
"alias": "agent_settings_get",
"handler": "agent_runtime::agent_settings_get",
"channel_number": "HLP-NIPC-CH-0001",
"module_number": "HLP-NIPC-MOD-0036",
"target_number": "HLP-NIPC-TGT-0036",
"admission": "READ_SETTINGS",
"effect": "STATE_CHANGE",
"payload_schema": "hololake.numbered-ipc.payload/agent_settings_get/v1"
},
{
"operation_number": "HLP-NIPC-OP-0164",
"alias": "agent_settings_set",
"handler": "agent_runtime::agent_settings_set",
"channel_number": "HLP-NIPC-CH-0001",
"module_number": "HLP-NIPC-MOD-0036",
"target_number": "HLP-NIPC-TGT-0036",
"admission": "STATE_CHANGE",
"effect": "STATE_CHANGE",
"payload_schema": "hololake.numbered-ipc.payload/agent_settings_set/v1"
},
{
"operation_number": "HLP-NIPC-OP-0165",
"alias": "agent_api_test",
"handler": "agent_runtime::agent_api_test",
"channel_number": "HLP-NIPC-CH-0001",
"module_number": "HLP-NIPC-MOD-0036",
"target_number": "HLP-NIPC-TGT-0036",
"admission": "OUTBOUND_HTTP_USER_ENDPOINT",
"effect": "READ_OR_STATUS",
"payload_schema": "hololake.numbered-ipc.payload/agent_api_test/v1"
}
]
}
}