forked from ChaiHao/BPOS-MVP
编排层③:活动装入/换版入口 —— 开发完能装进来,不必跑种子
此前活动只能靠 seed 装入,治理台没有任何入口 —— 这是「逐个开发活动」的拦路石。 补 POST /api/gov/activities(无代码通道:交清单 + .js 产物,都是数据), 两审在服务端跑;不过审按发布门同样的式样回 412 + ApiError.detail 带审计结论 (直接回业务体的话类型化客户端拿不到详情)。活动库给「装入 / 换版」卡:选文件或粘贴两份。 实测:0.1.0 → 0.2.0 版本并存;声明未注册的工具即 412 并点名到工具。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -1531,6 +1531,398 @@ export declare const saveWorkGroupRoute: {
|
|||||||
}, z.core.$strip>;
|
}, z.core.$strip>;
|
||||||
}, z.core.$strip>;
|
}, z.core.$strip>;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* 经安装通道装入活动包 —— **无代码通道**(ADR-004):交的是清单 + .js 产物,都是数据。
|
||||||
|
*
|
||||||
|
* 安装两审在服务端跑:静态审读清单(工具契约在否、模型名绑没绑、模版有没有脚本、
|
||||||
|
* 声明与已物化的台账冲不冲),回放审重演历史(首装无历史即免,以样例集替代)。
|
||||||
|
* **恒为新增、版本并存**:装入不覆盖旧版本,在途任务按其启动时版本跑完。
|
||||||
|
*/
|
||||||
|
export declare const installActivityRoute: {
|
||||||
|
readonly method: "POST";
|
||||||
|
readonly path: "/api/gov/activities";
|
||||||
|
readonly body: z.ZodObject<{
|
||||||
|
manifest: z.ZodObject<{
|
||||||
|
identity: z.ZodObject<{
|
||||||
|
activityId: z.core.$ZodBranded<z.ZodString, "ActivityId", "out">;
|
||||||
|
name: z.ZodString;
|
||||||
|
packageVersion: z.ZodString;
|
||||||
|
category: z.ZodString;
|
||||||
|
paradigm: z.ZodEnum<{
|
||||||
|
loop: "loop";
|
||||||
|
flow: "flow";
|
||||||
|
}>;
|
||||||
|
sdkVersion: z.ZodString;
|
||||||
|
checksum: z.ZodString;
|
||||||
|
signature: z.ZodOptional<z.ZodString>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
contract: z.ZodObject<{
|
||||||
|
activityId: z.core.$ZodBranded<z.ZodString, "ActivityId", "out">;
|
||||||
|
version: z.ZodString;
|
||||||
|
input: z.ZodObject<{
|
||||||
|
data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
||||||
|
messageAllowed: z.ZodDefault<z.ZodBoolean>;
|
||||||
|
messageHint: z.ZodOptional<z.ZodString>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
output: z.ZodObject<{
|
||||||
|
mandatory: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
payload: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
||||||
|
description: z.ZodOptional<z.ZodString>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
selective: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
group: z.ZodString;
|
||||||
|
ports: z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
payload: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
||||||
|
description: z.ZodOptional<z.ZodString>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
requiredDeliverables: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
key: z.ZodString;
|
||||||
|
label: z.ZodString;
|
||||||
|
schema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
acceptanceCriteria: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
key: z.ZodString;
|
||||||
|
label: z.ZodString;
|
||||||
|
level: z.ZodEnum<{
|
||||||
|
L1: "L1";
|
||||||
|
L2: "L2";
|
||||||
|
L3: "L3";
|
||||||
|
L4: "L4";
|
||||||
|
L5: "L5";
|
||||||
|
}>;
|
||||||
|
predicate: z.ZodOptional<z.ZodString>;
|
||||||
|
modelRef: z.ZodOptional<z.ZodString>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
prohibitions: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
key: z.ZodString;
|
||||||
|
statement: z.ZodString;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
authorization: z.ZodObject<{
|
||||||
|
discretion: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
key: z.ZodString;
|
||||||
|
statement: z.ZodString;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
preauthorizedActions: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
tool: z.ZodString;
|
||||||
|
operation: z.ZodString;
|
||||||
|
limit: z.ZodOptional<z.ZodString>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
humanCallBudget: z.ZodNumber;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
resources: z.ZodObject<{
|
||||||
|
tools: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
version: z.ZodOptional<z.ZodString>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
skills: z.ZodDefault<z.ZodArray<z.core.$ZodBranded<z.ZodString, "SkillId", "out">>>;
|
||||||
|
models: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
||||||
|
roles: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
||||||
|
budget: z.ZodObject<{
|
||||||
|
steps: z.ZodNumber;
|
||||||
|
tokens: z.ZodNumber;
|
||||||
|
activeMinutes: z.ZodNumber;
|
||||||
|
humanCalls: z.ZodNumber;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
declarations: z.ZodObject<{
|
||||||
|
models: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
||||||
|
tools: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
version: z.ZodOptional<z.ZodString>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
ledger: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
domain: z.ZodString;
|
||||||
|
object: z.ZodString;
|
||||||
|
label: z.ZodOptional<z.ZodString>;
|
||||||
|
fields: z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
type: z.ZodEnum<{
|
||||||
|
number: "number";
|
||||||
|
boolean: "boolean";
|
||||||
|
json: "json";
|
||||||
|
text: "text";
|
||||||
|
date: "date";
|
||||||
|
integer: "integer";
|
||||||
|
timestamp: "timestamp";
|
||||||
|
}>;
|
||||||
|
label: z.ZodOptional<z.ZodString>;
|
||||||
|
primaryKey: z.ZodDefault<z.ZodBoolean>;
|
||||||
|
masked: z.ZodDefault<z.ZodBoolean>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
listeners: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
origin: z.ZodEnum<{
|
||||||
|
static: "static";
|
||||||
|
dynamic: "dynamic";
|
||||||
|
}>;
|
||||||
|
eventType: z.ZodEnum<{
|
||||||
|
human: "human";
|
||||||
|
data: "data";
|
||||||
|
time: "time";
|
||||||
|
control: "control";
|
||||||
|
}>;
|
||||||
|
keyFilter: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||||
|
condition: z.ZodOptional<z.ZodString>;
|
||||||
|
semantic: z.ZodEnum<{
|
||||||
|
observe: "observe";
|
||||||
|
"complete-step": "complete-step";
|
||||||
|
}>;
|
||||||
|
deadline: z.ZodString;
|
||||||
|
escalation: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
||||||
|
nudge: "nudge";
|
||||||
|
reroute: "reroute";
|
||||||
|
escalate: "escalate";
|
||||||
|
}>>>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
harness: z.ZodObject<{
|
||||||
|
memoryWindow: z.ZodDefault<z.ZodNumber>;
|
||||||
|
stallAfter: z.ZodDefault<z.ZodString>;
|
||||||
|
nudge: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
after: z.ZodString;
|
||||||
|
action: z.ZodEnum<{
|
||||||
|
nudge: "nudge";
|
||||||
|
escalate: "escalate";
|
||||||
|
}>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
retry: z.ZodDefault<z.ZodObject<{
|
||||||
|
times: z.ZodDefault<z.ZodNumber>;
|
||||||
|
backoff: z.ZodDefault<z.ZodString>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
assets: z.ZodObject<{
|
||||||
|
businessModel: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
||||||
|
paradigm: z.ZodLiteral<"loop">;
|
||||||
|
cmmnXml: z.ZodString;
|
||||||
|
narrative: z.ZodString;
|
||||||
|
dmn: z.ZodObject<{
|
||||||
|
drd: z.ZodArray<z.ZodObject<{
|
||||||
|
decision: z.ZodString;
|
||||||
|
requires: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
||||||
|
inputs: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
tables: z.ZodArray<z.ZodObject<{
|
||||||
|
id: z.ZodString;
|
||||||
|
label: z.ZodString;
|
||||||
|
hitPolicy: z.ZodDefault<z.ZodEnum<{
|
||||||
|
UNIQUE: "UNIQUE";
|
||||||
|
FIRST: "FIRST";
|
||||||
|
PRIORITY: "PRIORITY";
|
||||||
|
COLLECT: "COLLECT";
|
||||||
|
}>>;
|
||||||
|
inputs: z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
expression: z.ZodString;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
outputs: z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
rules: z.ZodArray<z.ZodObject<{
|
||||||
|
id: z.ZodString;
|
||||||
|
when: z.ZodArray<z.ZodString>;
|
||||||
|
then: z.ZodArray<z.ZodUnknown>;
|
||||||
|
annotation: z.ZodOptional<z.ZodString>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>, z.ZodObject<{
|
||||||
|
paradigm: z.ZodLiteral<"flow">;
|
||||||
|
steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"tool">;
|
||||||
|
tool: z.ZodString;
|
||||||
|
name: z.ZodString;
|
||||||
|
label: z.ZodString;
|
||||||
|
input: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||||
|
output: z.ZodOptional<z.ZodObject<{
|
||||||
|
domain: z.ZodString;
|
||||||
|
object: z.ZodString;
|
||||||
|
key: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||||
|
fields: z.ZodRecord<z.ZodString, z.ZodString>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
when: z.ZodOptional<z.ZodString>;
|
||||||
|
view: z.ZodOptional<z.ZodString>;
|
||||||
|
failure: z.ZodObject<{
|
||||||
|
retry: z.ZodObject<{
|
||||||
|
times: z.ZodNumber;
|
||||||
|
backoff: z.ZodString;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
fallback: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"human">;
|
||||||
|
workOrder: z.ZodEnum<{
|
||||||
|
execution: "execution";
|
||||||
|
acceptance: "acceptance";
|
||||||
|
}>;
|
||||||
|
}, z.core.$strip>, z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"blocked">;
|
||||||
|
}, z.core.$strip>], "kind">;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>, z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"llm">;
|
||||||
|
model: z.ZodString;
|
||||||
|
template: z.ZodString;
|
||||||
|
outputSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
||||||
|
name: z.ZodString;
|
||||||
|
label: z.ZodString;
|
||||||
|
input: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||||
|
output: z.ZodOptional<z.ZodObject<{
|
||||||
|
domain: z.ZodString;
|
||||||
|
object: z.ZodString;
|
||||||
|
key: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||||
|
fields: z.ZodRecord<z.ZodString, z.ZodString>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
when: z.ZodOptional<z.ZodString>;
|
||||||
|
view: z.ZodOptional<z.ZodString>;
|
||||||
|
failure: z.ZodObject<{
|
||||||
|
retry: z.ZodObject<{
|
||||||
|
times: z.ZodNumber;
|
||||||
|
backoff: z.ZodString;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
fallback: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"human">;
|
||||||
|
workOrder: z.ZodEnum<{
|
||||||
|
execution: "execution";
|
||||||
|
acceptance: "acceptance";
|
||||||
|
}>;
|
||||||
|
}, z.core.$strip>, z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"blocked">;
|
||||||
|
}, z.core.$strip>], "kind">;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>, z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"human">;
|
||||||
|
workOrder: z.ZodEnum<{
|
||||||
|
execution: "execution";
|
||||||
|
acceptance: "acceptance";
|
||||||
|
}>;
|
||||||
|
card: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
||||||
|
deadline: z.ZodString;
|
||||||
|
name: z.ZodString;
|
||||||
|
label: z.ZodString;
|
||||||
|
input: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||||
|
output: z.ZodOptional<z.ZodObject<{
|
||||||
|
domain: z.ZodString;
|
||||||
|
object: z.ZodString;
|
||||||
|
key: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||||
|
fields: z.ZodRecord<z.ZodString, z.ZodString>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
when: z.ZodOptional<z.ZodString>;
|
||||||
|
view: z.ZodOptional<z.ZodString>;
|
||||||
|
failure: z.ZodObject<{
|
||||||
|
retry: z.ZodObject<{
|
||||||
|
times: z.ZodNumber;
|
||||||
|
backoff: z.ZodString;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
fallback: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"human">;
|
||||||
|
workOrder: z.ZodEnum<{
|
||||||
|
execution: "execution";
|
||||||
|
acceptance: "acceptance";
|
||||||
|
}>;
|
||||||
|
}, z.core.$strip>, z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"blocked">;
|
||||||
|
}, z.core.$strip>], "kind">;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>, z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"pure-tool">;
|
||||||
|
tool: z.ZodString;
|
||||||
|
name: z.ZodString;
|
||||||
|
label: z.ZodString;
|
||||||
|
input: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||||
|
output: z.ZodOptional<z.ZodObject<{
|
||||||
|
domain: z.ZodString;
|
||||||
|
object: z.ZodString;
|
||||||
|
key: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
||||||
|
fields: z.ZodRecord<z.ZodString, z.ZodString>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
when: z.ZodOptional<z.ZodString>;
|
||||||
|
view: z.ZodOptional<z.ZodString>;
|
||||||
|
failure: z.ZodObject<{
|
||||||
|
retry: z.ZodObject<{
|
||||||
|
times: z.ZodNumber;
|
||||||
|
backoff: z.ZodString;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
fallback: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"human">;
|
||||||
|
workOrder: z.ZodEnum<{
|
||||||
|
execution: "execution";
|
||||||
|
acceptance: "acceptance";
|
||||||
|
}>;
|
||||||
|
}, z.core.$strip>, z.ZodObject<{
|
||||||
|
kind: z.ZodLiteral<"blocked">;
|
||||||
|
}, z.core.$strip>], "kind">;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>], "kind">>;
|
||||||
|
parallelGroups: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
steps: z.ZodArray<z.ZodString>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
}, z.core.$strip>], "paradigm">;
|
||||||
|
skills: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
id: z.core.$ZodBranded<z.ZodString, "SkillId", "out">;
|
||||||
|
label: z.ZodString;
|
||||||
|
applicability: z.ZodString;
|
||||||
|
method: z.ZodString;
|
||||||
|
crystallized: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
tool: z.ZodString;
|
||||||
|
input: z.ZodRecord<z.ZodString, z.ZodString>;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
knowledgeRefs: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
||||||
|
version: z.ZodString;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
viewTemplates: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
html: z.ZodString;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
cardSchemas: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
||||||
|
distillHooks: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||||
|
on: z.ZodEnum<{
|
||||||
|
terminal: "terminal";
|
||||||
|
milestone: "milestone";
|
||||||
|
}>;
|
||||||
|
milestone: z.ZodOptional<z.ZodString>;
|
||||||
|
prompt: z.ZodString;
|
||||||
|
}, z.core.$strip>>>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
samples: z.ZodArray<z.ZodObject<{
|
||||||
|
name: z.ZodString;
|
||||||
|
input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
||||||
|
message: z.ZodOptional<z.ZodString>;
|
||||||
|
expect: z.ZodObject<{
|
||||||
|
ports: z.ZodArray<z.ZodString>;
|
||||||
|
payloadShape: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
entry: z.ZodObject<{
|
||||||
|
file: z.ZodString;
|
||||||
|
checksum: z.ZodString;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
artifact: z.ZodString;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
readonly output: z.ZodObject<{
|
||||||
|
accepted: z.ZodBoolean;
|
||||||
|
activityId: z.ZodString;
|
||||||
|
packageVersion: z.ZodString;
|
||||||
|
staticFindings: z.ZodArray<z.ZodObject<{
|
||||||
|
code: z.ZodString;
|
||||||
|
severity: z.ZodString;
|
||||||
|
message: z.ZodString;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
replay: z.ZodObject<{
|
||||||
|
oldPassStillPass: z.ZodBoolean;
|
||||||
|
checked: z.ZodNumber;
|
||||||
|
skippedNoHistory: z.ZodBoolean;
|
||||||
|
regressions: z.ZodArray<z.ZodObject<{
|
||||||
|
taskId: z.ZodString;
|
||||||
|
detail: z.ZodString;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* 导入自定义工具 —— 与第一方工具走**同一条门**:静态审 + 试运行审。
|
* 导入自定义工具 —— 与第一方工具走**同一条门**:静态审 + 试运行审。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
listActivityMemoryRoute,
|
listActivityMemoryRoute,
|
||||||
listGovTasksRoute,
|
listGovTasksRoute,
|
||||||
listLedgerObjectsRoute,
|
listLedgerObjectsRoute,
|
||||||
|
installActivityRoute,
|
||||||
listProcessPackagesRoute,
|
listProcessPackagesRoute,
|
||||||
listToolsRoute,
|
listToolsRoute,
|
||||||
listTriggersRoute,
|
listTriggersRoute,
|
||||||
@@ -33,6 +34,8 @@ import {
|
|||||||
upsertTriggerRoute,
|
upsertTriggerRoute,
|
||||||
validateProcessRoute,
|
validateProcessRoute,
|
||||||
} from '@contracts';
|
} from '@contracts';
|
||||||
|
import { InstallRejectedError } from '@modules/activity-registry';
|
||||||
|
import type { InstallVerdict } from '@modules/activity-registry';
|
||||||
import { NotPublishableError } from '@modules/process';
|
import { NotPublishableError } from '@modules/process';
|
||||||
import type { Container } from '../container.ts';
|
import type { Container } from '../container.ts';
|
||||||
import type { AppEnv } from '../http-env.ts';
|
import type { AppEnv } from '../http-env.ts';
|
||||||
@@ -63,6 +66,7 @@ export function registerGovernanceOpsRoutes(app: Hono<AppEnv>, container: Contai
|
|||||||
const readTrigger = guard('trigger', 'read');
|
const readTrigger = guard('trigger', 'read');
|
||||||
const governTrigger = guard('trigger', 'govern');
|
const governTrigger = guard('trigger', 'govern');
|
||||||
const readActivity = guard('activity', 'read');
|
const readActivity = guard('activity', 'read');
|
||||||
|
const governActivity = guard('activity', 'govern');
|
||||||
const readTool = guard('tool', 'read');
|
const readTool = guard('tool', 'read');
|
||||||
const governTool = guard('tool', 'govern');
|
const governTool = guard('tool', 'govern');
|
||||||
const readData = guard('data', 'read');
|
const readData = guard('data', 'read');
|
||||||
@@ -351,6 +355,51 @@ export function registerGovernanceOpsRoutes(app: Hono<AppEnv>, container: Contai
|
|||||||
|
|
||||||
/* ── 活动库管理:两维分类 × 两条版本序列 ─────────────────────────── */
|
/* ── 活动库管理:两维分类 × 两条版本序列 ─────────────────────────── */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 装入 / 换版 —— 经**安装通道**,无代码通道(ADR-004):交清单 + .js 产物,都是数据。
|
||||||
|
* 两审在这里跑;不过审即 412 并把审计结论原样回给人看,不静默失败。
|
||||||
|
* 恒为新增、版本并存:装入不覆盖旧版本,在途任务按启动时版本跑完。
|
||||||
|
*/
|
||||||
|
app.post(installActivityRoute.path, async (c) => {
|
||||||
|
const denied = await governActivity(c.get('account'));
|
||||||
|
if (denied) return c.json(denied, denyStatus(denied));
|
||||||
|
const parsed = installActivityRoute.body.safeParse(await c.req.json());
|
||||||
|
if (!parsed.success) {
|
||||||
|
const body: ApiError = { code: 'validation-failed', message: '活动清单不合 schema', detail: parsed.error.issues };
|
||||||
|
return c.json(body, 400);
|
||||||
|
}
|
||||||
|
const { manifest, artifact } = parsed.data;
|
||||||
|
const reply = (verdict: InstallVerdict, accepted: boolean) => ({
|
||||||
|
accepted,
|
||||||
|
activityId: manifest.identity.activityId,
|
||||||
|
packageVersion: manifest.identity.packageVersion,
|
||||||
|
staticFindings: verdict.staticFindings.map((f) => ({ code: f.code, severity: f.severity, message: f.message })),
|
||||||
|
replay: {
|
||||||
|
oldPassStillPass: verdict.replay.oldPassStillPass,
|
||||||
|
checked: verdict.replay.checked,
|
||||||
|
skippedNoHistory: verdict.replay.skippedNoHistory,
|
||||||
|
regressions: verdict.replay.regressions.map((r) => ({ taskId: r.taskId, detail: r.detail })),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
return c.json(reply(await container.registry.install(manifest, artifact), true));
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof InstallRejectedError) {
|
||||||
|
/*
|
||||||
|
* 两审未过:不上架。**按 ApiError 形状回**(与发布门一致)——
|
||||||
|
* 类型化客户端只从 `detail` 取详情,直接回业务体的话前端拿不到审计结论。
|
||||||
|
*/
|
||||||
|
const body: ApiError = {
|
||||||
|
code: 'precondition-failed',
|
||||||
|
message: error.message,
|
||||||
|
detail: reply(error.verdict, false),
|
||||||
|
};
|
||||||
|
return c.json(body, 412);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.get(listActivitiesRoute.path, async (c) => {
|
app.get(listActivitiesRoute.path, async (c) => {
|
||||||
const denied = await readActivity(c.get('account'));
|
const denied = await readActivity(c.get('account'));
|
||||||
if (denied) return c.json(denied, denyStatus(denied));
|
if (denied) return c.json(denied, denyStatus(denied));
|
||||||
|
|||||||
@@ -6,7 +6,37 @@
|
|||||||
* 区首页只负责导航,治理动作一律落在下钻详情页的**就地确认带**(影响预览三必答)。
|
* 区首页只负责导航,治理动作一律落在下钻详情页的**就地确认带**(影响预览三必答)。
|
||||||
*/
|
*/
|
||||||
import { Ico } from '@web-shared/Ico.tsx';
|
import { Ico } from '@web-shared/Ico.tsx';
|
||||||
import { Card, Chip, Clear, Entry, Note, PageHead, Prop, QueryGate, St } from '@web-shared/gov/primitives.tsx';
|
import { useState } from 'react';
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { installActivityRoute } from '@contracts';
|
||||||
|
import { ApiCallError, call } from '@web-shared/typed-fetch.ts';
|
||||||
|
import {
|
||||||
|
Acts,
|
||||||
|
Card,
|
||||||
|
Chip,
|
||||||
|
Clear,
|
||||||
|
Entry,
|
||||||
|
Field,
|
||||||
|
Note,
|
||||||
|
PageHead,
|
||||||
|
Prop,
|
||||||
|
QueryGate,
|
||||||
|
St,
|
||||||
|
} from '@web-shared/gov/primitives.tsx';
|
||||||
|
|
||||||
|
/** 装入回参 —— 与 `installActivityRoute.output` 同形 */
|
||||||
|
type InstallReply = {
|
||||||
|
accepted: boolean;
|
||||||
|
activityId: string;
|
||||||
|
packageVersion: string;
|
||||||
|
staticFindings: ReadonlyArray<{ code: string; severity: string; message: string }>;
|
||||||
|
replay: {
|
||||||
|
oldPassStillPass: boolean;
|
||||||
|
checked: number;
|
||||||
|
skippedNoHistory: boolean;
|
||||||
|
regressions: ReadonlyArray<{ taskId: string; detail: string }>;
|
||||||
|
};
|
||||||
|
};
|
||||||
import { PARA } from '@web-shared/gov/tone.ts';
|
import { PARA } from '@web-shared/gov/tone.ts';
|
||||||
import type { Nav } from '@web-shared/gov/gov-route.ts';
|
import type { Nav } from '@web-shared/gov/gov-route.ts';
|
||||||
import {
|
import {
|
||||||
@@ -27,6 +57,7 @@ export function LibraryHome({ nav }: HomeProps) {
|
|||||||
每活动两条版本序列——包版本走安装两审,资产版本走进化管线。
|
每活动两条版本序列——包版本走安装两审,资产版本走进化管线。
|
||||||
<b>审批点与网关不在这里</b>:它们是流程层的系统内置要素,零开发、不入库。
|
<b>审批点与网关不在这里</b>:它们是流程层的系统内置要素,零开发、不入库。
|
||||||
</Note>
|
</Note>
|
||||||
|
<InstallCard />
|
||||||
{activities.length === 0 ? (
|
{activities.length === 0 ? (
|
||||||
<Clear>货架是空的 —— 装一个活动进来,编排里才引用得到它。</Clear>
|
<Clear>货架是空的 —— 装一个活动进来,编排里才引用得到它。</Clear>
|
||||||
) : (
|
) : (
|
||||||
@@ -187,3 +218,141 @@ export function ActPage({ id, nav }: { id: string; nav: Nav }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------------- 装入 / 换版(安装通道) ---------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开发完一个活动,从这里装进来 —— **无代码通道**(ADR-004):交的是清单 + .js 产物,都是数据。
|
||||||
|
*
|
||||||
|
* 两审在服务端跑:静态审读清单,回放审重演历史(首装无历史即免)。
|
||||||
|
* 恒为新增、版本并存:装入不覆盖旧版本,在途任务按其启动时版本跑完。
|
||||||
|
*/
|
||||||
|
function InstallCard() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [manifestText, setManifestText] = useState('');
|
||||||
|
const [artifact, setArtifact] = useState('');
|
||||||
|
|
||||||
|
const install = useMutation({
|
||||||
|
mutationFn: () =>
|
||||||
|
call<InstallReply>(installActivityRoute, {
|
||||||
|
body: { manifest: JSON.parse(manifestText) as unknown, artifact },
|
||||||
|
}),
|
||||||
|
onSuccess: (out) => {
|
||||||
|
if (out.accepted) {
|
||||||
|
void queryClient.invalidateQueries({ queryKey: ['gov', 'activities'] });
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const pick = (setter: (text: string) => void) => async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const file = e.target.files?.[0];
|
||||||
|
if (file !== undefined) setter(await file.text());
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 两审未过的结论:412 走的是 ApiCallError,详情在 detail 里 */
|
||||||
|
const rejected =
|
||||||
|
install.error instanceof ApiCallError && install.error.status === 412
|
||||||
|
? (install.error.detail as InstallReply | undefined)
|
||||||
|
: install.data?.accepted === false
|
||||||
|
? install.data
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (!open) {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
ico="package"
|
||||||
|
title="装入 / 换版"
|
||||||
|
extra={
|
||||||
|
<button className="g-btn primary" onClick={() => setOpen(true)}>
|
||||||
|
装一个活动
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Note>
|
||||||
|
交<b>清单</b>(manifest.json)+ <b>产物</b>(index.js)两份文件,两审当场跑:
|
||||||
|
静态审读清单(工具契约在否、模型名绑没绑、声明与已物化台账冲不冲),
|
||||||
|
回放审重演历史成功单 —— <b>旧成不坏</b>是生效硬门,首装无历史即免。
|
||||||
|
恒为新增、版本并存:装入不覆盖旧版本,在途任务按启动时版本跑完。
|
||||||
|
</Note>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card ico="package" title="装入 / 换版">
|
||||||
|
<Prop ico="file-text" title="清单 manifest.json" extra="身份 / 七件契约 / 声明 / 资产初始版 / 样例集 / 代码入口">
|
||||||
|
<Field k="选文件" hint="活动包 dist/manifest.json">
|
||||||
|
<input className="g-input" type="file" accept=".json,application/json" onChange={pick(setManifestText)} />
|
||||||
|
</Field>
|
||||||
|
<Field k="或直接粘贴">
|
||||||
|
<textarea
|
||||||
|
className="g-input"
|
||||||
|
rows={4}
|
||||||
|
value={manifestText}
|
||||||
|
placeholder='{ "identity": { "activityId": "rfq-intake", … } }'
|
||||||
|
onChange={(e) => setManifestText(e.target.value)}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Prop>
|
||||||
|
|
||||||
|
<Prop ico="terminal" title="产物 index.js" extra="只当数据存 —— 不 import、不 eval">
|
||||||
|
<Field k="选文件" hint="活动包 dist/index.js">
|
||||||
|
<input className="g-input" type="file" accept=".js,.mjs,text/javascript" onChange={pick(setArtifact)} />
|
||||||
|
</Field>
|
||||||
|
<Field k="或直接粘贴">
|
||||||
|
<textarea
|
||||||
|
className="g-input"
|
||||||
|
rows={3}
|
||||||
|
value={artifact}
|
||||||
|
placeholder="export default defineActivity({ … })"
|
||||||
|
onChange={(e) => setArtifact(e.target.value)}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Prop>
|
||||||
|
|
||||||
|
{rejected !== undefined && (
|
||||||
|
<Note tone="warn">
|
||||||
|
<b>两审未过,没有上架。</b>
|
||||||
|
{rejected.staticFindings.length > 0 && (
|
||||||
|
<> 静态审:{rejected.staticFindings.map((f) => f.message).join(';')}。</>
|
||||||
|
)}
|
||||||
|
{rejected.replay.regressions.length > 0 && (
|
||||||
|
<> 回放审:{rejected.replay.regressions.map((r) => `${r.taskId} ${r.detail}`).join(';')}。</>
|
||||||
|
)}
|
||||||
|
</Note>
|
||||||
|
)}
|
||||||
|
{install.data?.accepted === true && (
|
||||||
|
<Note tone="ok">
|
||||||
|
已装入 {install.data.activityId} v{install.data.packageVersion} —— 静态审{' '}
|
||||||
|
{install.data.staticFindings.length} 条提示;回放审
|
||||||
|
{install.data.replay.skippedNoHistory ? '免(无历史)' : `查了 ${install.data.replay.checked} 单`}。
|
||||||
|
</Note>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Acts
|
||||||
|
align="end"
|
||||||
|
items={[
|
||||||
|
{ label: '取消', ico: 'x', onClick: () => setOpen(false) },
|
||||||
|
{
|
||||||
|
label: install.isPending ? '两审中…' : '装入并送审',
|
||||||
|
ico: 'circle-check',
|
||||||
|
primary: true,
|
||||||
|
disabled: install.isPending || manifestText.trim() === '' || artifact.trim() === '',
|
||||||
|
ask: {
|
||||||
|
title: '经安装通道装入活动包',
|
||||||
|
note: <Note>无代码通道:交的是数据。两审过了才上架;不过审会把是哪一条拦的说清楚。</Note>,
|
||||||
|
impact: {
|
||||||
|
who: '此后新起的任务用新包版本;在途任务按启动时版本跑完',
|
||||||
|
undo: '版本并存,可停用回退',
|
||||||
|
when: '确认后当场跑两审',
|
||||||
|
},
|
||||||
|
okLabel: '确认装入',
|
||||||
|
onOk: () => install.mutate(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { disableCheckSchema, grantSchema, positionSchema, staffSchema, workGroup
|
|||||||
import { positionIdSchema, staffIdSchema, taskIdSchema } from '../id.ts';
|
import { positionIdSchema, staffIdSchema, taskIdSchema } from '../id.ts';
|
||||||
import { closureReportSchema, processPackageSchema, triggerConfigSchema } from '../process-package.ts';
|
import { closureReportSchema, processPackageSchema, triggerConfigSchema } from '../process-package.ts';
|
||||||
import { controlSemanticSchema, taskRuntimeStateSchema, terminalStateSchema, workflowStateSchema } from '../terminal.ts';
|
import { controlSemanticSchema, taskRuntimeStateSchema, terminalStateSchema, workflowStateSchema } from '../terminal.ts';
|
||||||
import { paradigmSchema } from '../manifest.ts';
|
import { activityManifestSchema, paradigmSchema } from '../manifest.ts';
|
||||||
import { reportMetricsSchema, reportPeriodSchema } from './workbench.ts';
|
import { reportMetricsSchema, reportPeriodSchema } from './workbench.ts';
|
||||||
|
|
||||||
/* ── 员工管理 ─────────────────────────────────────────────────────────── */
|
/* ── 员工管理 ─────────────────────────────────────────────────────────── */
|
||||||
@@ -278,6 +278,38 @@ export const saveWorkGroupRoute = {
|
|||||||
output: z.object({ group: workGroupSchema }),
|
output: z.object({ group: workGroupSchema }),
|
||||||
} as const satisfies RouteContract;
|
} as const satisfies RouteContract;
|
||||||
|
|
||||||
|
/* ── 活动库 · 装入 / 换版(安装通道) ─────────────────────────────── */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 经安装通道装入活动包 —— **无代码通道**(ADR-004):交的是清单 + .js 产物,都是数据。
|
||||||
|
*
|
||||||
|
* 安装两审在服务端跑:静态审读清单(工具契约在否、模型名绑没绑、模版有没有脚本、
|
||||||
|
* 声明与已物化的台账冲不冲),回放审重演历史(首装无历史即免,以样例集替代)。
|
||||||
|
* **恒为新增、版本并存**:装入不覆盖旧版本,在途任务按其启动时版本跑完。
|
||||||
|
*/
|
||||||
|
export const installActivityRoute = {
|
||||||
|
method: 'POST',
|
||||||
|
path: '/api/gov/activities',
|
||||||
|
body: z.object({
|
||||||
|
/** 清单六区:身份 / 七件契约 / 声明 / 资产初始版 / 样例集 / 代码入口 */
|
||||||
|
manifest: activityManifestSchema,
|
||||||
|
/** .js 产物原文 —— 只当数据存,不 import、不 eval */
|
||||||
|
artifact: z.string().min(1),
|
||||||
|
}),
|
||||||
|
output: z.object({
|
||||||
|
accepted: z.boolean(),
|
||||||
|
activityId: z.string(),
|
||||||
|
packageVersion: z.string(),
|
||||||
|
staticFindings: z.array(z.object({ code: z.string(), severity: z.string(), message: z.string() })),
|
||||||
|
replay: z.object({
|
||||||
|
oldPassStillPass: z.boolean(),
|
||||||
|
checked: z.number().int(),
|
||||||
|
skippedNoHistory: z.boolean(),
|
||||||
|
regressions: z.array(z.object({ taskId: z.string(), detail: z.string() })),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
} as const satisfies RouteContract;
|
||||||
|
|
||||||
/* ── 工具管理 · 导入自定义工具 ─────────────────────────────────────── */
|
/* ── 工具管理 · 导入自定义工具 ─────────────────────────────────────── */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user