@xopcai/xopc 0.0.24 → 0.0.26

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 (109) hide show
  1. package/dist/extensions/feishu/xopc.extension.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/agents-Clv9i1Kb.js +216 -0
  4. package/dist/gateway/static/root/assets/agents-Clv9i1Kb.js.map +1 -0
  5. package/dist/gateway/static/root/assets/{apps-page-tZz69XM3.js → apps-page-DqclV-PP.js} +2 -2
  6. package/dist/gateway/static/root/assets/{apps-page-tZz69XM3.js.map → apps-page-DqclV-PP.js.map} +1 -1
  7. package/dist/gateway/static/root/assets/{channels-settings-BAvk9-aK.js → channels-settings-CLyTYjrz.js} +3 -3
  8. package/dist/gateway/static/root/assets/{channels-settings-BAvk9-aK.js.map → channels-settings-CLyTYjrz.js.map} +1 -1
  9. package/dist/gateway/static/root/assets/cron-page-CU8lutMt.js +2 -0
  10. package/dist/gateway/static/root/assets/{cron-page-CANqvhK7.js.map → cron-page-CU8lutMt.js.map} +1 -1
  11. package/dist/gateway/static/root/assets/{cron-utils-DyOO6TdN.js → cron-utils-_UjiWax6.js} +2 -2
  12. package/dist/gateway/static/root/assets/{cron-utils-DyOO6TdN.js.map → cron-utils-_UjiWax6.js.map} +1 -1
  13. package/dist/gateway/static/root/assets/dist-Xqb4IGWC.js +2 -0
  14. package/dist/gateway/static/root/assets/{dist-Brod9LF3.js.map → dist-Xqb4IGWC.js.map} +1 -1
  15. package/dist/gateway/static/root/assets/{extension-debug-page-CDD7ozsC.js → extension-debug-page-CtTUkAmw.js} +2 -2
  16. package/dist/gateway/static/root/assets/{extension-debug-page-CDD7ozsC.js.map → extension-debug-page-CtTUkAmw.js.map} +1 -1
  17. package/dist/gateway/static/root/assets/{extension-page-UUFMjoWf.js → extension-page-C-aQU8qR.js} +2 -2
  18. package/dist/gateway/static/root/assets/{extension-page-UUFMjoWf.js.map → extension-page-C-aQU8qR.js.map} +1 -1
  19. package/dist/gateway/static/root/assets/{extension-settings-page-CP9JNc4m.js → extension-settings-page-b0y9aY-q.js} +2 -2
  20. package/dist/gateway/static/root/assets/extension-settings-page-b0y9aY-q.js.map +1 -0
  21. package/dist/gateway/static/root/assets/index-DhSFfSNN.css +1 -0
  22. package/dist/gateway/static/root/assets/index-Gr2HWo-G.js +4734 -0
  23. package/dist/gateway/static/root/assets/index-Gr2HWo-G.js.map +1 -0
  24. package/dist/gateway/static/root/assets/logs-page-DRI33XK4.js +2 -0
  25. package/dist/gateway/static/root/assets/{logs-page-Cr0eCGb4.js.map → logs-page-DRI33XK4.js.map} +1 -1
  26. package/dist/gateway/static/root/assets/sessions-page-Cryg-36Z.js +2 -0
  27. package/dist/gateway/static/root/assets/{sessions-page-DwLHN5GJ.js.map → sessions-page-Cryg-36Z.js.map} +1 -1
  28. package/dist/gateway/static/root/assets/settings-page-DFNKT9yg.js +2 -0
  29. package/dist/gateway/static/root/assets/settings-page-DFNKT9yg.js.map +1 -0
  30. package/dist/gateway/static/root/assets/skills-page-D4gfh0Ih.js +3 -0
  31. package/dist/gateway/static/root/assets/{skills-page-DgBYvH6B.js.map → skills-page-D4gfh0Ih.js.map} +1 -1
  32. package/dist/gateway/static/root/index.html +2 -2
  33. package/dist/package.js +1 -1
  34. package/dist/src/agent/memory/dreaming/config.d.ts +48 -0
  35. package/dist/src/agent/memory/dreaming/config.js +86 -0
  36. package/dist/src/agent/memory/dreaming/config.js.map +1 -0
  37. package/dist/src/agent/memory/dreaming/constants.d.ts +29 -0
  38. package/dist/src/agent/memory/dreaming/constants.js +38 -0
  39. package/dist/src/agent/memory/dreaming/constants.js.map +1 -0
  40. package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +21 -0
  41. package/dist/src/agent/memory/dreaming/deep-promotion.js +271 -0
  42. package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -0
  43. package/dist/src/agent/memory/dreaming/events.d.ts +36 -0
  44. package/dist/src/agent/memory/dreaming/events.js +44 -0
  45. package/dist/src/agent/memory/dreaming/events.js.map +1 -0
  46. package/dist/src/agent/memory/dreaming/last-run.d.ts +80 -0
  47. package/dist/src/agent/memory/dreaming/last-run.js +98 -0
  48. package/dist/src/agent/memory/dreaming/last-run.js.map +1 -0
  49. package/dist/src/agent/memory/dreaming/light-sweep.d.ts +19 -0
  50. package/dist/src/agent/memory/dreaming/light-sweep.js +328 -0
  51. package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -0
  52. package/dist/src/agent/memory/dreaming/preview.d.ts +28 -0
  53. package/dist/src/agent/memory/dreaming/preview.js +97 -0
  54. package/dist/src/agent/memory/dreaming/preview.js.map +1 -0
  55. package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +21 -0
  56. package/dist/src/agent/memory/dreaming/rem-patterns.js +286 -0
  57. package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -0
  58. package/dist/src/agent/memory/dreaming/short-term-store.d.ts +65 -0
  59. package/dist/src/agent/memory/dreaming/short-term-store.js +197 -0
  60. package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -0
  61. package/dist/src/agent/memory/dreaming/utils.d.ts +42 -0
  62. package/dist/src/agent/memory/dreaming/utils.js +141 -0
  63. package/dist/src/agent/memory/dreaming/utils.js.map +1 -0
  64. package/dist/src/agent/orchestration/agent-orchestrator.js +59 -0
  65. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  66. package/dist/src/agent/service.d.ts +6 -0
  67. package/dist/src/agent/service.js +78 -0
  68. package/dist/src/agent/service.js.map +1 -1
  69. package/dist/src/agent/tools/dreaming-tool.d.ts +7 -0
  70. package/dist/src/agent/tools/dreaming-tool.js +102 -0
  71. package/dist/src/agent/tools/dreaming-tool.js.map +1 -0
  72. package/dist/src/agent/tools/factory.js +5 -0
  73. package/dist/src/agent/tools/factory.js.map +1 -1
  74. package/dist/src/agent/tools/index.d.ts +1 -0
  75. package/dist/src/agent/tools/index.js +2 -1
  76. package/dist/src/agent/tools/memory-tool.js +9 -2
  77. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  78. package/dist/src/config/schema.d.ts +93 -0
  79. package/dist/src/config/schema.js +42 -1
  80. package/dist/src/config/schema.js.map +1 -1
  81. package/dist/src/gateway/hono/lib/config-payload.d.ts +31 -0
  82. package/dist/src/gateway/hono/routes/config.js +48 -0
  83. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  84. package/dist/src/gateway/hono/routes/dreaming.d.ts +3 -0
  85. package/dist/src/gateway/hono/routes/dreaming.js +288 -0
  86. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -0
  87. package/dist/src/gateway/hono/routes/index.js +2 -0
  88. package/dist/src/gateway/hono/routes/index.js.map +1 -1
  89. package/dist/src/gateway/hono/routes/models.js +26 -1
  90. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  91. package/dist/src/gateway/hono/routes/public-gateway.js +1 -0
  92. package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
  93. package/dist/src/gateway/lock.js +1 -1
  94. package/dist/src/gateway/service.js +7 -0
  95. package/dist/src/gateway/service.js.map +1 -1
  96. package/package.json +1 -1
  97. package/dist/gateway/static/root/assets/agents-CiZMJZRp.js +0 -216
  98. package/dist/gateway/static/root/assets/agents-CiZMJZRp.js.map +0 -1
  99. package/dist/gateway/static/root/assets/cron-page-CANqvhK7.js +0 -2
  100. package/dist/gateway/static/root/assets/dist-Brod9LF3.js +0 -2
  101. package/dist/gateway/static/root/assets/extension-settings-page-CP9JNc4m.js.map +0 -1
  102. package/dist/gateway/static/root/assets/index-BZvlG48D.js +0 -150
  103. package/dist/gateway/static/root/assets/index-BZvlG48D.js.map +0 -1
  104. package/dist/gateway/static/root/assets/index-DxkgyT8R.css +0 -1
  105. package/dist/gateway/static/root/assets/logs-page-Cr0eCGb4.js +0 -2
  106. package/dist/gateway/static/root/assets/sessions-page-DwLHN5GJ.js +0 -2
  107. package/dist/gateway/static/root/assets/settings-page-B3O3R0E4.js +0 -2
  108. package/dist/gateway/static/root/assets/settings-page-B3O3R0E4.js.map +0 -1
  109. package/dist/gateway/static/root/assets/skills-page-DgBYvH6B.js +0 -3
@@ -0,0 +1,288 @@
1
+ import { getWorkspacePath, init_schema } from "../../../config/schema.js";
2
+ import { DREAMING_CRON_NAME, DREAMING_DIR_RELATIVE, DREAMING_LAST_RUN_RELATIVE, DREAMING_LIGHT_CRON_NAME, DREAMING_LIGHT_SWEEP_TOKEN, DREAMING_REM_CRON_NAME, DREAMING_REM_SWEEP_TOKEN, DREAMING_SWEEP_TOKEN, SHORT_TERM_PROMOTION_LOCK_RELATIVE, SHORT_TERM_RECALL_STORE_RELATIVE } from "../../../agent/memory/dreaming/constants.js";
3
+ import { loadDreamingStore, saveDreamingStore } from "../../../agent/memory/dreaming/short-term-store.js";
4
+ import { resolveDreamingConfig } from "../../../agent/memory/dreaming/config.js";
5
+ import { parseDreamingLastRunFile } from "../../../agent/memory/dreaming/last-run.js";
6
+ import { readDreamingEvents } from "../../../agent/memory/dreaming/events.js";
7
+ import { previewDreamingDeepPromotion } from "../../../agent/memory/dreaming/preview.js";
8
+ import path from "node:path";
9
+ import fs from "node:fs/promises";
10
+ //#region src/gateway/hono/routes/dreaming.ts
11
+ init_schema();
12
+ function isRecord(v) {
13
+ return v !== null && typeof v === "object" && !Array.isArray(v);
14
+ }
15
+ async function readLockInfo(workspaceDir) {
16
+ const lockPath = path.join(workspaceDir, SHORT_TERM_PROMOTION_LOCK_RELATIVE);
17
+ try {
18
+ const [content, st] = await Promise.all([fs.readFile(lockPath, "utf-8"), fs.stat(lockPath)]);
19
+ return {
20
+ locked: true,
21
+ path: SHORT_TERM_PROMOTION_LOCK_RELATIVE,
22
+ content: content.trim(),
23
+ mtimeMs: st.mtimeMs
24
+ };
25
+ } catch (err) {
26
+ if (err?.code === "ENOENT") return { locked: false };
27
+ return {
28
+ locked: true,
29
+ path: SHORT_TERM_PROMOTION_LOCK_RELATIVE,
30
+ content: "unknown",
31
+ mtimeMs: void 0
32
+ };
33
+ }
34
+ }
35
+ async function readLastRun(workspaceDir) {
36
+ const fullPath = path.join(workspaceDir, DREAMING_LAST_RUN_RELATIVE);
37
+ try {
38
+ const text = await fs.readFile(fullPath, "utf-8");
39
+ let raw;
40
+ try {
41
+ raw = JSON.parse(text);
42
+ } catch (parseErr) {
43
+ return {
44
+ exists: true,
45
+ path: DREAMING_LAST_RUN_RELATIVE,
46
+ raw: null,
47
+ record: null,
48
+ parseError: parseErr instanceof Error ? parseErr.message : String(parseErr)
49
+ };
50
+ }
51
+ const record = parseDreamingLastRunFile(raw);
52
+ return {
53
+ exists: true,
54
+ path: DREAMING_LAST_RUN_RELATIVE,
55
+ raw,
56
+ record,
57
+ parseError: record ? null : "Invalid or unsupported last-run.json (expected v2 deep record)."
58
+ };
59
+ } catch (err) {
60
+ if (err?.code === "ENOENT") return { exists: false };
61
+ return {
62
+ exists: true,
63
+ path: DREAMING_LAST_RUN_RELATIVE,
64
+ raw: null,
65
+ record: null,
66
+ parseError: err instanceof Error ? err.message : String(err)
67
+ };
68
+ }
69
+ }
70
+ async function readPhaseLastRun(workspaceDir, filename) {
71
+ const relPath = path.join(DREAMING_DIR_RELATIVE, filename);
72
+ const fullPath = path.join(workspaceDir, relPath);
73
+ try {
74
+ const text = await fs.readFile(fullPath, "utf-8");
75
+ return {
76
+ exists: true,
77
+ path: relPath,
78
+ raw: JSON.parse(text)
79
+ };
80
+ } catch (err) {
81
+ if (err?.code === "ENOENT") return { exists: false };
82
+ return { exists: false };
83
+ }
84
+ }
85
+ function storeStats(store) {
86
+ const entries = Object.values(store.entries ?? {});
87
+ const promoted = entries.filter((e) => typeof e.promotedAt === "string" && e.promotedAt.trim());
88
+ const lastPromotedAt = promoted.map((e) => e.promotedAt).sort((a, b) => a < b ? 1 : a > b ? -1 : 0)[0];
89
+ return {
90
+ version: store.version,
91
+ updatedAt: store.updatedAt,
92
+ entryCount: entries.length,
93
+ promotedCount: promoted.length,
94
+ lastPromotedAt: lastPromotedAt ?? null
95
+ };
96
+ }
97
+ function payloadMessageFromJob(job) {
98
+ const p = job?.payload;
99
+ if (!p) return "";
100
+ if (p.kind === "agentTurn" && typeof p.message === "string") return p.message;
101
+ if (typeof p.text === "string") return p.text;
102
+ if (typeof p.message === "string") return p.message;
103
+ return "";
104
+ }
105
+ function registerDreamingRoutes(authenticated, deps) {
106
+ const { service } = deps;
107
+ authenticated.get("/api/dreaming", async (c) => {
108
+ const cfg = service.currentConfig;
109
+ const workspaceDir = getWorkspacePath(cfg);
110
+ if (!workspaceDir) return c.json({
111
+ ok: false,
112
+ error: { message: "Workspace not configured" }
113
+ }, 400);
114
+ const resolved = resolveDreamingConfig(cfg);
115
+ const { store } = await loadDreamingStore({ workspaceDir });
116
+ const lock = await readLockInfo(workspaceDir);
117
+ const [lastRun, lightLastRun, remLastRun] = await Promise.all([
118
+ readLastRun(workspaceDir),
119
+ readPhaseLastRun(workspaceDir, "last-run-light.json"),
120
+ readPhaseLastRun(workspaceDir, "last-run-rem.json")
121
+ ]);
122
+ return c.json({
123
+ ok: true,
124
+ payload: {
125
+ workspaceDir,
126
+ config: resolved,
127
+ storePath: SHORT_TERM_RECALL_STORE_RELATIVE,
128
+ store: storeStats(store),
129
+ lock,
130
+ lastRun,
131
+ lightLastRun,
132
+ remLastRun
133
+ }
134
+ });
135
+ });
136
+ authenticated.get("/api/dreaming/preview", async (c) => {
137
+ const cfg = service.currentConfig;
138
+ const workspaceDir = getWorkspacePath(cfg);
139
+ if (!workspaceDir) return c.json({
140
+ ok: false,
141
+ error: { message: "Workspace not configured" }
142
+ }, 400);
143
+ const resolved = resolveDreamingConfig(cfg);
144
+ const rawLimit = c.req.query("limit");
145
+ const limit = rawLimit ? Number(rawLimit) : 20;
146
+ const preview = await previewDreamingDeepPromotion({
147
+ workspaceDir,
148
+ config: resolved.deep,
149
+ limit: Number.isFinite(limit) ? limit : 20
150
+ });
151
+ return c.json({
152
+ ok: true,
153
+ payload: preview
154
+ });
155
+ });
156
+ authenticated.post("/api/dreaming/run", async (c) => {
157
+ let body;
158
+ try {
159
+ body = await c.req.json();
160
+ } catch {
161
+ body = {};
162
+ }
163
+ const requestedPhase = isRecord(body) && typeof body.phase === "string" && [
164
+ "light",
165
+ "deep",
166
+ "rem"
167
+ ].includes(body.phase) ? body.phase : "deep";
168
+ const { token, cronName } = {
169
+ light: {
170
+ token: DREAMING_LIGHT_SWEEP_TOKEN,
171
+ cronName: DREAMING_LIGHT_CRON_NAME
172
+ },
173
+ deep: {
174
+ token: DREAMING_SWEEP_TOKEN,
175
+ cronName: DREAMING_CRON_NAME
176
+ },
177
+ rem: {
178
+ token: DREAMING_REM_SWEEP_TOKEN,
179
+ cronName: DREAMING_REM_CRON_NAME
180
+ }
181
+ }[requestedPhase];
182
+ const jobs = await service.cronServiceInstance.listJobs();
183
+ const primary = jobs.find((job) => payloadMessageFromJob(job) === token) ?? jobs.find((job) => job.name === cronName) ?? (requestedPhase === "deep" ? jobs.find((job) => job.name?.includes?.("[managed-by=xopc.memory.dreaming]") ?? false) : void 0);
184
+ if (!primary) {
185
+ const dreaming = resolveDreamingConfig(service.currentConfig);
186
+ const hint = dreaming.enabled && dreaming.phases[requestedPhase].enabled ? `Dreaming ${requestedPhase} phase is enabled, but no cron job was found yet. Restart the gateway/agent process so it can reconcile managed cron jobs.` : `Dreaming ${requestedPhase} phase is disabled in config. Enable it first.`;
187
+ return c.json({
188
+ ok: false,
189
+ error: { message: `Dreaming ${requestedPhase} cron job not found. ${hint}` }
190
+ }, 404);
191
+ }
192
+ try {
193
+ service.emit("dreaming.phase.start", {
194
+ phase: requestedPhase,
195
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
196
+ });
197
+ await service.cronServiceInstance.runJobNow(primary.id);
198
+ service.emit("dreaming.phase.end", {
199
+ phase: requestedPhase,
200
+ ok: true,
201
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
202
+ });
203
+ return c.json({
204
+ ok: true,
205
+ payload: {
206
+ triggered: true,
207
+ jobId: primary.id,
208
+ phase: requestedPhase
209
+ }
210
+ });
211
+ } catch (err) {
212
+ const em = err instanceof Error ? err.message : String(err);
213
+ service.emit("dreaming.phase.end", {
214
+ phase: requestedPhase,
215
+ ok: false,
216
+ error: em,
217
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
218
+ });
219
+ return c.json({
220
+ ok: false,
221
+ error: { message: em || "Failed to trigger job" }
222
+ }, 400);
223
+ }
224
+ });
225
+ authenticated.post("/api/dreaming/action", async (c) => {
226
+ const cfg = service.currentConfig;
227
+ const workspaceDir = getWorkspacePath(cfg);
228
+ if (!workspaceDir) return c.json({
229
+ ok: false,
230
+ error: { message: "Workspace not configured" }
231
+ }, 400);
232
+ let body;
233
+ try {
234
+ body = await c.req.json();
235
+ } catch {
236
+ body = {};
237
+ }
238
+ const action = isRecord(body) && typeof body.action === "string" ? body.action.trim() : "";
239
+ if (action !== "reset_store" && action !== "clear_lock") return c.json({
240
+ ok: false,
241
+ error: { message: "Invalid action" }
242
+ }, 400);
243
+ if (action === "reset_store") {
244
+ await saveDreamingStore({
245
+ workspaceDir,
246
+ store: {
247
+ version: 1,
248
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
249
+ entries: {}
250
+ }
251
+ });
252
+ return c.json({
253
+ ok: true,
254
+ payload: {
255
+ reset: true,
256
+ storePath: SHORT_TERM_RECALL_STORE_RELATIVE
257
+ }
258
+ });
259
+ }
260
+ const lockPath = path.join(workspaceDir, SHORT_TERM_PROMOTION_LOCK_RELATIVE);
261
+ await fs.unlink(lockPath).catch(() => void 0);
262
+ return c.json({
263
+ ok: true,
264
+ payload: {
265
+ cleared: true,
266
+ lockPath: SHORT_TERM_PROMOTION_LOCK_RELATIVE
267
+ }
268
+ });
269
+ });
270
+ authenticated.get("/api/dreaming/events", async (c) => {
271
+ const cfg = service.currentConfig;
272
+ const workspaceDir = getWorkspacePath(cfg);
273
+ if (!workspaceDir) return c.json({
274
+ ok: false,
275
+ error: { message: "Workspace not configured" }
276
+ }, 400);
277
+ const rawLimit = c.req.query("limit");
278
+ const events = await readDreamingEvents(workspaceDir, rawLimit ? Math.min(Math.max(Number(rawLimit) || 50, 1), 200) : 50);
279
+ return c.json({
280
+ ok: true,
281
+ payload: { events }
282
+ });
283
+ });
284
+ }
285
+ //#endregion
286
+ export { registerDreamingRoutes };
287
+
288
+ //# sourceMappingURL=dreaming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dreaming.js","names":[],"sources":["../../../../../src/gateway/hono/routes/dreaming.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { getWorkspacePath, type Config } from '../../../config/schema.js';\nimport { resolveDreamingConfig } from '../../../agent/memory/dreaming/config.js';\nimport {\n DREAMING_CRON_NAME,\n DREAMING_CRON_TAG,\n DREAMING_DIR_RELATIVE,\n DREAMING_LAST_RUN_RELATIVE,\n DREAMING_LIGHT_CRON_NAME,\n DREAMING_LIGHT_SWEEP_TOKEN,\n DREAMING_REM_CRON_NAME,\n DREAMING_REM_SWEEP_TOKEN,\n DREAMING_SWEEP_TOKEN,\n SHORT_TERM_PROMOTION_LOCK_RELATIVE,\n SHORT_TERM_RECALL_STORE_RELATIVE,\n type DreamingPhaseId,\n} from '../../../agent/memory/dreaming/constants.js';\nimport { readDreamingEvents } from '../../../agent/memory/dreaming/events.js';\nimport { previewDreamingDeepPromotion } from '../../../agent/memory/dreaming/preview.js';\nimport { parseDreamingLastRunFile, type DreamingDeepLastRun } from '../../../agent/memory/dreaming/last-run.js';\nimport {\n loadDreamingStore,\n saveDreamingStore,\n type DreamingStore,\n} from '../../../agent/memory/dreaming/short-term-store.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return v !== null && typeof v === 'object' && !Array.isArray(v);\n}\n\nasync function readLockInfo(workspaceDir: string): Promise<\n | { locked: false }\n | { locked: true; path: string; content: string; mtimeMs?: number }\n> {\n const lockPath = path.join(workspaceDir, SHORT_TERM_PROMOTION_LOCK_RELATIVE);\n try {\n const [content, st] = await Promise.all([fs.readFile(lockPath, 'utf-8'), fs.stat(lockPath)]);\n return {\n locked: true,\n path: SHORT_TERM_PROMOTION_LOCK_RELATIVE,\n content: content.trim(),\n mtimeMs: st.mtimeMs,\n };\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code === 'ENOENT') return { locked: false };\n return { locked: true, path: SHORT_TERM_PROMOTION_LOCK_RELATIVE, content: 'unknown', mtimeMs: undefined };\n }\n}\n\nasync function readLastRun(\n workspaceDir: string,\n): Promise<\n | { exists: false }\n | {\n exists: true;\n path: string;\n raw: unknown;\n record: DreamingDeepLastRun | null;\n parseError: string | null;\n }\n> {\n const fullPath = path.join(workspaceDir, DREAMING_LAST_RUN_RELATIVE);\n try {\n const text = await fs.readFile(fullPath, 'utf-8');\n let raw: unknown;\n try {\n raw = JSON.parse(text) as unknown;\n } catch (parseErr) {\n return {\n exists: true,\n path: DREAMING_LAST_RUN_RELATIVE,\n raw: null,\n record: null,\n parseError: parseErr instanceof Error ? parseErr.message : String(parseErr),\n };\n }\n const record = parseDreamingLastRunFile(raw);\n return {\n exists: true,\n path: DREAMING_LAST_RUN_RELATIVE,\n raw,\n record,\n parseError: record ? null : 'Invalid or unsupported last-run.json (expected v2 deep record).',\n };\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code === 'ENOENT') return { exists: false };\n return {\n exists: true,\n path: DREAMING_LAST_RUN_RELATIVE,\n raw: null,\n record: null,\n parseError: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nasync function readPhaseLastRun(\n workspaceDir: string,\n filename: string,\n): Promise<{ exists: false } | { exists: true; path: string; raw: unknown }> {\n const relPath = path.join(DREAMING_DIR_RELATIVE, filename);\n const fullPath = path.join(workspaceDir, relPath);\n try {\n const text = await fs.readFile(fullPath, 'utf-8');\n const raw = JSON.parse(text) as unknown;\n return { exists: true, path: relPath, raw };\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code === 'ENOENT') return { exists: false };\n return { exists: false };\n }\n}\n\nfunction storeStats(store: DreamingStore): {\n version: number;\n updatedAt: string;\n entryCount: number;\n promotedCount: number;\n lastPromotedAt: string | null;\n} {\n const entries = Object.values(store.entries ?? {});\n const promoted = entries.filter((e) => typeof e.promotedAt === 'string' && e.promotedAt.trim());\n const lastPromotedAt = promoted\n .map((e) => e.promotedAt!)\n .sort((a, b) => (a < b ? 1 : a > b ? -1 : 0))[0];\n return {\n version: store.version,\n updatedAt: store.updatedAt,\n entryCount: entries.length,\n promotedCount: promoted.length,\n lastPromotedAt: lastPromotedAt ?? null,\n };\n}\n\nfunction payloadMessageFromJob(job: any): string {\n const p = job?.payload;\n if (!p) return '';\n if (p.kind === 'agentTurn' && typeof p.message === 'string') return p.message;\n if (typeof p.text === 'string') return p.text;\n if (typeof p.message === 'string') return p.message;\n return '';\n}\n\nexport function registerDreamingRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n authenticated.get('/api/dreaming', async (c) => {\n const cfg = service.currentConfig as Config;\n const workspaceDir = getWorkspacePath(cfg);\n if (!workspaceDir) {\n return c.json({ ok: false, error: { message: 'Workspace not configured' } }, 400);\n }\n\n const resolved = resolveDreamingConfig(cfg);\n const { store } = await loadDreamingStore({ workspaceDir });\n const lock = await readLockInfo(workspaceDir);\n\n // Read all three phase last-run files in parallel.\n const [lastRun, lightLastRun, remLastRun] = await Promise.all([\n readLastRun(workspaceDir),\n readPhaseLastRun(workspaceDir, 'last-run-light.json'),\n readPhaseLastRun(workspaceDir, 'last-run-rem.json'),\n ]);\n\n return c.json({\n ok: true,\n payload: {\n workspaceDir,\n config: resolved,\n storePath: SHORT_TERM_RECALL_STORE_RELATIVE,\n store: storeStats(store),\n lock,\n lastRun,\n lightLastRun,\n remLastRun,\n },\n });\n });\n\n authenticated.get('/api/dreaming/preview', async (c) => {\n const cfg = service.currentConfig as Config;\n const workspaceDir = getWorkspacePath(cfg);\n if (!workspaceDir) {\n return c.json({ ok: false, error: { message: 'Workspace not configured' } }, 400);\n }\n\n const resolved = resolveDreamingConfig(cfg);\n const rawLimit = c.req.query('limit');\n const limit = rawLimit ? Number(rawLimit) : 20;\n\n const preview = await previewDreamingDeepPromotion({\n workspaceDir,\n config: resolved.deep,\n limit: Number.isFinite(limit) ? limit : 20,\n });\n\n return c.json({ ok: true, payload: preview });\n });\n\n authenticated.post('/api/dreaming/run', async (c) => {\n let body: unknown;\n try { body = await c.req.json(); } catch { body = {}; }\n const requestedPhase: DreamingPhaseId =\n isRecord(body) && typeof body.phase === 'string' && ['light', 'deep', 'rem'].includes(body.phase)\n ? (body.phase as DreamingPhaseId)\n : 'deep';\n\n // Map phase → token + cron name for job lookup.\n const phaseTokenMap: Record<DreamingPhaseId, { token: string; cronName: string }> = {\n light: { token: DREAMING_LIGHT_SWEEP_TOKEN, cronName: DREAMING_LIGHT_CRON_NAME },\n deep: { token: DREAMING_SWEEP_TOKEN, cronName: DREAMING_CRON_NAME },\n rem: { token: DREAMING_REM_SWEEP_TOKEN, cronName: DREAMING_REM_CRON_NAME },\n };\n const { token, cronName } = phaseTokenMap[requestedPhase];\n\n const jobs = await service.cronServiceInstance.listJobs();\n const primary =\n jobs.find((job) => payloadMessageFromJob(job) === token) ??\n jobs.find((job) => job.name === cronName) ??\n (requestedPhase === 'deep'\n ? jobs.find((job) => (job.name?.includes?.(DREAMING_CRON_TAG) ?? false))\n : undefined);\n\n if (!primary) {\n const dreaming = resolveDreamingConfig(service.currentConfig as Config);\n const phaseEnabled = dreaming.enabled && dreaming.phases[requestedPhase].enabled;\n const hint = phaseEnabled\n ? `Dreaming ${requestedPhase} phase is enabled, but no cron job was found yet. Restart the gateway/agent process so it can reconcile managed cron jobs.`\n : `Dreaming ${requestedPhase} phase is disabled in config. Enable it first.`;\n return c.json({ ok: false, error: { message: `Dreaming ${requestedPhase} cron job not found. ${hint}` } }, 404);\n }\n\n try {\n // Broadcast phase start to all SSE subscribers (drives dreaming animation overlay).\n service.emit('dreaming.phase.start', { phase: requestedPhase, timestamp: new Date().toISOString() });\n\n await service.cronServiceInstance.runJobNow(primary.id);\n\n // Broadcast phase end (the cron job runs async, so this only marks \"triggered\").\n service.emit('dreaming.phase.end', { phase: requestedPhase, ok: true, timestamp: new Date().toISOString() });\n\n return c.json({ ok: true, payload: { triggered: true, jobId: primary.id, phase: requestedPhase } });\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n service.emit('dreaming.phase.end', { phase: requestedPhase, ok: false, error: em, timestamp: new Date().toISOString() });\n return c.json({ ok: false, error: { message: em || 'Failed to trigger job' } }, 400);\n }\n });\n\n authenticated.post('/api/dreaming/action', async (c) => {\n const cfg = service.currentConfig as Config;\n const workspaceDir = getWorkspacePath(cfg);\n if (!workspaceDir) {\n return c.json({ ok: false, error: { message: 'Workspace not configured' } }, 400);\n }\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n body = {};\n }\n const action = isRecord(body) && typeof body.action === 'string' ? body.action.trim() : '';\n\n if (action !== 'reset_store' && action !== 'clear_lock') {\n return c.json({ ok: false, error: { message: 'Invalid action' } }, 400);\n }\n\n if (action === 'reset_store') {\n const nowIso = new Date().toISOString();\n const next: DreamingStore = { version: 1, updatedAt: nowIso, entries: {} };\n await saveDreamingStore({ workspaceDir, store: next });\n return c.json({ ok: true, payload: { reset: true, storePath: SHORT_TERM_RECALL_STORE_RELATIVE } });\n }\n\n const lockPath = path.join(workspaceDir, SHORT_TERM_PROMOTION_LOCK_RELATIVE);\n await fs.unlink(lockPath).catch(() => undefined);\n return c.json({ ok: true, payload: { cleared: true, lockPath: SHORT_TERM_PROMOTION_LOCK_RELATIVE } });\n });\n\n authenticated.get('/api/dreaming/events', async (c) => {\n const cfg = service.currentConfig as Config;\n const workspaceDir = getWorkspacePath(cfg);\n if (!workspaceDir) {\n return c.json({ ok: false, error: { message: 'Workspace not configured' } }, 400);\n }\n\n const rawLimit = c.req.query('limit');\n const limit = rawLimit ? Math.min(Math.max(Number(rawLimit) || 50, 1), 200) : 50;\n\n const events = await readDreamingEvents(workspaceDir, limit);\n return c.json({ ok: true, payload: { events } });\n });\n}\n\n"],"mappings":";;;;;;;;;;aAI0E;AA0B1E,SAAS,SAAS,GAA0C;AAC1D,QAAO,MAAM,QAAQ,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,EAAE;;AAGjE,eAAe,aAAa,cAG1B;CACA,MAAM,WAAW,KAAK,KAAK,cAAc,mCAAmC;AAC5E,KAAI;EACF,MAAM,CAAC,SAAS,MAAM,MAAM,QAAQ,IAAI,CAAC,GAAG,SAAS,UAAU,QAAQ,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC;AAC5F,SAAO;GACL,QAAQ;GACR,MAAM;GACN,SAAS,QAAQ,MAAM;GACvB,SAAS,GAAG;GACb;UACM,KAAK;AAEZ,MADc,KAA2C,SAC5C,SAAU,QAAO,EAAE,QAAQ,OAAO;AAC/C,SAAO;GAAE,QAAQ;GAAM,MAAM;GAAoC,SAAS;GAAW,SAAS,KAAA;GAAW;;;AAI7G,eAAe,YACb,cAUA;CACA,MAAM,WAAW,KAAK,KAAK,cAAc,2BAA2B;AACpE,KAAI;EACF,MAAM,OAAO,MAAM,GAAG,SAAS,UAAU,QAAQ;EACjD,IAAI;AACJ,MAAI;AACF,SAAM,KAAK,MAAM,KAAK;WACf,UAAU;AACjB,UAAO;IACL,QAAQ;IACR,MAAM;IACN,KAAK;IACL,QAAQ;IACR,YAAY,oBAAoB,QAAQ,SAAS,UAAU,OAAO,SAAS;IAC5E;;EAEH,MAAM,SAAS,yBAAyB,IAAI;AAC5C,SAAO;GACL,QAAQ;GACR,MAAM;GACN;GACA;GACA,YAAY,SAAS,OAAO;GAC7B;UACM,KAAK;AAEZ,MADc,KAA2C,SAC5C,SAAU,QAAO,EAAE,QAAQ,OAAO;AAC/C,SAAO;GACL,QAAQ;GACR,MAAM;GACN,KAAK;GACL,QAAQ;GACR,YAAY,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;GAC7D;;;AAIL,eAAe,iBACb,cACA,UAC2E;CAC3E,MAAM,UAAU,KAAK,KAAK,uBAAuB,SAAS;CAC1D,MAAM,WAAW,KAAK,KAAK,cAAc,QAAQ;AACjD,KAAI;EACF,MAAM,OAAO,MAAM,GAAG,SAAS,UAAU,QAAQ;AAEjD,SAAO;GAAE,QAAQ;GAAM,MAAM;GAAS,KAD1B,KAAK,MAAM,KACkB;GAAE;UACpC,KAAK;AAEZ,MADc,KAA2C,SAC5C,SAAU,QAAO,EAAE,QAAQ,OAAO;AAC/C,SAAO,EAAE,QAAQ,OAAO;;;AAI5B,SAAS,WAAW,OAMlB;CACA,MAAM,UAAU,OAAO,OAAO,MAAM,WAAW,EAAE,CAAC;CAClD,MAAM,WAAW,QAAQ,QAAQ,MAAM,OAAO,EAAE,eAAe,YAAY,EAAE,WAAW,MAAM,CAAC;CAC/F,MAAM,iBAAiB,SACpB,KAAK,MAAM,EAAE,WAAY,CACzB,MAAM,GAAG,MAAO,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,EAAG,CAAC;AAChD,QAAO;EACL,SAAS,MAAM;EACf,WAAW,MAAM;EACjB,YAAY,QAAQ;EACpB,eAAe,SAAS;EACxB,gBAAgB,kBAAkB;EACnC;;AAGH,SAAS,sBAAsB,KAAkB;CAC/C,MAAM,IAAI,KAAK;AACf,KAAI,CAAC,EAAG,QAAO;AACf,KAAI,EAAE,SAAS,eAAe,OAAO,EAAE,YAAY,SAAU,QAAO,EAAE;AACtE,KAAI,OAAO,EAAE,SAAS,SAAU,QAAO,EAAE;AACzC,KAAI,OAAO,EAAE,YAAY,SAAU,QAAO,EAAE;AAC5C,QAAO;;AAGT,SAAgB,uBAAuB,eAAqB,MAAoC;CAC9F,MAAM,EAAE,YAAY;AAEpB,eAAc,IAAI,iBAAiB,OAAO,MAAM;EAC9C,MAAM,MAAM,QAAQ;EACpB,MAAM,eAAe,iBAAiB,IAAI;AAC1C,MAAI,CAAC,aACH,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,4BAA4B;GAAE,EAAE,IAAI;EAGnF,MAAM,WAAW,sBAAsB,IAAI;EAC3C,MAAM,EAAE,UAAU,MAAM,kBAAkB,EAAE,cAAc,CAAC;EAC3D,MAAM,OAAO,MAAM,aAAa,aAAa;EAG7C,MAAM,CAAC,SAAS,cAAc,cAAc,MAAM,QAAQ,IAAI;GAC5D,YAAY,aAAa;GACzB,iBAAiB,cAAc,sBAAsB;GACrD,iBAAiB,cAAc,oBAAoB;GACpD,CAAC;AAEF,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IACP;IACA,QAAQ;IACR,WAAW;IACX,OAAO,WAAW,MAAM;IACxB;IACA;IACA;IACA;IACD;GACF,CAAC;GACF;AAEF,eAAc,IAAI,yBAAyB,OAAO,MAAM;EACtD,MAAM,MAAM,QAAQ;EACpB,MAAM,eAAe,iBAAiB,IAAI;AAC1C,MAAI,CAAC,aACH,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,4BAA4B;GAAE,EAAE,IAAI;EAGnF,MAAM,WAAW,sBAAsB,IAAI;EAC3C,MAAM,WAAW,EAAE,IAAI,MAAM,QAAQ;EACrC,MAAM,QAAQ,WAAW,OAAO,SAAS,GAAG;EAE5C,MAAM,UAAU,MAAM,6BAA6B;GACjD;GACA,QAAQ,SAAS;GACjB,OAAO,OAAO,SAAS,MAAM,GAAG,QAAQ;GACzC,CAAC;AAEF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS;GAAS,CAAC;GAC7C;AAEF,eAAc,KAAK,qBAAqB,OAAO,MAAM;EACnD,IAAI;AACJ,MAAI;AAAE,UAAO,MAAM,EAAE,IAAI,MAAM;UAAU;AAAE,UAAO,EAAE;;EACpD,MAAM,iBACJ,SAAS,KAAK,IAAI,OAAO,KAAK,UAAU,YAAY;GAAC;GAAS;GAAQ;GAAM,CAAC,SAAS,KAAK,MAAM,GAC5F,KAAK,QACN;EAQN,MAAM,EAAE,OAAO,aAAa;GAJ1B,OAAO;IAAE,OAAO;IAA4B,UAAU;IAA0B;GAChF,MAAM;IAAE,OAAO;IAAsB,UAAU;IAAoB;GACnE,KAAK;IAAE,OAAO;IAA0B,UAAU;IAAwB;GAEnC,CAAC;EAE1C,MAAM,OAAO,MAAM,QAAQ,oBAAoB,UAAU;EACzD,MAAM,UACJ,KAAK,MAAM,QAAQ,sBAAsB,IAAI,KAAK,MAAM,IACxD,KAAK,MAAM,QAAQ,IAAI,SAAS,SAAS,KACxC,mBAAmB,SAChB,KAAK,MAAM,QAAS,IAAI,MAAM,WAAA,oCAA6B,IAAI,MAAO,GACtE,KAAA;AAEN,MAAI,CAAC,SAAS;GACZ,MAAM,WAAW,sBAAsB,QAAQ,cAAwB;GAEvE,MAAM,OADe,SAAS,WAAW,SAAS,OAAO,gBAAgB,UAErE,YAAY,eAAe,8HAC3B,YAAY,eAAe;AAC/B,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,EAAE,SAAS,YAAY,eAAe,uBAAuB,QAAQ;IAAE,EAAE,IAAI;;AAGjH,MAAI;AAEF,WAAQ,KAAK,wBAAwB;IAAE,OAAO;IAAgB,4BAAW,IAAI,MAAM,EAAC,aAAa;IAAE,CAAC;AAEpG,SAAM,QAAQ,oBAAoB,UAAU,QAAQ,GAAG;AAGvD,WAAQ,KAAK,sBAAsB;IAAE,OAAO;IAAgB,IAAI;IAAM,4BAAW,IAAI,MAAM,EAAC,aAAa;IAAE,CAAC;AAE5G,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,SAAS;KAAE,WAAW;KAAM,OAAO,QAAQ;KAAI,OAAO;KAAgB;IAAE,CAAC;WAC5F,KAAK;GACZ,MAAM,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC3D,WAAQ,KAAK,sBAAsB;IAAE,OAAO;IAAgB,IAAI;IAAO,OAAO;IAAI,4BAAW,IAAI,MAAM,EAAC,aAAa;IAAE,CAAC;AACxH,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,EAAE,SAAS,MAAM,yBAAyB;IAAE,EAAE,IAAI;;GAEtF;AAEF,eAAc,KAAK,wBAAwB,OAAO,MAAM;EACtD,MAAM,MAAM,QAAQ;EACpB,MAAM,eAAe,iBAAiB,IAAI;AAC1C,MAAI,CAAC,aACH,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,4BAA4B;GAAE,EAAE,IAAI;EAGnF,IAAI;AACJ,MAAI;AACF,UAAO,MAAM,EAAE,IAAI,MAAM;UACnB;AACN,UAAO,EAAE;;EAEX,MAAM,SAAS,SAAS,KAAK,IAAI,OAAO,KAAK,WAAW,WAAW,KAAK,OAAO,MAAM,GAAG;AAExF,MAAI,WAAW,iBAAiB,WAAW,aACzC,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,kBAAkB;GAAE,EAAE,IAAI;AAGzE,MAAI,WAAW,eAAe;AAG5B,SAAM,kBAAkB;IAAE;IAAc,OAAO;KADjB,SAAS;KAAG,4BAD3B,IAAI,MAAM,EAAC,aACiC;KAAE,SAAS,EAAE;KACrB;IAAE,CAAC;AACtD,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,SAAS;KAAE,OAAO;KAAM,WAAW;KAAkC;IAAE,CAAC;;EAGpG,MAAM,WAAW,KAAK,KAAK,cAAc,mCAAmC;AAC5E,QAAM,GAAG,OAAO,SAAS,CAAC,YAAY,KAAA,EAAU;AAChD,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS;IAAE,SAAS;IAAM,UAAU;IAAoC;GAAE,CAAC;GACrG;AAEF,eAAc,IAAI,wBAAwB,OAAO,MAAM;EACrD,MAAM,MAAM,QAAQ;EACpB,MAAM,eAAe,iBAAiB,IAAI;AAC1C,MAAI,CAAC,aACH,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,4BAA4B;GAAE,EAAE,IAAI;EAGnF,MAAM,WAAW,EAAE,IAAI,MAAM,QAAQ;EAGrC,MAAM,SAAS,MAAM,mBAAmB,cAF1B,WAAW,KAAK,IAAI,KAAK,IAAI,OAAO,SAAS,IAAI,IAAI,EAAE,EAAE,IAAI,GAAG,GAElB;AAC5D,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS,EAAE,QAAQ;GAAE,CAAC;GAChD"}
@@ -6,6 +6,7 @@ import { registerCommandsSkillsRoutes } from "./commands-skills.js";
6
6
  import { registerConfigRoutes } from "./config.js";
7
7
  import { registerDoctorRoutes } from "./doctor.js";
8
8
  import { registerCronRoutes } from "./cron.js";
9
+ import { registerDreamingRoutes } from "./dreaming.js";
9
10
  import { registerExtensionGatewayRoutes } from "./extension-gateway.js";
10
11
  import { registerHostFsRoutes } from "./host-fs.js";
11
12
  import { registerLogsRoutes } from "./logs.js";
@@ -23,6 +24,7 @@ function registerAuthenticatedRoutes(authenticated, deps) {
23
24
  registerChannelRoutes(authenticated, deps);
24
25
  registerConfigRoutes(authenticated, deps);
25
26
  registerDoctorRoutes(authenticated, deps);
27
+ registerDreamingRoutes(authenticated, deps);
26
28
  registerAgentsRoutes(authenticated, deps);
27
29
  registerAuthRegistryExtensionsRoutes(authenticated, deps);
28
30
  registerModelsRoutes(authenticated, deps);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/gateway/hono/routes/index.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { registerAgentStreamRoutes } from './agent-stream.js';\nimport { registerAgentsRoutes } from './agents.js';\nimport { registerAuthRegistryExtensionsRoutes } from './auth-registry-extensions.js';\nimport { registerChannelRoutes } from './channels.js';\nimport { registerCommandsSkillsRoutes } from './commands-skills.js';\nimport { registerConfigRoutes } from './config.js';\nimport { registerDoctorRoutes } from './doctor.js';\nimport { registerCronRoutes } from './cron.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { registerExtensionGatewayRoutes } from './extension-gateway.js';\nimport { registerHostFsRoutes } from './host-fs.js';\nimport { registerLogsRoutes } from './logs.js';\nimport { registerModelsRoutes } from './models.js';\nimport { registerSessionsRoutes } from './sessions.js';\nimport { registerStatusRoutes } from './status.js';\nimport { registerUpdateRoutes } from './update.js';\nimport { registerWorkspaceRoutes } from './workspace.js';\n\nexport function registerAuthenticatedRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n registerStatusRoutes(authenticated, deps);\n registerWorkspaceRoutes(authenticated, deps);\n registerHostFsRoutes(authenticated, deps);\n registerAgentStreamRoutes(authenticated, deps);\n registerChannelRoutes(authenticated, deps);\n registerConfigRoutes(authenticated, deps);\n registerDoctorRoutes(authenticated, deps);\n registerAgentsRoutes(authenticated, deps);\n registerAuthRegistryExtensionsRoutes(authenticated, deps);\n registerModelsRoutes(authenticated, deps);\n registerCommandsSkillsRoutes(authenticated, deps);\n registerCronRoutes(authenticated, deps);\n registerSessionsRoutes(authenticated, deps);\n registerLogsRoutes(authenticated, deps);\n registerExtensionGatewayRoutes(authenticated, deps);\n registerUpdateRoutes(authenticated, deps);\n}\n\nexport type { AuthenticatedRouteDeps } from './deps.js';\n"],"mappings":";;;;;;;;;;;;;;;;;AAoBA,SAAgB,4BAA4B,eAAqB,MAAoC;AACnG,sBAAqB,eAAe,KAAK;AACzC,yBAAwB,eAAe,KAAK;AAC5C,sBAAqB,eAAe,KAAK;AACzC,2BAA0B,eAAe,KAAK;AAC9C,uBAAsB,eAAe,KAAK;AAC1C,sBAAqB,eAAe,KAAK;AACzC,sBAAqB,eAAe,KAAK;AACzC,sBAAqB,eAAe,KAAK;AACzC,sCAAqC,eAAe,KAAK;AACzD,sBAAqB,eAAe,KAAK;AACzC,8BAA6B,eAAe,KAAK;AACjD,oBAAmB,eAAe,KAAK;AACvC,wBAAuB,eAAe,KAAK;AAC3C,oBAAmB,eAAe,KAAK;AACvC,gCAA+B,eAAe,KAAK;AACnD,sBAAqB,eAAe,KAAK"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/gateway/hono/routes/index.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { registerAgentStreamRoutes } from './agent-stream.js';\nimport { registerAgentsRoutes } from './agents.js';\nimport { registerAuthRegistryExtensionsRoutes } from './auth-registry-extensions.js';\nimport { registerChannelRoutes } from './channels.js';\nimport { registerCommandsSkillsRoutes } from './commands-skills.js';\nimport { registerConfigRoutes } from './config.js';\nimport { registerDoctorRoutes } from './doctor.js';\nimport { registerCronRoutes } from './cron.js';\nimport { registerDreamingRoutes } from './dreaming.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { registerExtensionGatewayRoutes } from './extension-gateway.js';\nimport { registerHostFsRoutes } from './host-fs.js';\nimport { registerLogsRoutes } from './logs.js';\nimport { registerModelsRoutes } from './models.js';\nimport { registerSessionsRoutes } from './sessions.js';\nimport { registerStatusRoutes } from './status.js';\nimport { registerUpdateRoutes } from './update.js';\nimport { registerWorkspaceRoutes } from './workspace.js';\n\nexport function registerAuthenticatedRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n registerStatusRoutes(authenticated, deps);\n registerWorkspaceRoutes(authenticated, deps);\n registerHostFsRoutes(authenticated, deps);\n registerAgentStreamRoutes(authenticated, deps);\n registerChannelRoutes(authenticated, deps);\n registerConfigRoutes(authenticated, deps);\n registerDoctorRoutes(authenticated, deps);\n registerDreamingRoutes(authenticated, deps);\n registerAgentsRoutes(authenticated, deps);\n registerAuthRegistryExtensionsRoutes(authenticated, deps);\n registerModelsRoutes(authenticated, deps);\n registerCommandsSkillsRoutes(authenticated, deps);\n registerCronRoutes(authenticated, deps);\n registerSessionsRoutes(authenticated, deps);\n registerLogsRoutes(authenticated, deps);\n registerExtensionGatewayRoutes(authenticated, deps);\n registerUpdateRoutes(authenticated, deps);\n}\n\nexport type { AuthenticatedRouteDeps } from './deps.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,SAAgB,4BAA4B,eAAqB,MAAoC;AACnG,sBAAqB,eAAe,KAAK;AACzC,yBAAwB,eAAe,KAAK;AAC5C,sBAAqB,eAAe,KAAK;AACzC,2BAA0B,eAAe,KAAK;AAC9C,uBAAsB,eAAe,KAAK;AAC1C,sBAAqB,eAAe,KAAK;AACzC,sBAAqB,eAAe,KAAK;AACzC,wBAAuB,eAAe,KAAK;AAC3C,sBAAqB,eAAe,KAAK;AACzC,sCAAqC,eAAe,KAAK;AACzD,sBAAqB,eAAe,KAAK;AACzC,8BAA6B,eAAe,KAAK;AACjD,oBAAmB,eAAe,KAAK;AACvC,wBAAuB,eAAe,KAAK;AAC3C,oBAAmB,eAAe,KAAK;AACvC,gCAA+B,eAAe,KAAK;AACnD,sBAAqB,eAAe,KAAK"}
@@ -2,6 +2,7 @@ import { resolveModelsJsonPath } from "../../../config/paths.js";
2
2
  import { init_resolve_config_value, testApiKeyResolution } from "../../../config/resolve-config-value.js";
3
3
  import { init_models_json, loadModelsJson, saveModelsJson, validateModelsConfig } from "../../../config/models-json.js";
4
4
  import { getModelRegistry } from "../../../providers/model-registry.js";
5
+ import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
5
6
  import { getProviderRegistry, init_plugin_registry } from "../../../providers/plugin-registry.js";
6
7
  import { PROVIDER_META, getAllModels, getAllProviders, getAvailableModels, getProviderActiveKeySource, init_providers, isProviderConfigured } from "../../../providers/index.js";
7
8
  import { listImageGenerationProvidersSummary } from "../../../agent/image/generation/runtime.js";
@@ -9,6 +10,7 @@ import { listImageGenerationProvidersSummary } from "../../../agent/image/genera
9
10
  init_models_json();
10
11
  init_resolve_config_value();
11
12
  init_providers();
13
+ init_credentials();
12
14
  init_plugin_registry();
13
15
  function mapPluginModel(providerId, model, available) {
14
16
  return {
@@ -28,7 +30,7 @@ function mapPluginModel(providerId, model, available) {
28
30
  };
29
31
  }
30
32
  function registerModelsRoutes(authenticated, deps) {
31
- const { service } = deps;
33
+ const { service, strictRateLimitMiddleware } = deps;
32
34
  authenticated.get("/api/models-json", async (c) => {
33
35
  const path = resolveModelsJsonPath();
34
36
  const { config, error } = loadModelsJson(path);
@@ -201,6 +203,29 @@ function registerModelsRoutes(authenticated, deps) {
201
203
  payload: { providers: meta }
202
204
  });
203
205
  });
206
+ authenticated.delete("/api/providers/:providerId/key", strictRateLimitMiddleware, async (c) => {
207
+ const providerId = c.req.param("providerId");
208
+ if (!providerId) return c.json({
209
+ ok: false,
210
+ error: { message: "Missing providerId" }
211
+ }, 400);
212
+ const normalizedProvider = providerId.toLowerCase();
213
+ const profileId = `${normalizedProvider}:default`;
214
+ const resolver = new CredentialResolver();
215
+ try {
216
+ await resolver.deleteProfile(profileId);
217
+ return c.json({
218
+ ok: true,
219
+ payload: { deleted: normalizedProvider }
220
+ });
221
+ } catch (error) {
222
+ const errorMessage = error instanceof Error ? error.message : String(error);
223
+ return c.json({
224
+ ok: false,
225
+ error: { message: `Failed to delete key: ${errorMessage}` }
226
+ }, 500);
227
+ }
228
+ });
204
229
  }
205
230
  //#endregion
206
231
  export { registerModelsRoutes };
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","names":["getModelsJsonPath"],"sources":["../../../../../src/gateway/hono/routes/models.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport {\n getModelsJsonPath,\n loadModelsJson,\n saveModelsJson,\n validateModelsConfig,\n} from '../../../config/models-json.js';\nimport { testApiKeyResolution } from '../../../config/resolve-config-value.js';\nimport { listImageGenerationProvidersSummary } from '../../../agent/image/generation/runtime.js';\nimport {\n getAllModels,\n getAvailableModels,\n getModelRegistry,\n getAllProviders,\n getProviderActiveKeySource,\n isProviderConfigured,\n PROVIDER_META,\n} from '../../../providers/index.js';\nimport { getProviderRegistry } from '../../../providers/plugin-registry.js';\nimport type { ProviderModelDefinition } from '../../../extensions/types/providers.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nfunction mapPluginModel(providerId: string, model: ProviderModelDefinition, available: boolean) {\n return {\n id: `${providerId}/${model.id}`,\n name: model.name,\n provider: providerId,\n contextWindow: model.contextWindow ?? 128000,\n maxTokens: model.maxOutputTokens ?? 4096,\n reasoning: false,\n vision: model.supportsImages ?? false,\n cost: { input: model.pricing?.input ?? 0, output: model.pricing?.output ?? 0 },\n available,\n source: 'extension' as const,\n };\n}\n\nexport function registerModelsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // GET /api/models-json - Get models.json configuration\n authenticated.get('/api/models-json', async (c) => {\n const path = getModelsJsonPath();\n const { config, error } = loadModelsJson(path);\n const registry = getModelRegistry();\n \n return c.json({\n ok: true,\n payload: {\n config,\n path,\n exists: error === undefined,\n loadError: error || registry.getError(),\n },\n });\n });\n\n // POST /api/models-json/validate - Validate models.json configuration\n authenticated.post('/api/models-json/validate', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const result = validateModelsConfig(config);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // PATCH /api/models-json - Save models.json configuration\n authenticated.patch('/api/models-json', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const path = getModelsJsonPath();\n const result = saveModelsJson(path, config);\n \n if (!result.success) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n \n // Refresh registry\n const registry = getModelRegistry();\n registry.refresh();\n \n // Emit event\n service.emit('models-json.updated', { \n modelCount: registry.getAll().length,\n });\n \n return c.json({ \n ok: true, \n payload: { \n saved: true,\n modelCount: registry.getAll().length,\n },\n });\n });\n\n // POST /api/models-json/reload - Hot reload models.json\n authenticated.post('/api/models-json/reload', async (c) => {\n const registry = getModelRegistry();\n registry.refresh();\n \n const error = registry.getError();\n const models = registry.getAll();\n \n service.emit('models-json.reloaded', { \n modelCount: models.length,\n error: error || undefined,\n });\n \n return c.json({\n ok: true,\n payload: {\n modelCount: models.length,\n error,\n },\n });\n });\n\n // POST /api/models-json/test-api-key - Test API key resolution\n authenticated.post('/api/models-json/test-api-key', async (c) => {\n const body = await c.req.json();\n const { value } = body;\n \n const result = testApiKeyResolution(value);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // GET /api/models - Get available models (only configured providers)\n authenticated.get('/api/models', async (c) => {\n const pluginRegistry = getProviderRegistry();\n const models = (await getAvailableModels()).map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, true));\n existingIds.add(compositeId);\n }\n }\n }\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/image/providers — registered image generation providers and models (not in LLM model registry)\n authenticated.get('/api/image/providers', (c) => {\n const providers = listImageGenerationProvidersSummary();\n return c.json({ ok: true, payload: { providers } });\n });\n\n // GET /api/providers - Get ALL available providers and models\n authenticated.get('/api/providers', async (c) => {\n const pluginRegistry = getProviderRegistry();\n const allModels = getAllModels();\n const availableModels = await getAvailableModels();\n const configured = new Set(availableModels.map(m => `${m.provider}/${m.id}`));\n\n const models = allModels.map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n available: configured.has(`${m.provider}/${m.id}`),\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, configured.has(compositeId)));\n existingIds.add(compositeId);\n }\n }\n }\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/providers/meta - Get provider metadata (categories, display names)\n authenticated.get('/api/providers/meta', async (c) => {\n const providers = getAllProviders();\n const pluginRegistry = getProviderRegistry();\n\n const meta = await Promise.all(\n providers.map(async (provider) => {\n const plugin = pluginRegistry.get(provider);\n return {\n id: provider,\n name: plugin?.name ?? PROVIDER_META[provider]?.name ?? provider,\n category: plugin ? ('extension' as const) : PROVIDER_META[provider]?.category || 'specialty',\n supportsOAuth: plugin ? false : (PROVIDER_META[provider]?.supportsOAuth ?? false),\n supportsApiKey: plugin ? true : (PROVIDER_META[provider]?.supportsApiKey ?? true),\n configured: await isProviderConfigured(provider),\n activeKeySource: await getProviderActiveKeySource(provider),\n };\n }),\n );\n\n const knownProviderIds = new Set(providers);\n for (const plugin of pluginRegistry.listAll()) {\n if (!knownProviderIds.has(plugin.id)) {\n meta.push({\n id: plugin.id,\n name: plugin.name,\n category: 'extension',\n supportsOAuth: false,\n supportsApiKey: true,\n configured: true,\n activeKeySource: 'extension',\n });\n }\n }\n\n return c.json({ ok: true, payload: { providers: meta } });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"models.js","names":["getModelsJsonPath"],"sources":["../../../../../src/gateway/hono/routes/models.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport {\n getModelsJsonPath,\n loadModelsJson,\n saveModelsJson,\n validateModelsConfig,\n} from '../../../config/models-json.js';\nimport { testApiKeyResolution } from '../../../config/resolve-config-value.js';\nimport { listImageGenerationProvidersSummary } from '../../../agent/image/generation/runtime.js';\nimport {\n getAllModels,\n getAvailableModels,\n getModelRegistry,\n getAllProviders,\n getProviderActiveKeySource,\n isProviderConfigured,\n PROVIDER_META,\n} from '../../../providers/index.js';\nimport { CredentialResolver } from '../../../auth/credentials.js';\nimport { getProviderRegistry } from '../../../providers/plugin-registry.js';\nimport type { ProviderModelDefinition } from '../../../extensions/types/providers.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nfunction mapPluginModel(providerId: string, model: ProviderModelDefinition, available: boolean) {\n return {\n id: `${providerId}/${model.id}`,\n name: model.name,\n provider: providerId,\n contextWindow: model.contextWindow ?? 128000,\n maxTokens: model.maxOutputTokens ?? 4096,\n reasoning: false,\n vision: model.supportsImages ?? false,\n cost: { input: model.pricing?.input ?? 0, output: model.pricing?.output ?? 0 },\n available,\n source: 'extension' as const,\n };\n}\n\nexport function registerModelsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n // GET /api/models-json - Get models.json configuration\n authenticated.get('/api/models-json', async (c) => {\n const path = getModelsJsonPath();\n const { config, error } = loadModelsJson(path);\n const registry = getModelRegistry();\n \n return c.json({\n ok: true,\n payload: {\n config,\n path,\n exists: error === undefined,\n loadError: error || registry.getError(),\n },\n });\n });\n\n // POST /api/models-json/validate - Validate models.json configuration\n authenticated.post('/api/models-json/validate', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const result = validateModelsConfig(config);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // PATCH /api/models-json - Save models.json configuration\n authenticated.patch('/api/models-json', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const path = getModelsJsonPath();\n const result = saveModelsJson(path, config);\n \n if (!result.success) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n \n // Refresh registry\n const registry = getModelRegistry();\n registry.refresh();\n \n // Emit event\n service.emit('models-json.updated', { \n modelCount: registry.getAll().length,\n });\n \n return c.json({ \n ok: true, \n payload: { \n saved: true,\n modelCount: registry.getAll().length,\n },\n });\n });\n\n // POST /api/models-json/reload - Hot reload models.json\n authenticated.post('/api/models-json/reload', async (c) => {\n const registry = getModelRegistry();\n registry.refresh();\n \n const error = registry.getError();\n const models = registry.getAll();\n \n service.emit('models-json.reloaded', { \n modelCount: models.length,\n error: error || undefined,\n });\n \n return c.json({\n ok: true,\n payload: {\n modelCount: models.length,\n error,\n },\n });\n });\n\n // POST /api/models-json/test-api-key - Test API key resolution\n authenticated.post('/api/models-json/test-api-key', async (c) => {\n const body = await c.req.json();\n const { value } = body;\n \n const result = testApiKeyResolution(value);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // GET /api/models - Get available models (only configured providers)\n authenticated.get('/api/models', async (c) => {\n const pluginRegistry = getProviderRegistry();\n const models = (await getAvailableModels()).map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, true));\n existingIds.add(compositeId);\n }\n }\n }\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/image/providers — registered image generation providers and models (not in LLM model registry)\n authenticated.get('/api/image/providers', (c) => {\n const providers = listImageGenerationProvidersSummary();\n return c.json({ ok: true, payload: { providers } });\n });\n\n // GET /api/providers - Get ALL available providers and models\n authenticated.get('/api/providers', async (c) => {\n const pluginRegistry = getProviderRegistry();\n const allModels = getAllModels();\n const availableModels = await getAvailableModels();\n const configured = new Set(availableModels.map(m => `${m.provider}/${m.id}`));\n\n const models = allModels.map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n available: configured.has(`${m.provider}/${m.id}`),\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, configured.has(compositeId)));\n existingIds.add(compositeId);\n }\n }\n }\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/providers/meta - Get provider metadata (categories, display names)\n authenticated.get('/api/providers/meta', async (c) => {\n const providers = getAllProviders();\n const pluginRegistry = getProviderRegistry();\n\n const meta = await Promise.all(\n providers.map(async (provider) => {\n const plugin = pluginRegistry.get(provider);\n return {\n id: provider,\n name: plugin?.name ?? PROVIDER_META[provider]?.name ?? provider,\n category: plugin ? ('extension' as const) : PROVIDER_META[provider]?.category || 'specialty',\n supportsOAuth: plugin ? false : (PROVIDER_META[provider]?.supportsOAuth ?? false),\n supportsApiKey: plugin ? true : (PROVIDER_META[provider]?.supportsApiKey ?? true),\n configured: await isProviderConfigured(provider),\n activeKeySource: await getProviderActiveKeySource(provider),\n };\n }),\n );\n\n const knownProviderIds = new Set(providers);\n for (const plugin of pluginRegistry.listAll()) {\n if (!knownProviderIds.has(plugin.id)) {\n meta.push({\n id: plugin.id,\n name: plugin.name,\n category: 'extension',\n supportsOAuth: false,\n supportsApiKey: true,\n configured: true,\n activeKeySource: 'extension',\n });\n }\n }\n\n return c.json({ ok: true, payload: { providers: meta } });\n });\n\n // DELETE /api/providers/:providerId/key - Remove a provider's stored API key\n authenticated.delete('/api/providers/:providerId/key', strictRateLimitMiddleware, async (c) => {\n const providerId = c.req.param('providerId');\n if (!providerId) {\n return c.json({ ok: false, error: { message: 'Missing providerId' } }, 400);\n }\n\n const normalizedProvider = providerId.toLowerCase();\n const profileId = `${normalizedProvider}:default`;\n const resolver = new CredentialResolver();\n\n try {\n await resolver.deleteProfile(profileId);\n return c.json({ ok: true, payload: { deleted: normalizedProvider } });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return c.json({ ok: false, error: { message: `Failed to delete key: ${errorMessage}` } }, 500);\n }\n });\n}\n"],"mappings":"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"}
@@ -39,6 +39,7 @@ function registerPublicGatewayRoutes(app, service) {
39
39
  "PATCH /api/agents/:id",
40
40
  "DELETE /api/agents/:id",
41
41
  "GET/PUT /api/agents/:id/files/...",
42
+ "DELETE /api/providers/:providerId/key",
42
43
  "PATCH /api/config",
43
44
  "POST /api/config/reload",
44
45
  "POST /api/heartbeat/trigger",
@@ -1 +1 @@
1
- {"version":3,"file":"public-gateway.js","names":[],"sources":["../../../../../src/gateway/hono/routes/public-gateway.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport type { GatewayService } from '../../service.js';\nimport { serveStaticFile } from '../lib/static-ui.js';\n\nexport function registerPublicGatewayRoutes(app: Hono, service: GatewayService): void {\n app.get('/health', (c) => {\n return c.json(service.getHealth());\n });\n\n /** Public liveness probe (no auth) — minimal payload for CLI / load balancers. */\n app.get('/api/health', (c) => {\n const health = service.getHealth();\n return c.json({\n status: 'ok',\n version: health.version,\n uptime: health.uptime,\n });\n });\n\n app.get('/api', (c) => {\n return c.json({\n service: 'xopc-gateway',\n version: PACKAGE_VERSION,\n transport: 'streamable-http',\n endpoints: [\n 'GET /health',\n 'GET /api/health',\n 'GET /status',\n 'GET /api/status',\n 'POST /api/agent (SSE stream / JSON)',\n 'POST /api/agent/abort',\n 'POST /api/agent/steer',\n 'POST /api/send',\n 'GET /api/events (SSE stream)',\n 'GET /api/channels/status',\n 'POST /api/channels/weixin/login/start',\n 'GET /api/channels/weixin/login/:sessionKey',\n 'GET /api/config',\n 'GET /api/agents',\n 'POST /api/agents',\n 'PATCH /api/agents/:id',\n 'DELETE /api/agents/:id',\n 'GET/PUT /api/agents/:id/files/...',\n 'PATCH /api/config',\n 'POST /api/config/reload',\n 'POST /api/heartbeat/trigger',\n '... /api/cron/*',\n 'GET/PATCH /api/sessions/:key/agent-config',\n '... /api/sessions/*',\n 'GET /api/host/fs/meta',\n 'GET /api/host/fs/list',\n ],\n });\n });\n\n app.get('/assets/*', (c) => {\n const path = c.req.path.replace('/assets/', '');\n const response = serveStaticFile(`assets/${path}`);\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n /** From `web/public/channel-icons/` (Vite copies to static root). Public: img requests send no Bearer token. */\n app.get('/channel-icons/*', (c) => {\n const path = c.req.path.replace('/channel-icons/', '');\n const response = serveStaticFile(`channel-icons/${path}`);\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/favicon.ico', (c) => {\n const response = serveStaticFile('favicon.ico');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo.svg', (c) => {\n const response = serveStaticFile('logo.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo-dark.svg', (c) => {\n const response = serveStaticFile('logo-dark.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/', (c) => {\n const response = serveStaticFile('index.html');\n if (response) return response;\n return c.text('UI not found', 404);\n });\n}\n"],"mappings":";;;sBAE8D;AAI9D,SAAgB,4BAA4B,KAAW,SAA+B;AACpF,KAAI,IAAI,YAAY,MAAM;AACxB,SAAO,EAAE,KAAK,QAAQ,WAAW,CAAC;GAClC;;AAGF,KAAI,IAAI,gBAAgB,MAAM;EAC5B,MAAM,SAAS,QAAQ,WAAW;AAClC,SAAO,EAAE,KAAK;GACZ,QAAQ;GACR,SAAS,OAAO;GAChB,QAAQ,OAAO;GAChB,CAAC;GACF;AAEF,KAAI,IAAI,SAAS,MAAM;AACrB,SAAO,EAAE,KAAK;GACZ,SAAS;GACT,SAAS;GACT,WAAW;GACX,WAAW;IACT;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;GACF,CAAC;GACF;AAEF,KAAI,IAAI,cAAc,MAAM;EAE1B,MAAM,WAAW,gBAAgB,UADpB,EAAE,IAAI,KAAK,QAAQ,YAAY,GACG,GAAG;AAClD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;;AAGF,KAAI,IAAI,qBAAqB,MAAM;EAEjC,MAAM,WAAW,gBAAgB,iBADpB,EAAE,IAAI,KAAK,QAAQ,mBAAmB,GACG,GAAG;AACzD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,iBAAiB,MAAM;EAC7B,MAAM,WAAW,gBAAgB,cAAc;AAC/C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,cAAc,MAAM;EAC1B,MAAM,WAAW,gBAAgB,WAAW;AAC5C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,mBAAmB,MAAM;EAC/B,MAAM,WAAW,gBAAgB,gBAAgB;AACjD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,MAAM,MAAM;EAClB,MAAM,WAAW,gBAAgB,aAAa;AAC9C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,gBAAgB,IAAI;GAClC"}
1
+ {"version":3,"file":"public-gateway.js","names":[],"sources":["../../../../../src/gateway/hono/routes/public-gateway.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport type { GatewayService } from '../../service.js';\nimport { serveStaticFile } from '../lib/static-ui.js';\n\nexport function registerPublicGatewayRoutes(app: Hono, service: GatewayService): void {\n app.get('/health', (c) => {\n return c.json(service.getHealth());\n });\n\n /** Public liveness probe (no auth) — minimal payload for CLI / load balancers. */\n app.get('/api/health', (c) => {\n const health = service.getHealth();\n return c.json({\n status: 'ok',\n version: health.version,\n uptime: health.uptime,\n });\n });\n\n app.get('/api', (c) => {\n return c.json({\n service: 'xopc-gateway',\n version: PACKAGE_VERSION,\n transport: 'streamable-http',\n endpoints: [\n 'GET /health',\n 'GET /api/health',\n 'GET /status',\n 'GET /api/status',\n 'POST /api/agent (SSE stream / JSON)',\n 'POST /api/agent/abort',\n 'POST /api/agent/steer',\n 'POST /api/send',\n 'GET /api/events (SSE stream)',\n 'GET /api/channels/status',\n 'POST /api/channels/weixin/login/start',\n 'GET /api/channels/weixin/login/:sessionKey',\n 'GET /api/config',\n 'GET /api/agents',\n 'POST /api/agents',\n 'PATCH /api/agents/:id',\n 'DELETE /api/agents/:id',\n 'GET/PUT /api/agents/:id/files/...',\n 'DELETE /api/providers/:providerId/key',\n 'PATCH /api/config',\n 'POST /api/config/reload',\n 'POST /api/heartbeat/trigger',\n '... /api/cron/*',\n 'GET/PATCH /api/sessions/:key/agent-config',\n '... /api/sessions/*',\n 'GET /api/host/fs/meta',\n 'GET /api/host/fs/list',\n ],\n });\n });\n\n app.get('/assets/*', (c) => {\n const path = c.req.path.replace('/assets/', '');\n const response = serveStaticFile(`assets/${path}`);\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n /** From `web/public/channel-icons/` (Vite copies to static root). Public: img requests send no Bearer token. */\n app.get('/channel-icons/*', (c) => {\n const path = c.req.path.replace('/channel-icons/', '');\n const response = serveStaticFile(`channel-icons/${path}`);\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/favicon.ico', (c) => {\n const response = serveStaticFile('favicon.ico');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo.svg', (c) => {\n const response = serveStaticFile('logo.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo-dark.svg', (c) => {\n const response = serveStaticFile('logo-dark.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/', (c) => {\n const response = serveStaticFile('index.html');\n if (response) return response;\n return c.text('UI not found', 404);\n });\n}\n"],"mappings":";;;sBAE8D;AAI9D,SAAgB,4BAA4B,KAAW,SAA+B;AACpF,KAAI,IAAI,YAAY,MAAM;AACxB,SAAO,EAAE,KAAK,QAAQ,WAAW,CAAC;GAClC;;AAGF,KAAI,IAAI,gBAAgB,MAAM;EAC5B,MAAM,SAAS,QAAQ,WAAW;AAClC,SAAO,EAAE,KAAK;GACZ,QAAQ;GACR,SAAS,OAAO;GAChB,QAAQ,OAAO;GAChB,CAAC;GACF;AAEF,KAAI,IAAI,SAAS,MAAM;AACrB,SAAO,EAAE,KAAK;GACZ,SAAS;GACT,SAAS;GACT,WAAW;GACX,WAAW;IACT;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;GACF,CAAC;GACF;AAEF,KAAI,IAAI,cAAc,MAAM;EAE1B,MAAM,WAAW,gBAAgB,UADpB,EAAE,IAAI,KAAK,QAAQ,YAAY,GACG,GAAG;AAClD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;;AAGF,KAAI,IAAI,qBAAqB,MAAM;EAEjC,MAAM,WAAW,gBAAgB,iBADpB,EAAE,IAAI,KAAK,QAAQ,mBAAmB,GACG,GAAG;AACzD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,iBAAiB,MAAM;EAC7B,MAAM,WAAW,gBAAgB,cAAc;AAC/C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,cAAc,MAAM;EAC1B,MAAM,WAAW,gBAAgB,WAAW;AAC5C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,mBAAmB,MAAM;EAC/B,MAAM,WAAW,gBAAgB,gBAAgB;AACjD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,MAAM,MAAM;EAClB,MAAM,WAAW,gBAAgB,aAAa;AAC9C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,gBAAgB,IAAI;GAClC"}
@@ -1,9 +1,9 @@
1
1
  import path from "node:path";
2
2
  import fsSync from "node:fs";
3
3
  import fs from "node:fs/promises";
4
+ import { createHash } from "node:crypto";
4
5
  import { homedir } from "os";
5
6
  import net from "node:net";
6
- import { createHash } from "node:crypto";
7
7
  //#region src/gateway/lock.ts
8
8
  /**
9
9
  * Gateway Lock - Prevents multiple gateway instances from running simultaneously
@@ -485,6 +485,13 @@ var GatewayService = class {
485
485
  await saveConfig(configToWrite, this.configPath);
486
486
  this.config = loadConfig(this.configPath);
487
487
  this.agentService.applyAgentDefaultsFromConfig(this.config);
488
+ await this.agentService.reconcileDreamingNow().catch((err) => {
489
+ const em = err instanceof Error ? err.message : String(err);
490
+ log.warn({
491
+ err,
492
+ errorMessage: em
493
+ }, `Dreaming cron reconcile after save failed: ${em}`);
494
+ });
488
495
  }
489
496
  async saveConfig(config) {
490
497
  try {