clawmini 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +59 -0
- package/README.md +4 -2
- package/dist/adapter-discord/index.d.mts.map +1 -1
- package/dist/adapter-discord/index.mjs +13 -4
- package/dist/adapter-discord/index.mjs.map +1 -1
- package/dist/cli/index.mjs +7 -6
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lite.mjs +16 -10
- package/dist/cli/lite.mjs.map +1 -1
- package/dist/daemon/index.mjs +590 -401
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/{fetch-BjZVyU3Z.mjs → fetch-Cn1XNyiO.mjs} +1 -1
- package/dist/{fetch-BjZVyU3Z.mjs.map → fetch-Cn1XNyiO.mjs.map} +1 -1
- package/dist/lite-oSYSvaOr.mjs +164 -0
- package/dist/lite-oSYSvaOr.mjs.map +1 -0
- package/dist/web/_app/immutable/chunks/{CAZeqksE.js → 8YNcRyEk.js} +1 -1
- package/dist/web/_app/immutable/chunks/{B3YcEpQV.js → DQoygso7.js} +1 -1
- package/dist/web/_app/immutable/entry/{app.ZuicLpkH.js → app.DO5eYwVz.js} +2 -2
- package/dist/web/_app/immutable/entry/start.D48mVn1m.js +1 -0
- package/dist/web/_app/immutable/nodes/{0.BB1CjKco.js → 0.B-0CcADM.js} +1 -1
- package/dist/web/_app/immutable/nodes/{1.CdSgEHu9.js → 1.FixKgvRO.js} +1 -1
- package/{web/.svelte-kit/output/client/_app/immutable/nodes/3.CKp7Wkn8.js → dist/web/_app/immutable/nodes/3.ncP0xLO6.js} +1 -1
- package/dist/web/_app/immutable/nodes/{4.FyeoMY-Y.js → 4.CQYJEgv8.js} +1 -1
- package/dist/web/_app/immutable/nodes/{5.D6mVN7l7.js → 5.BpJUN6QH.js} +1 -1
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +6 -6
- package/dist/{workspace-BC1ahx4R.mjs → workspace-DjoNjhW0.mjs} +12 -42
- package/dist/workspace-DjoNjhW0.mjs.map +1 -0
- package/docs/15_lite_fetch_pending/development_log.md +31 -0
- package/docs/15_lite_fetch_pending/notes.md +48 -0
- package/docs/15_lite_fetch_pending/prd.md +39 -0
- package/docs/15_lite_fetch_pending/questions.md +3 -0
- package/docs/15_lite_fetch_pending/tickets.md +42 -0
- package/docs/CHECKS.md +2 -2
- package/eslint.config.js +12 -0
- package/package.json +3 -2
- package/src/adapter-discord/client.ts +1 -1
- package/src/adapter-discord/index.ts +22 -5
- package/src/cli/client.ts +8 -3
- package/src/cli/e2e/adapter-discord.test.ts +2 -2
- package/src/cli/e2e/daemon.test.ts +2 -1
- package/src/cli/e2e/export-lite-func.test.ts +41 -13
- package/src/cli/e2e/fallbacks.test.ts +4 -0
- package/src/cli/lite.ts +24 -6
- package/src/daemon/api/agent-router.ts +191 -0
- package/src/daemon/{router.test.ts → api/index.test.ts} +101 -34
- package/src/daemon/api/index.ts +4 -0
- package/src/daemon/{router-policy-request.test.ts → api/policy-request.test.ts} +27 -13
- package/src/daemon/api/router-utils.ts +159 -0
- package/src/daemon/api/trpc.ts +30 -0
- package/src/daemon/api/user-router.ts +221 -0
- package/src/daemon/index.ts +3 -3
- package/src/daemon/message-interruption.test.ts +17 -10
- package/src/daemon/message-typing.test.ts +1 -1
- package/src/daemon/message.ts +260 -239
- package/src/daemon/observation.test.ts +1 -1
- package/src/daemon/queue.test.ts +28 -0
- package/src/daemon/queue.ts +30 -15
- package/src/daemon/request-store.test.ts +4 -4
- package/src/daemon/request-store.ts +3 -1
- package/src/shared/workspace.ts +4 -5
- package/templates/debug/settings.json +5 -0
- package/templates/environments/macos/env.json +1 -1
- package/templates/environments/macos-proxy/env.json +1 -1
- package/templates/gemini-claw/.gemini/hooks/insert-pending.sh +9 -0
- package/templates/gemini-claw/.gemini/settings.json +14 -1
- package/templates/gemini-claw/.gemini/system.md +2 -0
- package/web/.svelte-kit/generated/server/internal.js +1 -1
- package/web/.svelte-kit/output/client/.vite/manifest.json +26 -26
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{CAZeqksE.js → 8YNcRyEk.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{B3YcEpQV.js → DQoygso7.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/{app.ZuicLpkH.js → app.DO5eYwVz.js} +2 -2
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.D48mVn1m.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{0.BB1CjKco.js → 0.B-0CcADM.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{1.CdSgEHu9.js → 1.FixKgvRO.js} +1 -1
- package/{dist/web/_app/immutable/nodes/3.CKp7Wkn8.js → web/.svelte-kit/output/client/_app/immutable/nodes/3.ncP0xLO6.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{4.FyeoMY-Y.js → 4.CQYJEgv8.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.D6mVN7l7.js → 5.BpJUN6QH.js} +1 -1
- package/web/.svelte-kit/output/client/_app/version.json +1 -1
- package/web/.svelte-kit/output/server/chunks/internal.js +1 -1
- package/web/.svelte-kit/output/server/manifest-full.js +1 -1
- package/web/.svelte-kit/output/server/manifest.js +1 -1
- package/web/.svelte-kit/output/server/nodes/0.js +1 -1
- package/web/.svelte-kit/output/server/nodes/1.js +1 -1
- package/web/.svelte-kit/output/server/nodes/3.js +1 -1
- package/web/.svelte-kit/output/server/nodes/4.js +1 -1
- package/web/.svelte-kit/output/server/nodes/5.js +1 -1
- package/dist/chats-BcbxvPlj.mjs +0 -29
- package/dist/chats-BcbxvPlj.mjs.map +0 -1
- package/dist/chats-CpRQrNHj.mjs +0 -91
- package/dist/chats-CpRQrNHj.mjs.map +0 -1
- package/dist/fs-B5wW0oaH.mjs +0 -14
- package/dist/fs-B5wW0oaH.mjs.map +0 -1
- package/dist/lite-DBUuHsX0.mjs +0 -80
- package/dist/lite-DBUuHsX0.mjs.map +0 -1
- package/dist/policy-utils-BvfOK6Ih.mjs +0 -114
- package/dist/policy-utils-BvfOK6Ih.mjs.map +0 -1
- package/dist/rolldown-runtime-95iHPtFO.mjs +0 -18
- package/dist/web/_app/immutable/entry/start.DuQwh4Nz.js +0 -1
- package/dist/workspace-BC1ahx4R.mjs.map +0 -1
- package/src/daemon/router.ts +0 -510
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.DuQwh4Nz.js +0 -1
package/dist/daemon/index.mjs
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import { C as CronJobSchema, _ as readSettings, a as getAgent, c as getSettingsPath, g as readPolicies, h as readEnvironment, i as getActiveEnvironmentInfo, l as getSocketPath, m as readChatSettings, o as getClawminiDir, p as readAgentSessionSettings, s as getEnvironmentPath, u as getWorkspaceRoot,
|
|
2
|
-
import { n as
|
|
3
|
-
import
|
|
4
|
-
import { n as exportLiteToEnvironment } from "../lite-DBUuHsX0.mjs";
|
|
5
|
-
import { a as daemonEvents, i as DAEMON_EVENT_TYPING, o as emitTyping, r as DAEMON_EVENT_MESSAGE_APPENDED, t as appendMessage } from "../chats-BcbxvPlj.mjs";
|
|
6
|
-
import { n as executeSafe, r as interpolateArgs, t as createSnapshot } from "../policy-utils-BvfOK6Ih.mjs";
|
|
7
|
-
import fs from "node:fs";
|
|
1
|
+
import { C as CronJobSchema, S as pathIsInsideDir, _ as readSettings, a as getAgent, b as writeChatSettings, c as getSettingsPath, g as readPolicies, h as readEnvironment, i as getActiveEnvironmentInfo, l as getSocketPath, m as readChatSettings, o as getClawminiDir, p as readAgentSessionSettings, s as getEnvironmentPath, u as getWorkspaceRoot, v as writeAgentSessionSettings, w as SettingsSchema } from "../workspace-DjoNjhW0.mjs";
|
|
2
|
+
import { d as getMessages$1, n as exportLiteToEnvironment, o as appendMessage$1, p as listChats, u as getDefaultChatId } from "../lite-oSYSvaOr.mjs";
|
|
3
|
+
import fs, { constants } from "node:fs";
|
|
8
4
|
import path from "node:path";
|
|
9
5
|
import { execSync, spawn } from "node:child_process";
|
|
10
6
|
import fs$1 from "node:fs/promises";
|
|
@@ -13,126 +9,52 @@ import http from "node:http";
|
|
|
13
9
|
import net from "node:net";
|
|
14
10
|
import { createHTTPHandler } from "@trpc/server/adapters/standalone";
|
|
15
11
|
import { TRPCError, initTRPC } from "@trpc/server";
|
|
12
|
+
import schedule from "node-schedule";
|
|
13
|
+
import { EventEmitter, on } from "node:events";
|
|
14
|
+
import crypto$1, { randomBytes, randomUUID } from "node:crypto";
|
|
16
15
|
import fs$2 from "fs/promises";
|
|
17
16
|
import path$1 from "path";
|
|
18
17
|
import { randomInt } from "crypto";
|
|
19
|
-
import crypto$1, { randomUUID } from "node:crypto";
|
|
20
|
-
import schedule from "node-schedule";
|
|
21
18
|
|
|
22
|
-
//#region src/daemon/
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
]),
|
|
33
|
-
createdAt: z.number(),
|
|
34
|
-
rejectionReason: z.string().optional(),
|
|
35
|
-
chatId: z.string(),
|
|
36
|
-
agentId: z.string()
|
|
37
|
-
});
|
|
38
|
-
function isENOENT(err) {
|
|
39
|
-
return Boolean(err && typeof err === "object" && "code" in err && err.code === "ENOENT");
|
|
40
|
-
}
|
|
41
|
-
var RequestStore = class {
|
|
42
|
-
baseDir;
|
|
43
|
-
constructor(startDir = process.cwd()) {
|
|
44
|
-
this.baseDir = path$1.join(getClawminiDir(startDir), "tmp", "requests");
|
|
45
|
-
}
|
|
46
|
-
async init() {
|
|
47
|
-
await fs$2.mkdir(this.baseDir, { recursive: true });
|
|
48
|
-
}
|
|
49
|
-
getFilePath(id) {
|
|
50
|
-
return path$1.join(this.baseDir, `${id}.json`);
|
|
51
|
-
}
|
|
52
|
-
async save(request) {
|
|
53
|
-
await this.init();
|
|
54
|
-
const filePath = this.getFilePath(request.id);
|
|
55
|
-
await fs$2.writeFile(filePath, JSON.stringify(request, null, 2), "utf8");
|
|
56
|
-
}
|
|
57
|
-
async load(id) {
|
|
58
|
-
const normalizedId = normalizePolicyId(id);
|
|
59
|
-
const filePath = this.getFilePath(normalizedId);
|
|
60
|
-
try {
|
|
61
|
-
const data = await fs$2.readFile(filePath, "utf8");
|
|
62
|
-
return PolicyRequestSchema.parse(JSON.parse(data));
|
|
63
|
-
} catch (err) {
|
|
64
|
-
if (isENOENT(err)) return null;
|
|
65
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
66
|
-
console.warn(`Failed to parse request file ${filePath}:`, msg);
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
async list() {
|
|
71
|
-
await this.init();
|
|
72
|
-
const requests = [];
|
|
73
|
-
try {
|
|
74
|
-
const files = await fs$2.readdir(this.baseDir);
|
|
75
|
-
for (const file of files) {
|
|
76
|
-
if (!file.endsWith(".json")) continue;
|
|
77
|
-
const id = path$1.basename(file, ".json");
|
|
78
|
-
const req = await this.load(id);
|
|
79
|
-
if (req) requests.push(req);
|
|
80
|
-
}
|
|
81
|
-
} catch (err) {
|
|
82
|
-
if (!isENOENT(err)) throw err;
|
|
83
|
-
}
|
|
84
|
-
return requests.sort((a, b) => b.createdAt - a.createdAt);
|
|
19
|
+
//#region src/daemon/api/trpc.ts
|
|
20
|
+
const t = initTRPC.context().create();
|
|
21
|
+
const router = t.router;
|
|
22
|
+
const publicProcedure = t.procedure;
|
|
23
|
+
const apiAuthMiddleware = t.middleware(({ ctx, next }) => {
|
|
24
|
+
if (ctx.isApiServer) {
|
|
25
|
+
if (!ctx.tokenPayload) throw new TRPCError({
|
|
26
|
+
code: "UNAUTHORIZED",
|
|
27
|
+
message: "Missing or invalid token"
|
|
28
|
+
});
|
|
85
29
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
30
|
+
return next({ ctx: {
|
|
31
|
+
...ctx,
|
|
32
|
+
tokenPayload: ctx.tokenPayload
|
|
33
|
+
} });
|
|
34
|
+
});
|
|
35
|
+
const apiProcedure = t.procedure.use(apiAuthMiddleware);
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/daemon/events.ts
|
|
39
|
+
const daemonEvents = new EventEmitter();
|
|
40
|
+
const DAEMON_EVENT_MESSAGE_APPENDED = "message-appended";
|
|
41
|
+
const DAEMON_EVENT_TYPING = "typing";
|
|
42
|
+
function emitMessageAppended(chatId, message) {
|
|
43
|
+
daemonEvents.emit(DAEMON_EVENT_MESSAGE_APPENDED, {
|
|
44
|
+
chatId,
|
|
45
|
+
message
|
|
46
|
+
});
|
|
92
47
|
}
|
|
93
|
-
function
|
|
94
|
-
|
|
48
|
+
function emitTyping(chatId) {
|
|
49
|
+
daemonEvents.emit(DAEMON_EVENT_TYPING, { chatId });
|
|
95
50
|
}
|
|
96
51
|
|
|
97
52
|
//#endregion
|
|
98
|
-
//#region src/daemon/
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
snapshotDir;
|
|
104
|
-
constructor(store, agentDir, snapshotDir, maxPending = 100) {
|
|
105
|
-
this.store = store;
|
|
106
|
-
this.agentDir = agentDir;
|
|
107
|
-
this.snapshotDir = snapshotDir;
|
|
108
|
-
this.maxPending = maxPending;
|
|
109
|
-
}
|
|
110
|
-
async createRequest(commandName, args, fileMappings, chatId, agentId) {
|
|
111
|
-
const allRequests = await this.store.list();
|
|
112
|
-
if (allRequests.filter((r) => r.state === "Pending").length >= this.maxPending) throw new Error(`Maximum number of pending requests (${this.maxPending}) reached.`);
|
|
113
|
-
const snapshotMappings = {};
|
|
114
|
-
for (const [key, requestedPath] of Object.entries(fileMappings)) snapshotMappings[key] = await createSnapshot(requestedPath, this.agentDir, this.snapshotDir);
|
|
115
|
-
let id = "";
|
|
116
|
-
do
|
|
117
|
-
id = generateRandomAlphaNumericString(3);
|
|
118
|
-
while (allRequests.some((r) => r.id === id));
|
|
119
|
-
const request = {
|
|
120
|
-
id,
|
|
121
|
-
commandName,
|
|
122
|
-
args,
|
|
123
|
-
fileMappings: snapshotMappings,
|
|
124
|
-
state: "Pending",
|
|
125
|
-
createdAt: Date.now(),
|
|
126
|
-
chatId,
|
|
127
|
-
agentId
|
|
128
|
-
};
|
|
129
|
-
await this.store.save(request);
|
|
130
|
-
return request;
|
|
131
|
-
}
|
|
132
|
-
getInterpolatedArgs(request) {
|
|
133
|
-
return interpolateArgs(request.args, request.fileMappings);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
53
|
+
//#region src/daemon/chats.ts
|
|
54
|
+
async function appendMessage(id, message, startDir = process.cwd()) {
|
|
55
|
+
await appendMessage$1(id, message, startDir);
|
|
56
|
+
emitMessageAppended(id, message);
|
|
57
|
+
}
|
|
136
58
|
|
|
137
59
|
//#endregion
|
|
138
60
|
//#region src/daemon/queue.ts
|
|
@@ -170,35 +92,38 @@ var Queue = class {
|
|
|
170
92
|
this.processNext().catch(() => {});
|
|
171
93
|
}
|
|
172
94
|
}
|
|
173
|
-
abortCurrent() {
|
|
95
|
+
abortCurrent(predicate) {
|
|
174
96
|
if (this.currentController) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
97
|
+
if (!predicate || this.currentPayload !== void 0 && predicate(this.currentPayload)) {
|
|
98
|
+
const error = /* @__PURE__ */ new Error("Task aborted");
|
|
99
|
+
error.name = "AbortError";
|
|
100
|
+
this.currentController.abort(error);
|
|
101
|
+
}
|
|
178
102
|
}
|
|
179
103
|
}
|
|
180
104
|
getCurrentPayload() {
|
|
181
105
|
return this.currentPayload;
|
|
182
106
|
}
|
|
183
|
-
clear(reason = "Task cleared") {
|
|
184
|
-
const tasksToClear = [...this.pending];
|
|
185
|
-
this.pending =
|
|
107
|
+
clear(reason = "Task cleared", predicate) {
|
|
108
|
+
const tasksToClear = predicate ? this.pending.filter((p) => p.payload !== void 0 && predicate(p.payload)) : [...this.pending];
|
|
109
|
+
if (predicate) this.pending = this.pending.filter((p) => !(p.payload !== void 0 && predicate(p.payload)));
|
|
110
|
+
else this.pending = [];
|
|
186
111
|
for (const { reject } of tasksToClear) {
|
|
187
112
|
const error = new Error(reason);
|
|
188
113
|
error.name = "AbortError";
|
|
189
114
|
reject(error);
|
|
190
115
|
}
|
|
191
116
|
}
|
|
192
|
-
extractPending() {
|
|
193
|
-
const extracted = this.pending.map((p) => p.payload).filter((p) => p !== void 0);
|
|
194
|
-
this.clear("Task extracted for batching");
|
|
117
|
+
extractPending(predicate) {
|
|
118
|
+
const extracted = this.pending.map((p) => p.payload).filter((p) => p !== void 0 && (!predicate || predicate(p)));
|
|
119
|
+
this.clear("Task extracted for batching", predicate);
|
|
195
120
|
return extracted;
|
|
196
121
|
}
|
|
197
122
|
};
|
|
198
|
-
const
|
|
199
|
-
function
|
|
200
|
-
if (!
|
|
201
|
-
return
|
|
123
|
+
const messageQueues = /* @__PURE__ */ new Map();
|
|
124
|
+
function getMessageQueue(dir) {
|
|
125
|
+
if (!messageQueues.has(dir)) messageQueues.set(dir, new Queue());
|
|
126
|
+
return messageQueues.get(dir);
|
|
202
127
|
}
|
|
203
128
|
|
|
204
129
|
//#endregion
|
|
@@ -274,6 +199,181 @@ const slashStop = createSlashActionRouter("stop", "stop", "Stopping current task
|
|
|
274
199
|
//#region src/daemon/routers/slash-interrupt.ts
|
|
275
200
|
const slashInterrupt = createSlashActionRouter("interrupt", "interrupt", "Interrupting current task...");
|
|
276
201
|
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/daemon/request-store.ts
|
|
204
|
+
const PolicyRequestSchema = z.object({
|
|
205
|
+
id: z.string(),
|
|
206
|
+
commandName: z.string(),
|
|
207
|
+
args: z.array(z.string()),
|
|
208
|
+
fileMappings: z.record(z.string(), z.string()),
|
|
209
|
+
state: z.enum([
|
|
210
|
+
"Pending",
|
|
211
|
+
"Approved",
|
|
212
|
+
"Rejected"
|
|
213
|
+
]),
|
|
214
|
+
createdAt: z.number(),
|
|
215
|
+
rejectionReason: z.string().optional(),
|
|
216
|
+
chatId: z.string(),
|
|
217
|
+
agentId: z.string()
|
|
218
|
+
});
|
|
219
|
+
function isENOENT(err) {
|
|
220
|
+
return Boolean(err && typeof err === "object" && "code" in err && err.code === "ENOENT");
|
|
221
|
+
}
|
|
222
|
+
var RequestStore = class {
|
|
223
|
+
baseDir;
|
|
224
|
+
constructor(startDir = process.cwd()) {
|
|
225
|
+
this.baseDir = path$1.join(getClawminiDir(startDir), "tmp", "requests");
|
|
226
|
+
}
|
|
227
|
+
async init() {
|
|
228
|
+
await fs$2.mkdir(this.baseDir, { recursive: true });
|
|
229
|
+
}
|
|
230
|
+
getFilePath(id) {
|
|
231
|
+
return path$1.join(this.baseDir, `${id}.json`);
|
|
232
|
+
}
|
|
233
|
+
async save(request) {
|
|
234
|
+
await this.init();
|
|
235
|
+
const normalizedId = normalizePolicyId(request.id);
|
|
236
|
+
request.id = normalizedId;
|
|
237
|
+
const filePath = this.getFilePath(normalizedId);
|
|
238
|
+
await fs$2.writeFile(filePath, JSON.stringify(request, null, 2), "utf8");
|
|
239
|
+
}
|
|
240
|
+
async load(id) {
|
|
241
|
+
const normalizedId = normalizePolicyId(id);
|
|
242
|
+
const filePath = this.getFilePath(normalizedId);
|
|
243
|
+
try {
|
|
244
|
+
const data = await fs$2.readFile(filePath, "utf8");
|
|
245
|
+
return PolicyRequestSchema.parse(JSON.parse(data));
|
|
246
|
+
} catch (err) {
|
|
247
|
+
if (isENOENT(err)) return null;
|
|
248
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
249
|
+
console.warn(`Failed to parse request file ${filePath}:`, msg);
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async list() {
|
|
254
|
+
await this.init();
|
|
255
|
+
const requests = [];
|
|
256
|
+
try {
|
|
257
|
+
const files = await fs$2.readdir(this.baseDir);
|
|
258
|
+
for (const file of files) {
|
|
259
|
+
if (!file.endsWith(".json")) continue;
|
|
260
|
+
const id = path$1.basename(file, ".json");
|
|
261
|
+
const req = await this.load(id);
|
|
262
|
+
if (req) requests.push(req);
|
|
263
|
+
}
|
|
264
|
+
} catch (err) {
|
|
265
|
+
if (!isENOENT(err)) throw err;
|
|
266
|
+
}
|
|
267
|
+
return requests.sort((a, b) => b.createdAt - a.createdAt);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
function generateRandomAlphaNumericString(length) {
|
|
271
|
+
const characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
272
|
+
let result = "";
|
|
273
|
+
for (let i = 0; i < length; i++) result += characters[Math.floor(randomInt(36))];
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
276
|
+
function normalizePolicyId(id) {
|
|
277
|
+
return id.toLocaleUpperCase().trim();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/daemon/policy-utils.ts
|
|
282
|
+
const MAX_SNAPSHOT_SIZE = 5 * 1024 * 1024;
|
|
283
|
+
async function createSnapshot(requestedPath, agentDir, snapshotDir) {
|
|
284
|
+
let realAgentDir;
|
|
285
|
+
try {
|
|
286
|
+
realAgentDir = await fs$1.realpath(agentDir);
|
|
287
|
+
} catch (err) {
|
|
288
|
+
throw new Error(`Agent directory not found or cannot be resolved: ${agentDir}`, { cause: err });
|
|
289
|
+
}
|
|
290
|
+
const resolvedRequestedPath = path.resolve(realAgentDir, requestedPath);
|
|
291
|
+
if (!pathIsInsideDir(resolvedRequestedPath, realAgentDir, { allowSameDir: true })) throw new Error(`Security Error: Path resolves outside the allowed agent directory: ${resolvedRequestedPath}`);
|
|
292
|
+
let stat;
|
|
293
|
+
try {
|
|
294
|
+
stat = await fs$1.lstat(resolvedRequestedPath);
|
|
295
|
+
} catch (err) {
|
|
296
|
+
throw new Error(`File not found or cannot be accessed: ${requestedPath}`, { cause: err });
|
|
297
|
+
}
|
|
298
|
+
if (stat.isSymbolicLink()) throw new Error(`Security Error: Symlinks are not allowed: ${requestedPath}`);
|
|
299
|
+
if (!stat.isFile()) throw new Error(`Requested path is not a file: ${requestedPath}`);
|
|
300
|
+
if (stat.size > MAX_SNAPSHOT_SIZE) throw new Error(`File exceeds maximum snapshot size of 5MB: ${requestedPath}`);
|
|
301
|
+
const ext = path.extname(resolvedRequestedPath);
|
|
302
|
+
const base = path.basename(resolvedRequestedPath, ext);
|
|
303
|
+
await fs$1.mkdir(snapshotDir, { recursive: true });
|
|
304
|
+
let snapshotPath;
|
|
305
|
+
while (true) {
|
|
306
|
+
const snapshotFileName = `${base}_${randomBytes(8).toString("hex")}${ext}`;
|
|
307
|
+
snapshotPath = path.join(snapshotDir, snapshotFileName);
|
|
308
|
+
try {
|
|
309
|
+
await fs$1.copyFile(resolvedRequestedPath, snapshotPath, constants.COPYFILE_EXCL);
|
|
310
|
+
break;
|
|
311
|
+
} catch (err) {
|
|
312
|
+
if (err instanceof Error && "code" in err && err.code === "EEXIST") continue;
|
|
313
|
+
throw err;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return snapshotPath;
|
|
317
|
+
}
|
|
318
|
+
function interpolateArgs(args, snapshots) {
|
|
319
|
+
return args.map((arg) => {
|
|
320
|
+
let interpolated = arg;
|
|
321
|
+
for (const [key, snapshotPath] of Object.entries(snapshots)) {
|
|
322
|
+
const variable = `{{${key}}}`;
|
|
323
|
+
interpolated = interpolated.replaceAll(variable, snapshotPath);
|
|
324
|
+
}
|
|
325
|
+
return interpolated;
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
function executeSafe(command, args, options) {
|
|
329
|
+
return new Promise((resolve) => {
|
|
330
|
+
const p = spawn(command, args, {
|
|
331
|
+
shell: false,
|
|
332
|
+
cwd: options?.cwd,
|
|
333
|
+
env: options?.env
|
|
334
|
+
});
|
|
335
|
+
let stdout = "";
|
|
336
|
+
let stderr = "";
|
|
337
|
+
if (p.stdout) p.stdout.on("data", (data) => {
|
|
338
|
+
stdout += data.toString();
|
|
339
|
+
});
|
|
340
|
+
if (p.stderr) p.stderr.on("data", (data) => {
|
|
341
|
+
stderr += data.toString();
|
|
342
|
+
});
|
|
343
|
+
p.on("close", (code) => {
|
|
344
|
+
resolve({
|
|
345
|
+
stdout,
|
|
346
|
+
stderr,
|
|
347
|
+
exitCode: code ?? 1
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
p.on("error", (err) => {
|
|
351
|
+
resolve({
|
|
352
|
+
stdout: "",
|
|
353
|
+
stderr: err.toString(),
|
|
354
|
+
exitCode: 1
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
async function generateRequestPreview(request) {
|
|
360
|
+
let previewContent = `Sandbox Policy Request: ${request.commandName}\n`;
|
|
361
|
+
previewContent += `ID: ${request.id}\n`;
|
|
362
|
+
if (request.args.length > 0) previewContent += `Args: ${request.args.join(" ")}\n`;
|
|
363
|
+
for (const [name, snapPath] of Object.entries(request.fileMappings)) {
|
|
364
|
+
previewContent += `File [${name}]:\n`;
|
|
365
|
+
try {
|
|
366
|
+
let content = await fs$1.readFile(snapPath, "utf8");
|
|
367
|
+
if (content.length > 500) content = content.substring(0, 500) + "\n... (truncated)\n";
|
|
368
|
+
previewContent += content;
|
|
369
|
+
} catch (e) {
|
|
370
|
+
previewContent += `<Error reading file: ${e.message}>\n`;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
previewContent += `\nUse /approve ${request.id} or /reject ${request.id} [reason]`;
|
|
374
|
+
return previewContent;
|
|
375
|
+
}
|
|
376
|
+
|
|
277
377
|
//#endregion
|
|
278
378
|
//#region src/daemon/routers/slash-policies.ts
|
|
279
379
|
async function loadAndValidateRequest(id, state) {
|
|
@@ -533,6 +633,9 @@ function calculateDelay(attempt, baseDelayMs, isFallback = false) {
|
|
|
533
633
|
const delay = baseDelayMs * Math.pow(2, effectiveAttempt - 1);
|
|
534
634
|
return Math.min(delay, 15e3);
|
|
535
635
|
}
|
|
636
|
+
function formatPendingMessages(payloads) {
|
|
637
|
+
return payloads.map((text) => `<message>\n${text}\n</message>`).join("\n\n");
|
|
638
|
+
}
|
|
536
639
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
537
640
|
async function resolveSessionState(chatId, cwd, sessionId, overrideAgentId) {
|
|
538
641
|
const chatSettings = await readChatSettings(chatId, cwd);
|
|
@@ -633,18 +736,21 @@ async function executeDirectMessage(chatId, state, settings, cwd, runCommand, no
|
|
|
633
736
|
...state.reply.includes("NO_REPLY_NECESSARY") ? { level: "verbose" } : {}
|
|
634
737
|
});
|
|
635
738
|
if (!state.message.trim() && state.action !== "stop" && state.action !== "interrupt") return;
|
|
636
|
-
const queue =
|
|
739
|
+
const queue = getMessageQueue(cwd);
|
|
637
740
|
if (state.action === "stop") {
|
|
638
741
|
queue.abortCurrent();
|
|
639
742
|
queue.clear();
|
|
640
743
|
return;
|
|
641
744
|
}
|
|
642
745
|
if (state.action === "interrupt") {
|
|
746
|
+
const targetSessionId = state.sessionId || "default";
|
|
747
|
+
const isMatchingSession = (p) => p.sessionId === targetSessionId;
|
|
643
748
|
const currentPayload = queue.getCurrentPayload();
|
|
644
|
-
|
|
645
|
-
const extracted = queue.extractPending();
|
|
646
|
-
|
|
647
|
-
|
|
749
|
+
const currentMatches = currentPayload ? isMatchingSession(currentPayload) : false;
|
|
750
|
+
const extracted = queue.extractPending(isMatchingSession);
|
|
751
|
+
queue.abortCurrent(isMatchingSession);
|
|
752
|
+
const payloads = currentMatches && currentPayload ? [currentPayload, ...extracted] : extracted;
|
|
753
|
+
if (payloads.length > 0) state.message = `${formatPendingMessages(payloads.map((p) => p.text))}\n\n<message>\n${state.message}\n</message>`.trim();
|
|
648
754
|
}
|
|
649
755
|
if (!state.message.trim()) return;
|
|
650
756
|
const routerEnv = state.env ?? {};
|
|
@@ -807,8 +913,15 @@ async function executeDirectMessage(chatId, state, settings, cwd, runCommand, no
|
|
|
807
913
|
if (success) break;
|
|
808
914
|
}
|
|
809
915
|
if (lastLogMsg) await appendMessage(chatId, lastLogMsg);
|
|
810
|
-
},
|
|
811
|
-
|
|
916
|
+
}, {
|
|
917
|
+
text: state.message,
|
|
918
|
+
sessionId: state.sessionId || "default"
|
|
919
|
+
});
|
|
920
|
+
if (!noWait) try {
|
|
921
|
+
await taskPromise;
|
|
922
|
+
} catch (err) {
|
|
923
|
+
if (!(err instanceof Error && err.name === "AbortError")) throw err;
|
|
924
|
+
}
|
|
812
925
|
else taskPromise.catch((err) => {
|
|
813
926
|
if (err.name !== "AbortError") console.error("Task execution error:", err);
|
|
814
927
|
});
|
|
@@ -1018,23 +1131,7 @@ var CronManager = class {
|
|
|
1018
1131
|
const cronManager = new CronManager();
|
|
1019
1132
|
|
|
1020
1133
|
//#endregion
|
|
1021
|
-
//#region src/daemon/router.ts
|
|
1022
|
-
const t = initTRPC.context().create();
|
|
1023
|
-
const router = t.router;
|
|
1024
|
-
const publicProcedure = t.procedure;
|
|
1025
|
-
const apiAuthMiddleware = t.middleware(({ ctx, next }) => {
|
|
1026
|
-
if (ctx.isApiServer) {
|
|
1027
|
-
if (!ctx.tokenPayload) throw new TRPCError({
|
|
1028
|
-
code: "UNAUTHORIZED",
|
|
1029
|
-
message: "Missing or invalid token"
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1032
|
-
return next({ ctx: {
|
|
1033
|
-
...ctx,
|
|
1034
|
-
tokenPayload: ctx.tokenPayload
|
|
1035
|
-
} });
|
|
1036
|
-
});
|
|
1037
|
-
const apiProcedure = t.procedure.use(apiAuthMiddleware);
|
|
1134
|
+
//#region src/daemon/api/router-utils.ts
|
|
1038
1135
|
async function getUniquePath(p) {
|
|
1039
1136
|
let currentPath = p;
|
|
1040
1137
|
let counter = 1;
|
|
@@ -1060,16 +1157,6 @@ async function resolveAgentDir(agentId, workspaceRoot) {
|
|
|
1060
1157
|
}
|
|
1061
1158
|
return workspaceRoot;
|
|
1062
1159
|
}
|
|
1063
|
-
async function resolveAndCheckChatId(ctx, inputChatId) {
|
|
1064
|
-
const chatId = inputChatId ?? (ctx.isApiServer && ctx.tokenPayload ? ctx.tokenPayload.chatId : await getDefaultChatId());
|
|
1065
|
-
if (ctx.isApiServer && ctx.tokenPayload) {
|
|
1066
|
-
if (ctx.tokenPayload.chatId !== chatId) throw new TRPCError({
|
|
1067
|
-
code: "FORBIDDEN",
|
|
1068
|
-
message: "Token not authorized for this chat"
|
|
1069
|
-
});
|
|
1070
|
-
}
|
|
1071
|
-
return chatId;
|
|
1072
|
-
}
|
|
1073
1160
|
async function getAgentFilesDir(agentId, chatId, settings, workspaceRoot) {
|
|
1074
1161
|
const chatSettings = await readChatSettings(chatId) ?? {};
|
|
1075
1162
|
const targetAgentId = agentId ?? chatSettings.defaultAgent ?? "default";
|
|
@@ -1084,8 +1171,6 @@ async function getAgentFilesDir(agentId, chatId, settings, workspaceRoot) {
|
|
|
1084
1171
|
return path.resolve(agentDir, agentFilesDir);
|
|
1085
1172
|
}
|
|
1086
1173
|
async function validateAttachments(files) {
|
|
1087
|
-
const { pathIsInsideDir } = await import("../fs-B5wW0oaH.mjs").then((n) => n.t);
|
|
1088
|
-
const { getClawminiDir } = await import("../workspace-BC1ahx4R.mjs").then((n) => n.v);
|
|
1089
1174
|
const tmpDir = path.join(getClawminiDir(process.cwd()), "tmp");
|
|
1090
1175
|
for (const file of files) {
|
|
1091
1176
|
const absoluteFile = path.resolve(process.cwd(), file);
|
|
@@ -1104,7 +1189,6 @@ async function validateAttachments(files) {
|
|
|
1104
1189
|
}
|
|
1105
1190
|
}
|
|
1106
1191
|
async function validateLogFile(file, agentDir, workspaceRoot) {
|
|
1107
|
-
const { pathIsInsideDir } = await import("../fs-B5wW0oaH.mjs").then((n) => n.t);
|
|
1108
1192
|
const resolvedPath = path.resolve(agentDir, file);
|
|
1109
1193
|
if (!pathIsInsideDir(resolvedPath, agentDir, { allowSameDir: true })) throw new TRPCError({
|
|
1110
1194
|
code: "BAD_REQUEST",
|
|
@@ -1120,244 +1204,349 @@ async function validateLogFile(file, agentDir, workspaceRoot) {
|
|
|
1120
1204
|
}
|
|
1121
1205
|
return path.relative(workspaceRoot, resolvedPath);
|
|
1122
1206
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
settings = JSON.parse(settingsStr);
|
|
1147
|
-
} catch (err) {
|
|
1148
|
-
throw new Error(`Failed to read settings from ${settingsPath}: ${err}`, { cause: err });
|
|
1149
|
-
}
|
|
1150
|
-
const files = input.data.files;
|
|
1151
|
-
if (files && files.length > 0) {
|
|
1152
|
-
const workspaceRoot = getWorkspaceRoot(process.cwd());
|
|
1153
|
-
const chatSettings = await readChatSettings(chatId) ?? {};
|
|
1154
|
-
const agentDir = await resolveAgentDir(agentId ?? chatSettings.defaultAgent ?? "default", workspaceRoot);
|
|
1155
|
-
const absoluteFilesDir = await getAgentFilesDir(agentId, chatId, settings, workspaceRoot);
|
|
1156
|
-
const adapterNamespace = input.data.adapter || "cli";
|
|
1157
|
-
const targetDir = path.join(absoluteFilesDir, adapterNamespace);
|
|
1158
|
-
const { pathIsInsideDir } = await import("../fs-B5wW0oaH.mjs").then((n) => n.t);
|
|
1159
|
-
if (!pathIsInsideDir(targetDir, workspaceRoot, { allowSameDir: true })) throw new TRPCError({
|
|
1160
|
-
code: "BAD_REQUEST",
|
|
1161
|
-
message: "Target directory must be within the workspace."
|
|
1162
|
-
});
|
|
1163
|
-
await validateAttachments(files);
|
|
1164
|
-
await fs$1.mkdir(targetDir, { recursive: true });
|
|
1165
|
-
const finalPaths = [];
|
|
1166
|
-
for (const file of files) {
|
|
1167
|
-
const fileName = path.basename(file);
|
|
1168
|
-
const targetPath = await getUniquePath(path.join(targetDir, fileName));
|
|
1169
|
-
try {
|
|
1170
|
-
await fs$1.rename(file, targetPath);
|
|
1171
|
-
} catch {
|
|
1172
|
-
await fs$1.copyFile(file, targetPath);
|
|
1173
|
-
await fs$1.unlink(file);
|
|
1174
|
-
}
|
|
1175
|
-
finalPaths.push(path.relative(agentDir, targetPath));
|
|
1176
|
-
}
|
|
1177
|
-
const fileList = `Attached files:\n${finalPaths.map((p) => `- ${p}`).join("\n")}`;
|
|
1178
|
-
message = message ? `${message}\n\n${fileList}` : fileList;
|
|
1179
|
-
}
|
|
1180
|
-
await handleUserMessage(chatId, message, settings, void 0, noWait, (args) => runCommand({
|
|
1181
|
-
...args,
|
|
1182
|
-
logToTerminal: true
|
|
1183
|
-
}), sessionId, agentId);
|
|
1184
|
-
return { success: true };
|
|
1185
|
-
}),
|
|
1186
|
-
getMessages: apiProcedure.input(z.object({
|
|
1187
|
-
chatId: z.string().optional(),
|
|
1188
|
-
limit: z.number().optional()
|
|
1189
|
-
})).query(async ({ input, ctx }) => {
|
|
1190
|
-
return getMessages(await resolveAndCheckChatId(ctx, input.chatId), input.limit);
|
|
1191
|
-
}),
|
|
1192
|
-
waitForMessages: apiProcedure.input(z.object({
|
|
1193
|
-
chatId: z.string().optional(),
|
|
1194
|
-
lastMessageId: z.string().optional()
|
|
1195
|
-
})).subscription(async function* ({ input, ctx, signal }) {
|
|
1196
|
-
const chatId = await resolveAndCheckChatId(ctx, input.chatId);
|
|
1197
|
-
if (input.lastMessageId) {
|
|
1198
|
-
const messages = await getMessages(chatId);
|
|
1199
|
-
const lastIndex = messages.findIndex((m) => m.id === input.lastMessageId);
|
|
1200
|
-
if (lastIndex !== -1 && lastIndex < messages.length - 1) yield messages.slice(lastIndex + 1);
|
|
1201
|
-
}
|
|
1202
|
-
const { on } = await import("node:events");
|
|
1203
|
-
try {
|
|
1204
|
-
for await (const [event] of on(daemonEvents, DAEMON_EVENT_MESSAGE_APPENDED, { signal })) if (event.chatId === chatId) yield [event.message];
|
|
1205
|
-
} catch (err) {
|
|
1206
|
-
if (err instanceof Error && err.name === "AbortError") return;
|
|
1207
|
-
throw err;
|
|
1208
|
-
}
|
|
1209
|
-
}),
|
|
1210
|
-
waitForTyping: apiProcedure.input(z.object({ chatId: z.string().optional() })).subscription(async function* ({ input, ctx, signal }) {
|
|
1211
|
-
const chatId = await resolveAndCheckChatId(ctx, input.chatId);
|
|
1212
|
-
const { on } = await import("node:events");
|
|
1213
|
-
try {
|
|
1214
|
-
for await (const [event] of on(daemonEvents, DAEMON_EVENT_TYPING, { signal })) if (event.chatId === chatId) yield event;
|
|
1215
|
-
} catch (err) {
|
|
1216
|
-
if (err instanceof Error && err.name === "AbortError") return;
|
|
1217
|
-
throw err;
|
|
1218
|
-
}
|
|
1219
|
-
}),
|
|
1220
|
-
ping: publicProcedure.query(() => {
|
|
1221
|
-
return { status: "ok" };
|
|
1222
|
-
}),
|
|
1223
|
-
shutdown: publicProcedure.mutation(() => {
|
|
1224
|
-
setTimeout(() => {
|
|
1225
|
-
console.log("Shutting down daemon...");
|
|
1226
|
-
process.kill(process.pid, "SIGTERM");
|
|
1227
|
-
}, 100);
|
|
1228
|
-
return { success: true };
|
|
1229
|
-
}),
|
|
1230
|
-
logMessage: apiProcedure.input(z.object({
|
|
1231
|
-
chatId: z.string().optional(),
|
|
1232
|
-
message: z.string().optional(),
|
|
1233
|
-
files: z.array(z.string()).optional()
|
|
1234
|
-
})).mutation(async ({ input, ctx }) => {
|
|
1235
|
-
const chatId = await resolveAndCheckChatId(ctx, input.chatId);
|
|
1236
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1237
|
-
const id = Date.now().toString() + Math.random().toString(36).substring(2, 7);
|
|
1238
|
-
const filePaths = [];
|
|
1239
|
-
if (input.files && input.files.length > 0) {
|
|
1240
|
-
const workspaceRoot = getWorkspaceRoot(process.cwd());
|
|
1241
|
-
const agentDir = await resolveAgentDir(ctx.tokenPayload?.agentId, workspaceRoot);
|
|
1242
|
-
for (const file of input.files) {
|
|
1243
|
-
const validPath = await validateLogFile(file, agentDir, workspaceRoot);
|
|
1244
|
-
filePaths.push(validPath);
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
const filesArgStr = filePaths.map((p) => ` --file ${p}`).join("");
|
|
1248
|
-
const logMsg = {
|
|
1249
|
-
id,
|
|
1250
|
-
messageId: id,
|
|
1251
|
-
role: "log",
|
|
1252
|
-
source: "router",
|
|
1253
|
-
content: input.message || "",
|
|
1254
|
-
stderr: "",
|
|
1255
|
-
timestamp,
|
|
1256
|
-
command: `clawmini-lite log${filesArgStr}`,
|
|
1257
|
-
cwd: process.cwd(),
|
|
1258
|
-
exitCode: 0,
|
|
1259
|
-
...filePaths.length > 0 ? { files: filePaths } : {}
|
|
1260
|
-
};
|
|
1261
|
-
await import("../chats-BcbxvPlj.mjs").then((n) => n.n).then((m) => m.appendMessage(chatId, logMsg));
|
|
1262
|
-
return { success: true };
|
|
1263
|
-
}),
|
|
1264
|
-
listCronJobs: apiProcedure.input(z.object({ chatId: z.string().optional() })).query(async ({ input, ctx }) => {
|
|
1265
|
-
return (await readChatSettings(await resolveAndCheckChatId(ctx, input.chatId)))?.jobs ?? [];
|
|
1266
|
-
}),
|
|
1267
|
-
addCronJob: apiProcedure.input(z.object({
|
|
1268
|
-
chatId: z.string().optional(),
|
|
1269
|
-
job: CronJobSchema
|
|
1270
|
-
})).mutation(async ({ input, ctx }) => {
|
|
1271
|
-
const chatId = await resolveAndCheckChatId(ctx, input.chatId);
|
|
1272
|
-
const settings = await readChatSettings(chatId) || {};
|
|
1273
|
-
const cronJobs = settings.jobs ?? [];
|
|
1274
|
-
const existingIndex = cronJobs.findIndex((j) => j.id === input.job.id);
|
|
1275
|
-
if (existingIndex >= 0) cronJobs[existingIndex] = input.job;
|
|
1276
|
-
else cronJobs.push(input.job);
|
|
1277
|
-
settings.jobs = cronJobs;
|
|
1207
|
+
async function listCronJobsShared(chatId) {
|
|
1208
|
+
return (await readChatSettings(chatId))?.jobs ?? [];
|
|
1209
|
+
}
|
|
1210
|
+
async function addCronJobShared(chatId, job) {
|
|
1211
|
+
const settings = await readChatSettings(chatId) || {};
|
|
1212
|
+
const cronJobs = settings.jobs ?? [];
|
|
1213
|
+
const existingIndex = cronJobs.findIndex((j) => j.id === job.id);
|
|
1214
|
+
if (existingIndex >= 0) cronJobs[existingIndex] = job;
|
|
1215
|
+
else cronJobs.push(job);
|
|
1216
|
+
settings.jobs = cronJobs;
|
|
1217
|
+
await writeChatSettings(chatId, settings);
|
|
1218
|
+
cronManager.scheduleJob(chatId, job);
|
|
1219
|
+
return { success: true };
|
|
1220
|
+
}
|
|
1221
|
+
async function deleteCronJobShared(chatId, id) {
|
|
1222
|
+
const settings = await readChatSettings(chatId);
|
|
1223
|
+
if (!settings || !settings.jobs) return {
|
|
1224
|
+
success: true,
|
|
1225
|
+
deleted: false
|
|
1226
|
+
};
|
|
1227
|
+
const initialLength = settings.jobs.length;
|
|
1228
|
+
settings.jobs = settings.jobs.filter((j) => j.id !== id);
|
|
1229
|
+
if (settings.jobs.length !== initialLength) {
|
|
1278
1230
|
await writeChatSettings(chatId, settings);
|
|
1279
|
-
cronManager.
|
|
1280
|
-
return { success: true };
|
|
1281
|
-
}),
|
|
1282
|
-
deleteCronJob: apiProcedure.input(z.object({
|
|
1283
|
-
chatId: z.string().optional(),
|
|
1284
|
-
id: z.string()
|
|
1285
|
-
})).mutation(async ({ input, ctx }) => {
|
|
1286
|
-
const chatId = await resolveAndCheckChatId(ctx, input.chatId);
|
|
1287
|
-
const settings = await readChatSettings(chatId);
|
|
1288
|
-
if (!settings || !settings.jobs) return {
|
|
1289
|
-
success: true,
|
|
1290
|
-
deleted: false
|
|
1291
|
-
};
|
|
1292
|
-
const initialLength = settings.jobs.length;
|
|
1293
|
-
settings.jobs = settings.jobs.filter((j) => j.id !== input.id);
|
|
1294
|
-
if (settings.jobs.length !== initialLength) {
|
|
1295
|
-
await writeChatSettings(chatId, settings);
|
|
1296
|
-
cronManager.unscheduleJob(chatId, input.id);
|
|
1297
|
-
return {
|
|
1298
|
-
success: true,
|
|
1299
|
-
deleted: true
|
|
1300
|
-
};
|
|
1301
|
-
}
|
|
1231
|
+
cronManager.unscheduleJob(chatId, id);
|
|
1302
1232
|
return {
|
|
1303
1233
|
success: true,
|
|
1304
|
-
deleted:
|
|
1305
|
-
};
|
|
1306
|
-
}),
|
|
1307
|
-
listPolicies: apiProcedure.query(async () => {
|
|
1308
|
-
return await readPolicies();
|
|
1309
|
-
}),
|
|
1310
|
-
executePolicyHelp: apiProcedure.input(z.object({ commandName: z.string() })).query(async ({ input }) => {
|
|
1311
|
-
const policy = (await readPolicies())?.policies?.[input.commandName];
|
|
1312
|
-
if (!policy) throw new TRPCError({
|
|
1313
|
-
code: "NOT_FOUND",
|
|
1314
|
-
message: `Policy not found: ${input.commandName}`
|
|
1315
|
-
});
|
|
1316
|
-
if (!policy.allowHelp) return {
|
|
1317
|
-
stdout: "",
|
|
1318
|
-
stderr: "This command does not support --help\n",
|
|
1319
|
-
exitCode: 1
|
|
1234
|
+
deleted: true
|
|
1320
1235
|
};
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1236
|
+
}
|
|
1237
|
+
return {
|
|
1238
|
+
success: true,
|
|
1239
|
+
deleted: false
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
//#endregion
|
|
1244
|
+
//#region src/daemon/api/user-router.ts
|
|
1245
|
+
const sendMessage = apiProcedure.input(z.object({
|
|
1246
|
+
type: z.literal("send-message"),
|
|
1247
|
+
client: z.literal("cli"),
|
|
1248
|
+
data: z.object({
|
|
1249
|
+
message: z.string(),
|
|
1250
|
+
chatId: z.string().optional(),
|
|
1251
|
+
sessionId: z.string().optional(),
|
|
1252
|
+
agentId: z.string().optional(),
|
|
1253
|
+
noWait: z.boolean().optional(),
|
|
1254
|
+
files: z.array(z.string()).optional(),
|
|
1255
|
+
adapter: z.string().optional()
|
|
1256
|
+
})
|
|
1257
|
+
})).mutation(async ({ input }) => {
|
|
1258
|
+
let message = input.data.message;
|
|
1259
|
+
const chatId = input.data.chatId ?? await getDefaultChatId();
|
|
1260
|
+
const noWait = input.data.noWait ?? false;
|
|
1261
|
+
const sessionId = input.data.sessionId;
|
|
1262
|
+
const agentId = input.data.agentId;
|
|
1263
|
+
const settingsPath = getSettingsPath();
|
|
1264
|
+
let settings;
|
|
1265
|
+
try {
|
|
1266
|
+
const settingsStr = await fs$1.readFile(settingsPath, "utf8");
|
|
1267
|
+
settings = JSON.parse(settingsStr);
|
|
1268
|
+
} catch (err) {
|
|
1269
|
+
throw new Error(`Failed to read settings from ${settingsPath}: ${err}`, { cause: err });
|
|
1270
|
+
}
|
|
1271
|
+
const files = input.data.files;
|
|
1272
|
+
if (files && files.length > 0) {
|
|
1336
1273
|
const workspaceRoot = getWorkspaceRoot(process.cwd());
|
|
1337
|
-
const
|
|
1338
|
-
const
|
|
1339
|
-
const
|
|
1340
|
-
const
|
|
1341
|
-
const
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1274
|
+
const chatSettings = await readChatSettings(chatId) ?? {};
|
|
1275
|
+
const agentDir = await resolveAgentDir(agentId ?? chatSettings.defaultAgent ?? "default", workspaceRoot);
|
|
1276
|
+
const absoluteFilesDir = await getAgentFilesDir(agentId, chatId, settings, workspaceRoot);
|
|
1277
|
+
const adapterNamespace = input.data.adapter || "cli";
|
|
1278
|
+
const targetDir = path.join(absoluteFilesDir, adapterNamespace);
|
|
1279
|
+
if (!pathIsInsideDir(targetDir, workspaceRoot, { allowSameDir: true })) throw new TRPCError({
|
|
1280
|
+
code: "BAD_REQUEST",
|
|
1281
|
+
message: "Target directory must be within the workspace."
|
|
1282
|
+
});
|
|
1283
|
+
await validateAttachments(files);
|
|
1284
|
+
await fs$1.mkdir(targetDir, { recursive: true });
|
|
1285
|
+
const finalPaths = [];
|
|
1286
|
+
for (const file of files) {
|
|
1287
|
+
const fileName = path.basename(file);
|
|
1288
|
+
const targetPath = await getUniquePath(path.join(targetDir, fileName));
|
|
1289
|
+
try {
|
|
1290
|
+
await fs$1.rename(file, targetPath);
|
|
1291
|
+
} catch {
|
|
1292
|
+
await fs$1.copyFile(file, targetPath);
|
|
1293
|
+
await fs$1.unlink(file);
|
|
1294
|
+
}
|
|
1295
|
+
finalPaths.push(path.relative(agentDir, targetPath));
|
|
1296
|
+
}
|
|
1297
|
+
const fileList = `Attached files:\n${finalPaths.map((p) => `- ${p}`).join("\n")}`;
|
|
1298
|
+
message = message ? `${message}\n\n${fileList}` : fileList;
|
|
1299
|
+
}
|
|
1300
|
+
await handleUserMessage(chatId, message, settings, void 0, noWait, (args) => runCommand({
|
|
1301
|
+
...args,
|
|
1302
|
+
logToTerminal: true
|
|
1303
|
+
}), sessionId, agentId);
|
|
1304
|
+
return { success: true };
|
|
1305
|
+
});
|
|
1306
|
+
const getMessages = apiProcedure.input(z.object({
|
|
1307
|
+
chatId: z.string().optional(),
|
|
1308
|
+
limit: z.number().optional()
|
|
1309
|
+
})).query(async ({ input }) => {
|
|
1310
|
+
return getMessages$1(input.chatId ?? await getDefaultChatId(), input.limit);
|
|
1311
|
+
});
|
|
1312
|
+
const waitForMessages = apiProcedure.input(z.object({
|
|
1313
|
+
chatId: z.string().optional(),
|
|
1314
|
+
lastMessageId: z.string().optional()
|
|
1315
|
+
})).subscription(async function* ({ input, signal }) {
|
|
1316
|
+
const chatId = input.chatId ?? await getDefaultChatId();
|
|
1317
|
+
if (input.lastMessageId) {
|
|
1318
|
+
const messages = await getMessages$1(chatId);
|
|
1319
|
+
const lastIndex = messages.findIndex((m) => m.id === input.lastMessageId);
|
|
1320
|
+
if (lastIndex !== -1 && lastIndex < messages.length - 1) yield messages.slice(lastIndex + 1);
|
|
1321
|
+
}
|
|
1322
|
+
try {
|
|
1323
|
+
for await (const [event] of on(daemonEvents, DAEMON_EVENT_MESSAGE_APPENDED, { signal })) if (event.chatId === chatId) yield [event.message];
|
|
1324
|
+
} catch (err) {
|
|
1325
|
+
if (err instanceof Error && err.name === "AbortError") return;
|
|
1326
|
+
throw err;
|
|
1327
|
+
}
|
|
1328
|
+
});
|
|
1329
|
+
const waitForTyping = apiProcedure.input(z.object({ chatId: z.string().optional() })).subscription(async function* ({ input, signal }) {
|
|
1330
|
+
const chatId = input.chatId ?? await getDefaultChatId();
|
|
1331
|
+
try {
|
|
1332
|
+
for await (const [event] of on(daemonEvents, DAEMON_EVENT_TYPING, { signal })) if (event.chatId === chatId) yield event;
|
|
1333
|
+
} catch (err) {
|
|
1334
|
+
if (err instanceof Error && err.name === "AbortError") return;
|
|
1335
|
+
throw err;
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
const ping = publicProcedure.query(() => {
|
|
1339
|
+
return { status: "ok" };
|
|
1340
|
+
});
|
|
1341
|
+
const shutdown = publicProcedure.mutation(() => {
|
|
1342
|
+
setTimeout(() => {
|
|
1343
|
+
console.log("Shutting down daemon...");
|
|
1344
|
+
process.kill(process.pid, "SIGTERM");
|
|
1345
|
+
}, 100);
|
|
1346
|
+
return { success: true };
|
|
1347
|
+
});
|
|
1348
|
+
const userListCronJobs = apiProcedure.input(z.object({ chatId: z.string().optional() })).query(async ({ input }) => {
|
|
1349
|
+
return listCronJobsShared(input.chatId ?? await getDefaultChatId());
|
|
1350
|
+
});
|
|
1351
|
+
const userAddCronJob = apiProcedure.input(z.object({
|
|
1352
|
+
chatId: z.string().optional(),
|
|
1353
|
+
job: CronJobSchema
|
|
1354
|
+
})).mutation(async ({ input }) => {
|
|
1355
|
+
return addCronJobShared(input.chatId ?? await getDefaultChatId(), input.job);
|
|
1356
|
+
});
|
|
1357
|
+
const userDeleteCronJob = apiProcedure.input(z.object({
|
|
1358
|
+
chatId: z.string().optional(),
|
|
1359
|
+
id: z.string()
|
|
1360
|
+
})).mutation(async ({ input }) => {
|
|
1361
|
+
return deleteCronJobShared(input.chatId ?? await getDefaultChatId(), input.id);
|
|
1362
|
+
});
|
|
1363
|
+
const userRouter = router({
|
|
1364
|
+
sendMessage,
|
|
1365
|
+
getMessages,
|
|
1366
|
+
waitForMessages,
|
|
1367
|
+
waitForTyping,
|
|
1368
|
+
ping,
|
|
1369
|
+
shutdown,
|
|
1370
|
+
listCronJobs: userListCronJobs,
|
|
1371
|
+
addCronJob: userAddCronJob,
|
|
1372
|
+
deleteCronJob: userDeleteCronJob
|
|
1373
|
+
});
|
|
1374
|
+
|
|
1375
|
+
//#endregion
|
|
1376
|
+
//#region src/daemon/policy-request-service.ts
|
|
1377
|
+
var PolicyRequestService = class {
|
|
1378
|
+
store;
|
|
1379
|
+
maxPending;
|
|
1380
|
+
agentDir;
|
|
1381
|
+
snapshotDir;
|
|
1382
|
+
constructor(store, agentDir, snapshotDir, maxPending = 100) {
|
|
1383
|
+
this.store = store;
|
|
1384
|
+
this.agentDir = agentDir;
|
|
1385
|
+
this.snapshotDir = snapshotDir;
|
|
1386
|
+
this.maxPending = maxPending;
|
|
1387
|
+
}
|
|
1388
|
+
async createRequest(commandName, args, fileMappings, chatId, agentId) {
|
|
1389
|
+
const allRequests = await this.store.list();
|
|
1390
|
+
if (allRequests.filter((r) => r.state === "Pending").length >= this.maxPending) throw new Error(`Maximum number of pending requests (${this.maxPending}) reached.`);
|
|
1391
|
+
const snapshotMappings = {};
|
|
1392
|
+
for (const [key, requestedPath] of Object.entries(fileMappings)) snapshotMappings[key] = await createSnapshot(requestedPath, this.agentDir, this.snapshotDir);
|
|
1393
|
+
let id = "";
|
|
1394
|
+
do
|
|
1395
|
+
id = generateRandomAlphaNumericString(3);
|
|
1396
|
+
while (allRequests.some((r) => r.id === id));
|
|
1397
|
+
const request = {
|
|
1398
|
+
id,
|
|
1399
|
+
commandName,
|
|
1400
|
+
args,
|
|
1401
|
+
fileMappings: snapshotMappings,
|
|
1402
|
+
state: "Pending",
|
|
1403
|
+
createdAt: Date.now(),
|
|
1404
|
+
chatId,
|
|
1405
|
+
agentId
|
|
1355
1406
|
};
|
|
1356
|
-
await
|
|
1407
|
+
await this.store.save(request);
|
|
1357
1408
|
return request;
|
|
1358
|
-
}
|
|
1409
|
+
}
|
|
1410
|
+
getInterpolatedArgs(request) {
|
|
1411
|
+
return interpolateArgs(request.args, request.fileMappings);
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
|
|
1415
|
+
//#endregion
|
|
1416
|
+
//#region src/daemon/api/agent-router.ts
|
|
1417
|
+
const logMessage = apiProcedure.input(z.object({
|
|
1418
|
+
message: z.string().optional(),
|
|
1419
|
+
files: z.array(z.string()).optional()
|
|
1420
|
+
})).mutation(async ({ input, ctx }) => {
|
|
1421
|
+
if (!ctx.tokenPayload) throw new TRPCError({
|
|
1422
|
+
code: "UNAUTHORIZED",
|
|
1423
|
+
message: "Missing token"
|
|
1424
|
+
});
|
|
1425
|
+
const chatId = ctx.tokenPayload.chatId;
|
|
1426
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1427
|
+
const id = Date.now().toString() + Math.random().toString(36).substring(2, 7);
|
|
1428
|
+
const filePaths = [];
|
|
1429
|
+
if (input.files && input.files.length > 0) {
|
|
1430
|
+
const workspaceRoot = getWorkspaceRoot(process.cwd());
|
|
1431
|
+
const agentDir = await resolveAgentDir(ctx.tokenPayload?.agentId, workspaceRoot);
|
|
1432
|
+
for (const file of input.files) {
|
|
1433
|
+
const validPath = await validateLogFile(file, agentDir, workspaceRoot);
|
|
1434
|
+
filePaths.push(validPath);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
const filesArgStr = filePaths.map((p) => ` --file ${p}`).join("");
|
|
1438
|
+
await appendMessage(chatId, {
|
|
1439
|
+
id,
|
|
1440
|
+
messageId: id,
|
|
1441
|
+
role: "log",
|
|
1442
|
+
source: "router",
|
|
1443
|
+
content: input.message || "",
|
|
1444
|
+
stderr: "",
|
|
1445
|
+
timestamp,
|
|
1446
|
+
command: `clawmini-lite log${filesArgStr}`,
|
|
1447
|
+
cwd: process.cwd(),
|
|
1448
|
+
exitCode: 0,
|
|
1449
|
+
...filePaths.length > 0 ? { files: filePaths } : {}
|
|
1450
|
+
});
|
|
1451
|
+
return { success: true };
|
|
1452
|
+
});
|
|
1453
|
+
const agentListCronJobs = apiProcedure.query(async ({ ctx }) => {
|
|
1454
|
+
if (!ctx.tokenPayload) throw new TRPCError({
|
|
1455
|
+
code: "UNAUTHORIZED",
|
|
1456
|
+
message: "Missing token"
|
|
1457
|
+
});
|
|
1458
|
+
const chatId = ctx.tokenPayload.chatId;
|
|
1459
|
+
return listCronJobsShared(chatId);
|
|
1460
|
+
});
|
|
1461
|
+
const agentAddCronJob = apiProcedure.input(z.object({ job: CronJobSchema })).mutation(async ({ input, ctx }) => {
|
|
1462
|
+
if (!ctx.tokenPayload) throw new TRPCError({
|
|
1463
|
+
code: "UNAUTHORIZED",
|
|
1464
|
+
message: "Missing token"
|
|
1465
|
+
});
|
|
1466
|
+
const chatId = ctx.tokenPayload.chatId;
|
|
1467
|
+
return addCronJobShared(chatId, {
|
|
1468
|
+
...input.job,
|
|
1469
|
+
agentId: ctx.tokenPayload.agentId
|
|
1470
|
+
});
|
|
1471
|
+
});
|
|
1472
|
+
const agentDeleteCronJob = apiProcedure.input(z.object({ id: z.string() })).mutation(async ({ input, ctx }) => {
|
|
1473
|
+
if (!ctx.tokenPayload) throw new TRPCError({
|
|
1474
|
+
code: "UNAUTHORIZED",
|
|
1475
|
+
message: "Missing token"
|
|
1476
|
+
});
|
|
1477
|
+
const chatId = ctx.tokenPayload.chatId;
|
|
1478
|
+
return deleteCronJobShared(chatId, input.id);
|
|
1479
|
+
});
|
|
1480
|
+
const listPolicies = apiProcedure.query(async () => {
|
|
1481
|
+
return await readPolicies();
|
|
1482
|
+
});
|
|
1483
|
+
const executePolicyHelp = apiProcedure.input(z.object({ commandName: z.string() })).query(async ({ input }) => {
|
|
1484
|
+
const policy = (await readPolicies())?.policies?.[input.commandName];
|
|
1485
|
+
if (!policy) throw new TRPCError({
|
|
1486
|
+
code: "NOT_FOUND",
|
|
1487
|
+
message: `Policy not found: ${input.commandName}`
|
|
1488
|
+
});
|
|
1489
|
+
if (!policy.allowHelp) return {
|
|
1490
|
+
stdout: "",
|
|
1491
|
+
stderr: "This command does not support --help\n",
|
|
1492
|
+
exitCode: 1
|
|
1493
|
+
};
|
|
1494
|
+
const fullArgs = [...policy.args || [], "--help"];
|
|
1495
|
+
const { stdout, stderr, exitCode } = await executeSafe(policy.command, fullArgs, { cwd: getWorkspaceRoot() });
|
|
1496
|
+
return {
|
|
1497
|
+
stdout,
|
|
1498
|
+
stderr,
|
|
1499
|
+
exitCode
|
|
1500
|
+
};
|
|
1501
|
+
});
|
|
1502
|
+
const createPolicyRequest = apiProcedure.input(z.object({
|
|
1503
|
+
commandName: z.string(),
|
|
1504
|
+
args: z.array(z.string()),
|
|
1505
|
+
fileMappings: z.record(z.string(), z.string())
|
|
1506
|
+
})).mutation(async ({ input, ctx }) => {
|
|
1507
|
+
if (!ctx.tokenPayload) throw new TRPCError({
|
|
1508
|
+
code: "UNAUTHORIZED",
|
|
1509
|
+
message: "Missing token"
|
|
1510
|
+
});
|
|
1511
|
+
const workspaceRoot = getWorkspaceRoot(process.cwd());
|
|
1512
|
+
const snapshotDir = path.join(getClawminiDir(process.cwd()), "tmp", "snapshots");
|
|
1513
|
+
const service = new PolicyRequestService(new RequestStore(process.cwd()), await resolveAgentDir(ctx.tokenPayload?.agentId, workspaceRoot), snapshotDir);
|
|
1514
|
+
const chatId = ctx.tokenPayload.chatId;
|
|
1515
|
+
const agentId = ctx.tokenPayload.agentId;
|
|
1516
|
+
const request = await service.createRequest(input.commandName, input.args, input.fileMappings, chatId, agentId);
|
|
1517
|
+
const previewContent = await generateRequestPreview(request);
|
|
1518
|
+
await appendMessage(chatId, {
|
|
1519
|
+
id: randomUUID(),
|
|
1520
|
+
messageId: randomUUID(),
|
|
1521
|
+
role: "log",
|
|
1522
|
+
source: "router",
|
|
1523
|
+
content: previewContent,
|
|
1524
|
+
stderr: "",
|
|
1525
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1526
|
+
command: "policy-request",
|
|
1527
|
+
cwd: process.cwd(),
|
|
1528
|
+
exitCode: 0
|
|
1529
|
+
});
|
|
1530
|
+
return request;
|
|
1531
|
+
});
|
|
1532
|
+
const fetchPendingMessages = apiProcedure.mutation(async ({ ctx }) => {
|
|
1533
|
+
const queue = getMessageQueue(process.cwd());
|
|
1534
|
+
const targetSessionId = ctx.tokenPayload?.sessionId || "default";
|
|
1535
|
+
const extracted = queue.extractPending((p) => p.sessionId === targetSessionId);
|
|
1536
|
+
if (extracted.length === 0) return { messages: "" };
|
|
1537
|
+
return { messages: formatPendingMessages(extracted.map((p) => p.text)) };
|
|
1538
|
+
});
|
|
1539
|
+
const agentRouter = router({
|
|
1540
|
+
logMessage,
|
|
1541
|
+
listCronJobs: agentListCronJobs,
|
|
1542
|
+
addCronJob: agentAddCronJob,
|
|
1543
|
+
deleteCronJob: agentDeleteCronJob,
|
|
1544
|
+
listPolicies,
|
|
1545
|
+
executePolicyHelp,
|
|
1546
|
+
createPolicyRequest,
|
|
1547
|
+
fetchPendingMessages,
|
|
1548
|
+
ping
|
|
1359
1549
|
});
|
|
1360
|
-
const appRouter = AppRouter;
|
|
1361
1550
|
|
|
1362
1551
|
//#endregion
|
|
1363
1552
|
//#region src/daemon/index.ts
|
|
@@ -1431,7 +1620,7 @@ async function initDaemon() {
|
|
|
1431
1620
|
readyPromiseResolve = resolve;
|
|
1432
1621
|
});
|
|
1433
1622
|
const handler = createHTTPHandler({
|
|
1434
|
-
router:
|
|
1623
|
+
router: userRouter,
|
|
1435
1624
|
createContext: ({ req, res }) => ({
|
|
1436
1625
|
req,
|
|
1437
1626
|
res,
|
|
@@ -1464,7 +1653,7 @@ async function initDaemon() {
|
|
|
1464
1653
|
let apiServer;
|
|
1465
1654
|
if (apiCtx) {
|
|
1466
1655
|
const apiHandler = createHTTPHandler({
|
|
1467
|
-
router:
|
|
1656
|
+
router: agentRouter,
|
|
1468
1657
|
createContext: ({ req, res }) => {
|
|
1469
1658
|
let tokenPayload = null;
|
|
1470
1659
|
const authHeader = req.headers.authorization;
|