@zhushanwen/extension-protocol 0.13.0 → 0.15.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 +223 -1
- package/dist/index.js +190 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -80,6 +80,26 @@ interface GuiComponentProps {
|
|
|
80
80
|
*/
|
|
81
81
|
sections?: GuiComponent[][];
|
|
82
82
|
};
|
|
83
|
+
/**
|
|
84
|
+
* 操作按钮栏——GuiComponent 协议首个交互原语(设计 AP-3)。
|
|
85
|
+
* 点击经宿主壳 provide 的执行器走既有命令链(commandRegistry.execute → WS
|
|
86
|
+
* plugin.executeCommand),协议不新增回调通道(设计 §3.3 D2)。
|
|
87
|
+
* 未含此 type 的旧宿主自动降级 ansi-text 可读文本,PROTOCOL_VERSION 不 bump
|
|
88
|
+
* (设计 §3.3 D8,降级契约 P5)。
|
|
89
|
+
*/
|
|
90
|
+
'action-bar': {
|
|
91
|
+
items: {
|
|
92
|
+
id: string;
|
|
93
|
+
label: string;
|
|
94
|
+
/** 视觉档位:只保留当前唯一实际消费的 danger(删除按钮);更多档位有真实消费方时再加 */
|
|
95
|
+
kind?: 'danger';
|
|
96
|
+
disabled?: boolean;
|
|
97
|
+
/** 缺省 = 纯展示项(不可点、弱化样式) */
|
|
98
|
+
commandId?: string;
|
|
99
|
+
/** 只许标量:args 原样传给插件 handler,禁嵌套对象防无 schema 结构化旁路(设计 AP-3 校验) */
|
|
100
|
+
args?: Record<string, string | number | boolean>;
|
|
101
|
+
}[];
|
|
102
|
+
};
|
|
83
103
|
/** 自定义组件——逃生口(仅限内置 extension 编译期注册) */
|
|
84
104
|
'custom': {
|
|
85
105
|
component: string;
|
|
@@ -504,6 +524,176 @@ declare function getAskUserOther(answers: AskUserAnswers, question: AskUserQuest
|
|
|
504
524
|
*/
|
|
505
525
|
declare function isAskUserQuestion(value: unknown): value is AskUserQuestion;
|
|
506
526
|
|
|
527
|
+
type ScheduleSpec = {
|
|
528
|
+
mode: 'cron';
|
|
529
|
+
cronExpression: string;
|
|
530
|
+
} | {
|
|
531
|
+
mode: 'interval';
|
|
532
|
+
intervalMs: number;
|
|
533
|
+
};
|
|
534
|
+
type TaskKind = 'once' | 'recurring';
|
|
535
|
+
type TaskStatus = 'success' | 'failed';
|
|
536
|
+
interface ScheduledTask {
|
|
537
|
+
id: string;
|
|
538
|
+
name: string;
|
|
539
|
+
prompt: string;
|
|
540
|
+
kind: TaskKind;
|
|
541
|
+
schedule: ScheduleSpec;
|
|
542
|
+
model?: string;
|
|
543
|
+
enabled: boolean;
|
|
544
|
+
createdAt: number;
|
|
545
|
+
nextRunAt: number;
|
|
546
|
+
expiresAt?: number;
|
|
547
|
+
runCount: number;
|
|
548
|
+
lastRunAt?: number;
|
|
549
|
+
lastStatus?: TaskStatus;
|
|
550
|
+
lastError?: string;
|
|
551
|
+
history: ExecutionRecord[];
|
|
552
|
+
ownerSessionFile?: string;
|
|
553
|
+
pending?: boolean;
|
|
554
|
+
}
|
|
555
|
+
interface ExecutionRecord {
|
|
556
|
+
at: number;
|
|
557
|
+
status: TaskStatus;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* history 裁剪上限(ext-simplify-08 L5 单点):runtime 侧 dispatch 累积
|
|
561
|
+
* (onDispatchSuccess)与 replay 侧 advance 折叠共用同一上限——
|
|
562
|
+
* 双处各持字面量会漂移(曾 runtime.ts / replay.ts 各写一份 20),收敛到本文件单点导出。
|
|
563
|
+
*/
|
|
564
|
+
declare const HISTORY_LIMIT = 20;
|
|
565
|
+
/**
|
|
566
|
+
* 追加执行记录并按 HISTORY_LIMIT 裁剪(ext-simplify-17 B4 单点):runtime 侧 dispatch
|
|
567
|
+
* 累积与 replay 侧 advance 折叠共用的 push+trim——三处内联时与上限字面量同源存在
|
|
568
|
+
* 「漏改一处」漂移风险,随上限一并收敛。
|
|
569
|
+
*/
|
|
570
|
+
declare function appendExecutionRecord(task: ScheduledTask, at: number, status: TaskStatus): void;
|
|
571
|
+
/**
|
|
572
|
+
* pi.appendEntry 写入的 custom entry customType 标识(ext-simplify-17 B1 单点):
|
|
573
|
+
* backend.appendEntry 写入 / replay 折叠过滤 / importer 旧 store 导入三处共用——
|
|
574
|
+
* 各持字面量时「改一处漏两处」会使写入与重放识别脱节(写入新标识、重放不认,任务静默丢失)。
|
|
575
|
+
*/
|
|
576
|
+
declare const TASK_ENTRY_TYPE = "pi-scheduler:task";
|
|
577
|
+
/**
|
|
578
|
+
* upsert op 携带的全量任务快照(不含 ownerSessionFile / pending)。
|
|
579
|
+
* ownerSessionFile 放在 op 顶层(见 SchedulerEntryOp.upsert),
|
|
580
|
+
* pending 是运行时标记不持久化。其余字段与 ScheduledTask 对齐。
|
|
581
|
+
*/
|
|
582
|
+
interface TaskSnapshot {
|
|
583
|
+
id: string;
|
|
584
|
+
name: string;
|
|
585
|
+
prompt: string;
|
|
586
|
+
kind: TaskKind;
|
|
587
|
+
schedule: ScheduleSpec;
|
|
588
|
+
model?: string;
|
|
589
|
+
enabled: boolean;
|
|
590
|
+
createdAt: number;
|
|
591
|
+
nextRunAt: number;
|
|
592
|
+
expiresAt?: number;
|
|
593
|
+
runCount: number;
|
|
594
|
+
lastRunAt?: number;
|
|
595
|
+
lastStatus?: TaskStatus;
|
|
596
|
+
lastError?: string;
|
|
597
|
+
history: ExecutionRecord[];
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* pi.appendEntry(TASK_ENTRY_TYPE, SchedulerEntryOp) 写入 session JSONL 的 op 联合类型。
|
|
601
|
+
*
|
|
602
|
+
* advance.status 固定为 'success'(CL8):对齐现有 TaskStatus='success'|'failed',
|
|
603
|
+
* 而非继承的 DM-SCHEDULER-OP 词表 'ok'。唯一 emit 值——按 CL7,advance 仅在 dispatch
|
|
604
|
+
* 成功(nextRunAt 实际推进)时 append,失败 dispatch 不 append(transient 失败重试语义)。
|
|
605
|
+
* fold 的 `task.lastStatus = entry.status` 直接赋值合法('success' 属 TaskStatus)。
|
|
606
|
+
*/
|
|
607
|
+
type SchedulerEntryOp = {
|
|
608
|
+
op: 'upsert';
|
|
609
|
+
taskId: string;
|
|
610
|
+
ownerSessionFile: string;
|
|
611
|
+
task: TaskSnapshot;
|
|
612
|
+
} | {
|
|
613
|
+
op: 'advance';
|
|
614
|
+
taskId: string;
|
|
615
|
+
nextRunAt: number;
|
|
616
|
+
at: number;
|
|
617
|
+
status: 'success';
|
|
618
|
+
} | {
|
|
619
|
+
op: 'toggle';
|
|
620
|
+
taskId: string;
|
|
621
|
+
enabled: boolean;
|
|
622
|
+
nextRunAt?: number;
|
|
623
|
+
} | {
|
|
624
|
+
op: 'delete';
|
|
625
|
+
taskId: string;
|
|
626
|
+
};
|
|
627
|
+
/**
|
|
628
|
+
* TaskSnapshot → ScheduledTask(replay 侧重建):pending 不持久化故不恢复,
|
|
629
|
+
* ownerSessionFile 由调用方(replay applyUpsert)从 op 顶层补回。history 逐项深拷贝——
|
|
630
|
+
* 避免恢复出的运行时 task 与快照共享数组/元素引用(task 后续被 mutate 时不污染快照)。
|
|
631
|
+
*/
|
|
632
|
+
declare function snapshotToTask(snapshot: TaskSnapshot): ScheduledTask;
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* 折叠期降级日志注入点:包内不持有任何 logger 依赖(零 pi 依赖收敛),由调用方注入。
|
|
636
|
+
* 省略时降级路径静默(折叠行为不受影响——返回值与注入无关)。
|
|
637
|
+
*/
|
|
638
|
+
interface ReplayFoldOptions {
|
|
639
|
+
warn?: (message: string, context?: unknown) => void;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* CustomEntry 的最小可识别形状(duck-typed,不依赖 @earendil-works/pi-coding-agent 的
|
|
643
|
+
* 具体 SessionEntry 类型)。与 pending-notifications/state.ts、goal/ports.ts 同款:
|
|
644
|
+
* 纯函数可独立单测,调用方传入真实 SessionEntry[] 时按结构兼容。
|
|
645
|
+
*/
|
|
646
|
+
interface SchedulerEntryLike {
|
|
647
|
+
type: string;
|
|
648
|
+
customType?: string;
|
|
649
|
+
data?: unknown;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* 从 CustomEntry 序列折叠恢复 per-task 末态(event sourcing)。
|
|
653
|
+
*
|
|
654
|
+
* 两类调用方:
|
|
655
|
+
* - pi 扩展 session_start 重放:PiSchedulerBackend.loadTasks() 委托本函数,把当前 session 的
|
|
656
|
+
* TASK_ENTRY_TYPE custom entries 折叠成运行时任务 Map。
|
|
657
|
+
* - taiji plugin 条目镜像:对 readEntries 拉取的累计 entries 调用本函数折叠出任务表
|
|
658
|
+
* (与扩展同一实现,插件与扩展折叠结果构造性一致)。
|
|
659
|
+
*
|
|
660
|
+
* 两步:
|
|
661
|
+
* ① 全量折叠(foldEntries)——遍历 customType===TASK_ENTRY_TYPE 的 entries,按 op 类型折叠:
|
|
662
|
+
* - upsert → 用快照重建任务(ownerSessionFile 来自 op 顶层)
|
|
663
|
+
* - advance → nextRunAt=新值 / lastRunAt=at / runCount++ / history.push(裁20) / lastStatus=status(gap2)
|
|
664
|
+
* - toggle → enabled=新值
|
|
665
|
+
* - delete → 从 Map 移除(后续同 taskId 的 advance/toggle 对不存在 taskId 为 no-op,安全)
|
|
666
|
+
* advance/toggle/delete 对不存在的 taskId 为 no-op,因此 fork 继承的完整序列必须先全量折叠,
|
|
667
|
+
* 不能在处理 upsert 时按 owner 跳过(否则后续无 owner 字段的 op 会作用于「不存在的 taskId」丢失)。
|
|
668
|
+
* ② 折叠完成后按 task.ownerSessionFile !== currentSessionFile 整体过滤(gap1,filterNonOwnerTasks):
|
|
669
|
+
* 移除 fork 继承的非 owner 任务——fork 出的 session B 继承了 owner=A 的 upsert+advance 序列,
|
|
670
|
+
* 但 B 不应拥有 A 的任务,重放后整体过滤掉。
|
|
671
|
+
*
|
|
672
|
+
* append-only 时序保证 nextRunAt 不回退(D1):advance entry 按写入顺序折叠,自然取到最后推进值。
|
|
673
|
+
*
|
|
674
|
+
* getEntries 解析/迭代异常 → options.warn + 返回空 Map(gap4):降级为无任务而非崩溃调用方。
|
|
675
|
+
*/
|
|
676
|
+
declare function replayFoldEntries(entries: Iterable<SchedulerEntryLike>, currentSessionFile: string | undefined, options?: ReplayFoldOptions): Map<string, ScheduledTask>;
|
|
677
|
+
|
|
678
|
+
declare const MS_PER_DAY = 86400000;
|
|
679
|
+
declare const MS_PER_HOUR = 3600000;
|
|
680
|
+
declare const MS_PER_MINUTE = 60000;
|
|
681
|
+
declare const MS_PER_SECOND = 1000;
|
|
682
|
+
/** 格式化毫秒数为可读 duration 字符串。优先使用最大单位:300000 → "5m",不是 "300s"。 */
|
|
683
|
+
declare function formatDuration(ms: number): string;
|
|
684
|
+
/** Format ScheduleSpec to readable string. kind 区分 once/recurring(once 显示 'once in X' 而非误导性的 'every X')。 */
|
|
685
|
+
declare function formatSchedule(spec: ScheduleSpec, kind?: TaskKind): string;
|
|
686
|
+
/**
|
|
687
|
+
* 格式化时间戳为相对时间字符串。
|
|
688
|
+
* 未来: "in 5m"
|
|
689
|
+
* 过去: "5m ago"
|
|
690
|
+
* 当前(+-5s): "now"
|
|
691
|
+
*
|
|
692
|
+
* now 可选参数:基准时间戳,默认 Date.now()。测试可传固定值快进/锁定,
|
|
693
|
+
* 生产调用方无需传(参数可选,行为不变)。
|
|
694
|
+
*/
|
|
695
|
+
declare function formatRelativeTime(timestamp: number, now?: number): string;
|
|
696
|
+
|
|
507
697
|
/**
|
|
508
698
|
* scheduler 创建确认弹框的协议类型(Draft / FormResult)。
|
|
509
699
|
*
|
|
@@ -972,6 +1162,38 @@ declare function isInFlightReportAck(v: unknown): v is typeof INFLIGHT_REPORT_AC
|
|
|
972
1162
|
*/
|
|
973
1163
|
declare const SUBAGENT_INFLIGHT_MARKER = "\0TAIJI_SUBAGENT_INFLIGHT";
|
|
974
1164
|
|
|
1165
|
+
/**
|
|
1166
|
+
* subagent-workflow 通知通道的 custom_message customType 词表(单源)。
|
|
1167
|
+
*
|
|
1168
|
+
* 契约两端(值逐字节依赖,改名 = 跨侧破坏性变更):
|
|
1169
|
+
* - 写侧:@zhushanwen/pi-subagent-workflow extension(workflow 收口通知 / bg-notify
|
|
1170
|
+
* 送达 / 定向消息留痕,经 pi.sendMessage 落 custom_message entry 进 session JSONL)
|
|
1171
|
+
* 与 @zhushanwen/subagent-core(notifier 送达 + notify ledger 默认通道);
|
|
1172
|
+
* - 读侧:taiji 三层——@taiji/shared(COMPLETE_NOTIFY_CUSTOM_TYPES display 覆写
|
|
1173
|
+
* 集合 + parseSubagentDirective 判型)、runtime(event-interpreter W18 失效信号 /
|
|
1174
|
+
* subagent-extractor legacy 扫描)、core(notify-summary 边界聚合判据)。
|
|
1175
|
+
*
|
|
1176
|
+
* 历史上双侧各持裸字面量、零跨侧锚定(值相等靠手工同步,commit 21578c74f 在案)。
|
|
1177
|
+
* 收敛本单源后两侧 import 同一常量;等值锁 = 壳 __tests__/contract.notify-custom-types.test.ts
|
|
1178
|
+
* (值锚定 + 生产码不得本地重定义,防镜像回潮)。
|
|
1179
|
+
*
|
|
1180
|
+
* 注意与 worker 协议帧的 `type: "workflow-result"`(subagent-core worker-message-pump /
|
|
1181
|
+
* worker-script-builder 的 postMessage 帧 type)是同名不同域——那是引擎进程内 RPC 形状,
|
|
1182
|
+
* 不跨 pi session 边界,不进本词表。
|
|
1183
|
+
*/
|
|
1184
|
+
/** workflow run 收口通知的送达 customType。runtime event-interpreter 按它识别 run 完成
|
|
1185
|
+
* 并驱动 W18 workflow-record 失效信号;shared 完成通知 display 覆写集合亦按它收录。
|
|
1186
|
+
* 与 SUBAGENT_BG_NOTIFY_CUSTOM_TYPE 通道互斥(互用会让失效信号误判通道语义)。 */
|
|
1187
|
+
declare const WORKFLOW_RESULT_CUSTOM_TYPE: "workflow-result";
|
|
1188
|
+
/** subagent 后台完成通知的送达 customType(notifier 单条/合批 + notify ledger 默认通道;
|
|
1189
|
+
* 壳 index.ts 的 registerMessageRenderer 同按它注册 TUI 渲染)。legacy 链路的
|
|
1190
|
+
* subagent-extractor 磁盘扫描、shared display 覆写集合均按它判型。 */
|
|
1191
|
+
declare const SUBAGENT_BG_NOTIFY_CUSTOM_TYPE: "subagent-bg-notify";
|
|
1192
|
+
/** subagent 定向消息留痕的 customType(composer 四符号 `@` 定向对话:GUI 经 client.prompt
|
|
1193
|
+
* 触发 /subagents message,成功派发后落 custom_message entry——一 entry 双消费:主 agent
|
|
1194
|
+
* 上下文 + renderer 定向气泡)。shared parseSubagentDirective / runtime display 覆写消费。 */
|
|
1195
|
+
declare const SUBAGENT_DIRECTIVE_CUSTOM_TYPE: "subagent-directive";
|
|
1196
|
+
|
|
975
1197
|
/**
|
|
976
1198
|
* plugin-bridge 请求的 title marker。runtime event-adapter 和 pi 侧
|
|
977
1199
|
* bridge extension(@zhushanwen/pi-plugin-bridge)双端消费此 marker,
|
|
@@ -1170,4 +1392,4 @@ declare function collectActivePendingIds(entries: unknown[], opts?: CollectPendi
|
|
|
1170
1392
|
type MappedPendingStatus = 'completed' | 'failed' | 'cancelled' | 'expired' | 'time_limited' | 'aborted';
|
|
1171
1393
|
declare function mapReasonToStatus(reason: string): MappedPendingStatus;
|
|
1172
1394
|
|
|
1173
|
-
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 FormAnswers, type FormOption, type FormQuestion, GUI_WIDGET_MARKER, type GuiComponent, type GuiComponentProps, type GuiComponentType, type GuiContext, type GuiRenderResult, INFLIGHT_REPORT_ACK, 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, SCHEDULE_CREATE_MARKER, SESSION_MANAGER_ACTIONS, SESSION_MANAGER_MARKER, SUBAGENTS_ENGINES_FILENAME, SUBAGENT_INFLIGHT_MARKER, type ScheduleDraft, type ScheduleFormResult, type ScheduleKind, type ScheduleQuestion, 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 StatItem, type SubagentEngineConfigView, type SubagentEnginesFile, type SubagentInFlightReport, type TextQuestion, type TreeItem, type TreeItemIcon, UI_FORM_MARKER, type UiFormInteractOptions, type UiFormInteractResult, type WidgetIconPathsRejection, type WidgetIconPathsValidation, type WidgetMeta, applyPendingDiff, callMarkerRpc, collectActivePendingIds, dateToOnceCron, extractGui, firstContentText, formatChannelErrorText, getAskUserAnswer, getAskUserOther, guiComponent, guiResult, guiSetWidget, isAskUserQuestion, isBridgeErrorResponse, isBridgeInterceptResponse, isBridgeSyncPayload, isBridgeToolExecuteResponse, isChannelErrorResult, isFormAnswers, isFormQuestion, isGuiCapable, isGuiComponent, isGuiRenderResult, isInFlightReportAck, isScheduleDraft, isScheduleFormResult, isSessionManagerAbortParams, isSessionManagerCreateParams, isSessionManagerHistoryParams, isSessionManagerListParams, isSessionManagerSendParams, isSessionManagerStatusParams, isSubagentInFlightReport, isSyncedTool, mapReasonToStatus, onceCronToDate, scanPendingEntries, setWidgetDual, uiFormInteract, validateWidgetIconPaths };
|
|
1395
|
+
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 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, isSessionManagerSendParams, isSessionManagerStatusParams, isSubagentInFlightReport, isSyncedTool, mapReasonToStatus, onceCronToDate, replayFoldEntries, scanPendingEntries, setWidgetDual, snapshotToTask, uiFormInteract, validateWidgetIconPaths };
|
package/dist/index.js
CHANGED
|
@@ -185,6 +185,176 @@ function isAskUserQuestion(value) {
|
|
|
185
185
|
return typeof q.question === "string" && (q.header === void 0 || typeof q.header === "string") && (q.options === void 0 || Array.isArray(q.options)) && (q.multiSelect === void 0 || typeof q.multiSelect === "boolean") && (q.allowOther === void 0 || typeof q.allowOther === "boolean");
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// src/extensions/scheduler/types.ts
|
|
189
|
+
var HISTORY_LIMIT = 20;
|
|
190
|
+
function appendExecutionRecord(task, at, status) {
|
|
191
|
+
task.history.push({ at, status });
|
|
192
|
+
if (task.history.length > HISTORY_LIMIT) task.history.shift();
|
|
193
|
+
}
|
|
194
|
+
var TASK_ENTRY_TYPE = "pi-scheduler:task";
|
|
195
|
+
function snapshotToTask(snapshot) {
|
|
196
|
+
return {
|
|
197
|
+
id: snapshot.id,
|
|
198
|
+
name: snapshot.name,
|
|
199
|
+
prompt: snapshot.prompt,
|
|
200
|
+
kind: snapshot.kind,
|
|
201
|
+
schedule: snapshot.schedule,
|
|
202
|
+
model: snapshot.model,
|
|
203
|
+
enabled: snapshot.enabled,
|
|
204
|
+
createdAt: snapshot.createdAt,
|
|
205
|
+
nextRunAt: snapshot.nextRunAt,
|
|
206
|
+
expiresAt: snapshot.expiresAt,
|
|
207
|
+
runCount: snapshot.runCount,
|
|
208
|
+
lastRunAt: snapshot.lastRunAt,
|
|
209
|
+
lastStatus: snapshot.lastStatus,
|
|
210
|
+
lastError: snapshot.lastError,
|
|
211
|
+
history: snapshot.history.map((h) => ({ ...h }))
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// src/extensions/scheduler/replay.ts
|
|
216
|
+
function toErrorMessage(e) {
|
|
217
|
+
return e instanceof Error ? e.message : String(e);
|
|
218
|
+
}
|
|
219
|
+
function replayFoldEntries(entries, currentSessionFile, options) {
|
|
220
|
+
try {
|
|
221
|
+
const tasks = /* @__PURE__ */ new Map();
|
|
222
|
+
foldEntries(entries, tasks, options);
|
|
223
|
+
filterNonOwnerTasks(tasks, currentSessionFile);
|
|
224
|
+
return tasks;
|
|
225
|
+
} catch (err) {
|
|
226
|
+
options?.warn?.("replayFoldEntries failed", { error: toErrorMessage(err) });
|
|
227
|
+
return /* @__PURE__ */ new Map();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function foldEntries(entries, tasks, options) {
|
|
231
|
+
for (const entry of entries) {
|
|
232
|
+
if (entry.type !== "custom" || entry.customType !== TASK_ENTRY_TYPE) continue;
|
|
233
|
+
if (!isSchedulerEntryOp(entry.data)) continue;
|
|
234
|
+
const op = entry.data;
|
|
235
|
+
try {
|
|
236
|
+
applyOp(tasks, op);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
options?.warn?.("skipping corrupted scheduler entry", { error: toErrorMessage(err) });
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function applyOp(tasks, op) {
|
|
244
|
+
switch (op.op) {
|
|
245
|
+
case "upsert":
|
|
246
|
+
applyUpsert(tasks, op);
|
|
247
|
+
break;
|
|
248
|
+
case "advance":
|
|
249
|
+
applyAdvance(tasks, op);
|
|
250
|
+
break;
|
|
251
|
+
case "toggle":
|
|
252
|
+
applyToggle(tasks, op);
|
|
253
|
+
break;
|
|
254
|
+
case "delete":
|
|
255
|
+
applyDelete(tasks, op);
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function applyUpsert(tasks, op) {
|
|
260
|
+
tasks.set(op.taskId, { ...snapshotToTask(op.task), ownerSessionFile: op.ownerSessionFile });
|
|
261
|
+
}
|
|
262
|
+
function applyAdvance(tasks, op) {
|
|
263
|
+
const task = tasks.get(op.taskId);
|
|
264
|
+
if (!task) return;
|
|
265
|
+
task.nextRunAt = op.nextRunAt;
|
|
266
|
+
task.lastRunAt = op.at;
|
|
267
|
+
task.runCount += 1;
|
|
268
|
+
appendExecutionRecord(task, op.at, op.status);
|
|
269
|
+
task.lastStatus = op.status;
|
|
270
|
+
}
|
|
271
|
+
function applyToggle(tasks, op) {
|
|
272
|
+
const task = tasks.get(op.taskId);
|
|
273
|
+
if (!task) return;
|
|
274
|
+
task.enabled = op.enabled;
|
|
275
|
+
if (op.nextRunAt !== void 0) task.nextRunAt = op.nextRunAt;
|
|
276
|
+
}
|
|
277
|
+
function applyDelete(tasks, op) {
|
|
278
|
+
tasks.delete(op.taskId);
|
|
279
|
+
}
|
|
280
|
+
function filterNonOwnerTasks(tasks, currentSessionFile) {
|
|
281
|
+
for (const [id, task] of tasks) {
|
|
282
|
+
if (task.ownerSessionFile !== currentSessionFile) {
|
|
283
|
+
tasks.delete(id);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function isSchedulerEntryOp(data) {
|
|
288
|
+
if (!data || typeof data !== "object") return false;
|
|
289
|
+
const record = data;
|
|
290
|
+
const op = record.op;
|
|
291
|
+
if (op === "upsert") {
|
|
292
|
+
return typeof record.taskId === "string" && typeof record.task === "object" && record.task !== null;
|
|
293
|
+
}
|
|
294
|
+
if (op === "advance") {
|
|
295
|
+
return typeof record.taskId === "string" && typeof record.nextRunAt === "number" && typeof record.at === "number" && record.status === "success";
|
|
296
|
+
}
|
|
297
|
+
if (op === "toggle") {
|
|
298
|
+
return typeof record.taskId === "string" && typeof record.enabled === "boolean" && (record.nextRunAt === void 0 || typeof record.nextRunAt === "number");
|
|
299
|
+
}
|
|
300
|
+
if (op === "delete") {
|
|
301
|
+
return typeof record.taskId === "string";
|
|
302
|
+
}
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// src/extensions/scheduler/format.ts
|
|
307
|
+
var MS_PER_DAY = 864e5;
|
|
308
|
+
var MS_PER_HOUR = 36e5;
|
|
309
|
+
var MS_PER_MINUTE = 6e4;
|
|
310
|
+
var MS_PER_SECOND = 1e3;
|
|
311
|
+
var NOW_THRESHOLD_MS = 5e3;
|
|
312
|
+
function formatDuration(ms) {
|
|
313
|
+
if (ms <= 0) return "0s";
|
|
314
|
+
const units = [
|
|
315
|
+
["d", MS_PER_DAY],
|
|
316
|
+
["h", MS_PER_HOUR],
|
|
317
|
+
["m", MS_PER_MINUTE],
|
|
318
|
+
["s", MS_PER_SECOND]
|
|
319
|
+
];
|
|
320
|
+
for (const [suffix, divisor] of units) {
|
|
321
|
+
if (ms >= divisor && ms % divisor === 0) {
|
|
322
|
+
return `${ms / divisor}${suffix}`;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return `${Math.round(ms / MS_PER_SECOND)}s`;
|
|
326
|
+
}
|
|
327
|
+
function formatSchedule(spec, kind) {
|
|
328
|
+
if (spec.mode === "interval") {
|
|
329
|
+
return kind === "once" ? `once in ${formatDuration(spec.intervalMs)}` : `every ${formatDuration(spec.intervalMs)}`;
|
|
330
|
+
}
|
|
331
|
+
return spec.cronExpression;
|
|
332
|
+
}
|
|
333
|
+
function formatRelativeTime(timestamp, now) {
|
|
334
|
+
const currentTime = now ?? Date.now();
|
|
335
|
+
const diff = timestamp - currentTime;
|
|
336
|
+
if (Math.abs(diff) < NOW_THRESHOLD_MS) return "now";
|
|
337
|
+
const absDiff = Math.abs(diff);
|
|
338
|
+
const units = [
|
|
339
|
+
["d", MS_PER_DAY],
|
|
340
|
+
["h", MS_PER_HOUR],
|
|
341
|
+
["m", MS_PER_MINUTE],
|
|
342
|
+
["s", MS_PER_SECOND]
|
|
343
|
+
];
|
|
344
|
+
let formatted = "";
|
|
345
|
+
for (const [suffix, divisor] of units) {
|
|
346
|
+
if (absDiff >= divisor) {
|
|
347
|
+
const value = Math.floor(absDiff / divisor);
|
|
348
|
+
formatted = `${value}${suffix}`;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (!formatted) {
|
|
353
|
+
formatted = `${Math.round(absDiff / MS_PER_SECOND)}s`;
|
|
354
|
+
}
|
|
355
|
+
return diff > 0 ? `in ${formatted}` : `${formatted} ago`;
|
|
356
|
+
}
|
|
357
|
+
|
|
188
358
|
// src/extensions/scheduler-create/marker.ts
|
|
189
359
|
var SCHEDULE_CREATE_MARKER = "\0TAIJI_SCHEDULE_CREATE";
|
|
190
360
|
|
|
@@ -392,6 +562,11 @@ function isInFlightReportAck(v) {
|
|
|
392
562
|
return v === INFLIGHT_REPORT_ACK;
|
|
393
563
|
}
|
|
394
564
|
|
|
565
|
+
// src/extensions/subagent-notify/custom-types.ts
|
|
566
|
+
var WORKFLOW_RESULT_CUSTOM_TYPE = "workflow-result";
|
|
567
|
+
var SUBAGENT_BG_NOTIFY_CUSTOM_TYPE = "subagent-bg-notify";
|
|
568
|
+
var SUBAGENT_DIRECTIVE_CUSTOM_TYPE = "subagent-directive";
|
|
569
|
+
|
|
395
570
|
// src/extensions/plugin-bridge/marker.ts
|
|
396
571
|
var BRIDGE_MARKER = "\0TAIJI_BRIDGE";
|
|
397
572
|
var BRIDGE_METHODS = ["bridge:sync", "bridge:tool_execute", "bridge:event", "bridge:intercept"];
|
|
@@ -493,8 +668,13 @@ export {
|
|
|
493
668
|
BRIDGE_MARKER,
|
|
494
669
|
BRIDGE_METHODS,
|
|
495
670
|
GUI_WIDGET_MARKER,
|
|
671
|
+
HISTORY_LIMIT,
|
|
496
672
|
INFLIGHT_REPORT_ACK,
|
|
497
673
|
MAX_TERMINAL_REGISTRY_ENTRIES,
|
|
674
|
+
MS_PER_DAY,
|
|
675
|
+
MS_PER_HOUR,
|
|
676
|
+
MS_PER_MINUTE,
|
|
677
|
+
MS_PER_SECOND,
|
|
498
678
|
PENDING_REGISTER_ENTRY_TYPE,
|
|
499
679
|
PENDING_UNREGISTER_ENTRY_TYPE,
|
|
500
680
|
PLAN_REVIEW_MARKER,
|
|
@@ -503,8 +683,13 @@ export {
|
|
|
503
683
|
SESSION_MANAGER_ACTIONS,
|
|
504
684
|
SESSION_MANAGER_MARKER,
|
|
505
685
|
SUBAGENTS_ENGINES_FILENAME,
|
|
686
|
+
SUBAGENT_BG_NOTIFY_CUSTOM_TYPE,
|
|
687
|
+
SUBAGENT_DIRECTIVE_CUSTOM_TYPE,
|
|
506
688
|
SUBAGENT_INFLIGHT_MARKER,
|
|
689
|
+
TASK_ENTRY_TYPE,
|
|
507
690
|
UI_FORM_MARKER,
|
|
691
|
+
WORKFLOW_RESULT_CUSTOM_TYPE,
|
|
692
|
+
appendExecutionRecord,
|
|
508
693
|
applyPendingDiff,
|
|
509
694
|
callMarkerRpc,
|
|
510
695
|
collectActivePendingIds,
|
|
@@ -512,6 +697,9 @@ export {
|
|
|
512
697
|
extractGui,
|
|
513
698
|
firstContentText,
|
|
514
699
|
formatChannelErrorText,
|
|
700
|
+
formatDuration,
|
|
701
|
+
formatRelativeTime,
|
|
702
|
+
formatSchedule,
|
|
515
703
|
getAskUserAnswer,
|
|
516
704
|
getAskUserOther,
|
|
517
705
|
guiComponent,
|
|
@@ -544,8 +732,10 @@ export {
|
|
|
544
732
|
isTerminalBackgroundTaskState,
|
|
545
733
|
mapReasonToStatus,
|
|
546
734
|
onceCronToDate,
|
|
735
|
+
replayFoldEntries,
|
|
547
736
|
scanPendingEntries,
|
|
548
737
|
setWidgetDual,
|
|
738
|
+
snapshotToTask,
|
|
549
739
|
uiFormInteract,
|
|
550
740
|
validateWidgetIconPaths
|
|
551
741
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhushanwen/extension-protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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",
|