/** * 控制权按态转交 —— 纯逻辑,零 IO(编码规范 §5.3;语义出处 OS 4.1,AM 07)。 * * 「视图区容器与对话区输出框的控制权由活动与系统**共同持有**: * 任务激活(Agent 机制运行)时归**活动** —— 视图流控与对话输出由活动驱动; * 流程流转(节点间、审批点、终态前后)时归**系统** —— 流转、审批与终态回执由系统呈现。 * 转交随引擎的激活 / 完成事件自动发生,活动不感知交接。 * **输入侧不参与转交**:全部人类输入永远经系统的对话流卡片协议回传。」 */ export const CONTROL_HOLDERS = ['activity', 'system'] as const; export type ControlHolder = (typeof CONTROL_HOLDERS)[number]; /** 任务在交互层的态 —— 决定输出侧控制权归谁 */ export const INTERACTION_PHASES = [ 'activating', 'active', 'awaiting-human', 'awaiting-event', 'approving', 'transitioning', 'terminal', ] as const; export type InteractionPhase = (typeof INTERACTION_PHASES)[number]; /** 输出侧控制权:活动在跑就归活动,其余一律归系统 */ export function outputControl(phase: InteractionPhase): ControlHolder { switch (phase) { case 'active': case 'awaiting-human': case 'awaiting-event': return 'activity'; case 'activating': case 'approving': case 'transitioning': case 'terminal': return 'system'; } } /** 输入侧**永远**归系统 —— 单入口,不参与转交 */ export function inputControl(): ControlHolder { return 'system'; } /** 转交是否发生 —— 引擎的激活 / 完成事件驱动;活动不感知 */ export function handoverHappens(from: InteractionPhase, to: InteractionPhase): boolean { return outputControl(from) !== outputControl(to); } /* ── 视图区:只读呈现容器,无脚本执行权(AM 07) ────────────────────── */ export type TemplateViolation = { readonly code: 'script' | 'event-handler' | 'external-resource'; readonly message: string }; const SCRIPT = /<\s*script\b/i; const EVENT_HANDLER = /\son[a-z]+\s*=/i; const EXTERNAL = /(src|href)\s*=\s*["']?\s*(https?:)?\/\//i; /** * 模版无脚本 —— 安装静态审与推送前都用它。 * 「模版是**内容**不是代码:web 零活动代码,容器渲染净化、无脚本执行权。」 */ export function checkTemplate(html: string): TemplateViolation[] { const out: TemplateViolation[] = []; if (SCRIPT.test(html)) out.push({ code: 'script', message: '视图模版不得含