@ai-setting/roy-agent-core 1.7.77 → 1.7.88

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.
Files changed (155) hide show
  1. package/dist/config/config-protection.d.ts +89 -0
  2. package/dist/config/index.d.ts +1 -0
  3. package/dist/config/index.js +23 -7
  4. package/dist/env/agent/agent-component.d.ts +43 -22
  5. package/dist/env/agent/agent-component.js +13 -12
  6. package/dist/env/agent/index.js +13 -12
  7. package/dist/env/agent/types.d.ts +46 -12
  8. package/dist/env/commands/index.js +7 -7
  9. package/dist/env/context/index.js +3 -3
  10. package/dist/env/debug/index.js +7 -7
  11. package/dist/env/error-reply.d.ts +6 -0
  12. package/dist/env/error-reply.js +1 -1
  13. package/dist/env/event-source/bounty-im-handler.d.ts +8 -0
  14. package/dist/env/event-source/es-command.d.ts +39 -0
  15. package/dist/env/event-source/es-plugins.d.ts +68 -0
  16. package/dist/env/event-source/event-source-component.d.ts +15 -0
  17. package/dist/env/event-source/event-source-handlers.d.ts +84 -0
  18. package/dist/env/event-source/event-source-handlers.js +40 -23
  19. package/dist/env/event-source/event-store.js +2 -2
  20. package/dist/env/event-source/index.d.ts +5 -1
  21. package/dist/env/event-source/index.js +75 -23
  22. package/dist/env/event-source/timer-handler.d.ts +98 -0
  23. package/dist/env/event-source/types.d.ts +154 -2
  24. package/dist/env/event-source/wecom-card-action-handler.d.ts +373 -0
  25. package/dist/env/event-source/wecom-card-builder.d.ts +426 -0
  26. package/dist/env/event-source/wecom-cli-handler.d.ts +291 -0
  27. package/dist/env/event-source/wecom-cli-sender.d.ts +88 -0
  28. package/dist/env/event-source/wecom-media.d.ts +130 -0
  29. package/dist/env/event-source/wecom-respond-registry.d.ts +151 -0
  30. package/dist/env/event-source/wecom-respond-registry.js +33 -0
  31. package/dist/env/event-source/wecom-session-card-sender.d.ts +135 -0
  32. package/dist/env/event-source/wecom-session-card-sender.js +153 -0
  33. package/dist/env/event-source/wecom-ws-bridge.d.ts +213 -0
  34. package/dist/env/hook/index.js +5 -5
  35. package/dist/env/index.js +51 -45
  36. package/dist/env/llm/index.js +9 -8
  37. package/dist/env/log-trace/index.js +7 -7
  38. package/dist/env/log-trace/trace-filters.d.ts +6 -1
  39. package/dist/env/mcp/index.js +7 -7
  40. package/dist/env/memory/index.js +7 -7
  41. package/dist/env/plugin/index.js +7 -7
  42. package/dist/env/prompt/index.js +8 -8
  43. package/dist/env/prompt/prompts-index.d.ts +1 -1
  44. package/dist/env/session/group-session-link.d.ts +99 -0
  45. package/dist/env/session/index.js +11 -10
  46. package/dist/env/session/session-component.d.ts +89 -0
  47. package/dist/env/session/storage/index.js +5 -4
  48. package/dist/env/session/types.d.ts +10 -0
  49. package/dist/env/skill/index.js +7 -7
  50. package/dist/env/task/delegate/delegate-channel-hint.d.ts +39 -0
  51. package/dist/env/task/delegate/delegate-tool.d.ts +132 -7
  52. package/dist/env/task/delegate/delegate-tool.js +13 -9
  53. package/dist/env/task/delegate/index.js +8 -8
  54. package/dist/env/task/index.js +18 -18
  55. package/dist/env/task/mcp/index.js +4 -4
  56. package/dist/env/task/plugins/card-subject.d.ts +117 -0
  57. package/dist/env/task/plugins/index.d.ts +2 -0
  58. package/dist/env/task/plugins/index.js +39 -16
  59. package/dist/env/task/plugins/lark-card-action-handler.d.ts +261 -6
  60. package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +542 -2
  61. package/dist/env/task/plugins/lark-card-patch-notifier.js +12 -2
  62. package/dist/env/task/plugins/lark-card-state-store.d.ts +60 -0
  63. package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +61 -0
  64. package/dist/env/task/plugins/sub-session-activity.d.ts +415 -0
  65. package/dist/env/task/plugins/wecom-card-state-store.d.ts +121 -0
  66. package/dist/env/task/plugins/wecom-session-card-store.d.ts +134 -0
  67. package/dist/env/task/plugins/wecom-session-card-store.js +23 -0
  68. package/dist/env/task/plugins/wecom-task-notify-plugin.d.ts +264 -0
  69. package/dist/env/task/storage/index.js +3 -3
  70. package/dist/env/task/tools/index.js +4 -4
  71. package/dist/env/tool/built-in/index.d.ts +2 -0
  72. package/dist/env/tool/built-in/index.js +9 -2
  73. package/dist/env/tool/index.js +14 -9
  74. package/dist/env/tool/types.d.ts +25 -0
  75. package/dist/env/tool/validator.d.ts +8 -0
  76. package/dist/env/workflow/engine/index.js +12 -12
  77. package/dist/env/workflow/hooks/index.js +7 -7
  78. package/dist/env/workflow/index.js +24 -23
  79. package/dist/env/workflow/nodes/index.js +2 -2
  80. package/dist/env/workflow/plugins/index.js +10 -8
  81. package/dist/env/workflow/service/index.js +2 -2
  82. package/dist/env/workflow/storage/index.js +3 -3
  83. package/dist/env/workflow/tools/index.js +16 -15
  84. package/dist/env/workflow/utils/index.js +4 -4
  85. package/dist/index.d.ts +1 -1
  86. package/dist/index.js +118 -62
  87. package/dist/shared/@ai-setting/{roy-agent-core-dc9zq75z.js → roy-agent-core-0crmsc12.js} +3 -3
  88. package/dist/shared/@ai-setting/{roy-agent-core-aa2j7bk9.js → roy-agent-core-0sbmdz8d.js} +171 -36
  89. package/dist/shared/@ai-setting/{roy-agent-core-87942bw4.js → roy-agent-core-1mhyh4c5.js} +1 -1
  90. package/dist/shared/@ai-setting/{roy-agent-core-v6vr6za7.js → roy-agent-core-1vv4fx15.js} +4 -4
  91. package/dist/shared/@ai-setting/roy-agent-core-2stt4rp5.js +134 -0
  92. package/dist/shared/@ai-setting/{roy-agent-core-nwbfepba.js → roy-agent-core-3e040tc5.js} +1 -1
  93. package/dist/shared/@ai-setting/roy-agent-core-418zc9ha.js +288 -0
  94. package/dist/shared/@ai-setting/{roy-agent-core-r5wt1h3c.js → roy-agent-core-4fkxy2gv.js} +1 -1
  95. package/dist/shared/@ai-setting/{roy-agent-core-na18zwj0.js → roy-agent-core-4t3yskp8.js} +1 -1
  96. package/dist/shared/@ai-setting/{roy-agent-core-5pr4zp88.js → roy-agent-core-5kzhaap1.js} +1 -1
  97. package/dist/shared/@ai-setting/{roy-agent-core-qq96p0tj.js → roy-agent-core-5s2t8z00.js} +22 -1
  98. package/dist/shared/@ai-setting/{roy-agent-core-6rh8k6ba.js → roy-agent-core-6gj1hc5z.js} +7 -7
  99. package/dist/shared/@ai-setting/{roy-agent-core-ezvpreqz.js → roy-agent-core-6k8mb7zx.js} +1 -1
  100. package/dist/shared/@ai-setting/{roy-agent-core-g8htfwxj.js → roy-agent-core-7f10p7m2.js} +1 -1
  101. package/dist/shared/@ai-setting/roy-agent-core-7kvpc0w5.js +177 -0
  102. package/dist/shared/@ai-setting/{roy-agent-core-h21gngxf.js → roy-agent-core-7yh5wps0.js} +1 -1
  103. package/dist/shared/@ai-setting/{roy-agent-core-efkjyh69.js → roy-agent-core-9710zwwz.js} +1 -1
  104. package/dist/shared/@ai-setting/{roy-agent-core-6cy43nss.js → roy-agent-core-9c565frx.js} +49 -9
  105. package/dist/shared/@ai-setting/{roy-agent-core-fghc2m8z.js → roy-agent-core-aa8kv18f.js} +34 -2
  106. package/dist/shared/@ai-setting/{roy-agent-core-ew6qb5yx.js → roy-agent-core-an35dzbf.js} +6 -6
  107. package/dist/shared/@ai-setting/{roy-agent-core-mww0mnd9.js → roy-agent-core-azyz78ky.js} +7 -7
  108. package/dist/shared/@ai-setting/{roy-agent-core-264qexac.js → roy-agent-core-b7h39vrc.js} +4 -4
  109. package/dist/shared/@ai-setting/{roy-agent-core-dqxec05w.js → roy-agent-core-bjtc9d35.js} +2 -2
  110. package/dist/shared/@ai-setting/roy-agent-core-c4ec7k0p.js +426 -0
  111. package/dist/shared/@ai-setting/{roy-agent-core-ddyk1rc0.js → roy-agent-core-cre2y2ct.js} +160 -4
  112. package/dist/shared/@ai-setting/{roy-agent-core-tr3ep81v.js → roy-agent-core-d6zdbgtc.js} +1 -1
  113. package/dist/shared/@ai-setting/{roy-agent-core-0qyrk5k0.js → roy-agent-core-ds6qzmf8.js} +14 -5
  114. package/dist/shared/@ai-setting/{roy-agent-core-cgtq6427.js → roy-agent-core-e08bvpaq.js} +1 -1
  115. package/dist/shared/@ai-setting/{roy-agent-core-12n08pg5.js → roy-agent-core-e69qxdyy.js} +1 -1
  116. package/dist/shared/@ai-setting/{roy-agent-core-rhtdspx6.js → roy-agent-core-fan8g0z1.js} +10 -10
  117. package/dist/shared/@ai-setting/{roy-agent-core-xcp8vwax.js → roy-agent-core-fepm835e.js} +2 -2
  118. package/dist/shared/@ai-setting/{roy-agent-core-6j02sbee.js → roy-agent-core-fhg03v43.js} +1 -1
  119. package/dist/shared/@ai-setting/{roy-agent-core-99nwgj84.js → roy-agent-core-fzw9xzm1.js} +1 -1
  120. package/dist/shared/@ai-setting/{roy-agent-core-dvtg4sn0.js → roy-agent-core-g8yr733d.js} +1 -1
  121. package/dist/shared/@ai-setting/{roy-agent-core-3gpygqcx.js → roy-agent-core-gr5h1dyr.js} +2753 -358
  122. package/dist/shared/@ai-setting/roy-agent-core-h1e1fm9b.js +380 -0
  123. package/dist/shared/@ai-setting/{roy-agent-core-c2gbt68e.js → roy-agent-core-h83zdsrq.js} +2 -2
  124. package/dist/shared/@ai-setting/{roy-agent-core-8ez6mccb.js → roy-agent-core-k3gcvybs.js} +5 -1
  125. package/dist/shared/@ai-setting/{roy-agent-core-pgvcf91v.js → roy-agent-core-m39v7qpx.js} +2 -2
  126. package/dist/shared/@ai-setting/{roy-agent-core-tm1mxttk.js → roy-agent-core-mf5p38yf.js} +2 -2
  127. package/dist/shared/@ai-setting/{roy-agent-core-83bewqx8.js → roy-agent-core-mvh0td7p.js} +2 -2
  128. package/dist/shared/@ai-setting/{roy-agent-core-v85n42ve.js → roy-agent-core-mx855td4.js} +17 -38
  129. package/dist/shared/@ai-setting/{roy-agent-core-v87njmq7.js → roy-agent-core-n197medr.js} +13 -13
  130. package/dist/shared/@ai-setting/{roy-agent-core-cmprygrp.js → roy-agent-core-nqkfkpf4.js} +4 -4
  131. package/dist/shared/@ai-setting/{roy-agent-core-7cbpmk4q.js → roy-agent-core-p31ftgq9.js} +1 -1
  132. package/dist/shared/@ai-setting/{roy-agent-core-vffccgf6.js → roy-agent-core-qwd2dq5q.js} +10 -3
  133. package/dist/shared/@ai-setting/{roy-agent-core-rsn44n9y.js → roy-agent-core-ra66sf50.js} +2526 -942
  134. package/dist/shared/@ai-setting/{roy-agent-core-1v4g0d4x.js → roy-agent-core-rm7seqwb.js} +1 -1
  135. package/dist/shared/@ai-setting/{roy-agent-core-w0qjeq2v.js → roy-agent-core-shb1qsyg.js} +1041 -18
  136. package/dist/shared/@ai-setting/{roy-agent-core-ax9e9szb.js → roy-agent-core-smf94h73.js} +1 -1
  137. package/dist/shared/@ai-setting/{roy-agent-core-acj8ag08.js → roy-agent-core-tjnabyvq.js} +1 -1
  138. package/dist/shared/@ai-setting/{roy-agent-core-qqaak24r.js → roy-agent-core-tkpp1ba0.js} +1 -1
  139. package/dist/shared/@ai-setting/{roy-agent-core-9vhq7fvv.js → roy-agent-core-tpm1dd1g.js} +34 -88
  140. package/dist/shared/@ai-setting/{roy-agent-core-ed233k5z.js → roy-agent-core-v1n0106v.js} +1 -1
  141. package/dist/shared/@ai-setting/{roy-agent-core-zxz5fkwj.js → roy-agent-core-v6yshv0z.js} +1 -1
  142. package/dist/shared/@ai-setting/{roy-agent-core-mcy5apay.js → roy-agent-core-vf9sp6s3.js} +1 -1
  143. package/dist/shared/@ai-setting/{roy-agent-core-q813vafd.js → roy-agent-core-vpcxv1ty.js} +1 -1
  144. package/dist/shared/@ai-setting/{roy-agent-core-bxkjk7zx.js → roy-agent-core-vx8zc847.js} +4 -1
  145. package/dist/shared/@ai-setting/{roy-agent-core-xvt7kf7p.js → roy-agent-core-w9ryeg2p.js} +3 -3
  146. package/dist/shared/@ai-setting/{roy-agent-core-es203w7p.js → roy-agent-core-wqs6yypq.js} +1 -1
  147. package/dist/shared/@ai-setting/{roy-agent-core-hd3n57zs.js → roy-agent-core-wr1qexzq.js} +5 -5
  148. package/dist/shared/@ai-setting/roy-agent-core-wxrkcb17.js +56 -0
  149. package/dist/shared/@ai-setting/{roy-agent-core-0snm5hc5.js → roy-agent-core-y6shd91r.js} +1 -1
  150. package/dist/shared/@ai-setting/{roy-agent-core-9vxh6f8h.js → roy-agent-core-y7fqtzk2.js} +7 -7
  151. package/dist/shared/@ai-setting/{roy-agent-core-cpcd24n2.js → roy-agent-core-yet36q5k.js} +2 -2
  152. package/dist/shared/@ai-setting/{roy-agent-core-3fh1f7s7.js → roy-agent-core-yfpnkc4z.js} +5 -5
  153. package/dist/shared/@ai-setting/{roy-agent-core-0v27y99n.js → roy-agent-core-yh68z1bg.js} +65 -4
  154. package/package.json +18 -1
  155. /package/dist/shared/@ai-setting/{roy-agent-core-b4x6x4k2.js → roy-agent-core-m1fgtnrc.js} +0 -0
@@ -4,35 +4,35 @@ import {
4
4
  } from "./roy-agent-core-fttgm52a.js";
5
5
  import {
6
6
  getSharedEventStore
7
- } from "./roy-agent-core-na18zwj0.js";
7
+ } from "./roy-agent-core-4t3yskp8.js";
8
8
  import {
9
9
  builtInPrompts
10
- } from "./roy-agent-core-9vxh6f8h.js";
10
+ } from "./roy-agent-core-y7fqtzk2.js";
11
11
  import {
12
12
  TaskHookPoints
13
13
  } from "./roy-agent-core-1pg0fepg.js";
14
14
  import {
15
15
  DEFAULT_SUBAGENT_PROMPT
16
- } from "./roy-agent-core-ed233k5z.js";
16
+ } from "./roy-agent-core-v1n0106v.js";
17
17
  import {
18
18
  runWithBgTaskIdAsync
19
19
  } from "./roy-agent-core-c1v263jn.js";
20
20
  import {
21
21
  globalHookManager,
22
22
  init_global_hook_manager
23
- } from "./roy-agent-core-cpcd24n2.js";
23
+ } from "./roy-agent-core-yet36q5k.js";
24
24
  import {
25
25
  init_context
26
- } from "./roy-agent-core-qqaak24r.js";
26
+ } from "./roy-agent-core-tkpp1ba0.js";
27
27
  import {
28
28
  getCurrentTaskId,
29
29
  getEnvContext
30
- } from "./roy-agent-core-7cbpmk4q.js";
30
+ } from "./roy-agent-core-p31ftgq9.js";
31
31
  import {
32
32
  TracedAs,
33
33
  init_decorator,
34
34
  wrapFunction
35
- } from "./roy-agent-core-qq96p0tj.js";
35
+ } from "./roy-agent-core-5s2t8z00.js";
36
36
  import {
37
37
  createLogger,
38
38
  init_logger
@@ -47,6 +47,43 @@ init_decorator();
47
47
  init_context();
48
48
  import { z } from "zod";
49
49
 
50
+ // src/env/task/delegate/delegate-channel-hint.ts
51
+ var DELEGATE_CHANNEL_HINT_TITLE = "## 渠道交付提示(当前会话来自外部渠道)";
52
+ function buildDelegateChannelHint(channelType) {
53
+ if (!channelType)
54
+ return;
55
+ let channelBody;
56
+ if (channelType === "lark-cli" || channelType.startsWith("lark")) {
57
+ channelBody = [
58
+ `- 触发渠道是**飞书**。文档类产出(调研文档 / 报告 / PPT / doc 等)`,
59
+ ` 必须用**飞书云盘**存储:\`lark-cli docs +create --title <标题> --markdown @<本地md>\`,用完即弃。`,
60
+ `- 交付时只给**云盘链接**(https://my.feishu.cn/...),**不落本地路径**交付。`,
61
+ ` 本地路径只作中转(生成 md → 上传云盘 → 回复里贴云盘链接),不作为交付物。`
62
+ ].join(`
63
+ `);
64
+ } else if (channelType === "wecom-cli" || channelType.startsWith("wecom")) {
65
+ channelBody = [
66
+ `- 触发渠道是**企业微信**。文档类产出(调研文档 / docs / ppt 等)`,
67
+ ` 必须上传到**企微文档**,链接作为交付物:`,
68
+ ` - 在线文档:\`wecom-cli doc create --doc-name <标题> --doc-type doc --content-type text --file-path <本地md>\``,
69
+ ` - 微盘文件:\`wecom-cli disk files upload --file-path <本地文件>\`(默认传到我的空间)`,
70
+ `- 本地路径只作中转(生成 → 上传企微文档 → 回复里贴链接),**不落本地路径**交付。`
71
+ ].join(`
72
+ `);
73
+ }
74
+ if (!channelBody)
75
+ return;
76
+ return [
77
+ DELEGATE_CHANNEL_HINT_TITLE,
78
+ ``,
79
+ `通用措辞:当前会话来自外部渠道,交付类产出优先用该渠道的原生存储/展示方式,`,
80
+ `不要把本地文件路径当作交付物(渠道用户无法访问本机文件系统)。`,
81
+ ``,
82
+ channelBody
83
+ ].join(`
84
+ `);
85
+ }
86
+
50
87
  // src/env/task/delegate/subagent-resolver.ts
51
88
  function isKnownSubagentType(subagentType, registry) {
52
89
  if (getSubAgentSpec(subagentType)) {
@@ -743,7 +780,8 @@ var BackgroundTaskEventTypes = {
743
780
  FAILED: "task.background.failed",
744
781
  TIMEOUT: "task.background.timeout",
745
782
  STOPPED: "task.background.stopped",
746
- ASK_USER: "task.background.ask_user"
783
+ ASK_USER: "task.background.ask_user",
784
+ SESSION_STARTED: "task.background.session_started"
747
785
  };
748
786
  var builtInSubAgents = [
749
787
  {
@@ -825,6 +863,21 @@ var builtInSubAgents = [
825
863
  function getSubAgentSpec(id) {
826
864
  return builtInSubAgents.find((agent) => agent.id === id);
827
865
  }
866
+ function normalizeExtendTools(raw) {
867
+ if (!Array.isArray(raw))
868
+ return;
869
+ const out = [];
870
+ for (const v of raw) {
871
+ if (typeof v !== "string")
872
+ continue;
873
+ const trimmed = v.trim();
874
+ if (trimmed.length === 0)
875
+ continue;
876
+ if (!out.includes(trimmed))
877
+ out.push(trimmed);
878
+ }
879
+ return out.length > 0 ? out : undefined;
880
+ }
828
881
  function ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools) {
829
882
  const registry = agentComponent.getRegistry?.();
830
883
  if (registry) {
@@ -858,7 +911,7 @@ var DelegateToolParameters = z.object({
858
911
  timeout: z.number().describe("Task timeout in milliseconds. Default: 1800000 (30 minutes). If set, task will be terminated after timeout.").optional(),
859
912
  reason: z.string().describe("Brief reason for calling this tool (max 30 chars, e.g., 'Delegate refactor task')").optional(),
860
913
  similar_task_ids: z.array(z.number()).max(3).describe("Similar task IDs (max 3) to reference for improving task execution. Search for similar tasks before calling this tool."),
861
- sub_session_id: z.string().describe("Existing sub-agent session ID to resume. " + "If provided, the sub-agent will continue from the previous conversation " + "context (used for retry on timeout/failure). " + "Leave empty for a new session.").optional(),
914
+ sub_session_id: z.string().describe("⚠️ 硬约束:同一任务链的续跑必须传此参数(从终态 notify 的「子 session:」行" + "或 delegate 返回的「\uD83D\uDD17 Sub-session:」行复制)。" + "仅当旧 session 上下文已确认不可救(compact_session 后仍超限 / 迭代上限且无可复用断点)时才留空;" + "留空等于丢弃全部上下文,从零开始。").optional(),
862
915
  triggerEventId: z.string().describe("EventStore trigger event ID (ESPlugin v2). Pass it when this delegate_task " + "is triggered by an external event source (e.g. Feishu message) so the " + "completion notification can reply to the original chat instead of a " + "fallback channel. Leave empty if not triggered by an event source.").optional()
863
916
  });
864
917
  function buildEntryAgentPrompt(options) {
@@ -1058,7 +1111,7 @@ class BackgroundTaskManager {
1058
1111
  return;
1059
1112
  }
1060
1113
  }
1061
- publishBackgroundEvent(type, payload, parentSessionId, triggerEventId, replyChannel) {
1114
+ publishBackgroundEvent(type, payload, parentSessionId, triggerEventId, replyChannel, pluginEnabledSnapshot) {
1062
1115
  if (this.env?.pushEnvEvent) {
1063
1116
  this.env.pushEnvEvent({
1064
1117
  type,
@@ -1067,7 +1120,8 @@ class BackgroundTaskManager {
1067
1120
  source: "task.background",
1068
1121
  trigger_session_id: parentSessionId,
1069
1122
  ...triggerEventId ? { triggerEventId } : {},
1070
- ...replyChannel ? { replyChannel } : {}
1123
+ ...replyChannel ? { replyChannel } : {},
1124
+ ...pluginEnabledSnapshot ? { pluginEnabled: pluginEnabledSnapshot } : {}
1071
1125
  }
1072
1126
  });
1073
1127
  logger3.info(`[BackgroundTaskManager] Event published: ${type}`, {
@@ -1076,8 +1130,8 @@ class BackgroundTaskManager {
1076
1130
  });
1077
1131
  }
1078
1132
  }
1079
- publishBackgroundEventWithTrigger(type, payload, parentSessionId, triggerEventId, replyChannel) {
1080
- this.publishBackgroundEvent(type, payload, parentSessionId, triggerEventId, replyChannel);
1133
+ publishBackgroundEventWithTrigger(type, payload, parentSessionId, triggerEventId, replyChannel, pluginEnabledSnapshot) {
1134
+ this.publishBackgroundEvent(type, payload, parentSessionId, triggerEventId, replyChannel, pluginEnabledSnapshot);
1081
1135
  }
1082
1136
  static parseAskUserErrorFromMessage(error) {
1083
1137
  const rawErrorMessage = error instanceof Error ? error.message : String(error);
@@ -1115,7 +1169,7 @@ class BackgroundTaskManager {
1115
1169
  return null;
1116
1170
  }
1117
1171
  async createTask(options) {
1118
- const { parentSessionId, description, prompt, subagentType, timeout, similarTaskIds, existingSubSessionId, triggerEventId, model, fallbackModel, fallbackModels } = options;
1172
+ const { parentSessionId, description, prompt, subagentType, timeout, similarTaskIds, existingSubSessionId, triggerEventId, model, fallbackModel, fallbackModels, systemPrompt, extendTools } = options;
1119
1173
  const taskIdGen = `process_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
1120
1174
  const sessionComponent = this.getSessionComponent();
1121
1175
  if (!sessionComponent) {
@@ -1174,6 +1228,10 @@ class BackgroundTaskManager {
1174
1228
  if (profile) {
1175
1229
  metadata.larkProfile = profile;
1176
1230
  }
1231
+ const channelType = replyChannel?.type;
1232
+ if (channelType) {
1233
+ metadata.channelType = channelType;
1234
+ }
1177
1235
  }
1178
1236
  if (triggerEventId) {
1179
1237
  metadata.triggerEventId = triggerEventId;
@@ -1188,6 +1246,7 @@ class BackgroundTaskManager {
1188
1246
  }
1189
1247
  }
1190
1248
  const replyChannelSnapshot = captureReplyChannelSnapshot();
1249
+ const pluginEnabledSnapshot = capturePluginEnabledSnapshot();
1191
1250
  const abortController = new AbortController;
1192
1251
  if (this.processRegistries.size >= this.maxProcessRegistries) {
1193
1252
  this.cleanupEmptyProcessRegistries();
@@ -1216,7 +1275,10 @@ class BackgroundTaskManager {
1216
1275
  model,
1217
1276
  fallbackModel,
1218
1277
  fallbackModels,
1219
- replyChannel: replyChannelSnapshot
1278
+ systemPrompt,
1279
+ extendTools,
1280
+ replyChannel: replyChannelSnapshot,
1281
+ pluginEnabledSnapshot
1220
1282
  };
1221
1283
  this.tasks.set(taskIdGen, task);
1222
1284
  this.abortControllers.set(taskIdGen, abortController);
@@ -1229,7 +1291,17 @@ class BackgroundTaskManager {
1229
1291
  startedAt: createdAt,
1230
1292
  timeoutMs: timeout || DEFAULT_TIMEOUT
1231
1293
  };
1232
- this.publishBackgroundEvent(BackgroundTaskEventTypes.STARTED, startedPayload, parentSessionId, triggerEventId, replyChannelSnapshot);
1294
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.STARTED, startedPayload, parentSessionId, triggerEventId, replyChannelSnapshot, task.pluginEnabledSnapshot);
1295
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.SESSION_STARTED, {
1296
+ backgroundTaskId: taskIdGen,
1297
+ subSessionId: subSession.id,
1298
+ parentSessionId,
1299
+ description,
1300
+ subagentType,
1301
+ associatedTaskId: undefined,
1302
+ lifecycle: "running",
1303
+ startedAt: createdAt
1304
+ }, parentSessionId, triggerEventId, replyChannelSnapshot, task.pluginEnabledSnapshot);
1233
1305
  this.executeTask(taskIdGen, prompt, timeout, parentSessionId).catch((err) => {
1234
1306
  logger3.error(`[BackgroundTaskManager] executeTask unhandled rejection`, {
1235
1307
  taskId: taskIdGen,
@@ -1273,6 +1345,16 @@ class BackgroundTaskManager {
1273
1345
  if (task.associatedTaskId === undefined) {
1274
1346
  task.associatedTaskId = getCurrentTaskId();
1275
1347
  }
1348
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.SESSION_STARTED, {
1349
+ backgroundTaskId: task.id,
1350
+ subSessionId: task.subSessionId,
1351
+ parentSessionId: parentSessionId || task.parentSessionId,
1352
+ description: task.description,
1353
+ subagentType: task.subagentType,
1354
+ associatedTaskId: task.associatedTaskId,
1355
+ lifecycle: "completed",
1356
+ executionTimeMs
1357
+ }, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1276
1358
  const completedPayload = {
1277
1359
  backgroundTaskId: task.id,
1278
1360
  subSessionId: task.subSessionId,
@@ -1283,7 +1365,7 @@ class BackgroundTaskManager {
1283
1365
  executionTimeMs,
1284
1366
  associatedTaskId: task.associatedTaskId
1285
1367
  };
1286
- this.publishBackgroundEvent(BackgroundTaskEventTypes.COMPLETED, completedPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel);
1368
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.COMPLETED, completedPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1287
1369
  logger3.info(`[BackgroundTaskManager] Task completed successfully`, {
1288
1370
  taskId,
1289
1371
  executionTimeMs
@@ -1320,11 +1402,11 @@ class BackgroundTaskManager {
1320
1402
  executionTimeMs,
1321
1403
  hints: [
1322
1404
  "请把上面的问题原样通过 ask_user tool 展示给用户并等待答复",
1323
- `得到用户回复后,通过 delegate_task(subagentType="${task.subagentType}", existingSubSessionId="${task.subSessionId}", prompt=<基于用户回复>) 复用 sub-session 让 sub-agent 继承之前消息历史继续推进,无需实现 resume function`
1405
+ `得到用户回复后,通过 delegate_task(subagent_type="${task.subagentType}", sub_session_id="${task.subSessionId}", prompt=<基于用户回复>) 复用 sub-session 让 sub-agent 继承之前消息历史继续推进,无需实现 resume function`
1324
1406
  ],
1325
1407
  associatedTaskId: task.associatedTaskId
1326
1408
  };
1327
- this.publishBackgroundEvent(BackgroundTaskEventTypes.ASK_USER, askUserPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel);
1409
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.ASK_USER, askUserPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1328
1410
  logger3.info(`[BackgroundTaskManager] Task awaiting user input (ask_user cascade)`, {
1329
1411
  taskId,
1330
1412
  subSessionId: task.subSessionId,
@@ -1346,7 +1428,17 @@ class BackgroundTaskManager {
1346
1428
  executionTimeMs,
1347
1429
  associatedTaskId: task.associatedTaskId
1348
1430
  };
1349
- this.publishBackgroundEvent(BackgroundTaskEventTypes.STOPPED, stoppedPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel);
1431
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.STOPPED, stoppedPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1432
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.SESSION_STARTED, {
1433
+ backgroundTaskId: task.id,
1434
+ subSessionId: task.subSessionId,
1435
+ parentSessionId: parentSessionId || task.parentSessionId,
1436
+ description: task.description,
1437
+ subagentType: task.subagentType,
1438
+ associatedTaskId: task.associatedTaskId,
1439
+ lifecycle: "stopped",
1440
+ executionTimeMs
1441
+ }, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1350
1442
  } else if (errorMessage.startsWith("Task execution timeout after")) {
1351
1443
  task.status = "timeout";
1352
1444
  const timeoutPayload = {
@@ -1359,7 +1451,17 @@ class BackgroundTaskManager {
1359
1451
  executionTimeMs,
1360
1452
  associatedTaskId: task.associatedTaskId
1361
1453
  };
1362
- this.publishBackgroundEvent(BackgroundTaskEventTypes.TIMEOUT, timeoutPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel);
1454
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.TIMEOUT, timeoutPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1455
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.SESSION_STARTED, {
1456
+ backgroundTaskId: task.id,
1457
+ subSessionId: task.subSessionId,
1458
+ parentSessionId: parentSessionId || task.parentSessionId,
1459
+ description: task.description,
1460
+ subagentType: task.subagentType,
1461
+ associatedTaskId: task.associatedTaskId,
1462
+ lifecycle: "timeout",
1463
+ executionTimeMs
1464
+ }, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1363
1465
  } else {
1364
1466
  task.status = "failed";
1365
1467
  const failedPayload = {
@@ -1371,7 +1473,17 @@ class BackgroundTaskManager {
1371
1473
  executionTimeMs,
1372
1474
  associatedTaskId: task.associatedTaskId
1373
1475
  };
1374
- this.publishBackgroundEvent(BackgroundTaskEventTypes.FAILED, failedPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel);
1476
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.FAILED, failedPayload, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1477
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.SESSION_STARTED, {
1478
+ backgroundTaskId: task.id,
1479
+ subSessionId: task.subSessionId,
1480
+ parentSessionId: parentSessionId || task.parentSessionId,
1481
+ description: task.description,
1482
+ subagentType: task.subagentType,
1483
+ associatedTaskId: task.associatedTaskId,
1484
+ lifecycle: "failed",
1485
+ executionTimeMs
1486
+ }, parentSessionId || task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1375
1487
  }
1376
1488
  task.error = errorMessage;
1377
1489
  logger3.error(`[BackgroundTaskManager] Task execution error`, {
@@ -1416,7 +1528,7 @@ class BackgroundTaskManager {
1416
1528
  startedAt: task.createdAt,
1417
1529
  timeoutMs: task.timeoutMs
1418
1530
  };
1419
- this.publishBackgroundEvent(BackgroundTaskEventTypes.PROGRESS, progressPayload, parentSessionId, task.triggerEventId, task.replyChannel);
1531
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.PROGRESS, progressPayload, parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1420
1532
  }, PROGRESS_INTERVAL);
1421
1533
  this.progressTimers.set(taskId, timer);
1422
1534
  }
@@ -1444,14 +1556,10 @@ class BackgroundTaskManager {
1444
1556
  const basePrompt = resolved?.basePrompt || subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
1445
1557
  const deniedTools = resolved?.deniedTools || subAgent?.deniedTools || [];
1446
1558
  const allowedTools = resolved?.allowedTools || subAgent?.allowedTools;
1447
- let fullPrompt = basePrompt.replace(/{task_description}/g, taskDescription || "N/A");
1448
- fullPrompt += `
1449
-
1450
- ---
1451
-
1452
- # Session Info
1559
+ let fullPrompt = `# Session Info
1453
1560
  - task_id: ${taskId || "N/A"}
1454
1561
  - session_id: ${sessionId}
1562
+ - task_description: ${taskDescription || "N/A"}
1455
1563
 
1456
1564
  ---
1457
1565
 
@@ -1552,6 +1660,15 @@ ${reuseSection.markdown}`;
1552
1660
  error: err instanceof Error ? err.message : String(err)
1553
1661
  });
1554
1662
  }
1663
+ const channelTypeHint = metadata.channelType ?? getEnvContext()?.replyChannel?.type;
1664
+ const channelHint = buildDelegateChannelHint(channelTypeHint);
1665
+ if (channelHint) {
1666
+ fullPrompt += `
1667
+
1668
+ ---
1669
+
1670
+ ${channelHint}`;
1671
+ }
1555
1672
  const subAgentForRegister = subAgent ? { ...subAgent, allowedTools } : allowedTools ? {
1556
1673
  id: subagentType,
1557
1674
  name: subagentType,
@@ -1640,7 +1757,9 @@ ${reuseSection.markdown}`;
1640
1757
  runId: capturedRunId,
1641
1758
  ...inheritedModel ? { model: inheritedModel } : {},
1642
1759
  ...inheritedFallbackModel ? { fallbackModel: inheritedFallbackModel } : {},
1643
- ...Array.isArray(inheritedFallbackModels) ? { fallbackModels: inheritedFallbackModels } : {}
1760
+ ...Array.isArray(inheritedFallbackModels) ? { fallbackModels: inheritedFallbackModels } : {},
1761
+ ...task?.systemPrompt ? { metadata: { systemPrompt: task.systemPrompt } } : {},
1762
+ ...task?.extendTools?.length ? { extendTools: task.extendTools } : {}
1644
1763
  });
1645
1764
  };
1646
1765
  const wrappedPromise = processRegistry ? runWithProcessRegistryAsync(processRegistry, () => runWithBgTaskIdAsync(bgTaskId, () => invokeHandleQuery())) : runWithBgTaskIdAsync(bgTaskId, () => invokeHandleQuery());
@@ -1718,7 +1837,7 @@ ${reuseSection.markdown}`;
1718
1837
  executionTimeMs: task.startedAt ? task.completedAt - task.startedAt : 0,
1719
1838
  associatedTaskId: task.associatedTaskId
1720
1839
  };
1721
- this.publishBackgroundEvent(BackgroundTaskEventTypes.STOPPED, stoppedPayload, task.parentSessionId, task.triggerEventId, task.replyChannel);
1840
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.STOPPED, stoppedPayload, task.parentSessionId, task.triggerEventId, task.replyChannel, task.pluginEnabledSnapshot);
1722
1841
  this.finalizeTask(taskId, "stopped");
1723
1842
  return {
1724
1843
  success: true,
@@ -1828,7 +1947,7 @@ ${reuseSection.markdown}`;
1828
1947
  executionTimeMs: taskSafe.startedAt && taskSafe.completedAt ? taskSafe.completedAt - taskSafe.startedAt : 0,
1829
1948
  associatedTaskId: taskSafe.associatedTaskId
1830
1949
  };
1831
- this.publishBackgroundEvent(BackgroundTaskEventTypes.STOPPED, stoppedPayload, taskSafe.parentSessionId, taskSafe.triggerEventId, taskSafe.replyChannel);
1950
+ this.publishBackgroundEvent(BackgroundTaskEventTypes.STOPPED, stoppedPayload, taskSafe.parentSessionId, taskSafe.triggerEventId, taskSafe.replyChannel, taskSafe.pluginEnabledSnapshot);
1832
1951
  }
1833
1952
  }
1834
1953
  }
@@ -2056,7 +2175,7 @@ No need to poll — just wait for the notification and use \`task_get\` with the
2056
2175
  };
2057
2176
  await globalHookManager.execute(TaskHookPoints.DELEGATE_BEFORE, delegateCtx, { sessionId: parentSessionId });
2058
2177
  promptWithTaskInfo = delegateCtx.prompt;
2059
- return await handleBackgroundTask(backgroundTaskManager, parentSessionId, description, promptWithTaskInfo, delegateCtx.subagentType, delegateCtx.timeout, similar_task_ids, params.sub_session_id, resolvedTriggerEventId, ctx.model, ctx.fallbackModel, ctx.fallbackModels);
2178
+ return await handleBackgroundTask(backgroundTaskManager, parentSessionId, description, promptWithTaskInfo, delegateCtx.subagentType, delegateCtx.timeout, similar_task_ids, params.sub_session_id, resolvedTriggerEventId, ctx.model, ctx.fallbackModel, ctx.fallbackModels, ctx.metadata?.systemPrompt, normalizeExtendTools(ctx.metadata?.extendTools));
2060
2179
  }
2061
2180
  };
2062
2181
  tool.execute = wrapFunction(tool.execute, "delegate.execute", {
@@ -2100,7 +2219,19 @@ function _captureReplyChannelSnapshot() {
2100
2219
  };
2101
2220
  }
2102
2221
  var captureReplyChannelSnapshot = wrapFunction(_captureReplyChannelSnapshot, "delegate.captureReplyChannel", { recordParams: false, recordResult: true, recordError: true });
2103
- async function handleBackgroundTask(backgroundTaskManager, parentSessionId, description, prompt, subagentType, timeout, similarTaskIds, existingSubSessionId, triggerEventId, model, fallbackModel, fallbackModels) {
2222
+ function _capturePluginEnabledSnapshot() {
2223
+ const pluginEnabled = getEnvContext()?.pluginEnabled;
2224
+ if (!pluginEnabled)
2225
+ return;
2226
+ if (typeof pluginEnabled !== "object")
2227
+ return;
2228
+ const keys = Object.keys(pluginEnabled);
2229
+ if (keys.length === 0)
2230
+ return;
2231
+ return { ...pluginEnabled };
2232
+ }
2233
+ var capturePluginEnabledSnapshot = wrapFunction(_capturePluginEnabledSnapshot, "delegate.capturePluginEnabled", { recordParams: false, recordResult: true, recordError: true });
2234
+ async function handleBackgroundTask(backgroundTaskManager, parentSessionId, description, prompt, subagentType, timeout, similarTaskIds, existingSubSessionId, triggerEventId, model, fallbackModel, fallbackModels, systemPrompt, extendTools) {
2104
2235
  const startTime = Date.now();
2105
2236
  try {
2106
2237
  let actualSubagentType = subagentType;
@@ -2129,7 +2260,9 @@ async function handleBackgroundTask(backgroundTaskManager, parentSessionId, desc
2129
2260
  triggerEventId,
2130
2261
  model,
2131
2262
  fallbackModel,
2132
- fallbackModels
2263
+ fallbackModels,
2264
+ systemPrompt,
2265
+ extendTools
2133
2266
  });
2134
2267
  const output = [
2135
2268
  `✅ Background task accepted`,
@@ -2139,6 +2272,8 @@ async function handleBackgroundTask(backgroundTaskManager, parentSessionId, desc
2139
2272
  `\uD83E\uDD16 Sub-agent: ${actualSubagentType}${originalWorkflowName ? ` (workflow: ${originalWorkflowName})` : ""}`,
2140
2273
  `⏱️ Timeout: ${(timeout || DEFAULT_TIMEOUT) / 1000}s`,
2141
2274
  "",
2275
+ `\uD83D\uDD17 Sub-session: ${subSessionId} (续跑本任务:delegate_task(sub_session_id="${subSessionId}", prompt="..."))`,
2276
+ "",
2142
2277
  `Use stop_task with task_id="${bgProcessId}" to cancel this task.`
2143
2278
  ].join(`
2144
2279
  `);
@@ -2162,4 +2297,4 @@ async function handleBackgroundTask(backgroundTaskManager, parentSessionId, desc
2162
2297
  };
2163
2298
  }
2164
2299
  }
2165
- export { BackgroundTaskEventTypes, builtInSubAgents, getSubAgentSpec, DelegateToolParameters, buildEntryAgentPrompt, WORKFLOW_COMPAT_ALIASES, DEFAULT_TIMEOUT, PROGRESS_INTERVAL, BackgroundTaskManager, createDelegateTool, deriveTriggerEventIdFromEnvContext, captureReplyChannelSnapshot, handleBackgroundTask };
2300
+ export { BackgroundTaskEventTypes, builtInSubAgents, getSubAgentSpec, normalizeExtendTools, DelegateToolParameters, buildEntryAgentPrompt, WORKFLOW_COMPAT_ALIASES, DEFAULT_TIMEOUT, PROGRESS_INTERVAL, BackgroundTaskManager, createDelegateTool, deriveTriggerEventIdFromEnvContext, captureReplyChannelSnapshot, capturePluginEnabledSnapshot, handleBackgroundTask };
@@ -4,7 +4,7 @@ import {
4
4
  } from "./roy-agent-core-rvv6ydff.js";
5
5
  import {
6
6
  BaseComponent
7
- } from "./roy-agent-core-pgvcf91v.js";
7
+ } from "./roy-agent-core-m39v7qpx.js";
8
8
  import {
9
9
  __require
10
10
  } from "./roy-agent-core-fs0mn2jk.js";
@@ -3,17 +3,17 @@ import {
3
3
  } from "./roy-agent-core-az13yzmc.js";
4
4
  import {
5
5
  BaseComponent
6
- } from "./roy-agent-core-pgvcf91v.js";
6
+ } from "./roy-agent-core-m39v7qpx.js";
7
7
  import {
8
8
  globalHookManager,
9
9
  init_global_hook_manager
10
- } from "./roy-agent-core-cpcd24n2.js";
10
+ } from "./roy-agent-core-yet36q5k.js";
11
11
  import {
12
12
  init_context
13
- } from "./roy-agent-core-qqaak24r.js";
13
+ } from "./roy-agent-core-tkpp1ba0.js";
14
14
  import {
15
15
  getEnvContextOrEmpty
16
- } from "./roy-agent-core-7cbpmk4q.js";
16
+ } from "./roy-agent-core-p31ftgq9.js";
17
17
  import {
18
18
  createLogger,
19
19
  init_logger
@@ -0,0 +1,134 @@
1
+ // src/config/config-protection.ts
2
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, appendFileSync, rmSync, chmodSync } from "fs";
3
+ import { join } from "path";
4
+ var PROTECTED_CONFIG_FILES = [
5
+ "config.jsonc",
6
+ "auth.json",
7
+ "event-sources.json",
8
+ "wecom-credentials.json"
9
+ ];
10
+ var SNAPSHOT_KEEP = 10;
11
+ var SNAPSHOTS_DIRNAME = "snapshots";
12
+ var AUDIT_LOG_FILENAME = "audit.log";
13
+ var SNAP_META_FILENAME = ".snapshot-meta.json";
14
+ var SNAPSHOT_DIR_MODE = 448;
15
+ var SNAPSHOT_FILE_MODE = 384;
16
+ function pad2(n) {
17
+ return String(n).padStart(2, "0");
18
+ }
19
+ function snapshotTimestamp(d = new Date) {
20
+ return d.getUTCFullYear() + pad2(d.getUTCMonth() + 1) + pad2(d.getUTCDate()) + "T" + pad2(d.getUTCHours()) + "-" + pad2(d.getUTCMinutes()) + "-" + pad2(d.getUTCSeconds()) + "-" + String(d.getUTCMilliseconds()).padStart(3, "0") + "Z";
21
+ }
22
+ function snapshotsDir(configDir) {
23
+ return join(configDir, SNAPSHOTS_DIRNAME);
24
+ }
25
+ function snapshotConfigDir(configDir, now = new Date) {
26
+ if (!existsSync(configDir))
27
+ return null;
28
+ const snapRoot = snapshotsDir(configDir);
29
+ mkdirSync(snapRoot, { recursive: true });
30
+ const ts = snapshotTimestamp(now);
31
+ const snapDir = join(snapRoot, ts);
32
+ mkdirSync(snapDir, { recursive: true, mode: SNAPSHOT_DIR_MODE });
33
+ try {
34
+ chmodSync(snapDir, SNAPSHOT_DIR_MODE);
35
+ } catch {}
36
+ for (const file of PROTECTED_CONFIG_FILES) {
37
+ const src = join(configDir, file);
38
+ if (!existsSync(src))
39
+ continue;
40
+ try {
41
+ writeFileSync(join(snapDir, file), readFileSync(src), { mode: SNAPSHOT_FILE_MODE });
42
+ } catch {}
43
+ }
44
+ writeFileSync(join(snapDir, SNAP_META_FILENAME), JSON.stringify({ ts: now.toISOString(), source: configDir, pid: process.pid }));
45
+ pruneSnapshots(snapRoot, SNAPSHOT_KEEP);
46
+ return snapDir;
47
+ }
48
+ function pruneSnapshots(snapRoot, keep) {
49
+ const all = readdirSync(snapRoot).filter((n) => !n.startsWith(".")).sort();
50
+ const excess = all.length - keep;
51
+ for (let i = 0;i < excess; i++) {
52
+ try {
53
+ rmSync(join(snapRoot, all[i]), { recursive: true, force: true });
54
+ } catch {}
55
+ }
56
+ }
57
+ function appendAuditLog(configDir, entry) {
58
+ try {
59
+ const full = {
60
+ ts: new Date().toISOString(),
61
+ pid: process.pid,
62
+ ...entry
63
+ };
64
+ appendFileSync(join(configDir, AUDIT_LOG_FILENAME), JSON.stringify(full) + `
65
+ `);
66
+ } catch {}
67
+ }
68
+ function readAuditLog(configDir) {
69
+ const p = join(configDir, AUDIT_LOG_FILENAME);
70
+ if (!existsSync(p))
71
+ return [];
72
+ const out = [];
73
+ for (const line of readFileSync(p, "utf-8").split(`
74
+ `)) {
75
+ if (!line.trim())
76
+ continue;
77
+ try {
78
+ out.push(JSON.parse(line));
79
+ } catch {}
80
+ }
81
+ return out;
82
+ }
83
+ function checkSourceCountDrop(previousCount, newCount) {
84
+ if (previousCount <= 0)
85
+ return { allowed: true };
86
+ if (newCount >= previousCount)
87
+ return { allowed: true };
88
+ const dropRatio = (previousCount - newCount) / previousCount;
89
+ if (dropRatio > 0.3) {
90
+ return {
91
+ allowed: false,
92
+ reason: `source count drop ${(dropRatio * 100).toFixed(0)}% (${previousCount} -> ${newCount}) exceeds 30% threshold; refusing to overwrite (ROY_AGENT_ES_FORCE_SAVE=1 to override)`
93
+ };
94
+ }
95
+ return { allowed: true };
96
+ }
97
+ function readSourceCountFromDisk(configPath) {
98
+ try {
99
+ if (!existsSync(configPath))
100
+ return -1;
101
+ const cfg = JSON.parse(readFileSync(configPath, "utf-8"));
102
+ if (!cfg || !Array.isArray(cfg.sources))
103
+ return -1;
104
+ return cfg.sources.length;
105
+ } catch {
106
+ return -1;
107
+ }
108
+ }
109
+ function guardConfigWrite(configDir, file, writeFn) {
110
+ try {
111
+ const snapDir = snapshotConfigDir(configDir);
112
+ if (snapDir) {
113
+ appendAuditLog(configDir, {
114
+ file,
115
+ action: "pre-save-snapshot",
116
+ detail: `snapshot=${snapDir}`
117
+ });
118
+ }
119
+ } catch {}
120
+ try {
121
+ writeFn();
122
+ } catch (err) {
123
+ appendAuditLog(configDir, {
124
+ file,
125
+ action: "write-failed",
126
+ detail: err?.message ?? String(err)
127
+ });
128
+ return false;
129
+ }
130
+ appendAuditLog(configDir, { file, action: "save" });
131
+ return true;
132
+ }
133
+
134
+ export { PROTECTED_CONFIG_FILES, snapshotConfigDir, appendAuditLog, readAuditLog, checkSourceCountDrop, readSourceCountFromDisk, guardConfigWrite };
@@ -6,7 +6,7 @@ import {
6
6
  } from "./roy-agent-core-7hh0brvs.js";
7
7
  import {
8
8
  BaseComponent
9
- } from "./roy-agent-core-pgvcf91v.js";
9
+ } from "./roy-agent-core-m39v7qpx.js";
10
10
  import {
11
11
  createLogger,
12
12
  init_logger