forked from bai/curriculum-project-hub
feat(hub): 真实飞书读取 + 状态卡片 + 权限 gate + 部署脚本
FeishuRead(ADR-0003): feishuContextTool 从 stub 换成真实 lark im.v1.message.get(单条 trigger/reply/status_card)+ list(thread 回复); ADR-0003 chat 授权不变式不变(handler 已 gate)。 StatusCard: sendCard + buildRunStatusCard——完成/出错发 interactive card (status 文案 + model 选择器 + 取消按钮带 runId),替代纯文本。 Permission(ADR-0004, project-wise): triggerAgent 查 PermissionGrant 对 project 的 edit+ 能力(manage⊇edit 单调);sender open_id 当 principal (子类型学 OPEN,务实选择,permission.ts 标注);per-artifact OPEN; settings 组合规则 OPEN。无权限回 '无权限触发'。 Deploy: cph-hub.service systemd unit(ExecStartPre 跑 prisma migrate)+ install_service.sh(idempotent,seed env)+ deploy_platform.sh (rsync + npm ci + build + restart + healthz)。 client.ts 抽 createLarkClient/startFeishuListenerWithClient,tools 与 ws 共用同一 client。 tsc rc=0;prisma validate 通过;deploy 脚本 bash -n 通过。
This commit is contained in:
+12
-15
@@ -18,7 +18,8 @@ import { InMemoryModelRegistry } from "./agent/models.js";
|
||||
import { ToolRegistry, feishuContextTool } from "./agent/tools.js";
|
||||
import { readFileTool, writeFileTool, listFilesTool } from "./agent/workspace.js";
|
||||
import { cphCheckTool, cphBuildTool } from "./agent/cph.js";
|
||||
import { startFeishuListener } from "./feishu/client.js";
|
||||
import { createLarkClient, startFeishuListenerWithClient, type FeishuRuntime } from "./feishu/client.js";
|
||||
import { readFeishuContext } from "./feishu/read.js";
|
||||
import { makeTriggerHandler } from "./feishu/trigger.js";
|
||||
|
||||
function requireEnv(name: string): string {
|
||||
@@ -56,14 +57,15 @@ async function main(): Promise<void> {
|
||||
],
|
||||
);
|
||||
|
||||
// Build the lark client first — tools that call Feishu APIs hold it from boot.
|
||||
const feishuConfig = { appId: feishuAppId, appSecret: feishuAppSecret, botOpenId: feishuBotOpenId };
|
||||
const larkClient = createLarkClient(feishuConfig);
|
||||
const feishuRt: FeishuRuntime = { client: larkClient, logger: app.log };
|
||||
|
||||
const tools = new ToolRegistry();
|
||||
tools.register(
|
||||
// ADR-0003: the handler enforces chat==boundChat before any Feishu API call.
|
||||
// Real impl wraps @larksuiteoapi/node-sdk's im.message.list/read APIs.
|
||||
feishuContextTool(async (args, ctx) => {
|
||||
return JSON.stringify({ stub: true, anchor: args.anchor, id: args.id, projectId: ctx.projectId });
|
||||
}),
|
||||
);
|
||||
// ADR-0003: the handler enforces chat==boundChat before any API call;
|
||||
// real read wraps @larksuiteoapi/node-sdk's im.v1.message get/list.
|
||||
tools.register(feishuContextTool(readFeishuContext, feishuRt));
|
||||
// Workspace file tools (ADR-0007 directory tree, path-confined).
|
||||
tools.register(readFileTool());
|
||||
tools.register(writeFileTool());
|
||||
@@ -72,14 +74,9 @@ async function main(): Promise<void> {
|
||||
tools.register(cphCheckTool());
|
||||
tools.register(cphBuildTool());
|
||||
|
||||
// --- Feishu listener ---
|
||||
// --- Feishu listener (reuses the same lark client) ---
|
||||
const trigger = makeTriggerHandler({ prisma, provider, tools, models, logger: app.log });
|
||||
const feishuCtx = startFeishuListener(
|
||||
{ appId: feishuAppId, appSecret: feishuAppSecret, botOpenId: feishuBotOpenId },
|
||||
app.log,
|
||||
trigger,
|
||||
);
|
||||
void feishuCtx;
|
||||
startFeishuListenerWithClient(feishuConfig, larkClient, app.log, trigger);
|
||||
|
||||
app.listen({ port, host: "0.0.0.0" }, (err, address) => {
|
||||
if (err !== null) {
|
||||
|
||||
Reference in New Issue
Block a user