@spinabot/brigade 1.0.1 → 1.0.2
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/convex/_generated/api.d.ts +85 -0
- package/convex/_generated/api.js +23 -0
- package/convex/_generated/dataModel.d.ts +60 -0
- package/convex/_generated/server.d.ts +143 -0
- package/convex/_generated/server.js +93 -0
- package/convex/admin.d.ts +57 -0
- package/convex/admin.ts +315 -0
- package/convex/auth.d.ts +159 -0
- package/convex/auth.ts +217 -0
- package/convex/blobs.d.ts +38 -0
- package/convex/blobs.ts +115 -0
- package/convex/channels.d.ts +150 -0
- package/convex/channels.ts +455 -0
- package/convex/config.d.ts +67 -0
- package/convex/config.ts +168 -0
- package/convex/cron.d.ts +237 -0
- package/convex/cron.ts +199 -0
- package/convex/execApprovals.d.ts +31 -0
- package/convex/execApprovals.ts +58 -0
- package/convex/extensions.d.ts +30 -0
- package/convex/extensions.ts +51 -0
- package/convex/health.d.ts +18 -0
- package/convex/health.ts +69 -0
- package/convex/instance.d.ts +34 -0
- package/convex/instance.ts +82 -0
- package/convex/logs.d.ts +178 -0
- package/convex/logs.ts +253 -0
- package/convex/memory.d.ts +354 -0
- package/convex/memory.ts +536 -0
- package/convex/messages.d.ts +124 -0
- package/convex/messages.ts +347 -0
- package/convex/org.d.ts +75 -0
- package/convex/org.ts +99 -0
- package/convex/schema.d.ts +1130 -0
- package/convex/schema.ts +847 -0
- package/convex/sessions.d.ts +100 -0
- package/convex/sessions.ts +105 -0
- package/convex/skills.d.ts +73 -0
- package/convex/skills.ts +102 -0
- package/convex/subagents.d.ts +214 -0
- package/convex/subagents.ts +99 -0
- package/convex/tsconfig.json +23 -0
- package/convex/whatsappAuth.d.ts +52 -0
- package/convex/whatsappAuth.ts +151 -0
- package/convex/workspace.d.ts +49 -0
- package/convex/workspace.ts +106 -0
- package/dist/buildstamp.json +1 -1
- package/package.json +7 -1
- package/scripts/convex-dev.mjs +321 -0
- package/scripts/convex-push.mjs +69 -0
- package/scripts/install-convex.mjs +123 -0
package/convex/cron.d.ts
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
export declare const listJobs: import("convex/server").RegisteredQuery<"public", {
|
|
2
|
+
enabledOnly?: boolean | undefined;
|
|
3
|
+
ownerUserId: string;
|
|
4
|
+
}, Promise<{
|
|
5
|
+
_id: import("convex/values").GenericId<"cronJobs">;
|
|
6
|
+
_creationTime: number;
|
|
7
|
+
agentId?: string | undefined;
|
|
8
|
+
description?: string | undefined;
|
|
9
|
+
sessionKey?: string | undefined;
|
|
10
|
+
wakeMode?: string | undefined;
|
|
11
|
+
delivery?: ArrayBuffer | undefined;
|
|
12
|
+
failureAlert?: any;
|
|
13
|
+
deleteAfterRun?: boolean | undefined;
|
|
14
|
+
createdByChannelId?: string | undefined;
|
|
15
|
+
createdByConversationId?: string | undefined;
|
|
16
|
+
createdByAccountId?: string | undefined;
|
|
17
|
+
scheduleExpr?: string | undefined;
|
|
18
|
+
scheduleTz?: string | undefined;
|
|
19
|
+
scheduleStaggerMs?: number | undefined;
|
|
20
|
+
scheduleEveryMs?: number | undefined;
|
|
21
|
+
scheduleAnchorMs?: number | undefined;
|
|
22
|
+
scheduleAt?: number | undefined;
|
|
23
|
+
stateNextRunAtMs?: number | undefined;
|
|
24
|
+
stateLastRunAtMs?: number | undefined;
|
|
25
|
+
stateRunningAtMs?: number | undefined;
|
|
26
|
+
stateLastStatus?: string | undefined;
|
|
27
|
+
stateLastError?: string | undefined;
|
|
28
|
+
stateScheduleErrorCount?: number | undefined;
|
|
29
|
+
stateConsecutiveErrorCount?: number | undefined;
|
|
30
|
+
stateLastFailureAlertAtMs?: number | undefined;
|
|
31
|
+
stateLastDelivered?: boolean | undefined;
|
|
32
|
+
stateLastDeliveryStatus?: string | undefined;
|
|
33
|
+
stateLastDeliveryError?: string | undefined;
|
|
34
|
+
name: string;
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
sessionTarget: string;
|
|
37
|
+
payload: ArrayBuffer;
|
|
38
|
+
jobId: string;
|
|
39
|
+
updatedAtMs: number;
|
|
40
|
+
createdByKind: "owner" | "channel" | "legacy";
|
|
41
|
+
ownerUserId: string;
|
|
42
|
+
scheduleKind: "at" | "every" | "cron";
|
|
43
|
+
createdAtMs: number;
|
|
44
|
+
}[]>>;
|
|
45
|
+
export declare const getJob: import("convex/server").RegisteredQuery<"public", {
|
|
46
|
+
jobId: string;
|
|
47
|
+
ownerUserId: string;
|
|
48
|
+
}, Promise<{
|
|
49
|
+
_id: import("convex/values").GenericId<"cronJobs">;
|
|
50
|
+
_creationTime: number;
|
|
51
|
+
agentId?: string | undefined;
|
|
52
|
+
description?: string | undefined;
|
|
53
|
+
sessionKey?: string | undefined;
|
|
54
|
+
wakeMode?: string | undefined;
|
|
55
|
+
delivery?: ArrayBuffer | undefined;
|
|
56
|
+
failureAlert?: any;
|
|
57
|
+
deleteAfterRun?: boolean | undefined;
|
|
58
|
+
createdByChannelId?: string | undefined;
|
|
59
|
+
createdByConversationId?: string | undefined;
|
|
60
|
+
createdByAccountId?: string | undefined;
|
|
61
|
+
scheduleExpr?: string | undefined;
|
|
62
|
+
scheduleTz?: string | undefined;
|
|
63
|
+
scheduleStaggerMs?: number | undefined;
|
|
64
|
+
scheduleEveryMs?: number | undefined;
|
|
65
|
+
scheduleAnchorMs?: number | undefined;
|
|
66
|
+
scheduleAt?: number | undefined;
|
|
67
|
+
stateNextRunAtMs?: number | undefined;
|
|
68
|
+
stateLastRunAtMs?: number | undefined;
|
|
69
|
+
stateRunningAtMs?: number | undefined;
|
|
70
|
+
stateLastStatus?: string | undefined;
|
|
71
|
+
stateLastError?: string | undefined;
|
|
72
|
+
stateScheduleErrorCount?: number | undefined;
|
|
73
|
+
stateConsecutiveErrorCount?: number | undefined;
|
|
74
|
+
stateLastFailureAlertAtMs?: number | undefined;
|
|
75
|
+
stateLastDelivered?: boolean | undefined;
|
|
76
|
+
stateLastDeliveryStatus?: string | undefined;
|
|
77
|
+
stateLastDeliveryError?: string | undefined;
|
|
78
|
+
name: string;
|
|
79
|
+
enabled: boolean;
|
|
80
|
+
sessionTarget: string;
|
|
81
|
+
payload: ArrayBuffer;
|
|
82
|
+
jobId: string;
|
|
83
|
+
updatedAtMs: number;
|
|
84
|
+
createdByKind: "owner" | "channel" | "legacy";
|
|
85
|
+
ownerUserId: string;
|
|
86
|
+
scheduleKind: "at" | "every" | "cron";
|
|
87
|
+
createdAtMs: number;
|
|
88
|
+
} | null>>;
|
|
89
|
+
export declare const insertJob: import("convex/server").RegisteredMutation<"public", {
|
|
90
|
+
agentId?: string | undefined;
|
|
91
|
+
description?: string | undefined;
|
|
92
|
+
sessionKey?: string | undefined;
|
|
93
|
+
wakeMode?: string | undefined;
|
|
94
|
+
delivery?: ArrayBuffer | undefined;
|
|
95
|
+
failureAlert?: any;
|
|
96
|
+
deleteAfterRun?: boolean | undefined;
|
|
97
|
+
updatedAtMs?: number | undefined;
|
|
98
|
+
createdByChannelId?: string | undefined;
|
|
99
|
+
createdByConversationId?: string | undefined;
|
|
100
|
+
createdByAccountId?: string | undefined;
|
|
101
|
+
scheduleExpr?: string | undefined;
|
|
102
|
+
scheduleTz?: string | undefined;
|
|
103
|
+
scheduleStaggerMs?: number | undefined;
|
|
104
|
+
scheduleEveryMs?: number | undefined;
|
|
105
|
+
scheduleAnchorMs?: number | undefined;
|
|
106
|
+
scheduleAt?: number | undefined;
|
|
107
|
+
createdAtMs?: number | undefined;
|
|
108
|
+
stateNextRunAtMs?: number | undefined;
|
|
109
|
+
stateLastRunAtMs?: number | undefined;
|
|
110
|
+
stateRunningAtMs?: number | undefined;
|
|
111
|
+
stateLastStatus?: string | undefined;
|
|
112
|
+
stateLastError?: string | undefined;
|
|
113
|
+
stateScheduleErrorCount?: number | undefined;
|
|
114
|
+
stateConsecutiveErrorCount?: number | undefined;
|
|
115
|
+
stateLastFailureAlertAtMs?: number | undefined;
|
|
116
|
+
stateLastDelivered?: boolean | undefined;
|
|
117
|
+
stateLastDeliveryStatus?: string | undefined;
|
|
118
|
+
stateLastDeliveryError?: string | undefined;
|
|
119
|
+
name: string;
|
|
120
|
+
enabled: boolean;
|
|
121
|
+
sessionTarget: string;
|
|
122
|
+
payload: ArrayBuffer;
|
|
123
|
+
jobId: string;
|
|
124
|
+
createdByKind: "owner" | "channel" | "legacy";
|
|
125
|
+
ownerUserId: string;
|
|
126
|
+
scheduleKind: "at" | "every" | "cron";
|
|
127
|
+
}, Promise<void>>;
|
|
128
|
+
export declare const patchJob: import("convex/server").RegisteredMutation<"public", {
|
|
129
|
+
unset?: string[] | undefined;
|
|
130
|
+
jobId: string;
|
|
131
|
+
ownerUserId: string;
|
|
132
|
+
patch: any;
|
|
133
|
+
}, Promise<{
|
|
134
|
+
_id: import("convex/values").GenericId<"cronJobs">;
|
|
135
|
+
_creationTime: number;
|
|
136
|
+
agentId?: string | undefined;
|
|
137
|
+
description?: string | undefined;
|
|
138
|
+
sessionKey?: string | undefined;
|
|
139
|
+
wakeMode?: string | undefined;
|
|
140
|
+
delivery?: ArrayBuffer | undefined;
|
|
141
|
+
failureAlert?: any;
|
|
142
|
+
deleteAfterRun?: boolean | undefined;
|
|
143
|
+
createdByChannelId?: string | undefined;
|
|
144
|
+
createdByConversationId?: string | undefined;
|
|
145
|
+
createdByAccountId?: string | undefined;
|
|
146
|
+
scheduleExpr?: string | undefined;
|
|
147
|
+
scheduleTz?: string | undefined;
|
|
148
|
+
scheduleStaggerMs?: number | undefined;
|
|
149
|
+
scheduleEveryMs?: number | undefined;
|
|
150
|
+
scheduleAnchorMs?: number | undefined;
|
|
151
|
+
scheduleAt?: number | undefined;
|
|
152
|
+
stateNextRunAtMs?: number | undefined;
|
|
153
|
+
stateLastRunAtMs?: number | undefined;
|
|
154
|
+
stateRunningAtMs?: number | undefined;
|
|
155
|
+
stateLastStatus?: string | undefined;
|
|
156
|
+
stateLastError?: string | undefined;
|
|
157
|
+
stateScheduleErrorCount?: number | undefined;
|
|
158
|
+
stateConsecutiveErrorCount?: number | undefined;
|
|
159
|
+
stateLastFailureAlertAtMs?: number | undefined;
|
|
160
|
+
stateLastDelivered?: boolean | undefined;
|
|
161
|
+
stateLastDeliveryStatus?: string | undefined;
|
|
162
|
+
stateLastDeliveryError?: string | undefined;
|
|
163
|
+
name: string;
|
|
164
|
+
enabled: boolean;
|
|
165
|
+
sessionTarget: string;
|
|
166
|
+
payload: ArrayBuffer;
|
|
167
|
+
jobId: string;
|
|
168
|
+
updatedAtMs: number;
|
|
169
|
+
createdByKind: "owner" | "channel" | "legacy";
|
|
170
|
+
ownerUserId: string;
|
|
171
|
+
scheduleKind: "at" | "every" | "cron";
|
|
172
|
+
createdAtMs: number;
|
|
173
|
+
} | null>>;
|
|
174
|
+
export declare const deleteJob: import("convex/server").RegisteredMutation<"public", {
|
|
175
|
+
jobId: string;
|
|
176
|
+
ownerUserId: string;
|
|
177
|
+
}, Promise<boolean>>;
|
|
178
|
+
export declare const markRunning: import("convex/server").RegisteredMutation<"public", {
|
|
179
|
+
jobId: string;
|
|
180
|
+
ownerUserId: string;
|
|
181
|
+
runningAtMs: number;
|
|
182
|
+
}, Promise<boolean>>;
|
|
183
|
+
export declare const appendRunLog: import("convex/server").RegisteredMutation<"public", {
|
|
184
|
+
error?: string | undefined;
|
|
185
|
+
provider?: string | undefined;
|
|
186
|
+
delivered?: boolean | undefined;
|
|
187
|
+
sessionKey?: string | undefined;
|
|
188
|
+
nextRunAtMs?: number | undefined;
|
|
189
|
+
model?: string | undefined;
|
|
190
|
+
sessionId?: string | undefined;
|
|
191
|
+
runAtMs?: number | undefined;
|
|
192
|
+
summary?: ArrayBuffer | undefined;
|
|
193
|
+
durationMs?: number | undefined;
|
|
194
|
+
deliveryStatus?: string | undefined;
|
|
195
|
+
deliveryError?: string | undefined;
|
|
196
|
+
usageInput?: number | undefined;
|
|
197
|
+
usageOutput?: number | undefined;
|
|
198
|
+
usageCacheRead?: number | undefined;
|
|
199
|
+
usageCacheWrite?: number | undefined;
|
|
200
|
+
usageTotalTokens?: number | undefined;
|
|
201
|
+
usageCostUsd?: number | undefined;
|
|
202
|
+
jobId: string;
|
|
203
|
+
status: "error" | "ok" | "skipped";
|
|
204
|
+
ts: number;
|
|
205
|
+
ownerUserId: string;
|
|
206
|
+
}, Promise<void>>;
|
|
207
|
+
export declare const listRunLog: import("convex/server").RegisteredQuery<"public", {
|
|
208
|
+
limit?: number | undefined;
|
|
209
|
+
jobId: string;
|
|
210
|
+
ownerUserId: string;
|
|
211
|
+
}, Promise<{
|
|
212
|
+
_id: import("convex/values").GenericId<"cronRuns">;
|
|
213
|
+
_creationTime: number;
|
|
214
|
+
error?: string | undefined;
|
|
215
|
+
provider?: string | undefined;
|
|
216
|
+
delivered?: boolean | undefined;
|
|
217
|
+
sessionKey?: string | undefined;
|
|
218
|
+
nextRunAtMs?: number | undefined;
|
|
219
|
+
model?: string | undefined;
|
|
220
|
+
sessionId?: string | undefined;
|
|
221
|
+
runAtMs?: number | undefined;
|
|
222
|
+
summary?: ArrayBuffer | undefined;
|
|
223
|
+
durationMs?: number | undefined;
|
|
224
|
+
deliveryStatus?: string | undefined;
|
|
225
|
+
deliveryError?: string | undefined;
|
|
226
|
+
usageInput?: number | undefined;
|
|
227
|
+
usageOutput?: number | undefined;
|
|
228
|
+
usageCacheRead?: number | undefined;
|
|
229
|
+
usageCacheWrite?: number | undefined;
|
|
230
|
+
usageTotalTokens?: number | undefined;
|
|
231
|
+
usageCostUsd?: number | undefined;
|
|
232
|
+
jobId: string;
|
|
233
|
+
status: "error" | "ok" | "skipped";
|
|
234
|
+
ts: number;
|
|
235
|
+
ownerUserId: string;
|
|
236
|
+
}[]>>;
|
|
237
|
+
//# sourceMappingURL=cron.d.ts.map
|
package/convex/cron.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// convex/cron.ts — cronJobs + cronRuns + cronServiceState
|
|
2
|
+
import { v } from "convex/values";
|
|
3
|
+
import { mutation, query } from "./_generated/server.js";
|
|
4
|
+
|
|
5
|
+
const ScheduleKind = v.union(v.literal("cron"), v.literal("every"), v.literal("at"));
|
|
6
|
+
const RunStatus = v.union(v.literal("ok"), v.literal("error"), v.literal("skipped"));
|
|
7
|
+
const CreatedByKind = v.union(v.literal("owner"), v.literal("channel"), v.literal("legacy"));
|
|
8
|
+
|
|
9
|
+
export const listJobs = query({
|
|
10
|
+
args: { ownerUserId: v.string(), enabledOnly: v.optional(v.boolean()) },
|
|
11
|
+
handler: async (ctx, args) => {
|
|
12
|
+
if (args.enabledOnly) {
|
|
13
|
+
return ctx.db
|
|
14
|
+
.query("cronJobs")
|
|
15
|
+
.withIndex("by_owner_enabled_next", (q) =>
|
|
16
|
+
q.eq("ownerUserId", args.ownerUserId).eq("enabled", true),
|
|
17
|
+
)
|
|
18
|
+
.collect();
|
|
19
|
+
}
|
|
20
|
+
return ctx.db
|
|
21
|
+
.query("cronJobs")
|
|
22
|
+
.withIndex("by_owner_job", (q) => q.eq("ownerUserId", args.ownerUserId))
|
|
23
|
+
.collect();
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const getJob = query({
|
|
28
|
+
args: { ownerUserId: v.string(), jobId: v.string() },
|
|
29
|
+
handler: async (ctx, args) => {
|
|
30
|
+
return ctx.db
|
|
31
|
+
.query("cronJobs")
|
|
32
|
+
.withIndex("by_owner_job", (q) =>
|
|
33
|
+
q.eq("ownerUserId", args.ownerUserId).eq("jobId", args.jobId),
|
|
34
|
+
)
|
|
35
|
+
.first();
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const insertJob = mutation({
|
|
40
|
+
args: {
|
|
41
|
+
jobId: v.string(),
|
|
42
|
+
ownerUserId: v.string(),
|
|
43
|
+
name: v.string(),
|
|
44
|
+
description: v.optional(v.string()),
|
|
45
|
+
enabled: v.boolean(),
|
|
46
|
+
agentId: v.optional(v.string()),
|
|
47
|
+
sessionKey: v.optional(v.string()),
|
|
48
|
+
scheduleKind: ScheduleKind,
|
|
49
|
+
scheduleExpr: v.optional(v.string()),
|
|
50
|
+
scheduleTz: v.optional(v.string()),
|
|
51
|
+
scheduleStaggerMs: v.optional(v.number()),
|
|
52
|
+
scheduleEveryMs: v.optional(v.number()),
|
|
53
|
+
scheduleAnchorMs: v.optional(v.number()),
|
|
54
|
+
scheduleAt: v.optional(v.number()),
|
|
55
|
+
sessionTarget: v.string(),
|
|
56
|
+
wakeMode: v.optional(v.string()),
|
|
57
|
+
payload: v.bytes(),
|
|
58
|
+
delivery: v.optional(v.bytes()),
|
|
59
|
+
failureAlert: v.optional(v.any()),
|
|
60
|
+
deleteAfterRun: v.optional(v.boolean()),
|
|
61
|
+
createdByKind: CreatedByKind,
|
|
62
|
+
createdByChannelId: v.optional(v.string()),
|
|
63
|
+
createdByConversationId: v.optional(v.string()),
|
|
64
|
+
createdByAccountId: v.optional(v.string()),
|
|
65
|
+
// Honour client timestamps so a filesystem→convex migration preserves
|
|
66
|
+
// the original create/update times; default to now for fresh jobs.
|
|
67
|
+
createdAtMs: v.optional(v.number()),
|
|
68
|
+
updatedAtMs: v.optional(v.number()),
|
|
69
|
+
// Run-time state — carried through on migration so failure counts +
|
|
70
|
+
// last-fire bookkeeping survive the move.
|
|
71
|
+
stateNextRunAtMs: v.optional(v.number()),
|
|
72
|
+
stateLastRunAtMs: v.optional(v.number()),
|
|
73
|
+
stateRunningAtMs: v.optional(v.number()),
|
|
74
|
+
stateLastStatus: v.optional(v.string()),
|
|
75
|
+
stateLastError: v.optional(v.string()),
|
|
76
|
+
stateScheduleErrorCount: v.optional(v.number()),
|
|
77
|
+
stateConsecutiveErrorCount: v.optional(v.number()),
|
|
78
|
+
stateLastFailureAlertAtMs: v.optional(v.number()),
|
|
79
|
+
stateLastDelivered: v.optional(v.boolean()),
|
|
80
|
+
stateLastDeliveryStatus: v.optional(v.string()),
|
|
81
|
+
stateLastDeliveryError: v.optional(v.string()),
|
|
82
|
+
},
|
|
83
|
+
handler: async (ctx, args) => {
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
const { createdAtMs, updatedAtMs, ...rest } = args;
|
|
86
|
+
await ctx.db.insert("cronJobs", {
|
|
87
|
+
...rest,
|
|
88
|
+
createdAtMs: createdAtMs ?? now,
|
|
89
|
+
updatedAtMs: updatedAtMs ?? now,
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
export const patchJob = mutation({
|
|
95
|
+
args: {
|
|
96
|
+
ownerUserId: v.string(),
|
|
97
|
+
jobId: v.string(),
|
|
98
|
+
patch: v.any(),
|
|
99
|
+
// Column names to DELETE. Convex's arg serialiser strips
|
|
100
|
+
// `undefined`-valued object fields before they reach the handler, so a
|
|
101
|
+
// column can't be cleared from the client by patching it to undefined.
|
|
102
|
+
// We re-introduce the undefined HERE (server-side) where `db.patch`
|
|
103
|
+
// honours it as a field deletion.
|
|
104
|
+
unset: v.optional(v.array(v.string())),
|
|
105
|
+
},
|
|
106
|
+
handler: async (ctx, args) => {
|
|
107
|
+
const existing = await ctx.db
|
|
108
|
+
.query("cronJobs")
|
|
109
|
+
.withIndex("by_owner_job", (q) =>
|
|
110
|
+
q.eq("ownerUserId", args.ownerUserId).eq("jobId", args.jobId),
|
|
111
|
+
)
|
|
112
|
+
.first();
|
|
113
|
+
if (!existing) throw new Error(`cron: job ${args.jobId} not found`);
|
|
114
|
+
const patchObj: Record<string, unknown> = {
|
|
115
|
+
...(args.patch as Record<string, unknown>),
|
|
116
|
+
updatedAtMs: Date.now(),
|
|
117
|
+
};
|
|
118
|
+
if (args.unset) {
|
|
119
|
+
for (const col of args.unset) patchObj[col] = undefined;
|
|
120
|
+
}
|
|
121
|
+
await ctx.db.patch(existing._id, patchObj);
|
|
122
|
+
return await ctx.db.get(existing._id);
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
export const deleteJob = mutation({
|
|
127
|
+
args: { ownerUserId: v.string(), jobId: v.string() },
|
|
128
|
+
handler: async (ctx, args) => {
|
|
129
|
+
const existing = await ctx.db
|
|
130
|
+
.query("cronJobs")
|
|
131
|
+
.withIndex("by_owner_job", (q) =>
|
|
132
|
+
q.eq("ownerUserId", args.ownerUserId).eq("jobId", args.jobId),
|
|
133
|
+
)
|
|
134
|
+
.first();
|
|
135
|
+
if (!existing) return false;
|
|
136
|
+
await ctx.db.delete(existing._id);
|
|
137
|
+
return true;
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
export const markRunning = mutation({
|
|
142
|
+
args: { ownerUserId: v.string(), jobId: v.string(), runningAtMs: v.number() },
|
|
143
|
+
handler: async (ctx, args) => {
|
|
144
|
+
const job = await ctx.db
|
|
145
|
+
.query("cronJobs")
|
|
146
|
+
.withIndex("by_owner_job", (q) =>
|
|
147
|
+
q.eq("ownerUserId", args.ownerUserId).eq("jobId", args.jobId),
|
|
148
|
+
)
|
|
149
|
+
.first();
|
|
150
|
+
if (!job) return false;
|
|
151
|
+
if (job.stateRunningAtMs && job.stateRunningAtMs > 0) return false;
|
|
152
|
+
await ctx.db.patch(job._id, { stateRunningAtMs: args.runningAtMs });
|
|
153
|
+
return true;
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
export const appendRunLog = mutation({
|
|
158
|
+
args: {
|
|
159
|
+
ownerUserId: v.string(),
|
|
160
|
+
jobId: v.string(),
|
|
161
|
+
ts: v.number(),
|
|
162
|
+
status: RunStatus,
|
|
163
|
+
error: v.optional(v.string()),
|
|
164
|
+
summary: v.optional(v.bytes()),
|
|
165
|
+
delivered: v.optional(v.boolean()),
|
|
166
|
+
deliveryStatus: v.optional(v.string()),
|
|
167
|
+
deliveryError: v.optional(v.string()),
|
|
168
|
+
sessionId: v.optional(v.string()),
|
|
169
|
+
sessionKey: v.optional(v.string()),
|
|
170
|
+
runAtMs: v.optional(v.number()),
|
|
171
|
+
durationMs: v.optional(v.number()),
|
|
172
|
+
nextRunAtMs: v.optional(v.number()),
|
|
173
|
+
model: v.optional(v.string()),
|
|
174
|
+
provider: v.optional(v.string()),
|
|
175
|
+
usageInput: v.optional(v.number()),
|
|
176
|
+
usageOutput: v.optional(v.number()),
|
|
177
|
+
usageCacheRead: v.optional(v.number()),
|
|
178
|
+
usageCacheWrite: v.optional(v.number()),
|
|
179
|
+
usageTotalTokens: v.optional(v.number()),
|
|
180
|
+
usageCostUsd: v.optional(v.number()),
|
|
181
|
+
},
|
|
182
|
+
handler: async (ctx, args) => {
|
|
183
|
+
await ctx.db.insert("cronRuns", args);
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
export const listRunLog = query({
|
|
188
|
+
args: { ownerUserId: v.string(), jobId: v.string(), limit: v.optional(v.number()) },
|
|
189
|
+
handler: async (ctx, args) => {
|
|
190
|
+
const limit = args.limit && args.limit > 0 ? args.limit : 50;
|
|
191
|
+
return ctx.db
|
|
192
|
+
.query("cronRuns")
|
|
193
|
+
.withIndex("by_owner_job_ts", (q) =>
|
|
194
|
+
q.eq("ownerUserId", args.ownerUserId).eq("jobId", args.jobId),
|
|
195
|
+
)
|
|
196
|
+
.order("desc")
|
|
197
|
+
.take(limit);
|
|
198
|
+
},
|
|
199
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const list: import("convex/server").RegisteredQuery<"public", {
|
|
2
|
+
agentId: string;
|
|
3
|
+
ownerId: string;
|
|
4
|
+
}, Promise<{
|
|
5
|
+
_id: import("convex/values").GenericId<"execApprovals">;
|
|
6
|
+
_creationTime: number;
|
|
7
|
+
agentId: string;
|
|
8
|
+
value: string;
|
|
9
|
+
kind: "exact" | "pattern";
|
|
10
|
+
createdAt: number;
|
|
11
|
+
ownerId: string;
|
|
12
|
+
valueNormalised: string;
|
|
13
|
+
}[]>>;
|
|
14
|
+
export declare const insert: import("convex/server").RegisteredMutation<"public", {
|
|
15
|
+
agentId: string;
|
|
16
|
+
value: string;
|
|
17
|
+
kind: "exact" | "pattern";
|
|
18
|
+
ownerId: string;
|
|
19
|
+
valueNormalised: string;
|
|
20
|
+
}, Promise<{
|
|
21
|
+
inserted: boolean;
|
|
22
|
+
}>>;
|
|
23
|
+
export declare const remove: import("convex/server").RegisteredMutation<"public", {
|
|
24
|
+
agentId: string;
|
|
25
|
+
ownerId: string;
|
|
26
|
+
valueNormalised: string;
|
|
27
|
+
}, Promise<{
|
|
28
|
+
removedCommands: number;
|
|
29
|
+
removedPatterns: number;
|
|
30
|
+
}>>;
|
|
31
|
+
//# sourceMappingURL=execApprovals.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// convex/execApprovals.ts
|
|
2
|
+
import { v } from "convex/values";
|
|
3
|
+
import { mutation, query } from "./_generated/server.js";
|
|
4
|
+
|
|
5
|
+
const Kind = v.union(v.literal("exact"), v.literal("pattern"));
|
|
6
|
+
|
|
7
|
+
export const list = query({
|
|
8
|
+
args: { ownerId: v.string(), agentId: v.string() },
|
|
9
|
+
handler: async (ctx, args) => {
|
|
10
|
+
return ctx.db
|
|
11
|
+
.query("execApprovals")
|
|
12
|
+
.withIndex("by_owner_agent_kind", (q) =>
|
|
13
|
+
q.eq("ownerId", args.ownerId).eq("agentId", args.agentId),
|
|
14
|
+
)
|
|
15
|
+
.collect();
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const insert = mutation({
|
|
20
|
+
args: { ownerId: v.string(), agentId: v.string(), kind: Kind, value: v.string(), valueNormalised: v.string() },
|
|
21
|
+
handler: async (ctx, args) => {
|
|
22
|
+
const existing = await ctx.db
|
|
23
|
+
.query("execApprovals")
|
|
24
|
+
.withIndex("by_owner_agent_value", (q) =>
|
|
25
|
+
q
|
|
26
|
+
.eq("ownerId", args.ownerId)
|
|
27
|
+
.eq("agentId", args.agentId)
|
|
28
|
+
.eq("valueNormalised", args.valueNormalised),
|
|
29
|
+
)
|
|
30
|
+
.first();
|
|
31
|
+
if (existing) return { inserted: false };
|
|
32
|
+
await ctx.db.insert("execApprovals", { ...args, createdAt: Date.now() });
|
|
33
|
+
return { inserted: true };
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export const remove = mutation({
|
|
38
|
+
args: { ownerId: v.string(), agentId: v.string(), valueNormalised: v.string() },
|
|
39
|
+
handler: async (ctx, args) => {
|
|
40
|
+
const rows = await ctx.db
|
|
41
|
+
.query("execApprovals")
|
|
42
|
+
.withIndex("by_owner_agent_value", (q) =>
|
|
43
|
+
q
|
|
44
|
+
.eq("ownerId", args.ownerId)
|
|
45
|
+
.eq("agentId", args.agentId)
|
|
46
|
+
.eq("valueNormalised", args.valueNormalised),
|
|
47
|
+
)
|
|
48
|
+
.collect();
|
|
49
|
+
let removedCommands = 0;
|
|
50
|
+
let removedPatterns = 0;
|
|
51
|
+
for (const r of rows) {
|
|
52
|
+
if (r.kind === "exact") removedCommands += 1;
|
|
53
|
+
else removedPatterns += 1;
|
|
54
|
+
await ctx.db.delete(r._id);
|
|
55
|
+
}
|
|
56
|
+
return { removedCommands, removedPatterns };
|
|
57
|
+
},
|
|
58
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const list: import("convex/server").RegisteredQuery<"public", {}, Promise<{
|
|
2
|
+
_id: import("convex/values").GenericId<"extensions">;
|
|
3
|
+
_creationTime: number;
|
|
4
|
+
config?: ArrayBuffer | undefined;
|
|
5
|
+
bundleBytes?: ArrayBuffer | undefined;
|
|
6
|
+
manifest?: any;
|
|
7
|
+
bundleSha?: string | undefined;
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
createdBy: string;
|
|
10
|
+
createdAt: number;
|
|
11
|
+
origin: "bundled" | "user";
|
|
12
|
+
updatedAt: number;
|
|
13
|
+
moduleId: string;
|
|
14
|
+
sourceLabel: string;
|
|
15
|
+
}[]>>;
|
|
16
|
+
export declare const upsert: import("convex/server").RegisteredMutation<"public", {
|
|
17
|
+
config?: ArrayBuffer | undefined;
|
|
18
|
+
bundleBytes?: ArrayBuffer | undefined;
|
|
19
|
+
manifest?: any;
|
|
20
|
+
bundleSha?: string | undefined;
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
createdBy: string;
|
|
23
|
+
origin: "bundled" | "user";
|
|
24
|
+
moduleId: string;
|
|
25
|
+
sourceLabel: string;
|
|
26
|
+
}, Promise<void>>;
|
|
27
|
+
export declare const remove: import("convex/server").RegisteredMutation<"public", {
|
|
28
|
+
moduleId: string;
|
|
29
|
+
}, Promise<boolean>>;
|
|
30
|
+
//# sourceMappingURL=extensions.d.ts.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// convex/extensions.ts
|
|
2
|
+
import { v } from "convex/values";
|
|
3
|
+
import { mutation, query } from "./_generated/server.js";
|
|
4
|
+
|
|
5
|
+
const Origin = v.union(v.literal("bundled"), v.literal("user"));
|
|
6
|
+
|
|
7
|
+
export const list = query({
|
|
8
|
+
args: {},
|
|
9
|
+
handler: async (ctx) => {
|
|
10
|
+
return ctx.db.query("extensions").collect();
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const upsert = mutation({
|
|
15
|
+
args: {
|
|
16
|
+
moduleId: v.string(),
|
|
17
|
+
origin: Origin,
|
|
18
|
+
bundleBytes: v.optional(v.bytes()),
|
|
19
|
+
sourceLabel: v.string(),
|
|
20
|
+
manifest: v.optional(v.any()),
|
|
21
|
+
enabled: v.boolean(),
|
|
22
|
+
config: v.optional(v.bytes()),
|
|
23
|
+
bundleSha: v.optional(v.string()),
|
|
24
|
+
createdBy: v.string(),
|
|
25
|
+
},
|
|
26
|
+
handler: async (ctx, args) => {
|
|
27
|
+
const existing = await ctx.db
|
|
28
|
+
.query("extensions")
|
|
29
|
+
.withIndex("by_moduleId", (q) => q.eq("moduleId", args.moduleId))
|
|
30
|
+
.first();
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
if (existing) {
|
|
33
|
+
await ctx.db.replace(existing._id, { ...args, createdAt: existing.createdAt, updatedAt: now });
|
|
34
|
+
} else {
|
|
35
|
+
await ctx.db.insert("extensions", { ...args, createdAt: now, updatedAt: now });
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const remove = mutation({
|
|
41
|
+
args: { moduleId: v.string() },
|
|
42
|
+
handler: async (ctx, args) => {
|
|
43
|
+
const existing = await ctx.db
|
|
44
|
+
.query("extensions")
|
|
45
|
+
.withIndex("by_moduleId", (q) => q.eq("moduleId", args.moduleId))
|
|
46
|
+
.first();
|
|
47
|
+
if (!existing) return false;
|
|
48
|
+
await ctx.db.delete(existing._id);
|
|
49
|
+
return true;
|
|
50
|
+
},
|
|
51
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const ping: import("convex/server").RegisteredQuery<"public", {}, Promise<{
|
|
2
|
+
ok: boolean;
|
|
3
|
+
schemaVersion: number;
|
|
4
|
+
hasConfig: boolean;
|
|
5
|
+
now: number;
|
|
6
|
+
}>>;
|
|
7
|
+
export declare const BUNDLE_VERSION = 7;
|
|
8
|
+
export declare const bundleVersion: import("convex/server").RegisteredQuery<"public", {}, Promise<number>>;
|
|
9
|
+
export declare const getMeta: import("convex/server").RegisteredQuery<"public", {
|
|
10
|
+
key: string;
|
|
11
|
+
}, Promise<string | null>>;
|
|
12
|
+
export declare const setMeta: import("convex/server").RegisteredMutation<"public", {
|
|
13
|
+
key: string;
|
|
14
|
+
value: string;
|
|
15
|
+
}, Promise<{
|
|
16
|
+
updated: boolean;
|
|
17
|
+
}>>;
|
|
18
|
+
//# sourceMappingURL=health.d.ts.map
|
package/convex/health.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// convex/health.ts
|
|
2
|
+
//
|
|
3
|
+
// Convex-side liveness probe. ConvexBrigadeStore.healthcheck() calls this
|
|
4
|
+
// from filesystem-mode boot to confirm the backend is reachable + the
|
|
5
|
+
// schema is deployed. Returns the schema version + the number of seeded
|
|
6
|
+
// brigadeConfig rows so a freshly-deployed-but-empty backend reports
|
|
7
|
+
// distinctly from a populated one.
|
|
8
|
+
|
|
9
|
+
import { v } from "convex/values";
|
|
10
|
+
import { mutation, query } from "./_generated/server.js";
|
|
11
|
+
|
|
12
|
+
export const ping = query({
|
|
13
|
+
args: {},
|
|
14
|
+
handler: async (ctx) => {
|
|
15
|
+
const configRows = await ctx.db.query("brigadeConfig").take(1);
|
|
16
|
+
return {
|
|
17
|
+
ok: true,
|
|
18
|
+
schemaVersion: 2,
|
|
19
|
+
hasConfig: configRows.length > 0,
|
|
20
|
+
now: Date.now(),
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Brigade function-bundle version. The Node client (verifyConvexBundleVersion
|
|
26
|
+
// in src/storage/boot.ts) requires remote >= its expected constant at every
|
|
27
|
+
// convex boot, so a backend serving an older push fails the boot with ONE
|
|
28
|
+
// clear "run npm run convex:push" error instead of per-domain "Could not
|
|
29
|
+
// find public function" spam (auth/memory/channels hydration failures +
|
|
30
|
+
// per-turn transcript-flush errors). BUMP THIS — and the twin
|
|
31
|
+
// EXPECTED_CONVEX_BUNDLE_VERSION in src/storage/boot.ts — together whenever
|
|
32
|
+
// convex/ functions or the schema change shape.
|
|
33
|
+
export const BUNDLE_VERSION = 7;
|
|
34
|
+
|
|
35
|
+
export const bundleVersion = query({
|
|
36
|
+
args: {},
|
|
37
|
+
handler: async () => BUNDLE_VERSION,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// systemMeta — small singleton facts (encryption-key fingerprint, markers)
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
export const getMeta = query({
|
|
45
|
+
args: { key: v.string() },
|
|
46
|
+
handler: async (ctx, args) => {
|
|
47
|
+
const row = await ctx.db
|
|
48
|
+
.query("systemMeta")
|
|
49
|
+
.withIndex("by_key", (q) => q.eq("key", args.key))
|
|
50
|
+
.first();
|
|
51
|
+
return row?.value ?? null;
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export const setMeta = mutation({
|
|
56
|
+
args: { key: v.string(), value: v.string() },
|
|
57
|
+
handler: async (ctx, args) => {
|
|
58
|
+
const existing = await ctx.db
|
|
59
|
+
.query("systemMeta")
|
|
60
|
+
.withIndex("by_key", (q) => q.eq("key", args.key))
|
|
61
|
+
.first();
|
|
62
|
+
if (existing) {
|
|
63
|
+
await ctx.db.replace(existing._id, { ...args, updatedAt: Date.now() });
|
|
64
|
+
return { updated: true };
|
|
65
|
+
}
|
|
66
|
+
await ctx.db.insert("systemMeta", { ...args, updatedAt: Date.now() });
|
|
67
|
+
return { updated: false };
|
|
68
|
+
},
|
|
69
|
+
});
|