@zhushanwen/extension-protocol 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -183,27 +183,45 @@ interface PlanDocMeta {
183
183
  /**
184
184
  * submit-review 挂起审批时的 select payload(序列化为 options[0] JSON)。
185
185
  * extension 侧解析失败走 E5(logger.warn + tool result 报错提示重挂,垃圾数据不进对话流)。
186
+ *
187
+ * selfReview(自审结论,D9①③):agent 提交审批前的自审摘要,投影面到审批请求帧为止
188
+ * (不进 PlanStateView / session.planState 帧);有界性由写侧 4KB 单点截断保证
189
+ * (canonical 上限与截断 = src/extensions/plan/review-contract.ts,R3)。**optional 是兼容契约**:
190
+ * 旧扩展不携带 → 宿主自审行不渲染的降级形态;submit-review 的必填硬门在 tool 层执行
191
+ * (缺失/空 → tool result 错误纠偏,不 throw),wire 帧不设必填。
186
192
  */
187
193
  interface PlanReviewRequest {
188
194
  docs: PlanDocMeta[];
195
+ selfReview?: string;
189
196
  }
190
- /** 审批两键裁决。revise 携带评论、approve 不携带(结构上不可混带)。 */
191
- type PlanReviewDecision = 'approve' | 'revise';
197
+ /**
198
+ * 审批三键裁决(D3):approve 确认执行 / revise 提交修订(必带评论)/ dismiss 搁置
199
+ * (非破坏:不杀 turn、不丢状态,计划进度保留)。revise 携带评论、approve/dismiss
200
+ * 不携带(结构上不可混带)。值域守卫 canonical 版 = src/extensions/plan/review-contract.ts
201
+ * (运行时判别 TS 穷尽性管不到——未知值域降级语义见该模块「降级双分源」)。
202
+ */
203
+ type PlanReviewDecision = 'approve' | 'revise' | 'dismiss';
192
204
  /** 用户对某文档划选段落的一条评论:quote 是划选引文(agent 定位段落用),comment 是评语。 */
193
205
  interface PlanReviewComment {
194
206
  quote: string;
195
207
  comment: string;
196
208
  }
197
209
  /**
198
- * 审批条 respond 回传(判别联合:approve 无评论字段,revise 必带评论数组)。
199
- * extension 消费:approve → 走现状 complete 执行方式 select;revise → 评论清单以
200
- * 显式 deliverAs:'steer' 注入 + reviewState=revising。
210
+ * 审批条 respond 回传(判别联合:approve/dismiss 无评论字段,revise 必带评论数组)。
211
+ * extension 消费:approve → 走 complete 执行方式 select(transfer:reviewing→dispatching);
212
+ * revise → 评论清单以显式 deliverAs:'steer' 注入 + 转移 reviewing→revising;
213
+ * dismiss(D3 搁置)→ 转移 reviewing→planning 落盘,tool result 告知 agent「用户搁置了
214
+ * 本次审阅:plan 模式保持、文档与进度不变;简短告知用户已搁置并询问下一步,不要实施改动」。
215
+ * 未知 decision 值域降级 = 版本错配信号:与 malformed 同款 bad-response 出口引导重挂,
216
+ * 消费方额外 logger.warn 留痕(D3①)——判别与降级枚举见 src/extensions/plan/review-contract.ts。
201
217
  */
202
218
  type PlanReviewResponse = {
203
219
  decision: 'approve';
204
220
  } | {
205
221
  decision: 'revise';
206
222
  comments: PlanReviewComment[];
223
+ } | {
224
+ decision: 'dismiss';
207
225
  };
208
226
 
209
227
  /**
@@ -803,6 +821,183 @@ declare function isScheduleFormResult(value: unknown): value is ScheduleFormResu
803
821
  declare function dateToOnceCron(date: Date): string;
804
822
  declare function onceCronToDate(cron: string, now?: Date): Date | null;
805
823
 
824
+ /**
825
+ * plan 模式生命周期状态机(plan 模式状态机显式化 D1)——纯数据 + 纯函数,零依赖。
826
+ *
827
+ * plan 模式的状态散落在 pi 扩展 entry / runtime 挂起注册表 / renderer 派生公式三处时,
828
+ * 任意两者漂移即产「僵尸/谎言」UI(F1-F5)。本模块是全链路共享的单一状态契约:
829
+ * 8 值状态集 + 9 事件边表 + `transition` 纯函数(守卫集中一处)+ `derivePhase` 呈现映射。
830
+ *
831
+ * 语义要点(设计 D1 逐条锚定):
832
+ * - 非法转移返回 `{ ok: false }`,由调用方降级(**不 throw 炸 turn**);副作用不进返回值
833
+ * (effects-as-data 无已登记消费方属投机间接层),各 action 在转移成功后内联执行自身副作用。
834
+ * - `reviewing --dismiss--> planning`:用户「搁置」(协议级 dismiss 决策,D3)——落盘即
835
+ * planning,被搁置的审批不复活(F1/F2/F3 构造性消除)。
836
+ * - `reviewing --review_aborted--> planning`:挂起期外部 turn abort / TUI 取消(D3 连带)。
837
+ * - `dispatching --review_aborted--> approved`:批准事实保留——任一「无选择解散」出口
838
+ * (外部 turn abort 级联 / 表单取消 / 超时 / 交互通道故障折叠)统一落 approved,
839
+ * 不把「已批准」打回规划期(F5 不复活)。
840
+ * - `dispatching --later--> approved`:用户显式选「暂不执行」——是明确选择不是解散,
841
+ * 不得进 review_aborted 文案桶(A9 反向)。
842
+ * - `dispatching --exec_chosen--> completed`:选定执行方式并派发执行(终态)。
843
+ * - `approved --approve--> dispatching`:批准后 agent 再调 `complete` 重新选择执行方式
844
+ * (D1「approved 上 agent 再调 complete → dispatching」)。事件命名裁决:9 事件表无
845
+ * `complete` 员,本边取「执行确认」语义族最近员 `approve`(用户点确认执行与批准后重选
846
+ * 执行方式同为「确认执行、进入执行方式选择」的决策事件)——消费面接线见 consumers.md。
847
+ * - `approved` 其余转移仅 `exit`;活跃族非终态 `--exit--> exited`;idle 从未进入,
848
+ * exit 非法(防从未进 plan 的会话落噪音 exited entry);终态 `--enter--> planning`
849
+ * (新一轮);`revising` 保留独立态(E3 恢复文案分叉依赖,前提 P-7)。
850
+ * - `reviewing --submit--> reviewing`:审批重挂自环(E3 会话重启恢复 / D8「重新提交审批」
851
+ * 按钮——重提交不推进生命周期,落盘回 reviewing 重挂即等价于旧调用方特判放行形态)。
852
+ *
853
+ * 呈现映射(derivePhase):用户视角四主态 + idle 缺省——四主态是呈现,不是存储
854
+ * (用户口述模型 = 呈现层,reviewing/dispatching 两个挂起态是崩溃恢复的真实分叉点,
855
+ * 存储层保留 8 值)。终态两值(completed = 批准并派发执行 / exited = 主动退出)共享
856
+ * 全部终态规则,呈现层同映 'terminal'(诊断/审计语义保留存储区分)。
857
+ */
858
+ type PlanLifecycleState = 'idle' | 'planning' | 'reviewing' | 'revising' | 'approved' | 'dispatching' | 'completed' | 'exited';
859
+ /** 状态穷举表(运行时消费:E3 恢复查表 / 测试穷举基座)——顺序 = 生命周期自然序。 */
860
+ declare const PLAN_LIFECYCLE_STATES: readonly ["idle", "planning", "reviewing", "revising", "approved", "dispatching", "completed", "exited"];
861
+ type PlanLifecycleEvent = 'enter' | 'submit' | 'revise' | 'dismiss' | 'review_aborted' | 'approve' | 'exec_chosen' | 'later' | 'exit';
862
+ /** 事件穷举表——顺序 = 设计 D1 枚举序。 */
863
+ declare const PLAN_LIFECYCLE_EVENTS: readonly ["enter", "submit", "revise", "dismiss", "review_aborted", "approve", "exec_chosen", "later", "exit"];
864
+ type PlanTransitionResult = {
865
+ ok: true;
866
+ next: PlanLifecycleState;
867
+ } | {
868
+ ok: false;
869
+ };
870
+ /**
871
+ * 纯函数转移:`(state, event) → { ok: true, next } | { ok: false }`。
872
+ *
873
+ * 非法转移(含运行时垃圾 state/event 值——跨版本帧、坏反序列化)返回 `{ ok: false }`
874
+ * 且**不携带 next 键**,由调用方降级(不 throw 炸 turn)。调用方义务:`ok:false` 时
875
+ * 不落盘、不执行副作用(终态上 `ok:false` 不落盘即 D3 归口点的兜底保险)。
876
+ *
877
+ * 入口白名单守卫(与 derivePhase 同一机制):普通对象字面量查表会沿原型链命中继承键——
878
+ * `transition('reviewing', '__proto__')` 取出 Object.prototype、`('__proto__', 'valueOf')`
879
+ * 取出函数,均被误判为合法 next(违背本契约)。故垃圾键必须先挡在查表前。
880
+ * **选「枚举 includes 白名单」而非 null-prototype 表 / Object.hasOwn**:① transition 与
881
+ * derivePhase 共用同一守卫形态(单一机制,不并存两种写法);② PLAN_LIFECYCLE_STATES /
882
+ * PLAN_LIFECYCLE_EVENTS 就是值域 SSOT(测试穷举同源),includes 判定与之同源,
883
+ * 原型键天然不在白名单内。
884
+ */
885
+ declare function transition(state: PlanLifecycleState, event: PlanLifecycleEvent): PlanTransitionResult;
886
+ /**
887
+ * 用户视角呈现相位(四主态 + idle):
888
+ * - 'planning'(规划中)= planning | revising
889
+ * - 'reviewing'(待审批)= reviewing
890
+ * - 'approved'(已批准)= approved | dispatching(dispatching 呈「③审阅确认 · 已完成」,
891
+ * 阶段不倒退——F5 修正;细化渲染由消费方查 state,不另造相位)
892
+ * - 'terminal'(终态)= completed | exited(两值同映,区分只留存储/审计层)
893
+ * - 'idle'(无 plan)= idle
894
+ */
895
+ type PlanPhase = 'idle' | 'planning' | 'reviewing' | 'approved' | 'terminal';
896
+ /**
897
+ * 8 存储态 → 5 呈现相位的单点映射(renderer 阶段指示/状态带共用,禁止消费方各自 if 拼)。
898
+ * 运行时垃圾 state(混装格坏帧)降级 'idle'(无 plan 缺省,fail-safe 不误示进行中)。
899
+ *
900
+ * 入口白名单守卫(理由同 transition,见彼处):裸查表对继承键 'constructor' / 'toString'
901
+ * 会取出 Object 构造函数等并经 `?? 'idle'` 流出(非 nullish 不落兜底)——垃圾 state
902
+ * 必须精确落 'idle',函数/对象不得作为相位流入 renderer。
903
+ */
904
+ declare function derivePhase(state: PlanLifecycleState): PlanPhase;
905
+
906
+ /**
907
+ * plan 审阅回传值域契约(plan 模式状态机显式化 D3①⑤ / D9③)——纯函数守卫,零依赖。
908
+ *
909
+ * 为什么守卫是契约级承重:TS 判别联合的穷尽性(switch/never 断言)管不到运行时值域——
910
+ * respond 通道透传的是任意字符串 parse 出的 unknown(P-2),值域守卫漏改即「搁置应答被判
911
+ * 垃圾 → bad-response 引导重挂」再入循环(F1 复活路径)。canonical 守卫与判别联合同住
912
+ * 契约包,消费面(extensions/universal/plan tool.ts)接线见同目录 consumers.md。
913
+ *
914
+ * 降级双分源(D3①)——parse 失败必须区分两类(envelope 判别保留),消费面出口同款:
915
+ * - `unknown-decision`(对象合法但 decision 不在值域):版本错配信号(R2),消费方
916
+ * 额外 logger.warn 留痕;出口与文案与 malformed 同款——bad-response 报错提示重挂。
917
+ * 裁决与重审触发(候选替代 = 恢复独立 version-mismatch 不重挂出口)登记于消费方
918
+ * extensions/universal/plan/src/tool.ts「条目 7 降级」注释段。
919
+ * - `malformed`(非对象 / 缺 decision / 形状不合法):垃圾数据(E5 判据),bad-response
920
+ * 报错提示重挂。
921
+ *
922
+ * selfReview 有界字段(D9③ / R3):有界性由**写侧单点截断**保证(截断点 = 扩展 payload
923
+ * 构造处),4KB 上限与 UTF-8 字节界安全截断的唯一权威在本模块;透传层(runtime)不截、
924
+ * 入站守卫不二次截(上限已在写侧达成)。
925
+ */
926
+
927
+ /** selfReview 上限:4KB(UTF-8 字节)。超限即截(全文可要求 agent 贴对话流,R3)。 */
928
+ declare const PLAN_SELF_REVIEW_MAX_BYTES = 4096;
929
+ /**
930
+ * selfReview 写侧单点截断:按 UTF-8 字节预算截到**完整码点边界**(多字节字符不截半,
931
+ * 无替换字符噪音)。预算内原样返回;不追加省略号(消费方渲染时自行提示截断)。
932
+ */
933
+ declare function truncateSelfReview(text: string): string;
934
+ /**
935
+ * `PlanReviewRequest` 形状守卫(E5 垃圾数据判据):
936
+ * docs 必为 `PlanDocMeta[]`(逐项形状);selfReview 缺省或 string——**optional 是兼容契约**
937
+ * (旧扩展不携带 → 自审行不渲染的降级形态,D9③),值域上限不在此拒绝(写侧截断已界)。
938
+ * 空载荷(undefined/null/非对象/缺 docs)与非法形态(docs 非数组 / 元素形状不合法 /
939
+ * selfReview 非 string)一律 false,不 throw。
940
+ */
941
+ declare function isPlanReviewRequest(value: unknown): value is PlanReviewRequest;
942
+ /**
943
+ * respond 回传解析结果(error envelope 单源):
944
+ * - ok:归一化后的合法 `PlanReviewResponse`(多余键已剥——approve/dismiss 不携带评论是
945
+ * 结构保证,不信任宿主回传的附加形态)。
946
+ * - `unknown-decision`:decision 是 string 但不在值域 → 版本错配信号(消费方额外
947
+ * logger.warn 留痕;出口与 malformed 同款 bad-response 引导重挂,见文件头「降级双分源」)。
948
+ * - `malformed`:空载荷 / 非对象 / 形状不合法 → E5 判据,报错提示重挂。
949
+ */
950
+ type PlanReviewResponseEnvelope = {
951
+ ok: true;
952
+ response: PlanReviewResponse;
953
+ } | {
954
+ ok: false;
955
+ code: 'unknown-decision';
956
+ decision: string;
957
+ } | {
958
+ ok: false;
959
+ code: 'malformed';
960
+ };
961
+ /**
962
+ * respond 回传解析(值域守卫的判别版):dismiss 样本必通(D3 主干),未知 decision 值域
963
+ * 落降级枚举而非垃圾(两类降级可判别分离;消费面出口同款引导重挂,见文件头「降级双分源」)。
964
+ */
965
+ declare function parsePlanReviewResponse(value: unknown): PlanReviewResponseEnvelope;
966
+ /**
967
+ * `PlanReviewResponse` 值域守卫(含 dismiss 员,D3①)——`parsePlanReviewResponse` 的谓词形。
968
+ * 消费方需要区分 unknown-decision / malformed 两类降级时用 parse 版。
969
+ */
970
+ declare function isPlanReviewResponse(value: unknown): value is PlanReviewResponse;
971
+
972
+ /**
973
+ * plan-state entry 的 customType(pi appendEntry custom entry 判别键)。磁盘形态冻结:
974
+ * 扩展写读两侧(persistPlanState / isPlanStateEntry)与 runtime 投影链(plan-state-extractor /
975
+ * session-records)均消费本常量,值同源——改值即历史会话全部失联,禁改(冻结锚测试见
976
+ * 本目录 legacy-entries.test.ts)。
977
+ */
978
+ declare const PLAN_STATE_CUSTOM_TYPE = "plan-state";
979
+ /**
980
+ * 生命周期状态读取(D2 读方①②共用映射,原扩展 state.ts / runtime extractor 内联拷贝的
981
+ * 单源归并):
982
+ * ① 新字段直读(值域守卫:PLAN_LIFECYCLE_STATES 之外的垃圾值按缺失处理,落映射——
983
+ * 不信任外部写入);
984
+ * ② 旧 entry 无 state(或垃圾 state)时映射 reviewState(awaiting→reviewing /
985
+ * revising→revising / 其余值→planning|idle 按 isActive)。
986
+ */
987
+ declare function readLifecycleState(data: {
988
+ state?: unknown;
989
+ reviewState?: unknown;
990
+ }, isActive: boolean): PlanLifecycleState;
991
+ /**
992
+ * resumeHint 读取(D2 读方①②共用映射):新字段直读(只认 'resubmit' 一字面量)+
993
+ * 旧 reviewStateSource 同义映射('explain' 等存量值归无值——explain 交互已删);
994
+ * resumeHint 存在但非法(垃圾值)时不挡 reviewStateSource 映射(与原两份拷贝逐字同构)。
995
+ */
996
+ declare function readResumeHint(data: {
997
+ resumeHint?: unknown;
998
+ reviewStateSource?: unknown;
999
+ }): 'resubmit' | undefined;
1000
+
806
1001
  /**
807
1002
  * 统一提问表单协议(ui-form)的类型定义。
808
1003
  *
@@ -1510,4 +1705,4 @@ declare function collectActivePendingIds(entries: unknown[], opts?: CollectPendi
1510
1705
  type MappedPendingStatus = 'completed' | 'failed' | 'cancelled' | 'expired' | 'time_limited' | 'aborted';
1511
1706
  declare function mapReasonToStatus(reason: string): MappedPendingStatus;
1512
1707
 
1513
- export { ASK_USER_MARKER, type AskUserAnswers, type AskUserOption, type AskUserQuestion, BRIDGE_MARKER, BRIDGE_METHODS, type BridgeErrorResponse, type BridgeInterceptResponse, type BridgeMethod, type BridgeRequest, type BridgeSyncPayload, type BridgeToolExecuteResponse, type ChannelErrorResult, type ChoiceQuestion, type CollectPendingIdsOptions, type DualWidgetContent, type ExecutionRecord, type FormAnswers, type FormOption, type FormQuestion, GUI_WIDGET_MARKER, type GuiComponent, type GuiComponentProps, type GuiComponentType, type GuiContext, type GuiRenderResult, HISTORY_LIMIT, INFLIGHT_REPORT_ACK, MS_PER_DAY, MS_PER_HOUR, MS_PER_MINUTE, MS_PER_SECOND, type MappedPendingStatus, type MarkerRpcOptions, type MarkerRpcResult, PENDING_REGISTER_ENTRY_TYPE, PENDING_UNREGISTER_ENTRY_TYPE, PLAN_REVIEW_MARKER, PROTOCOL_VERSION, type PendingEntriesScan, type PlanDocMeta, type PlanReviewComment, type PlanReviewDecision, type PlanReviewRequest, type PlanReviewResponse, type ReplayFoldOptions, SCHEDULE_CREATE_MARKER, SESSION_MANAGER_ACTIONS, SESSION_MANAGER_MARKER, SUBAGENTS_ENGINES_FILENAME, SUBAGENT_BG_NOTIFY_CUSTOM_TYPE, SUBAGENT_DIRECTIVE_CUSTOM_TYPE, SUBAGENT_INFLIGHT_MARKER, type ScheduleDraft, type ScheduleFormResult, type ScheduleKind, type ScheduleQuestion, type ScheduleSpec, type ScheduledTask, type SchedulerEntryLike, type SchedulerEntryOp, type SessionManagerAbortParams, type SessionManagerAbortResult, type SessionManagerAction, type SessionManagerCreateParams, type SessionManagerCreateResult, type SessionManagerErrorResult, type SessionManagerHistoryParams, type SessionManagerHistoryResult, type SessionManagerListParams, type SessionManagerListResult, type SessionManagerParams, type SessionManagerSendParams, type SessionManagerSendResult, type SessionManagerSessionSummary, type SessionManagerStatusParams, type SessionManagerStatusResult, type SessionManagerWatchParams, type SessionManagerWatchReason, type SessionManagerWatchRespondPayload, type StatItem, type SubagentEngineConfigView, type SubagentEnginesFile, type SubagentInFlightReport, TASK_ENTRY_TYPE, type TaskKind, type TaskSnapshot, type TaskStatus, type TextQuestion, type TreeItem, type TreeItemIcon, UI_FORM_MARKER, type UiFormInteractOptions, type UiFormInteractResult, WORKFLOW_RESULT_CUSTOM_TYPE, type WidgetIconPathsRejection, type WidgetIconPathsValidation, type WidgetMeta, appendExecutionRecord, applyPendingDiff, callMarkerRpc, collectActivePendingIds, dateToOnceCron, extractGui, firstContentText, formatChannelErrorText, formatDuration, formatRelativeTime, formatSchedule, getAskUserAnswer, getAskUserOther, guiComponent, guiResult, guiSetWidget, isAskUserQuestion, isBridgeErrorResponse, isBridgeInterceptResponse, isBridgeSyncPayload, isBridgeToolExecuteResponse, isChannelErrorResult, isFormAnswers, isFormQuestion, isGuiCapable, isGuiComponent, isGuiRenderResult, isInFlightReportAck, isScheduleDraft, isScheduleFormResult, isSessionManagerAbortParams, isSessionManagerCreateParams, isSessionManagerHistoryParams, isSessionManagerListParams, isSessionManagerNotifyId, isSessionManagerSendParams, isSessionManagerStatusParams, isSessionManagerWatchParams, isSessionManagerWatchRespondPayload, isSubagentInFlightReport, isSyncedTool, mapReasonToStatus, onceCronToDate, replayFoldEntries, scanPendingEntries, setWidgetDual, snapshotToTask, uiFormInteract, validateWidgetIconPaths };
1708
+ export { ASK_USER_MARKER, type AskUserAnswers, type AskUserOption, type AskUserQuestion, BRIDGE_MARKER, BRIDGE_METHODS, type BridgeErrorResponse, type BridgeInterceptResponse, type BridgeMethod, type BridgeRequest, type BridgeSyncPayload, type BridgeToolExecuteResponse, type ChannelErrorResult, type ChoiceQuestion, type CollectPendingIdsOptions, type DualWidgetContent, type ExecutionRecord, type FormAnswers, type FormOption, type FormQuestion, GUI_WIDGET_MARKER, type GuiComponent, type GuiComponentProps, type GuiComponentType, type GuiContext, type GuiRenderResult, HISTORY_LIMIT, INFLIGHT_REPORT_ACK, MS_PER_DAY, MS_PER_HOUR, MS_PER_MINUTE, MS_PER_SECOND, type MappedPendingStatus, type MarkerRpcOptions, type MarkerRpcResult, PENDING_REGISTER_ENTRY_TYPE, PENDING_UNREGISTER_ENTRY_TYPE, PLAN_LIFECYCLE_EVENTS, PLAN_LIFECYCLE_STATES, PLAN_REVIEW_MARKER, PLAN_SELF_REVIEW_MAX_BYTES, PLAN_STATE_CUSTOM_TYPE, PROTOCOL_VERSION, type PendingEntriesScan, type PlanDocMeta, type PlanLifecycleEvent, type PlanLifecycleState, type PlanPhase, type PlanReviewComment, type PlanReviewDecision, type PlanReviewRequest, type PlanReviewResponse, type PlanReviewResponseEnvelope, type PlanTransitionResult, type ReplayFoldOptions, SCHEDULE_CREATE_MARKER, SESSION_MANAGER_ACTIONS, SESSION_MANAGER_MARKER, SUBAGENTS_ENGINES_FILENAME, SUBAGENT_BG_NOTIFY_CUSTOM_TYPE, SUBAGENT_DIRECTIVE_CUSTOM_TYPE, SUBAGENT_INFLIGHT_MARKER, type ScheduleDraft, type ScheduleFormResult, type ScheduleKind, type ScheduleQuestion, type ScheduleSpec, type ScheduledTask, type SchedulerEntryLike, type SchedulerEntryOp, type SessionManagerAbortParams, type SessionManagerAbortResult, type SessionManagerAction, type SessionManagerCreateParams, type SessionManagerCreateResult, type SessionManagerErrorResult, type SessionManagerHistoryParams, type SessionManagerHistoryResult, type SessionManagerListParams, type SessionManagerListResult, type SessionManagerParams, type SessionManagerSendParams, type SessionManagerSendResult, type SessionManagerSessionSummary, type SessionManagerStatusParams, type SessionManagerStatusResult, type SessionManagerWatchParams, type SessionManagerWatchReason, type SessionManagerWatchRespondPayload, type StatItem, type SubagentEngineConfigView, type SubagentEnginesFile, type SubagentInFlightReport, TASK_ENTRY_TYPE, type TaskKind, type TaskSnapshot, type TaskStatus, type TextQuestion, type TreeItem, type TreeItemIcon, UI_FORM_MARKER, type UiFormInteractOptions, type UiFormInteractResult, WORKFLOW_RESULT_CUSTOM_TYPE, type WidgetIconPathsRejection, type WidgetIconPathsValidation, type WidgetMeta, appendExecutionRecord, applyPendingDiff, callMarkerRpc, collectActivePendingIds, dateToOnceCron, derivePhase, extractGui, firstContentText, formatChannelErrorText, formatDuration, formatRelativeTime, formatSchedule, getAskUserAnswer, getAskUserOther, guiComponent, guiResult, guiSetWidget, isAskUserQuestion, isBridgeErrorResponse, isBridgeInterceptResponse, isBridgeSyncPayload, isBridgeToolExecuteResponse, isChannelErrorResult, isFormAnswers, isFormQuestion, isGuiCapable, isGuiComponent, isGuiRenderResult, isInFlightReportAck, isPlanReviewRequest, isPlanReviewResponse, isScheduleDraft, isScheduleFormResult, isSessionManagerAbortParams, isSessionManagerCreateParams, isSessionManagerHistoryParams, isSessionManagerListParams, isSessionManagerNotifyId, isSessionManagerSendParams, isSessionManagerStatusParams, isSessionManagerWatchParams, isSessionManagerWatchRespondPayload, isSubagentInFlightReport, isSyncedTool, mapReasonToStatus, onceCronToDate, parsePlanReviewResponse, readLifecycleState, readResumeHint, replayFoldEntries, scanPendingEntries, setWidgetDual, snapshotToTask, transition, truncateSelfReview, uiFormInteract, validateWidgetIconPaths };
package/dist/index.js CHANGED
@@ -413,6 +413,157 @@ function onceCronToDate(cron, now = /* @__PURE__ */ new Date()) {
413
413
  return null;
414
414
  }
415
415
 
416
+ // src/extensions/plan/state-machine.ts
417
+ var PLAN_LIFECYCLE_STATES = [
418
+ "idle",
419
+ "planning",
420
+ "reviewing",
421
+ "revising",
422
+ "approved",
423
+ "dispatching",
424
+ "completed",
425
+ "exited"
426
+ ];
427
+ var PLAN_LIFECYCLE_EVENTS = [
428
+ "enter",
429
+ "submit",
430
+ "revise",
431
+ "dismiss",
432
+ "review_aborted",
433
+ "approve",
434
+ "exec_chosen",
435
+ "later",
436
+ "exit"
437
+ ];
438
+ var TRANSITION_TABLE = {
439
+ idle: { enter: "planning" },
440
+ planning: { submit: "reviewing", exit: "exited" },
441
+ reviewing: {
442
+ submit: "reviewing",
443
+ revise: "revising",
444
+ dismiss: "planning",
445
+ review_aborted: "planning",
446
+ approve: "dispatching",
447
+ exit: "exited"
448
+ },
449
+ revising: { submit: "reviewing", exit: "exited" },
450
+ approved: { approve: "dispatching", exit: "exited" },
451
+ dispatching: {
452
+ review_aborted: "approved",
453
+ exec_chosen: "completed",
454
+ later: "approved",
455
+ exit: "exited"
456
+ },
457
+ completed: { enter: "planning" },
458
+ exited: { enter: "planning" }
459
+ };
460
+ function transition(state, event) {
461
+ if (!PLAN_LIFECYCLE_STATES.includes(state) || !PLAN_LIFECYCLE_EVENTS.includes(event)) {
462
+ return { ok: false };
463
+ }
464
+ const next = TRANSITION_TABLE[state][event];
465
+ return next === void 0 ? { ok: false } : { ok: true, next };
466
+ }
467
+ var PHASE_OF_STATE = {
468
+ idle: "idle",
469
+ planning: "planning",
470
+ reviewing: "reviewing",
471
+ revising: "planning",
472
+ approved: "approved",
473
+ dispatching: "approved",
474
+ completed: "terminal",
475
+ exited: "terminal"
476
+ };
477
+ function derivePhase(state) {
478
+ if (!PLAN_LIFECYCLE_STATES.includes(state)) return "idle";
479
+ return PHASE_OF_STATE[state];
480
+ }
481
+
482
+ // src/extensions/plan/review-contract.ts
483
+ var PLAN_SELF_REVIEW_MAX_BYTES = 4096;
484
+ var UTF8_1_BYTE_CP_MAX = 127;
485
+ var UTF8_2_BYTE_CP_MAX = 2047;
486
+ var UTF8_3_BYTE_CP_MAX = 65535;
487
+ function utf8ByteLengthOfCodePoint(cp) {
488
+ if (cp <= UTF8_1_BYTE_CP_MAX) return 1;
489
+ if (cp <= UTF8_2_BYTE_CP_MAX) return 2;
490
+ if (cp <= UTF8_3_BYTE_CP_MAX) return 3;
491
+ return 4;
492
+ }
493
+ function truncateSelfReview(text) {
494
+ let bytes = 0;
495
+ let i = 0;
496
+ while (i < text.length) {
497
+ const cp = text.codePointAt(i);
498
+ if (cp === void 0) break;
499
+ const size = utf8ByteLengthOfCodePoint(cp);
500
+ if (bytes + size > PLAN_SELF_REVIEW_MAX_BYTES) break;
501
+ bytes += size;
502
+ i += cp > UTF8_3_BYTE_CP_MAX ? 2 : 1;
503
+ }
504
+ return text.slice(0, i);
505
+ }
506
+ function isPlanDocMeta(value) {
507
+ if (typeof value !== "object" || value === null) return false;
508
+ const doc = value;
509
+ return typeof doc.fileName === "string" && typeof doc.absPath === "string" && typeof doc.sourceSkill === "string" && typeof doc.version === "number";
510
+ }
511
+ function isPlanReviewRequest(value) {
512
+ if (typeof value !== "object" || value === null) return false;
513
+ const req = value;
514
+ if (!Array.isArray(req.docs) || !req.docs.every(isPlanDocMeta)) return false;
515
+ if (req.selfReview !== void 0 && typeof req.selfReview !== "string") return false;
516
+ return true;
517
+ }
518
+ function normalizeComments(value) {
519
+ if (!Array.isArray(value)) return null;
520
+ const comments = [];
521
+ for (const item of value) {
522
+ if (typeof item !== "object" || item === null) return null;
523
+ const c = item;
524
+ if (typeof c.quote !== "string" || typeof c.comment !== "string") return null;
525
+ comments.push({ quote: c.quote, comment: c.comment });
526
+ }
527
+ return { decision: "revise", comments };
528
+ }
529
+ function parsePlanReviewResponse(value) {
530
+ if (typeof value !== "object" || value === null) return { ok: false, code: "malformed" };
531
+ const raw = value;
532
+ const decision = raw.decision;
533
+ if (typeof decision !== "string") return { ok: false, code: "malformed" };
534
+ switch (decision) {
535
+ case "approve":
536
+ return { ok: true, response: { decision: "approve" } };
537
+ case "dismiss":
538
+ return { ok: true, response: { decision: "dismiss" } };
539
+ case "revise": {
540
+ const response = normalizeComments(raw.comments);
541
+ return response === null ? { ok: false, code: "malformed" } : { ok: true, response };
542
+ }
543
+ default:
544
+ return { ok: false, code: "unknown-decision", decision };
545
+ }
546
+ }
547
+ function isPlanReviewResponse(value) {
548
+ return parsePlanReviewResponse(value).ok;
549
+ }
550
+
551
+ // src/extensions/plan/legacy-entries.ts
552
+ var PLAN_STATE_CUSTOM_TYPE = "plan-state";
553
+ function readLifecycleState(data, isActive) {
554
+ const raw = data.state;
555
+ if (typeof raw === "string" && PLAN_LIFECYCLE_STATES.includes(raw)) {
556
+ return raw;
557
+ }
558
+ if (data.reviewState === "awaiting") return "reviewing";
559
+ if (data.reviewState === "revising") return "revising";
560
+ return isActive ? "planning" : "idle";
561
+ }
562
+ function readResumeHint(data) {
563
+ if (data.resumeHint === "resubmit") return "resubmit";
564
+ return data.reviewStateSource === "resubmit" ? "resubmit" : void 0;
565
+ }
566
+
416
567
  // src/extensions/ui-form/marker.ts
417
568
  var UI_FORM_MARKER = "\0TAIJI_UI_FORM";
418
569
 
@@ -710,7 +861,11 @@ export {
710
861
  MS_PER_SECOND,
711
862
  PENDING_REGISTER_ENTRY_TYPE,
712
863
  PENDING_UNREGISTER_ENTRY_TYPE,
864
+ PLAN_LIFECYCLE_EVENTS,
865
+ PLAN_LIFECYCLE_STATES,
713
866
  PLAN_REVIEW_MARKER,
867
+ PLAN_SELF_REVIEW_MAX_BYTES,
868
+ PLAN_STATE_CUSTOM_TYPE,
714
869
  PROTOCOL_VERSION,
715
870
  SCHEDULE_CREATE_MARKER,
716
871
  SESSION_MANAGER_ACTIONS,
@@ -727,6 +882,7 @@ export {
727
882
  callMarkerRpc,
728
883
  collectActivePendingIds,
729
884
  dateToOnceCron,
885
+ derivePhase,
730
886
  extractGui,
731
887
  firstContentText,
732
888
  formatChannelErrorText,
@@ -752,6 +908,8 @@ export {
752
908
  isGuiComponent,
753
909
  isGuiRenderResult,
754
910
  isInFlightReportAck,
911
+ isPlanReviewRequest,
912
+ isPlanReviewResponse,
755
913
  isScheduleDraft,
756
914
  isScheduleFormResult,
757
915
  isSessionManagerAbortParams,
@@ -768,10 +926,15 @@ export {
768
926
  isTerminalBackgroundTaskState,
769
927
  mapReasonToStatus,
770
928
  onceCronToDate,
929
+ parsePlanReviewResponse,
930
+ readLifecycleState,
931
+ readResumeHint,
771
932
  replayFoldEntries,
772
933
  scanPendingEntries,
773
934
  setWidgetDual,
774
935
  snapshotToTask,
936
+ transition,
937
+ truncateSelfReview,
775
938
  uiFormInteract,
776
939
  validateWidgetIconPaths
777
940
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/extension-protocol",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Cross-layer pi extension contract package: dual-mode (TUI/GUI) rendering helpers, session/background-task/pending-entries protocols, and shared behavior primitives",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",