@downcity/agent 1.1.7 → 1.1.8

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 (274) hide show
  1. package/bin/agent/AgentContext.d.ts.map +1 -1
  2. package/bin/agent/AgentContext.js +1 -0
  3. package/bin/agent/AgentContext.js.map +1 -1
  4. package/bin/agent/AgentContextTypes.d.ts +5 -1
  5. package/bin/agent/AgentContextTypes.d.ts.map +1 -1
  6. package/bin/agent/AgentRuntime.d.ts +6 -1
  7. package/bin/agent/AgentRuntime.d.ts.map +1 -1
  8. package/bin/agent/AgentRuntime.js +22 -3
  9. package/bin/agent/AgentRuntime.js.map +1 -1
  10. package/bin/agent/AgentRuntimeState.d.ts.map +1 -1
  11. package/bin/agent/AgentRuntimeState.js +58 -2
  12. package/bin/agent/AgentRuntimeState.js.map +1 -1
  13. package/bin/agent/AgentRuntimeTypes.d.ts +5 -1
  14. package/bin/agent/AgentRuntimeTypes.d.ts.map +1 -1
  15. package/bin/agent/project/AgentInitializer.d.ts +3 -2
  16. package/bin/agent/project/AgentInitializer.d.ts.map +1 -1
  17. package/bin/agent/project/AgentInitializer.js +34 -44
  18. package/bin/agent/project/AgentInitializer.js.map +1 -1
  19. package/bin/config/Config.d.ts.map +1 -1
  20. package/bin/config/Config.js +2 -21
  21. package/bin/config/Config.js.map +1 -1
  22. package/bin/config/Paths.d.ts +1 -5
  23. package/bin/config/Paths.d.ts.map +1 -1
  24. package/bin/config/Paths.js +2 -8
  25. package/bin/config/Paths.js.map +1 -1
  26. package/bin/host/daemon/ProjectSetup.d.ts +2 -1
  27. package/bin/host/daemon/ProjectSetup.d.ts.map +1 -1
  28. package/bin/host/daemon/ProjectSetup.js +14 -21
  29. package/bin/host/daemon/ProjectSetup.js.map +1 -1
  30. package/bin/host/runtime/AgentHostRuntime.d.ts.map +1 -1
  31. package/bin/host/runtime/AgentHostRuntime.js +1 -2
  32. package/bin/host/runtime/AgentHostRuntime.js.map +1 -1
  33. package/bin/host/runtime/CityPaths.d.ts +0 -3
  34. package/bin/host/runtime/CityPaths.d.ts.map +1 -1
  35. package/bin/host/runtime/CityPaths.js +0 -3
  36. package/bin/host/runtime/CityPaths.js.map +1 -1
  37. package/bin/host/sdk/Agent.d.ts +1 -0
  38. package/bin/host/sdk/Agent.d.ts.map +1 -1
  39. package/bin/host/sdk/Agent.js +24 -2
  40. package/bin/host/sdk/Agent.js.map +1 -1
  41. package/bin/host/sdk/AgentSdkTypes.d.ts +9 -0
  42. package/bin/host/sdk/AgentSdkTypes.d.ts.map +1 -1
  43. package/bin/http/Server.d.ts.map +1 -1
  44. package/bin/http/Server.js +1 -11
  45. package/bin/http/Server.js.map +1 -1
  46. package/bin/http/auth/AuthEnv.d.ts +0 -9
  47. package/bin/http/auth/AuthEnv.d.ts.map +1 -1
  48. package/bin/http/auth/AuthEnv.js +0 -9
  49. package/bin/http/auth/AuthEnv.js.map +1 -1
  50. package/bin/http/auth/CliAuthStateStore.d.ts +0 -4
  51. package/bin/http/auth/CliAuthStateStore.d.ts.map +1 -1
  52. package/bin/http/auth/CliAuthStateStore.js +0 -4
  53. package/bin/http/auth/CliAuthStateStore.js.map +1 -1
  54. package/bin/http/control/ModelRoutes.d.ts.map +1 -1
  55. package/bin/http/control/ModelRoutes.js +3 -8
  56. package/bin/http/control/ModelRoutes.js.map +1 -1
  57. package/bin/index.d.ts +2 -6
  58. package/bin/index.d.ts.map +1 -1
  59. package/bin/index.js +2 -6
  60. package/bin/index.js.map +1 -1
  61. package/bin/model/CreateModel.d.ts +2 -2
  62. package/bin/model/CreateModel.d.ts.map +1 -1
  63. package/bin/model/CreateModel.js +13 -12
  64. package/bin/model/CreateModel.js.map +1 -1
  65. package/bin/plugin/Activation.d.ts +4 -0
  66. package/bin/plugin/Activation.d.ts.map +1 -1
  67. package/bin/plugin/Activation.js +2 -2
  68. package/bin/plugin/Activation.js.map +1 -1
  69. package/bin/plugin/LocalExecution.d.ts.map +1 -1
  70. package/bin/plugin/LocalExecution.js +23 -2
  71. package/bin/plugin/LocalExecution.js.map +1 -1
  72. package/bin/plugin/PluginRegistry.js +2 -2
  73. package/bin/plugin/PluginRegistry.js.map +1 -1
  74. package/bin/plugins/asr/Plugin.d.ts.map +1 -1
  75. package/bin/plugins/asr/Plugin.js +4 -5
  76. package/bin/plugins/asr/Plugin.js.map +1 -1
  77. package/bin/plugins/auth/Plugin.d.ts.map +1 -1
  78. package/bin/plugins/auth/Plugin.js +1 -0
  79. package/bin/plugins/auth/Plugin.js.map +1 -1
  80. package/bin/plugins/auth/runtime/AuthorizationConfig.d.ts +4 -4
  81. package/bin/plugins/auth/runtime/AuthorizationConfig.d.ts.map +1 -1
  82. package/bin/plugins/auth/runtime/AuthorizationConfig.js +28 -26
  83. package/bin/plugins/auth/runtime/AuthorizationConfig.js.map +1 -1
  84. package/bin/plugins/auth/runtime/AuthorizationPolicy.d.ts +2 -0
  85. package/bin/plugins/auth/runtime/AuthorizationPolicy.d.ts.map +1 -1
  86. package/bin/plugins/auth/runtime/AuthorizationPolicy.js +3 -2
  87. package/bin/plugins/auth/runtime/AuthorizationPolicy.js.map +1 -1
  88. package/bin/plugins/auth/runtime/AuthorizationStore.d.ts +1 -1
  89. package/bin/plugins/auth/runtime/AuthorizationStore.d.ts.map +1 -1
  90. package/bin/plugins/auth/runtime/AuthorizationStore.js +3 -4
  91. package/bin/plugins/auth/runtime/AuthorizationStore.js.map +1 -1
  92. package/bin/plugins/skill/Plugin.js +2 -2
  93. package/bin/plugins/skill/Plugin.js.map +1 -1
  94. package/bin/plugins/tts/Plugin.d.ts.map +1 -1
  95. package/bin/plugins/tts/Plugin.js +4 -5
  96. package/bin/plugins/tts/Plugin.js.map +1 -1
  97. package/bin/plugins/web/Plugin.d.ts.map +1 -1
  98. package/bin/plugins/web/Plugin.js +4 -5
  99. package/bin/plugins/web/Plugin.js.map +1 -1
  100. package/bin/plugins/workboard/Plugin.js +2 -2
  101. package/bin/plugins/workboard/Plugin.js.map +1 -1
  102. package/bin/service/builtins/chat/accounts/ChannelAccountService.d.ts +4 -1
  103. package/bin/service/builtins/chat/accounts/ChannelAccountService.d.ts.map +1 -1
  104. package/bin/service/builtins/chat/accounts/ChannelAccountService.js +64 -91
  105. package/bin/service/builtins/chat/accounts/ChannelAccountService.js.map +1 -1
  106. package/bin/service/builtins/chat/runtime/ChatChannelActions.d.ts.map +1 -1
  107. package/bin/service/builtins/chat/runtime/ChatChannelActions.js +11 -18
  108. package/bin/service/builtins/chat/runtime/ChatChannelActions.js.map +1 -1
  109. package/bin/service/builtins/chat/runtime/ChatChannelCore.d.ts +1 -1
  110. package/bin/service/builtins/chat/runtime/ChatChannelCore.d.ts.map +1 -1
  111. package/bin/service/builtins/chat/runtime/ChatChannelCore.js +9 -17
  112. package/bin/service/builtins/chat/runtime/ChatChannelCore.js.map +1 -1
  113. package/bin/service/builtins/memory/Action.d.ts +1 -5
  114. package/bin/service/builtins/memory/Action.d.ts.map +1 -1
  115. package/bin/service/builtins/memory/Action.js +4 -42
  116. package/bin/service/builtins/memory/Action.js.map +1 -1
  117. package/bin/service/builtins/memory/MemoryService.d.ts.map +1 -1
  118. package/bin/service/builtins/memory/MemoryService.js +2 -32
  119. package/bin/service/builtins/memory/MemoryService.js.map +1 -1
  120. package/bin/service/builtins/memory/runtime/Search.d.ts +7 -3
  121. package/bin/service/builtins/memory/runtime/Search.d.ts.map +1 -1
  122. package/bin/service/builtins/memory/runtime/Search.js +220 -16
  123. package/bin/service/builtins/memory/runtime/Search.js.map +1 -1
  124. package/bin/service/builtins/memory/runtime/Store.d.ts +9 -50
  125. package/bin/service/builtins/memory/runtime/Store.d.ts.map +1 -1
  126. package/bin/service/builtins/memory/runtime/Store.js +10 -130
  127. package/bin/service/builtins/memory/runtime/Store.js.map +1 -1
  128. package/bin/service/builtins/memory/runtime/Writer.d.ts.map +1 -1
  129. package/bin/service/builtins/memory/runtime/Writer.js +1 -2
  130. package/bin/service/builtins/memory/runtime/Writer.js.map +1 -1
  131. package/bin/service/builtins/memory/types/Memory.d.ts +3 -57
  132. package/bin/service/builtins/memory/types/Memory.d.ts.map +1 -1
  133. package/bin/service/schedule/Store.d.ts +22 -25
  134. package/bin/service/schedule/Store.d.ts.map +1 -1
  135. package/bin/service/schedule/Store.js +172 -154
  136. package/bin/service/schedule/Store.js.map +1 -1
  137. package/bin/session/composer/system/default/SystemDomain.d.ts.map +1 -1
  138. package/bin/session/composer/system/default/SystemDomain.js +1 -0
  139. package/bin/session/composer/system/default/SystemDomain.js.map +1 -1
  140. package/bin/shared/types/AgentHost.d.ts +120 -4
  141. package/bin/shared/types/AgentHost.d.ts.map +1 -1
  142. package/bin/shared/types/Plugin.d.ts +5 -1
  143. package/bin/shared/types/Plugin.d.ts.map +1 -1
  144. package/package.json +1 -4
  145. package/src/agent/AgentContext.ts +1 -0
  146. package/src/agent/AgentContextTypes.ts +5 -0
  147. package/src/agent/AgentRuntime.ts +32 -3
  148. package/src/agent/AgentRuntimeState.ts +66 -2
  149. package/src/agent/AgentRuntimeTypes.ts +5 -0
  150. package/src/agent/project/AgentInitializer.ts +40 -42
  151. package/src/config/Config.ts +2 -17
  152. package/src/config/Paths.ts +2 -9
  153. package/src/host/daemon/ProjectSetup.ts +19 -21
  154. package/src/host/runtime/AgentHostRuntime.ts +0 -2
  155. package/src/host/runtime/CityPaths.ts +0 -3
  156. package/src/host/sdk/Agent.ts +26 -2
  157. package/src/host/sdk/AgentSdkTypes.ts +10 -0
  158. package/src/http/Server.ts +0 -13
  159. package/src/http/auth/AuthEnv.ts +0 -9
  160. package/src/http/auth/CliAuthStateStore.ts +0 -4
  161. package/src/http/control/ModelRoutes.ts +3 -9
  162. package/src/index.ts +2 -12
  163. package/src/model/CreateModel.ts +15 -13
  164. package/src/plugin/Activation.ts +6 -2
  165. package/src/plugin/LocalExecution.ts +24 -2
  166. package/src/plugin/PluginRegistry.ts +2 -2
  167. package/src/plugins/asr/Plugin.ts +4 -5
  168. package/src/plugins/auth/Plugin.ts +1 -0
  169. package/src/plugins/auth/runtime/AuthorizationConfig.ts +47 -37
  170. package/src/plugins/auth/runtime/AuthorizationPolicy.ts +5 -2
  171. package/src/plugins/auth/runtime/AuthorizationStore.ts +6 -5
  172. package/src/plugins/skill/Plugin.ts +2 -2
  173. package/src/plugins/tts/Plugin.ts +4 -5
  174. package/src/plugins/web/Plugin.ts +4 -5
  175. package/src/plugins/workboard/Plugin.ts +2 -2
  176. package/src/service/builtins/chat/accounts/ChannelAccountService.ts +42 -62
  177. package/src/service/builtins/chat/runtime/ChatChannelActions.ts +12 -18
  178. package/src/service/builtins/chat/runtime/ChatChannelCore.ts +9 -14
  179. package/src/service/builtins/memory/Action.ts +6 -47
  180. package/src/service/builtins/memory/MemoryService.ts +1 -33
  181. package/src/service/builtins/memory/runtime/Search.ts +256 -16
  182. package/src/service/builtins/memory/runtime/Store.ts +13 -185
  183. package/src/service/builtins/memory/runtime/Writer.ts +1 -2
  184. package/src/service/builtins/memory/types/Memory.ts +2 -59
  185. package/src/service/schedule/Store.ts +215 -175
  186. package/src/session/composer/system/default/SystemDomain.ts +1 -0
  187. package/src/shared/types/AgentHost.ts +138 -4
  188. package/src/shared/types/Plugin.ts +5 -0
  189. package/tsconfig.tsbuildinfo +1 -1
  190. package/bin/http/auth/AuthMiddleware.d.ts +0 -36
  191. package/bin/http/auth/AuthMiddleware.d.ts.map +0 -1
  192. package/bin/http/auth/AuthMiddleware.js +0 -37
  193. package/bin/http/auth/AuthMiddleware.js.map +0 -1
  194. package/bin/http/auth/AuthRoutes.d.ts +0 -17
  195. package/bin/http/auth/AuthRoutes.d.ts.map +0 -1
  196. package/bin/http/auth/AuthRoutes.js +0 -78
  197. package/bin/http/auth/AuthRoutes.js.map +0 -1
  198. package/bin/http/auth/AuthService.d.ts +0 -119
  199. package/bin/http/auth/AuthService.d.ts.map +0 -1
  200. package/bin/http/auth/AuthService.js +0 -307
  201. package/bin/http/auth/AuthService.js.map +0 -1
  202. package/bin/http/auth/AuthStore.d.ts +0 -165
  203. package/bin/http/auth/AuthStore.d.ts.map +0 -1
  204. package/bin/http/auth/AuthStore.js +0 -442
  205. package/bin/http/auth/AuthStore.js.map +0 -1
  206. package/bin/http/auth/RoutePolicy.d.ts +0 -30
  207. package/bin/http/auth/RoutePolicy.d.ts.map +0 -1
  208. package/bin/http/auth/RoutePolicy.js +0 -229
  209. package/bin/http/auth/RoutePolicy.js.map +0 -1
  210. package/bin/plugin/Lifecycle.d.ts +0 -33
  211. package/bin/plugin/Lifecycle.d.ts.map +0 -1
  212. package/bin/plugin/Lifecycle.js +0 -102
  213. package/bin/plugin/Lifecycle.js.map +0 -1
  214. package/bin/service/builtins/memory/runtime/Indexer.d.ts +0 -71
  215. package/bin/service/builtins/memory/runtime/Indexer.d.ts.map +0 -1
  216. package/bin/service/builtins/memory/runtime/Indexer.js +0 -345
  217. package/bin/service/builtins/memory/runtime/Indexer.js.map +0 -1
  218. package/bin/service/schedule/Schema.d.ts +0 -171
  219. package/bin/service/schedule/Schema.d.ts.map +0 -1
  220. package/bin/service/schedule/Schema.js +0 -26
  221. package/bin/service/schedule/Schema.js.map +0 -1
  222. package/bin/shared/utils/store/StoreChannelAccountRepository.d.ts +0 -34
  223. package/bin/shared/utils/store/StoreChannelAccountRepository.d.ts.map +0 -1
  224. package/bin/shared/utils/store/StoreChannelAccountRepository.js +0 -198
  225. package/bin/shared/utils/store/StoreChannelAccountRepository.js.map +0 -1
  226. package/bin/shared/utils/store/StoreEnvRepository.d.ts +0 -98
  227. package/bin/shared/utils/store/StoreEnvRepository.d.ts.map +0 -1
  228. package/bin/shared/utils/store/StoreEnvRepository.js +0 -334
  229. package/bin/shared/utils/store/StoreEnvRepository.js.map +0 -1
  230. package/bin/shared/utils/store/StoreModelRepository.d.ts +0 -61
  231. package/bin/shared/utils/store/StoreModelRepository.d.ts.map +0 -1
  232. package/bin/shared/utils/store/StoreModelRepository.js +0 -278
  233. package/bin/shared/utils/store/StoreModelRepository.js.map +0 -1
  234. package/bin/shared/utils/store/StoreSchema.d.ts +0 -13
  235. package/bin/shared/utils/store/StoreSchema.d.ts.map +0 -1
  236. package/bin/shared/utils/store/StoreSchema.js +0 -319
  237. package/bin/shared/utils/store/StoreSchema.js.map +0 -1
  238. package/bin/shared/utils/store/StoreSecureSettings.d.ts +0 -33
  239. package/bin/shared/utils/store/StoreSecureSettings.d.ts.map +0 -1
  240. package/bin/shared/utils/store/StoreSecureSettings.js +0 -91
  241. package/bin/shared/utils/store/StoreSecureSettings.js.map +0 -1
  242. package/bin/shared/utils/store/StoreShared.d.ts +0 -44
  243. package/bin/shared/utils/store/StoreShared.d.ts.map +0 -1
  244. package/bin/shared/utils/store/StoreShared.js +0 -40
  245. package/bin/shared/utils/store/StoreShared.js.map +0 -1
  246. package/bin/shared/utils/store/crypto.d.ts +0 -24
  247. package/bin/shared/utils/store/crypto.d.ts.map +0 -1
  248. package/bin/shared/utils/store/crypto.js +0 -101
  249. package/bin/shared/utils/store/crypto.js.map +0 -1
  250. package/bin/shared/utils/store/index.d.ts +0 -230
  251. package/bin/shared/utils/store/index.d.ts.map +0 -1
  252. package/bin/shared/utils/store/index.js +0 -360
  253. package/bin/shared/utils/store/index.js.map +0 -1
  254. package/bin/shared/utils/store/schema.d.ts +0 -690
  255. package/bin/shared/utils/store/schema.d.ts.map +0 -1
  256. package/bin/shared/utils/store/schema.js +0 -81
  257. package/bin/shared/utils/store/schema.js.map +0 -1
  258. package/src/http/auth/AuthMiddleware.ts +0 -61
  259. package/src/http/auth/AuthRoutes.ts +0 -100
  260. package/src/http/auth/AuthService.ts +0 -367
  261. package/src/http/auth/AuthStore.ts +0 -572
  262. package/src/http/auth/RoutePolicy.ts +0 -255
  263. package/src/plugin/Lifecycle.ts +0 -116
  264. package/src/service/builtins/memory/runtime/Indexer.ts +0 -466
  265. package/src/service/schedule/Schema.ts +0 -34
  266. package/src/shared/utils/store/StoreChannelAccountRepository.ts +0 -269
  267. package/src/shared/utils/store/StoreEnvRepository.ts +0 -452
  268. package/src/shared/utils/store/StoreModelRepository.ts +0 -324
  269. package/src/shared/utils/store/StoreSchema.ts +0 -344
  270. package/src/shared/utils/store/StoreSecureSettings.ts +0 -126
  271. package/src/shared/utils/store/StoreShared.ts +0 -67
  272. package/src/shared/utils/store/crypto.ts +0 -112
  273. package/src/shared/utils/store/index.ts +0 -497
  274. package/src/shared/utils/store/schema.ts +0 -103
@@ -2,16 +2,13 @@
2
2
  * Service Schedule 持久化存储。
3
3
  *
4
4
  * 关键点(中文)
5
- * - 使用项目内 SQLite 持久化 one-shot service action 调度任务。
6
- * - 当前模块只维护“当前状态”,不维护额外审计事件流。
5
+ * - 调度任务改为使用项目内 `jsonl` 事件流持久化,不再依赖 SQLite。
6
+ * - 这里采用“全量重放 + 内存归并”的最简实现,保持职责清晰且易于迁移。
7
+ * - 文件只记录状态事件;对外仍暴露稳定的调度任务查询与状态更新接口。
7
8
  */
8
9
 
9
10
  import fs from "fs-extra";
10
- import Database from "better-sqlite3";
11
11
  import path from "node:path";
12
- import { and, asc, desc, eq, inArray, lte } from "drizzle-orm";
13
- import { drizzle } from "drizzle-orm/better-sqlite3";
14
- import { scheduledJobsTable } from "./Schema.js";
15
12
  import type {
16
13
  CreateScheduledJobInput,
17
14
  ScheduledJobRecord,
@@ -21,80 +18,137 @@ import type { JsonValue } from "@/shared/types/Json.js";
21
18
  import { generateId } from "@shared/utils/Id.js";
22
19
  import { getDowncityScheduleDbPath } from "@/config/Paths.js";
23
20
 
24
- type ScheduledJobRow = typeof scheduledJobsTable.$inferSelect;
21
+ type ScheduledJobEvent =
22
+ | {
23
+ /**
24
+ * 事件版本号。
25
+ */
26
+ v: 1;
27
+ /**
28
+ * 事件类型:创建任务。
29
+ */
30
+ type: "created";
31
+ /**
32
+ * 调度任务快照。
33
+ */
34
+ job: ScheduledJobRecord;
35
+ }
36
+ | {
37
+ /**
38
+ * 事件版本号。
39
+ */
40
+ v: 1;
41
+ /**
42
+ * 事件类型:状态更新。
43
+ */
44
+ type: "status";
45
+ /**
46
+ * 目标任务 ID。
47
+ */
48
+ jobId: string;
49
+ /**
50
+ * 新状态。
51
+ */
52
+ status: ScheduledJobStatus;
53
+ /**
54
+ * 最新更新时间。
55
+ */
56
+ updatedAt: number;
57
+ /**
58
+ * 可选错误信息。
59
+ */
60
+ error?: string;
61
+ };
62
+
63
+ function readJsonlLines(filePath: string): string[] {
64
+ if (!fs.existsSync(filePath)) return [];
65
+ const raw = fs.readFileSync(filePath, "utf-8");
66
+ return raw
67
+ .split(/\r?\n/)
68
+ .map((line) => line.trim())
69
+ .filter(Boolean);
70
+ }
71
+
72
+ function normalizeJobRecord(input: ScheduledJobRecord): ScheduledJobRecord {
73
+ return {
74
+ id: String(input.id || "").trim(),
75
+ serviceName: String(input.serviceName || "").trim(),
76
+ actionName: String(input.actionName || "").trim(),
77
+ payload: input.payload ?? null,
78
+ runAtMs: Math.trunc(input.runAtMs),
79
+ status: input.status,
80
+ ...(typeof input.error === "string" && input.error ? { error: input.error } : {}),
81
+ createdAt: Math.trunc(input.createdAt),
82
+ updatedAt: Math.trunc(input.updatedAt),
83
+ };
84
+ }
85
+
86
+ function parseEvent(line: string): ScheduledJobEvent | null {
87
+ try {
88
+ const raw = JSON.parse(line) as Partial<ScheduledJobEvent> | null;
89
+ if (!raw || typeof raw !== "object") return null;
90
+ if (raw.type === "created" && raw.job) {
91
+ return {
92
+ v: 1,
93
+ type: "created",
94
+ job: normalizeJobRecord(raw.job as ScheduledJobRecord),
95
+ };
96
+ }
97
+ if (
98
+ raw.type === "status" &&
99
+ typeof raw.jobId === "string" &&
100
+ typeof raw.status === "string" &&
101
+ typeof raw.updatedAt === "number"
102
+ ) {
103
+ return {
104
+ v: 1,
105
+ type: "status",
106
+ jobId: raw.jobId,
107
+ status: raw.status as ScheduledJobStatus,
108
+ updatedAt: Math.trunc(raw.updatedAt),
109
+ ...(typeof raw.error === "string" ? { error: raw.error } : {}),
110
+ };
111
+ }
112
+ return null;
113
+ } catch {
114
+ return null;
115
+ }
116
+ }
117
+
118
+ function compareJobs(a: ScheduledJobRecord, b: ScheduledJobRecord): number {
119
+ if (a.runAtMs !== b.runAtMs) return a.runAtMs - b.runAtMs;
120
+ return b.createdAt - a.createdAt;
121
+ }
25
122
 
26
123
  /**
27
124
  * Service Schedule Store。
28
125
  */
29
126
  export class ServiceScheduleStore {
30
- private readonly sqlite: Database.Database;
31
-
32
- private readonly db: ReturnType<typeof drizzle>;
127
+ private readonly filePath: string;
33
128
 
34
129
  constructor(projectRoot: string) {
35
- const dbPath = getDowncityScheduleDbPath(projectRoot);
36
- fs.ensureDirSync(path.dirname(dbPath));
37
- this.sqlite = new Database(dbPath);
38
- this.sqlite.pragma("journal_mode = WAL");
39
- this.db = drizzle(this.sqlite);
40
- this.ensureSchema();
41
- }
42
-
43
- /**
44
- * 初始化表结构。
45
- */
46
- private ensureSchema(): void {
47
- this.sqlite.exec(`
48
- CREATE TABLE IF NOT EXISTS scheduled_jobs (
49
- id TEXT PRIMARY KEY NOT NULL,
50
- service_name TEXT NOT NULL,
51
- action_name TEXT NOT NULL,
52
- payload_json TEXT NOT NULL,
53
- run_at_ms INTEGER NOT NULL,
54
- status TEXT NOT NULL,
55
- error TEXT,
56
- created_at INTEGER NOT NULL,
57
- updated_at INTEGER NOT NULL
58
- );
59
- `);
60
- this.sqlite.exec(`
61
- CREATE INDEX IF NOT EXISTS scheduled_jobs_status_run_at_idx
62
- ON scheduled_jobs(status, run_at_ms);
63
- `);
64
- this.sqlite.exec(`
65
- CREATE INDEX IF NOT EXISTS scheduled_jobs_run_at_idx
66
- ON scheduled_jobs(run_at_ms);
67
- `);
130
+ this.filePath = getDowncityScheduleDbPath(projectRoot);
131
+ fs.ensureDirSync(path.dirname(this.filePath));
132
+ if (!fs.existsSync(this.filePath)) {
133
+ fs.writeFileSync(this.filePath, "", "utf-8");
134
+ }
68
135
  }
69
136
 
70
137
  /**
71
- * 关闭数据库连接。
138
+ * 关闭存储。
139
+ *
140
+ * 说明(中文)
141
+ * - jsonl 版本无需保持长连接,因此 close 为 no-op。
72
142
  */
73
- close(): void {
74
- this.sqlite.close();
75
- }
143
+ close(): void {}
76
144
 
77
145
  /**
78
146
  * 创建调度任务。
79
147
  */
80
148
  createJob(input: CreateScheduledJobInput): ScheduledJobRecord {
81
149
  const now = Date.now();
82
- const id = `sched_${generateId()}`;
83
- const payloadJson = JSON.stringify(input.payload ?? null);
84
- this.db.insert(scheduledJobsTable).values({
85
- id,
86
- serviceName: String(input.serviceName || "").trim(),
87
- actionName: String(input.actionName || "").trim(),
88
- payloadJson,
89
- runAtMs: Math.trunc(input.runAtMs),
90
- status: "pending",
91
- error: null,
92
- createdAt: now,
93
- updatedAt: now,
94
- }).run();
95
-
96
- return {
97
- id,
150
+ const job: ScheduledJobRecord = {
151
+ id: `sched_${generateId()}`,
98
152
  serviceName: String(input.serviceName || "").trim(),
99
153
  actionName: String(input.actionName || "").trim(),
100
154
  payload: input.payload ?? null,
@@ -103,16 +157,21 @@ export class ServiceScheduleStore {
103
157
  createdAt: now,
104
158
  updatedAt: now,
105
159
  };
160
+ this.appendEvent({
161
+ v: 1,
162
+ type: "created",
163
+ job,
164
+ });
165
+ return job;
106
166
  }
107
167
 
108
168
  /**
109
169
  * 获取单个任务。
110
170
  */
111
171
  getJobById(jobId: string): ScheduledJobRecord | null {
112
- const row = this.db.select().from(scheduledJobsTable)
113
- .where(eq(scheduledJobsTable.id, String(jobId || "").trim()))
114
- .get();
115
- return row ? this.toJobRecord(row) : null;
172
+ const key = String(jobId || "").trim();
173
+ if (!key) return null;
174
+ return this.readJobMap().get(key) || null;
116
175
  }
117
176
 
118
177
  /**
@@ -120,19 +179,14 @@ export class ServiceScheduleStore {
120
179
  */
121
180
  listJobsByStatus(statuses: ScheduledJobStatus[]): ScheduledJobRecord[] {
122
181
  if (statuses.length === 0) return [];
123
- const rows = this.db.select().from(scheduledJobsTable)
124
- .where(inArray(scheduledJobsTable.status, statuses))
125
- .orderBy(asc(scheduledJobsTable.runAtMs))
126
- .all();
127
- return rows.map((row) => this.toJobRecord(row));
182
+ const allowed = new Set(statuses);
183
+ return this.readJobs()
184
+ .filter((job) => allowed.has(job.status))
185
+ .sort(compareJobs);
128
186
  }
129
187
 
130
188
  /**
131
189
  * 列出任务。
132
- *
133
- * 说明(中文)
134
- * - 默认按 `runAtMs` 升序返回,便于排查“接下来会执行什么”。
135
- * - 可选状态过滤与数量限制,避免一次输出过多记录。
136
190
  */
137
191
  listJobs(params?: {
138
192
  status?: ScheduledJobStatus;
@@ -142,75 +196,44 @@ export class ServiceScheduleStore {
142
196
  typeof params?.limit === "number" && Number.isFinite(params.limit)
143
197
  ? Math.max(1, Math.trunc(params.limit))
144
198
  : 100;
145
- const status = params?.status;
146
- const query = this.db.select().from(scheduledJobsTable);
147
- const rows =
148
- typeof status === "string" && status
149
- ? query
150
- .where(eq(scheduledJobsTable.status, status))
151
- .orderBy(asc(scheduledJobsTable.runAtMs), desc(scheduledJobsTable.createdAt))
152
- .limit(limit)
153
- .all()
154
- : query
155
- .orderBy(asc(scheduledJobsTable.runAtMs), desc(scheduledJobsTable.createdAt))
156
- .limit(limit)
157
- .all();
158
- return rows.map((row) => this.toJobRecord(row));
199
+ const jobs = this.readJobs()
200
+ .filter((job) => !params?.status || job.status === params.status)
201
+ .sort(compareJobs);
202
+ return jobs.slice(0, limit);
159
203
  }
160
204
 
161
205
  /**
162
206
  * 列出已到点且待执行的任务。
163
207
  */
164
208
  listDuePendingJobs(nowMs: number): ScheduledJobRecord[] {
165
- const rows = this.db.select().from(scheduledJobsTable)
166
- .where(
167
- and(
168
- eq(scheduledJobsTable.status, "pending"),
169
- lte(scheduledJobsTable.runAtMs, Math.trunc(nowMs)),
170
- ),
171
- )
172
- .orderBy(asc(scheduledJobsTable.runAtMs))
173
- .all();
174
- return rows.map((row) => this.toJobRecord(row));
209
+ return this.readJobs()
210
+ .filter((job) => job.status === "pending" && job.runAtMs <= Math.trunc(nowMs))
211
+ .sort(compareJobs);
175
212
  }
176
213
 
177
214
  /**
178
215
  * 启动恢复时,把历史 `running` 回退到 `pending`。
179
216
  */
180
217
  resetRunningJobsToPending(): number {
218
+ const runningJobs = this.readJobs().filter((job) => job.status === "running");
181
219
  const now = Date.now();
182
- const result = this.db.update(scheduledJobsTable)
183
- .set({
220
+ for (const job of runningJobs) {
221
+ this.appendEvent({
222
+ v: 1,
223
+ type: "status",
224
+ jobId: job.id,
184
225
  status: "pending",
185
226
  updatedAt: now,
186
- error: null,
187
- })
188
- .where(eq(scheduledJobsTable.status, "running"))
189
- .run();
190
- return Number(result.changes || 0);
227
+ });
228
+ }
229
+ return runningJobs.length;
191
230
  }
192
231
 
193
232
  /**
194
233
  * 将任务标记为执行中。
195
- *
196
- * 关键点(中文)
197
- * - 仅允许从 `pending` 进入 `running`,避免重复领取。
198
234
  */
199
235
  markJobRunning(jobId: string): boolean {
200
- const result = this.db.update(scheduledJobsTable)
201
- .set({
202
- status: "running",
203
- updatedAt: Date.now(),
204
- error: null,
205
- })
206
- .where(
207
- and(
208
- eq(scheduledJobsTable.id, String(jobId || "").trim()),
209
- eq(scheduledJobsTable.status, "pending"),
210
- ),
211
- )
212
- .run();
213
- return Number(result.changes || 0) > 0;
236
+ return this.transitionPendingJob(jobId, "running");
214
237
  }
215
238
 
216
239
  /**
@@ -246,71 +269,88 @@ export class ServiceScheduleStore {
246
269
 
247
270
  /**
248
271
  * 取消待执行任务。
249
- *
250
- * 关键点(中文)
251
- * - 仅允许取消 `pending`,避免打断已经开始执行的任务。
252
272
  */
253
273
  cancelPendingJob(jobId: string): boolean {
254
- const result = this.db.update(scheduledJobsTable)
255
- .set({
256
- status: "cancelled",
257
- updatedAt: Date.now(),
258
- error: null,
259
- })
260
- .where(
261
- and(
262
- eq(scheduledJobsTable.id, String(jobId || "").trim()),
263
- eq(scheduledJobsTable.status, "pending"),
264
- ),
265
- )
266
- .run();
267
- return Number(result.changes || 0) > 0;
274
+ return this.transitionPendingJob(jobId, "cancelled");
268
275
  }
269
276
 
270
277
  /**
271
- * 统一写入终态。
278
+ * 仅读取当前任务快照。
272
279
  */
273
- private updateTerminalStatus(params: {
274
- jobId: string;
275
- status: Exclude<ScheduledJobStatus, "pending" | "running">;
276
- error?: string;
277
- }): boolean {
278
- const result = this.db.update(scheduledJobsTable)
279
- .set({
280
- status: params.status,
281
- updatedAt: Date.now(),
282
- error: params.error ? String(params.error) : null,
283
- })
284
- .where(eq(scheduledJobsTable.id, String(params.jobId || "").trim()))
285
- .run();
286
- return Number(result.changes || 0) > 0;
280
+ private readJobs(): ScheduledJobRecord[] {
281
+ return [...this.readJobMap().values()];
287
282
  }
288
283
 
289
284
  /**
290
- * 行转业务对象。
285
+ * 重放事件流,构造当前任务快照。
291
286
  */
292
- private toJobRecord(row: ScheduledJobRow): ScheduledJobRecord {
293
- return {
294
- id: row.id,
295
- serviceName: row.serviceName,
296
- actionName: row.actionName,
297
- payload: this.parsePayloadJson(row.payloadJson),
298
- runAtMs: row.runAtMs,
299
- status: row.status as ScheduledJobStatus,
300
- ...(typeof row.error === "string" && row.error ? { error: row.error } : {}),
301
- createdAt: row.createdAt,
302
- updatedAt: row.updatedAt,
303
- };
287
+ private readJobMap(): Map<string, ScheduledJobRecord> {
288
+ const jobs = new Map<string, ScheduledJobRecord>();
289
+ for (const line of readJsonlLines(this.filePath)) {
290
+ const event = parseEvent(line);
291
+ if (!event) continue;
292
+ if (event.type === "created") {
293
+ jobs.set(event.job.id, normalizeJobRecord(event.job));
294
+ continue;
295
+ }
296
+ const current = jobs.get(event.jobId);
297
+ if (!current) continue;
298
+ jobs.set(event.jobId, {
299
+ ...current,
300
+ status: event.status,
301
+ updatedAt: event.updatedAt,
302
+ ...(event.error ? { error: event.error } : {}),
303
+ ...(event.status === "succeeded" || event.status === "cancelled"
304
+ ? { error: undefined }
305
+ : {}),
306
+ });
307
+ }
308
+ return jobs;
304
309
  }
305
310
 
306
311
  /**
307
- * 安全解析 payload JSON。
312
+ * 追加单条事件。
308
313
  */
309
- private parsePayloadJson(input: string): JsonValue {
310
- try {
311
- return JSON.parse(String(input || "null")) as JsonValue;
312
- } catch {
313
- return null;
314
+ private appendEvent(event: ScheduledJobEvent): void {
315
+ fs.appendFileSync(this.filePath, `${JSON.stringify(event)}\n`, "utf-8");
316
+ }
317
+
318
+ /**
319
+ * 执行 pending -> target 的状态迁移。
320
+ */
321
+ private transitionPendingJob(jobId: string, status: "running" | "cancelled"): boolean {
322
+ const current = this.getJobById(jobId);
323
+ if (!current || current.status !== "pending") {
324
+ return false;
314
325
  }
326
+ this.appendEvent({
327
+ v: 1,
328
+ type: "status",
329
+ jobId: current.id,
330
+ status,
331
+ updatedAt: Date.now(),
332
+ });
333
+ return true;
334
+ }
335
+
336
+ /**
337
+ * 统一写入终态。
338
+ */
339
+ private updateTerminalStatus(params: {
340
+ jobId: string;
341
+ status: Exclude<ScheduledJobStatus, "pending" | "running">;
342
+ error?: string;
343
+ }): boolean {
344
+ const current = this.getJobById(params.jobId);
345
+ if (!current) return false;
346
+ this.appendEvent({
347
+ v: 1,
348
+ type: "status",
349
+ jobId: current.id,
350
+ status: params.status,
351
+ updatedAt: Date.now(),
352
+ ...(params.error ? { error: String(params.error) } : {}),
353
+ });
354
+ return true;
315
355
  }
316
356
  }
@@ -244,6 +244,7 @@ export async function loadPluginSystemPrompts(input: {
244
244
  if (
245
245
  !isPluginEnabled({
246
246
  plugin,
247
+ context: input.context,
247
248
  })
248
249
  ) {
249
250
  continue;
@@ -8,6 +8,24 @@
8
8
  */
9
9
 
10
10
  import type { DowncityConfig } from "@/shared/types/DowncityConfig.js";
11
+ import type {
12
+ ChatAuthorizationChannel,
13
+ ChatAuthorizationConfig,
14
+ } from "@/shared/types/AuthPlugin.js";
15
+ import type {
16
+ ChatChannelAccountCreateInput,
17
+ ChatChannelAccountListItem,
18
+ ChatChannelAccountProbeResult,
19
+ ChatChannelAccountUpsertInput,
20
+ } from "@/service/builtins/chat/types/ChannelAccount.js";
21
+ import type {
22
+ StoredChannelAccount,
23
+ StoredModel,
24
+ StoredModelProvider,
25
+ } from "@/shared/types/Store.js";
26
+ import type { ChatChannelName } from "@/service/builtins/chat/types/ChannelStatus.js";
27
+ import type { AgentProjectInitializationInput } from "@/shared/types/AgentProject.js";
28
+ import type { PlatformModelChoice } from "@/agent/project/AgentInitializer.js";
11
29
 
12
30
  /**
13
31
  * Agent 路径能力集合。
@@ -37,10 +55,6 @@ export interface AgentPathRuntime {
37
55
  * `.downcity/chat/<sessionId>/history.jsonl` 文件路径。
38
56
  */
39
57
  getDowncityChatHistoryPath(sessionId: string): string;
40
- /**
41
- * `.downcity/memory/index.sqlite` 文件路径。
42
- */
43
- getDowncityMemoryIndexPath(): string;
44
58
  /**
45
59
  * `.downcity/memory/MEMORY.md` 文件路径。
46
60
  */
@@ -72,3 +86,123 @@ export interface AgentPluginConfigRuntime {
72
86
  */
73
87
  persistProjectPlugins(plugins: DowncityConfig["plugins"] | undefined): Promise<string>;
74
88
  }
89
+
90
+ /**
91
+ * Agent 可见的平台能力集合。
92
+ *
93
+ * 关键点(中文)
94
+ * - agent 只消费这些平台能力,不直接管理平台级持久化实现。
95
+ * - 具体数据存储与管理应由 city / control plane 提供。
96
+ */
97
+ export interface AgentPlatformRuntime {
98
+ /**
99
+ * 读取当前平台级全局环境变量快照。
100
+ */
101
+ getGlobalEnv(): Record<string, string>;
102
+ /**
103
+ * 读取指定 agent 项目的私有环境变量快照。
104
+ */
105
+ getAgentEnv(projectRoot: string): Record<string, string>;
106
+ /**
107
+ * 读取当前平台模型池中的全部模型。
108
+ */
109
+ listModels(): StoredModel[];
110
+ /**
111
+ * 读取当前平台模型池中的全部 provider。
112
+ */
113
+ listProviders(): Promise<StoredModelProvider[]>;
114
+ /**
115
+ * 按模型 ID 读取单个模型。
116
+ */
117
+ getModel(modelId: string): StoredModel | null;
118
+ /**
119
+ * 按账户 ID 读取单个渠道账户。
120
+ */
121
+ getChannelAccount(channelAccountId: string): StoredChannelAccount | null;
122
+ /**
123
+ * 列出当前平台保存的全部渠道账户安全视图。
124
+ */
125
+ listChannelAccounts?(): Promise<ChatChannelAccountListItem[]>;
126
+ /**
127
+ * 探测渠道凭据并返回建议账户信息。
128
+ */
129
+ probeChannelAccount?(input: {
130
+ channel: string;
131
+ botToken?: string;
132
+ appId?: string;
133
+ appSecret?: string;
134
+ domain?: string;
135
+ sandbox?: boolean;
136
+ }): Promise<ChatChannelAccountProbeResult>;
137
+ /**
138
+ * 创建新的渠道账户。
139
+ */
140
+ createChannelAccount?(input: ChatChannelAccountCreateInput): Promise<{
141
+ id: string;
142
+ probed: boolean;
143
+ message?: string;
144
+ }>;
145
+ /**
146
+ * 更新现有渠道账户。
147
+ */
148
+ updateChannelAccount?(input: ChatChannelAccountUpsertInput): Promise<void>;
149
+ /**
150
+ * 删除渠道账户。
151
+ */
152
+ removeChannelAccount?(channelAccountId: string): Promise<void>;
153
+ /**
154
+ * 解析某个渠道当前应使用的账户。
155
+ */
156
+ resolveChannelAccount?(params: {
157
+ projectRoot: string;
158
+ channel: ChatChannelName;
159
+ channelAccountId?: string;
160
+ }): StoredChannelAccount | null;
161
+ /**
162
+ * 读取当前 agent 的 chat 授权配置。
163
+ */
164
+ readChatAuthorizationConfig(projectRoot: string): ChatAuthorizationConfig;
165
+ /**
166
+ * 覆盖写入当前 agent 的 chat 授权配置。
167
+ */
168
+ writeChatAuthorizationConfig(
169
+ projectRoot: string,
170
+ nextConfig: ChatAuthorizationConfig,
171
+ ): Promise<ChatAuthorizationConfig>;
172
+ /**
173
+ * 设置当前 agent 某个渠道用户的授权角色。
174
+ */
175
+ setChatAuthorizationUserRole(params: {
176
+ projectRoot: string;
177
+ channel: ChatAuthorizationChannel;
178
+ userId: string;
179
+ roleId: string;
180
+ }): Promise<ChatAuthorizationConfig>;
181
+ /**
182
+ * 判断指定 plugin 当前是否启用。
183
+ */
184
+ isPluginEnabled(pluginName: string): boolean;
185
+ /**
186
+ * 设置指定 plugin 的全局启用态。
187
+ */
188
+ setPluginEnabled?(pluginName: string, enabled: boolean): void;
189
+ /**
190
+ * 列出平台模型选项。
191
+ */
192
+ listPlatformModelChoices?(): Promise<PlatformModelChoice[]>;
193
+ /**
194
+ * 初始化 agent 项目。
195
+ */
196
+ initializeAgentProject?(
197
+ input: AgentProjectInitializationInput,
198
+ ): Promise<{
199
+ projectRoot: string;
200
+ agentName: string;
201
+ createdFiles: string[];
202
+ skippedFiles: string[];
203
+ }>;
204
+ /**
205
+ * 校验项目执行绑定是否已就绪。
206
+ */
207
+ ensureRuntimeExecutionBindingReady?(projectRoot: string): void;
208
+ }
@@ -11,6 +11,7 @@ import type { Command } from "commander";
11
11
  import type { Context as HonoContext, Hono } from "hono";
12
12
  import type {
13
13
  AgentPathRuntime,
14
+ AgentPlatformRuntime,
14
15
  AgentPluginConfigRuntime,
15
16
  } from "@/shared/types/AgentHost.js";
16
17
  import type {
@@ -63,6 +64,10 @@ export interface PluginCommandContext {
63
64
  * 当前可见的 plugin 配置持久化能力集合。
64
65
  */
65
66
  pluginConfig: AgentPluginConfigRuntime;
67
+ /**
68
+ * 当前可见的平台能力集合。
69
+ */
70
+ platform: AgentPlatformRuntime;
66
71
  }
67
72
 
68
73
  /**