@songsid/agend 2.1.12-beta.6 → 2.1.12-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/agent-cli.js +13 -2
  2. package/dist/agent-cli.js.map +1 -1
  3. package/dist/backend/claude-code.d.ts +34 -1
  4. package/dist/backend/claude-code.js +123 -0
  5. package/dist/backend/claude-code.js.map +1 -1
  6. package/dist/backend/types.d.ts +21 -0
  7. package/dist/backend/types.js.map +1 -1
  8. package/dist/channel/adapters/discord.d.ts +13 -0
  9. package/dist/channel/adapters/discord.js +43 -0
  10. package/dist/channel/adapters/discord.js.map +1 -1
  11. package/dist/channel/mcp-tools.js +1 -1
  12. package/dist/channel/mcp-tools.js.map +1 -1
  13. package/dist/cli.js +26 -0
  14. package/dist/cli.js.map +1 -1
  15. package/dist/command-table.d.ts +1 -1
  16. package/dist/command-table.js +7 -1
  17. package/dist/command-table.js.map +1 -1
  18. package/dist/config-validator.js +4 -0
  19. package/dist/config-validator.js.map +1 -1
  20. package/dist/cpu-profile.d.ts +32 -0
  21. package/dist/cpu-profile.js +221 -0
  22. package/dist/cpu-profile.js.map +1 -0
  23. package/dist/daemon.d.ts +27 -1
  24. package/dist/daemon.js +131 -30
  25. package/dist/daemon.js.map +1 -1
  26. package/dist/delivery-outbox.d.ts +22 -0
  27. package/dist/delivery-outbox.js +111 -0
  28. package/dist/delivery-outbox.js.map +1 -1
  29. package/dist/fleet-context.d.ts +10 -1
  30. package/dist/fleet-manager.d.ts +66 -2
  31. package/dist/fleet-manager.js +409 -62
  32. package/dist/fleet-manager.js.map +1 -1
  33. package/dist/locale.js +26 -0
  34. package/dist/locale.js.map +1 -1
  35. package/dist/outbound-handlers.d.ts +2 -0
  36. package/dist/outbound-handlers.js +8 -0
  37. package/dist/outbound-handlers.js.map +1 -1
  38. package/dist/outbound-schemas.d.ts +15 -1
  39. package/dist/outbound-schemas.js +9 -3
  40. package/dist/outbound-schemas.js.map +1 -1
  41. package/dist/pane-input-residue.d.ts +2 -0
  42. package/dist/pane-input-residue.js +5 -1
  43. package/dist/pane-input-residue.js.map +1 -1
  44. package/dist/profile-control.d.ts +20 -0
  45. package/dist/profile-control.js +308 -0
  46. package/dist/profile-control.js.map +1 -0
  47. package/dist/runtime-cpu-profile.d.ts +37 -0
  48. package/dist/runtime-cpu-profile.js +123 -0
  49. package/dist/runtime-cpu-profile.js.map +1 -0
  50. package/dist/scheduler/db.d.ts +29 -4
  51. package/dist/scheduler/db.js +96 -6
  52. package/dist/scheduler/db.js.map +1 -1
  53. package/dist/scheduler/types.d.ts +33 -0
  54. package/dist/service-installer.d.ts +6 -0
  55. package/dist/service-installer.js +18 -2
  56. package/dist/service-installer.js.map +1 -1
  57. package/dist/topic-commands.d.ts +12 -1
  58. package/dist/topic-commands.js +33 -1
  59. package/dist/topic-commands.js.map +1 -1
  60. package/dist/types.d.ts +4 -0
  61. package/package.json +1 -1
@@ -0,0 +1,308 @@
1
+ import { createServer, createConnection } from "node:net";
2
+ import { constants } from "node:fs";
3
+ import { lstat, mkdir, open, chmod, unlink } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { performance } from "node:perf_hooks";
6
+ import { cpuProfileSeconds, CPU_PROFILE_ENV } from "./cpu-profile.js";
7
+ import { UNIX_SOCKET_PATH_MAX } from "./channel/ipc-bridge.js";
8
+ import { ProfileBusyError, profileDuration } from "./runtime-cpu-profile.js";
9
+ const INPUT_BYTES = 256;
10
+ export const profileSocketPath = (dataDir) => join(dataDir, "operator", "profile.sock");
11
+ function uid() {
12
+ if (!process.getuid)
13
+ throw new Error("Local CPU profile control requires Unix user permissions.");
14
+ return process.getuid();
15
+ }
16
+ async function checkRoot(dataDir) {
17
+ const root = await lstat(dataDir);
18
+ if (!root.isDirectory() || root.isSymbolicLink() || root.uid !== uid() || (root.mode & 0o022)) {
19
+ throw new Error("Profile control requires an owned real AGEND_HOME without group/other write permission.");
20
+ }
21
+ }
22
+ async function checkClientPath(dataDir) {
23
+ await checkRoot(dataDir);
24
+ const directory = await lstat(join(dataDir, "operator"));
25
+ const socket = await lstat(profileSocketPath(dataDir));
26
+ if (!directory.isDirectory() || directory.isSymbolicLink() || directory.uid !== uid() || (directory.mode & 0o077)
27
+ || !socket.isSocket() || socket.uid !== uid() || (socket.mode & 0o077)) {
28
+ throw new Error("Profile control is not a private socket owned by this user.");
29
+ }
30
+ }
31
+ /** Operator-only Unix socket; never attached to daemon/MCP IPC or any HTTP listener. */
32
+ export class ProfileControlServer {
33
+ dataDir;
34
+ profiler;
35
+ server = null;
36
+ clients = new Set();
37
+ closed = false;
38
+ inode = null;
39
+ closing = null;
40
+ constructor(dataDir, profiler) {
41
+ this.dataDir = dataDir;
42
+ this.profiler = profiler;
43
+ }
44
+ async listen() {
45
+ const deadline = performance.now() + 2000;
46
+ let timer;
47
+ try {
48
+ await Promise.race([this.bind(deadline).catch(async (err) => { if (this.closed)
49
+ await this.removeOwnedSocket(); throw err; }), new Promise((_yes, no) => {
50
+ timer = setTimeout(() => { this.closed = true; no(new Error("Profile socket startup timed out")); }, 2000);
51
+ })]);
52
+ }
53
+ catch (err) {
54
+ await this.close();
55
+ throw err;
56
+ }
57
+ finally {
58
+ clearTimeout(timer);
59
+ }
60
+ }
61
+ async bind(deadline) {
62
+ const current = () => {
63
+ if (this.closed || performance.now() >= deadline)
64
+ throw new Error("Profile socket startup expired.");
65
+ };
66
+ const path = profileSocketPath(this.dataDir);
67
+ if (Buffer.byteLength(path) >= UNIX_SOCKET_PATH_MAX)
68
+ throw new Error("Profile socket path exceeds the Unix socket limit.");
69
+ await checkRoot(this.dataDir);
70
+ current();
71
+ const directory = join(this.dataDir, "operator");
72
+ await mkdir(directory, { mode: 0o700 }).catch(err => { if (err.code !== "EEXIST")
73
+ throw err; });
74
+ current();
75
+ const dir = await open(directory, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
76
+ try {
77
+ current();
78
+ const info = await dir.stat();
79
+ current();
80
+ if (!info.isDirectory() || info.uid !== uid())
81
+ throw new Error("Profile operator directory is not owned by this user.");
82
+ await dir.chmod(0o700);
83
+ current(); // same fd checked and changed, never follow a replaced symlink
84
+ }
85
+ finally {
86
+ await dir.close();
87
+ }
88
+ current();
89
+ const existing = await lstat(path).catch(err => { if (err.code !== "ENOENT")
90
+ throw err; return null; });
91
+ current();
92
+ if (existing) {
93
+ if (!existing.isSocket() || existing.uid !== uid())
94
+ throw new Error("Refusing to replace a non-owned/non-socket profile path.");
95
+ await unlink(path);
96
+ current(); // only called after the fleet singleton has been claimed
97
+ }
98
+ const server = createServer(socket => this.accept(socket));
99
+ this.server = server;
100
+ server.on("error", () => { void this.close(); });
101
+ await new Promise((yes, no) => {
102
+ server.once("error", no);
103
+ server.listen(path, () => {
104
+ server.removeListener("error", no);
105
+ if (this.closed || performance.now() >= deadline) {
106
+ // A late native listen completion must not reopen an expired listener.
107
+ server.close();
108
+ no(new Error("Profile socket startup expired."));
109
+ }
110
+ else
111
+ yes();
112
+ });
113
+ });
114
+ // The 0700 parent already gates access while these asynchronous checks run.
115
+ const info = await lstat(path);
116
+ this.inode = info.ino;
117
+ current();
118
+ await chmod(path, 0o600);
119
+ current();
120
+ if (this.closed)
121
+ await this.removeOwnedSocket();
122
+ }
123
+ accept(socket) {
124
+ if (this.closed || this.clients.size >= 8) {
125
+ socket.destroy();
126
+ return;
127
+ }
128
+ this.clients.add(socket);
129
+ let buffer = "", bytes = 0, handled = false;
130
+ let timer;
131
+ const write = (value) => {
132
+ try {
133
+ if (!socket.destroyed)
134
+ socket.write(JSON.stringify(value) + "\n");
135
+ }
136
+ catch {
137
+ socket.destroy();
138
+ }
139
+ };
140
+ const expireAt = (deadline) => {
141
+ clearTimeout(timer);
142
+ const check = () => {
143
+ const remaining = deadline - performance.now();
144
+ if (remaining > 0)
145
+ timer = setTimeout(check, Math.ceil(remaining));
146
+ else
147
+ socket.destroy();
148
+ };
149
+ timer = setTimeout(check, Math.max(0, Math.ceil(deadline - performance.now())));
150
+ };
151
+ const inputDeadline = performance.now() + 2000;
152
+ expireAt(inputDeadline);
153
+ socket.on("close", () => { clearTimeout(timer); this.clients.delete(socket); });
154
+ socket.on("error", () => socket.destroy());
155
+ socket.on("data", (data) => {
156
+ if (handled || this.closed || socket.destroyed)
157
+ return;
158
+ if (performance.now() >= inputDeadline) {
159
+ socket.destroy();
160
+ return;
161
+ }
162
+ bytes += data.length;
163
+ if (bytes > INPUT_BYTES) {
164
+ socket.destroy();
165
+ return;
166
+ }
167
+ buffer += data.toString("utf8");
168
+ if (!buffer.includes("\n"))
169
+ return;
170
+ handled = true;
171
+ void (async () => {
172
+ try {
173
+ const request = JSON.parse(buffer.slice(0, buffer.indexOf("\n")));
174
+ if (!request || typeof request !== "object" || Object.keys(request).length !== 1
175
+ || !Object.hasOwn(request, "seconds") || typeof request.seconds !== "number")
176
+ throw new Error("Invalid profile request.");
177
+ const seconds = profileDuration(request.seconds);
178
+ expireAt(performance.now() + seconds * 1000 + 15_000);
179
+ const ticket = await this.profiler.start(seconds);
180
+ write({ status: "recording", seconds });
181
+ write({ status: "saved", ...await ticket.done });
182
+ }
183
+ catch (err) {
184
+ write({ status: "error", message: String(err), ...(err instanceof ProfileBusyError ? { remainingSeconds: err.remainingSeconds } : {}) });
185
+ }
186
+ finally {
187
+ clearTimeout(timer);
188
+ try {
189
+ socket.end();
190
+ }
191
+ catch {
192
+ socket.destroy();
193
+ }
194
+ }
195
+ })();
196
+ });
197
+ }
198
+ close() {
199
+ this.closed = true;
200
+ for (const socket of this.clients)
201
+ socket.destroy();
202
+ this.clients.clear();
203
+ this.closing ??= (async () => {
204
+ const server = this.server;
205
+ this.server = null;
206
+ let timer;
207
+ try {
208
+ if (server)
209
+ await Promise.race([
210
+ new Promise(resolve => server.close(() => resolve())),
211
+ new Promise(resolve => { timer = setTimeout(resolve, 2000); }),
212
+ ]);
213
+ }
214
+ finally {
215
+ clearTimeout(timer);
216
+ }
217
+ await this.removeOwnedSocket();
218
+ })();
219
+ return this.closing;
220
+ }
221
+ async removeOwnedSocket() {
222
+ if (this.inode !== null) {
223
+ const info = await lstat(profileSocketPath(this.dataDir)).catch(() => null);
224
+ if (info?.isSocket() && info.ino === this.inode && info.uid === uid())
225
+ await unlink(profileSocketPath(this.dataDir)).catch(() => { });
226
+ }
227
+ }
228
+ }
229
+ /** No fleet construction or fallback startup. Refuse agent env before filesystem/socket effects. */
230
+ export async function requestCpuProfile(dataDir, value, env = process.env) {
231
+ const seconds = cpuProfileSeconds({ ...env, [CPU_PROFILE_ENV]: String(value ?? 60) });
232
+ try {
233
+ await checkClientPath(dataDir);
234
+ }
235
+ catch (err) {
236
+ throw new Error(`Running fleet profile control unavailable: ${String(err)}`);
237
+ }
238
+ const deadline = performance.now() + seconds * 1000 + 20_000;
239
+ return new Promise((resolve, reject) => {
240
+ const socket = createConnection(profileSocketPath(dataDir));
241
+ let buffer = "", bytes = 0, settled = false;
242
+ let timer;
243
+ const finish = (err, result) => {
244
+ if (settled)
245
+ return;
246
+ settled = true;
247
+ clearTimeout(timer);
248
+ socket.destroy();
249
+ if (err)
250
+ reject(err);
251
+ else
252
+ resolve(result);
253
+ };
254
+ const check = () => {
255
+ const remaining = deadline - performance.now();
256
+ if (remaining > 0)
257
+ timer = setTimeout(check, Math.ceil(remaining));
258
+ else
259
+ finish(new Error("CPU profile request timed out; the fleet may still save its capture."));
260
+ };
261
+ timer = setTimeout(check, seconds * 1000 + 20_000);
262
+ socket.once("connect", () => {
263
+ if (settled || performance.now() >= deadline) {
264
+ finish(new Error("CPU profile connection arrived after its deadline."));
265
+ return;
266
+ }
267
+ try {
268
+ socket.write(JSON.stringify({ seconds }) + "\n");
269
+ }
270
+ catch (err) {
271
+ finish(err);
272
+ }
273
+ });
274
+ socket.on("error", err => finish(new Error(`Running fleet profile control unavailable: ${err.message}`)));
275
+ socket.on("close", () => finish(new Error("Fleet disconnected before the CPU profile result.")));
276
+ socket.on("data", (data) => {
277
+ bytes += data.length;
278
+ if (bytes > 8192) {
279
+ finish(new Error("Invalid CPU profile response."));
280
+ return;
281
+ }
282
+ buffer += data.toString("utf8");
283
+ while (buffer.includes("\n") && !settled) {
284
+ const end = buffer.indexOf("\n"), line = buffer.slice(0, end);
285
+ buffer = buffer.slice(end + 1);
286
+ try {
287
+ const result = JSON.parse(line);
288
+ if (performance.now() >= deadline) {
289
+ finish(new Error("CPU profile response arrived after its deadline."));
290
+ return;
291
+ }
292
+ if (result.status === "error") {
293
+ finish(typeof result.remainingSeconds === "number" ? new ProfileBusyError(result.remainingSeconds) : new Error(String(result.message)));
294
+ }
295
+ else if (result.status === "saved" && typeof result.path === "string" && (result.bytes === null || typeof result.bytes === "number")) {
296
+ finish(null, { path: result.path, bytes: result.bytes });
297
+ }
298
+ else if (result.status !== "recording")
299
+ finish(new Error("Invalid CPU profile response."));
300
+ }
301
+ catch (err) {
302
+ finish(err);
303
+ }
304
+ }
305
+ });
306
+ });
307
+ }
308
+ //# sourceMappingURL=profile-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-control.js","sourceRoot":"","sources":["../src/profile-control.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { startCpuProfileFromEnvironment, type CpuProfile } from "./cpu-profile.js";
2
+ export interface ProfileResult {
3
+ path: string;
4
+ bytes: number | null;
5
+ }
6
+ export interface ProfileTicket {
7
+ seconds: number;
8
+ done: Promise<ProfileResult>;
9
+ }
10
+ interface Logger {
11
+ info(message: string): void;
12
+ warn(message: string): void;
13
+ }
14
+ type Starter = typeof startCpuProfileFromEnvironment;
15
+ export declare class ProfileBusyError extends Error {
16
+ readonly remainingSeconds: number;
17
+ constructor(remainingSeconds: number);
18
+ }
19
+ export declare function profileDuration(value?: string | number): number;
20
+ /** One owner for startup-env, local operator and General recordings. No effect until start. */
21
+ export declare class RuntimeCpuProfiler {
22
+ private readonly options;
23
+ private active;
24
+ private closing;
25
+ constructor(options: {
26
+ dataDir: string;
27
+ logger: Logger;
28
+ start?: Starter;
29
+ });
30
+ get closed(): boolean;
31
+ start(value?: string | number): Promise<ProfileTicket>;
32
+ startFromEnvironment(env?: NodeJS.ProcessEnv): Promise<CpuProfile | null>;
33
+ /** Fence new starts synchronously, including requests racing a pending native start. */
34
+ shutdown(reason?: string): Promise<string | null>;
35
+ private finish;
36
+ }
37
+ export {};
@@ -0,0 +1,123 @@
1
+ import { performance } from "node:perf_hooks";
2
+ import { stat } from "node:fs/promises";
3
+ import { CPU_PROFILE_ENV, cpuProfileSeconds, startCpuProfileFromEnvironment } from "./cpu-profile.js";
4
+ export class ProfileBusyError extends Error {
5
+ remainingSeconds;
6
+ constructor(remainingSeconds) {
7
+ super(`A CPU profile is already recording or finishing (${remainingSeconds}s remaining).`);
8
+ this.remainingSeconds = remainingSeconds;
9
+ }
10
+ }
11
+ export function profileDuration(value) {
12
+ return cpuProfileSeconds({ [CPU_PROFILE_ENV]: String(value ?? 60) });
13
+ }
14
+ /** One owner for startup-env, local operator and General recordings. No effect until start. */
15
+ export class RuntimeCpuProfiler {
16
+ options;
17
+ active = null;
18
+ closing = false;
19
+ constructor(options) {
20
+ this.options = options;
21
+ }
22
+ get closed() { return this.closing; }
23
+ async start(value) {
24
+ const seconds = profileDuration(value);
25
+ if (this.closing)
26
+ throw new Error("Fleet is stopping; CPU profiling is unavailable.");
27
+ if (this.active)
28
+ throw new ProfileBusyError(Math.max(0, Math.ceil((this.active.deadline - performance.now()) / 1000)));
29
+ let resolve, reject;
30
+ const done = new Promise((yes, no) => { resolve = yes; reject = no; });
31
+ // Startup can fail before a caller gets a ticket; still let ticket holders observe rejection.
32
+ void done.catch(() => { });
33
+ const recording = { deadline: performance.now() + seconds * 1000, startup: Promise.resolve(null), done, resolve, reject };
34
+ this.active = recording; // reserve before the first await / native startup
35
+ recording.startup = Promise.resolve().then(() => (this.options.start ?? startCpuProfileFromEnvironment)({
36
+ dataDir: this.options.dataDir, logger: this.options.logger, env: { [CPU_PROFILE_ENV]: String(seconds) },
37
+ }));
38
+ try {
39
+ const handle = await recording.startup;
40
+ if (!handle)
41
+ throw new Error("CPU profiler could not start; see daemon.log.");
42
+ if (this.closing || this.active !== recording) {
43
+ await this.finish(recording, "startup superseded by shutdown");
44
+ throw new Error("Fleet stopped during CPU profile startup.");
45
+ }
46
+ const expire = () => {
47
+ if (this.active !== recording || recording.finishing)
48
+ return;
49
+ const remaining = recording.deadline - performance.now();
50
+ if (remaining > 0) {
51
+ recording.timer = setTimeout(expire, Math.ceil(remaining));
52
+ recording.timer.unref?.();
53
+ }
54
+ else
55
+ void this.finish(recording, "duration cap");
56
+ };
57
+ recording.timer = setTimeout(expire, Math.max(0, Math.ceil(recording.deadline - performance.now())));
58
+ recording.timer.unref?.();
59
+ return { seconds, done };
60
+ }
61
+ catch (err) {
62
+ await this.finish(recording, "startup failed");
63
+ throw err;
64
+ }
65
+ }
66
+ async startFromEnvironment(env = process.env) {
67
+ try {
68
+ const seconds = cpuProfileSeconds(env);
69
+ if (seconds === null)
70
+ return null;
71
+ await this.start(seconds);
72
+ return { stop: reason => this.shutdown(reason) };
73
+ }
74
+ catch (err) {
75
+ this.options.logger.warn(String(err));
76
+ return null;
77
+ }
78
+ }
79
+ /** Fence new starts synchronously, including requests racing a pending native start. */
80
+ shutdown(reason = "fleet shutdown") {
81
+ this.closing = true;
82
+ const current = this.active;
83
+ if (!current)
84
+ return Promise.resolve(null);
85
+ void this.finish(current, reason);
86
+ return current.done.then(result => result.path, () => null);
87
+ }
88
+ finish(recording, reason) {
89
+ recording.finishing ??= (async () => {
90
+ clearTimeout(recording.timer);
91
+ try {
92
+ const handle = await recording.startup;
93
+ const path = await handle?.stop(reason);
94
+ if (!path)
95
+ throw new Error("CPU profile was not saved; see daemon.log.");
96
+ let bytes = null;
97
+ const deadline = performance.now() + 2000;
98
+ let timer;
99
+ try {
100
+ const info = await Promise.race([stat(path), new Promise((_yes, no) => {
101
+ timer = setTimeout(() => no(new Error("Profile size lookup timed out")), 2000);
102
+ })]);
103
+ if (performance.now() < deadline && info.isFile())
104
+ bytes = info.size;
105
+ }
106
+ catch { /* a saved path remains useful if its size cannot be read */ }
107
+ finally {
108
+ clearTimeout(timer);
109
+ }
110
+ recording.resolve({ path, bytes });
111
+ }
112
+ catch (err) {
113
+ recording.reject(err instanceof Error ? err : new Error(String(err)));
114
+ }
115
+ finally {
116
+ if (this.active === recording)
117
+ this.active = null;
118
+ }
119
+ })();
120
+ return recording.finishing;
121
+ }
122
+ }
123
+ //# sourceMappingURL=runtime-cpu-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-cpu-profile.js","sourceRoot":"","sources":["../src/runtime-cpu-profile.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { Schedule, ScheduleRun, CreateScheduleParams, UpdateScheduleParams, Decision, CreateDecisionParams, UpdateDecisionParams, Task, CreateTaskParams, UpdateTaskParams } from "./types.js";
1
+ import type { Schedule, ScheduleRun, CreateScheduleParams, UpdateScheduleParams, Decision, CreateDecisionParams, UpdateDecisionParams, Task, TaskCompact, ListTasksOpts, CreateTaskParams, UpdateTaskParams } from "./types.js";
2
2
  export declare class SchedulerDb {
3
3
  private db;
4
4
  constructor(dbPath: string);
@@ -20,6 +20,15 @@ export declare class SchedulerDb {
20
20
  recordRun(scheduleId: string, status: string, detail?: string): void;
21
21
  getRuns(scheduleId: string, limit?: number): ScheduleRun[];
22
22
  pruneOldRuns(days?: number): void;
23
+ /**
24
+ * #1335: Prune done/cancelled tasks older than `days`. Open, claimed and
25
+ * blocked tasks are never pruned regardless of age.
26
+ * Cancelled tasks that appear in a live task's `depends_on` are also kept:
27
+ * pruning a cancelled dep would silently un-block a task whose prerequisite
28
+ * was explicitly cancelled (claimTask treats a missing dep as satisfied).
29
+ * Runs in async chunks of 500 rows with setImmediate yields (#1340 P4).
30
+ */
31
+ pruneOldTasks(days?: number): Promise<number>;
23
32
  dismissTip(userId: string, tipId: string): void;
24
33
  /** Tips are shared General-topic messages: one acknowledgement retires them fleet-wide. */
25
34
  listDismissedTipIds(): Set<string>;
@@ -48,10 +57,26 @@ export declare class SchedulerDb {
48
57
  private rowToTask;
49
58
  createTask(params: CreateTaskParams): Task;
50
59
  getTask(id: string): Task | null;
51
- listTasks(opts?: {
52
- assignee?: string;
53
- status?: string;
60
+ /** #1336: project a full Task down to the compact list row. */
61
+ private toCompact;
62
+ /**
63
+ * #1336: Resolve a task by an 8-hex (or longer) id prefix. A full 36-char
64
+ * UUID is matched exactly first. Throws on ambiguous or not-found so the
65
+ * caller surfaces a clear error instead of silently acting on the wrong row.
66
+ */
67
+ getTaskByPrefix(prefix: string): Task;
68
+ /**
69
+ * #1336: list tasks. Returns compact rows by default; pass `verbose: true`
70
+ * for full {@link Task} rows. `status` accepts a single value or an array
71
+ * (OR-matched). No implicit live-only filtering happens here — the caller
72
+ * decides the default status set.
73
+ */
74
+ listTasks(opts?: ListTasksOpts & {
75
+ verbose: true;
54
76
  }): Task[];
77
+ listTasks(opts?: ListTasksOpts): TaskCompact[];
78
+ /** Normalize a status filter (string | string[] | undefined) to a deduped non-empty array. */
79
+ private normalizeStatuses;
55
80
  updateTask(id: string, params: UpdateTaskParams): Task;
56
81
  claimTask(id: string, assignee: string): Task;
57
82
  completeTask(id: string, result?: string): Task;