@michael-joseph-miller/ant-bot 0.1.0 → 0.1.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/CHANGELOG.md +42 -5
- package/README.md +69 -24
- package/dist/{browser-OHRD7YI3.js → browser-4ZHHBD6J.js} +132 -4
- package/dist/browser-4ZHHBD6J.js.map +7 -0
- package/dist/{bundled-46DUK5PG.js → bundled-26SJR7EB.js} +5 -5
- package/dist/{bundled-46DUK5PG.js.map → bundled-26SJR7EB.js.map} +1 -1
- package/dist/{chunk-DYIJTUMY.js → chunk-AON76FHD.js} +113 -83
- package/dist/chunk-AON76FHD.js.map +7 -0
- package/dist/{chunk-AHAON6J7.js → chunk-CNCHYZVD.js} +2 -2
- package/dist/{chunk-AHAON6J7.js.map → chunk-CNCHYZVD.js.map} +1 -1
- package/dist/{chunk-Z2YT2PZN.js → chunk-GYWJUW4E.js} +6 -6
- package/dist/{chunk-Z2YT2PZN.js.map → chunk-GYWJUW4E.js.map} +3 -3
- package/dist/{chunk-7BOHBPB2.js → chunk-JCZBDGBA.js} +3 -3
- package/dist/{chunk-7BOHBPB2.js.map → chunk-JCZBDGBA.js.map} +1 -1
- package/dist/{chunk-KSQOVWP5.js → chunk-MSSHR6SW.js} +6 -6
- package/dist/chunk-MSSHR6SW.js.map +7 -0
- package/dist/index.js +28 -28
- package/dist/index.js.map +2 -2
- package/dist/{install-IY2M3OUQ.js → install-KTEW2CW3.js} +3 -3
- package/dist/{plugin-POMHVGD4.js → plugin-WYUCG6F7.js} +2 -2
- package/dist/{plugin-POMHVGD4.js.map → plugin-WYUCG6F7.js.map} +1 -1
- package/dist/{scheduler-Q7OHNGP6.js → scheduler-VZVHQWGD.js} +3 -3
- package/dist/scheduler-VZVHQWGD.js.map +7 -0
- package/dist/server.js +58 -41
- package/dist/server.js.map +3 -3
- package/dist/{skills-66WRX64H.js → skills-JUHWFBD6.js} +2 -2
- package/dist/skills-spec.js +2 -2
- package/dist/skills-spec.js.map +1 -1
- package/dist/{tools-P5537ASX.js → tools-YNE7ZRPR.js} +2 -2
- package/dist/{tools-P5537ASX.js.map → tools-YNE7ZRPR.js.map} +1 -1
- package/package.json +1 -1
- package/skills/README.md +1 -1
- package/web/dist/assets/index-BBZbK10k.js +130 -0
- package/web/dist/assets/index-BKrFsCQD.css +2 -0
- package/web/dist/index.html +2 -2
- package/dist/browser-OHRD7YI3.js.map +0 -7
- package/dist/chunk-DYIJTUMY.js.map +0 -7
- package/dist/chunk-KSQOVWP5.js.map +0 -7
- package/dist/scheduler-Q7OHNGP6.js.map +0 -7
- package/web/dist/assets/index-BLQ8rPiN.js +0 -130
- package/web/dist/assets/index-IEIkG_jd.css +0 -2
- /package/dist/{install-IY2M3OUQ.js.map → install-KTEW2CW3.js.map} +0 -0
- /package/dist/{skills-66WRX64H.js.map → skills-JUHWFBD6.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __antbotCreateRequire } from 'node:module';
|
|
2
2
|
const require = __antbotCreateRequire(import.meta.url);
|
|
3
3
|
|
|
4
|
-
//
|
|
4
|
+
// contract/dist/limits.js
|
|
5
5
|
var LIMITS = {
|
|
6
6
|
MAX_BOTS_AND_GROUPS: 50,
|
|
7
7
|
MIN_GROUP_MEMBERS: 2,
|
|
@@ -33,10 +33,10 @@ var LimitError = class extends Error {
|
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
//
|
|
36
|
+
// contract/dist/events.js
|
|
37
37
|
import { z as z2 } from "zod";
|
|
38
38
|
|
|
39
|
-
//
|
|
39
|
+
// contract/dist/entities.js
|
|
40
40
|
import { z } from "zod";
|
|
41
41
|
var BotStateSchema = z.enum([
|
|
42
42
|
"idle",
|
|
@@ -47,7 +47,8 @@ var BotStateSchema = z.enum([
|
|
|
47
47
|
"interrupted"
|
|
48
48
|
]);
|
|
49
49
|
var AttentionSchema = z.enum(["none", "unread", "needs_attention"]);
|
|
50
|
-
var
|
|
50
|
+
var MODEL_TIERS = ["fable", "opus", "sonnet", "haiku"];
|
|
51
|
+
var ModelTierSchema = z.enum(MODEL_TIERS);
|
|
51
52
|
var BotSchema = z.object({
|
|
52
53
|
id: z.string(),
|
|
53
54
|
slug: z.string().regex(/^[a-z0-9][a-z0-9-]*$/),
|
|
@@ -200,68 +201,116 @@ var UsageRowSchema = z.object({
|
|
|
200
201
|
});
|
|
201
202
|
var TurnOriginSchema = z.enum(["user", "bot", "routine", "system"]);
|
|
202
203
|
|
|
203
|
-
//
|
|
204
|
-
var
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
// contract/dist/events.js
|
|
205
|
+
var base = { seq: z2.number(), threadId: z2.string().nullable(), botId: z2.string().nullable() };
|
|
206
|
+
var ServerEventSchema = z2.discriminatedUnion("type", [
|
|
207
|
+
/** Connection handshake. Carries the current seq so a client can detect gaps. */
|
|
208
|
+
z2.object({ ...base, type: z2.literal("hello") }),
|
|
209
|
+
z2.object({ ...base, type: z2.literal("message.created"), message: MessageSchema }),
|
|
210
|
+
z2.object({ ...base, type: z2.literal("message.delta"), messageId: z2.string(), delta: z2.string() }),
|
|
211
|
+
z2.object({ ...base, type: z2.literal("message.done"), messageId: z2.string(), contentMd: z2.string() }),
|
|
212
|
+
z2.object({ ...base, type: z2.literal("message.card"), messageId: z2.string(), card: CardSchema, cardIndex: z2.number() }),
|
|
213
|
+
z2.object({ ...base, type: z2.literal("bot.state"), state: BotStateSchema, attention: AttentionSchema }),
|
|
214
|
+
z2.object({ ...base, type: z2.literal("approval.pending"), approval: ApprovalSchema }),
|
|
215
|
+
z2.object({ ...base, type: z2.literal("approval.resolved"), approval: ApprovalSchema }),
|
|
216
|
+
z2.object({ ...base, type: z2.literal("routine.run"), run: RoutineRunSchema }),
|
|
217
|
+
z2.object({ ...base, type: z2.literal("usage.tick"), inputTokens: z2.number(), outputTokens: z2.number(), model: z2.string() }),
|
|
218
|
+
z2.object({ ...base, type: z2.literal("notify"), title: z2.string(), body: z2.string(), level: z2.enum(["info", "warn", "error"]) }),
|
|
219
|
+
z2.object({ ...base, type: z2.literal("secret.request"), requestId: z2.string(), name: z2.string(), reason: z2.string() }),
|
|
220
|
+
z2.object({ ...base, type: z2.literal("thread.updated"), threadId2: z2.string() })
|
|
221
|
+
]);
|
|
222
|
+
var ScreencastInputSchema = z2.discriminatedUnion("kind", [
|
|
223
|
+
z2.object({
|
|
224
|
+
kind: z2.literal("mouse"),
|
|
225
|
+
action: z2.enum(["move", "down", "up", "wheel"]),
|
|
226
|
+
x: z2.number().min(0).max(1),
|
|
227
|
+
y: z2.number().min(0).max(1),
|
|
228
|
+
button: z2.enum(["left", "middle", "right"]).default("left"),
|
|
229
|
+
clickCount: z2.number().int().min(0).max(3).default(1),
|
|
230
|
+
/** Wheel deltas, in CSS pixels. Only read for `action: 'wheel'`. */
|
|
231
|
+
deltaX: z2.number().default(0),
|
|
232
|
+
deltaY: z2.number().default(0)
|
|
233
|
+
}),
|
|
234
|
+
z2.object({
|
|
235
|
+
kind: z2.literal("key"),
|
|
236
|
+
action: z2.enum(["down", "up"]),
|
|
237
|
+
/** A KeyboardEvent.key value — Playwright's keyboard maps these to the right key codes. */
|
|
238
|
+
key: z2.string().min(1).max(32)
|
|
239
|
+
}),
|
|
240
|
+
z2.object({
|
|
241
|
+
kind: z2.literal("text"),
|
|
242
|
+
/** Committed text (IME, paste, or a printable keypress), inserted verbatim. */
|
|
243
|
+
text: z2.string().min(1).max(4096)
|
|
244
|
+
})
|
|
245
|
+
]);
|
|
246
|
+
var ScreencastClientFrameSchema = z2.object({
|
|
247
|
+
type: z2.literal("input"),
|
|
248
|
+
input: ScreencastInputSchema
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// contract/dist/api.js
|
|
252
|
+
import { z as z3 } from "zod";
|
|
253
|
+
var CreateBotRequest = z3.object({
|
|
254
|
+
name: z3.string().min(1).max(60),
|
|
255
|
+
title: z3.string().max(120).optional(),
|
|
256
|
+
description: z3.string().max(8e3).optional(),
|
|
257
|
+
avatarEmoji: z3.string().max(8).optional(),
|
|
209
258
|
modelTier: ModelTierSchema.optional()
|
|
210
259
|
});
|
|
211
260
|
var UpdateBotRequest = CreateBotRequest.partial().extend({
|
|
212
|
-
pinned:
|
|
213
|
-
hidden:
|
|
214
|
-
notifications:
|
|
261
|
+
pinned: z3.boolean().optional(),
|
|
262
|
+
hidden: z3.boolean().optional(),
|
|
263
|
+
notifications: z3.boolean().optional()
|
|
215
264
|
});
|
|
216
|
-
var CreateThreadRequest =
|
|
217
|
-
kind:
|
|
218
|
-
title:
|
|
219
|
-
memberBotIds:
|
|
265
|
+
var CreateThreadRequest = z3.object({
|
|
266
|
+
kind: z3.enum(["dm", "group"]),
|
|
267
|
+
title: z3.string().optional(),
|
|
268
|
+
memberBotIds: z3.array(z3.string())
|
|
220
269
|
});
|
|
221
|
-
var PostMessageRequest =
|
|
222
|
-
contentMd:
|
|
223
|
-
attachmentIds:
|
|
224
|
-
replyToId:
|
|
270
|
+
var PostMessageRequest = z3.object({
|
|
271
|
+
contentMd: z3.string(),
|
|
272
|
+
attachmentIds: z3.array(z3.string()).optional(),
|
|
273
|
+
replyToId: z3.string().nullable().optional(),
|
|
225
274
|
/** explicit @-mention targets resolved by the client */
|
|
226
|
-
mentionBotIds:
|
|
227
|
-
mentionEveryone:
|
|
275
|
+
mentionBotIds: z3.array(z3.string()).optional(),
|
|
276
|
+
mentionEveryone: z3.boolean().optional()
|
|
228
277
|
});
|
|
229
|
-
var ApprovalDecisionRequest =
|
|
230
|
-
decision:
|
|
231
|
-
alwaysRule:
|
|
278
|
+
var ApprovalDecisionRequest = z3.object({
|
|
279
|
+
decision: z3.enum(["allow", "deny"]),
|
|
280
|
+
alwaysRule: z3.object({ toolPattern: z3.string(), inputPattern: z3.string().default(""), scopeNote: z3.string().default("") }).optional()
|
|
232
281
|
});
|
|
233
|
-
var CreateRuleRequest =
|
|
234
|
-
kind:
|
|
235
|
-
toolPattern:
|
|
236
|
-
inputPattern:
|
|
237
|
-
scopeNote:
|
|
282
|
+
var CreateRuleRequest = z3.object({
|
|
283
|
+
kind: z3.enum(["require", "allow"]),
|
|
284
|
+
toolPattern: z3.string().min(1),
|
|
285
|
+
inputPattern: z3.string().default(""),
|
|
286
|
+
scopeNote: z3.string().default("")
|
|
238
287
|
});
|
|
239
|
-
var CreateRoutineRequest =
|
|
240
|
-
botId:
|
|
241
|
-
name:
|
|
242
|
-
cronExpr:
|
|
243
|
-
timezone:
|
|
244
|
-
instructionMd:
|
|
245
|
-
enabled:
|
|
288
|
+
var CreateRoutineRequest = z3.object({
|
|
289
|
+
botId: z3.string(),
|
|
290
|
+
name: z3.string().min(1),
|
|
291
|
+
cronExpr: z3.string().min(1),
|
|
292
|
+
timezone: z3.string().optional(),
|
|
293
|
+
instructionMd: z3.string().min(1),
|
|
294
|
+
enabled: z3.boolean().optional()
|
|
246
295
|
});
|
|
247
|
-
var CreateSkillRequest =
|
|
248
|
-
name:
|
|
249
|
-
description:
|
|
250
|
-
bodyMd:
|
|
251
|
-
source:
|
|
296
|
+
var CreateSkillRequest = z3.object({
|
|
297
|
+
name: z3.string().min(1),
|
|
298
|
+
description: z3.string().default(""),
|
|
299
|
+
bodyMd: z3.string().min(1),
|
|
300
|
+
source: z3.enum(["user", "taught", "imported"]).optional()
|
|
252
301
|
});
|
|
253
302
|
var settingsFields = {
|
|
254
|
-
timezone:
|
|
255
|
-
maxConcurrentSessions:
|
|
256
|
-
autoReviewEnabled:
|
|
257
|
-
theme:
|
|
258
|
-
localExecution:
|
|
259
|
-
dailyTokenBudget:
|
|
260
|
-
notificationsEnabled:
|
|
261
|
-
billingMode:
|
|
262
|
-
computerMode:
|
|
303
|
+
timezone: z3.string(),
|
|
304
|
+
maxConcurrentSessions: z3.number().min(1).max(8),
|
|
305
|
+
autoReviewEnabled: z3.boolean(),
|
|
306
|
+
theme: z3.enum(["system", "light", "dark"]),
|
|
307
|
+
localExecution: z3.enum(["ask", "always", "never"]),
|
|
308
|
+
dailyTokenBudget: z3.number(),
|
|
309
|
+
notificationsEnabled: z3.boolean(),
|
|
310
|
+
billingMode: z3.enum(["subscription", "api"]),
|
|
311
|
+
computerMode: z3.enum(["host", "container"])
|
|
263
312
|
};
|
|
264
|
-
var SettingsSchema =
|
|
313
|
+
var SettingsSchema = z3.object({
|
|
265
314
|
timezone: settingsFields.timezone.default("UTC"),
|
|
266
315
|
maxConcurrentSessions: settingsFields.maxConcurrentSessions.default(2),
|
|
267
316
|
autoReviewEnabled: settingsFields.autoReviewEnabled.default(true),
|
|
@@ -272,41 +321,22 @@ var SettingsSchema = z2.object({
|
|
|
272
321
|
billingMode: settingsFields.billingMode.default("subscription"),
|
|
273
322
|
computerMode: settingsFields.computerMode.default("host")
|
|
274
323
|
});
|
|
275
|
-
var SettingsPatchSchema =
|
|
276
|
-
var SearchResultSchema =
|
|
277
|
-
kind:
|
|
278
|
-
id:
|
|
279
|
-
threadId:
|
|
280
|
-
botId:
|
|
281
|
-
title:
|
|
282
|
-
snippet:
|
|
283
|
-
createdAt:
|
|
324
|
+
var SettingsPatchSchema = z3.object(settingsFields).partial();
|
|
325
|
+
var SearchResultSchema = z3.object({
|
|
326
|
+
kind: z3.enum(["message", "file", "routine", "bot"]),
|
|
327
|
+
id: z3.string(),
|
|
328
|
+
threadId: z3.string().nullable(),
|
|
329
|
+
botId: z3.string().nullable(),
|
|
330
|
+
title: z3.string(),
|
|
331
|
+
snippet: z3.string(),
|
|
332
|
+
createdAt: z3.number()
|
|
284
333
|
});
|
|
285
334
|
|
|
286
|
-
// packages/shared/dist/events.js
|
|
287
|
-
import { z as z3 } from "zod";
|
|
288
|
-
var base = { seq: z3.number(), threadId: z3.string().nullable(), botId: z3.string().nullable() };
|
|
289
|
-
var ServerEventSchema = z3.discriminatedUnion("type", [
|
|
290
|
-
/** Connection handshake. Carries the current seq so a client can detect gaps. */
|
|
291
|
-
z3.object({ ...base, type: z3.literal("hello") }),
|
|
292
|
-
z3.object({ ...base, type: z3.literal("message.created"), message: MessageSchema }),
|
|
293
|
-
z3.object({ ...base, type: z3.literal("message.delta"), messageId: z3.string(), delta: z3.string() }),
|
|
294
|
-
z3.object({ ...base, type: z3.literal("message.done"), messageId: z3.string(), contentMd: z3.string() }),
|
|
295
|
-
z3.object({ ...base, type: z3.literal("message.card"), messageId: z3.string(), card: CardSchema, cardIndex: z3.number() }),
|
|
296
|
-
z3.object({ ...base, type: z3.literal("bot.state"), state: BotStateSchema, attention: AttentionSchema }),
|
|
297
|
-
z3.object({ ...base, type: z3.literal("approval.pending"), approval: ApprovalSchema }),
|
|
298
|
-
z3.object({ ...base, type: z3.literal("approval.resolved"), approval: ApprovalSchema }),
|
|
299
|
-
z3.object({ ...base, type: z3.literal("routine.run"), run: RoutineRunSchema }),
|
|
300
|
-
z3.object({ ...base, type: z3.literal("usage.tick"), inputTokens: z3.number(), outputTokens: z3.number(), model: z3.string() }),
|
|
301
|
-
z3.object({ ...base, type: z3.literal("notify"), title: z3.string(), body: z3.string(), level: z3.enum(["info", "warn", "error"]) }),
|
|
302
|
-
z3.object({ ...base, type: z3.literal("secret.request"), requestId: z3.string(), name: z3.string(), reason: z3.string() }),
|
|
303
|
-
z3.object({ ...base, type: z3.literal("thread.updated"), threadId2: z3.string() })
|
|
304
|
-
]);
|
|
305
|
-
|
|
306
335
|
export {
|
|
307
336
|
LIMITS,
|
|
308
337
|
LIMIT_ERROR,
|
|
309
338
|
LimitError,
|
|
339
|
+
ScreencastClientFrameSchema,
|
|
310
340
|
CreateBotRequest,
|
|
311
341
|
UpdateBotRequest,
|
|
312
342
|
CreateThreadRequest,
|
|
@@ -318,4 +348,4 @@ export {
|
|
|
318
348
|
SettingsSchema,
|
|
319
349
|
SettingsPatchSchema
|
|
320
350
|
};
|
|
321
|
-
//# sourceMappingURL=chunk-
|
|
351
|
+
//# sourceMappingURL=chunk-AON76FHD.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../contract/src/limits.ts", "../../contract/src/events.ts", "../../contract/src/entities.ts", "../../contract/src/api.ts"],
|
|
4
|
+
"sourcesContent": ["/** Operational limits \u2014 mirrors grok-bot-system-outline.md \u00A713. */\nexport const LIMITS = {\n MAX_BOTS_AND_GROUPS: 50,\n MIN_GROUP_MEMBERS: 2,\n MAX_GROUP_MEMBERS: 6,\n MAX_ROUTINES_PER_BOT: 50,\n ROUTINE_RUNS_RETAINED: 20,\n MAX_ATTACHMENTS_PER_MESSAGE: 6,\n MAX_ATTACHMENT_BYTES: 25 * 1024 * 1024,\n MAX_VIDEO_ATTACHMENT_BYTES: 200 * 1024 * 1024,\n MAX_BOT_TO_BOT_HOPS: 5,\n DEFAULT_MAX_CONCURRENT_SESSIONS: 2,\n APPROVAL_TIMEOUT_MS: 15 * 60 * 1000,\n TEACH_RECORDING_MAX_MS: 10 * 60 * 1000,\n} as const;\n\n/** Error codes returned by the service layer when a limit is violated. */\nexport const LIMIT_ERROR = {\n TOO_MANY_BOTS: 'TOO_MANY_BOTS',\n GROUP_SIZE: 'GROUP_SIZE',\n TOO_MANY_ROUTINES: 'TOO_MANY_ROUTINES',\n TOO_MANY_ATTACHMENTS: 'TOO_MANY_ATTACHMENTS',\n ATTACHMENT_TOO_LARGE: 'ATTACHMENT_TOO_LARGE',\n HOP_LIMIT: 'HOP_LIMIT',\n} as const;\nexport type LimitErrorCode = (typeof LIMIT_ERROR)[keyof typeof LIMIT_ERROR];\n\nexport class LimitError extends Error {\n constructor(\n public code: LimitErrorCode,\n message: string,\n ) {\n super(message);\n this.name = 'LimitError';\n }\n}\n", "import { z } from 'zod';\nimport { BotStateSchema, AttentionSchema, CardSchema, MessageSchema, ApprovalSchema, RoutineRunSchema } from './entities.js';\n\n/** Every server\u2192client event carries {threadId, botId, seq} for ordering/reconciliation. */\nconst base = { seq: z.number(), threadId: z.string().nullable(), botId: z.string().nullable() };\n\nexport const ServerEventSchema = z.discriminatedUnion('type', [\n /** Connection handshake. Carries the current seq so a client can detect gaps. */\n z.object({ ...base, type: z.literal('hello') }),\n z.object({ ...base, type: z.literal('message.created'), message: MessageSchema }),\n z.object({ ...base, type: z.literal('message.delta'), messageId: z.string(), delta: z.string() }),\n z.object({ ...base, type: z.literal('message.done'), messageId: z.string(), contentMd: z.string() }),\n z.object({ ...base, type: z.literal('message.card'), messageId: z.string(), card: CardSchema, cardIndex: z.number() }),\n z.object({ ...base, type: z.literal('bot.state'), state: BotStateSchema, attention: AttentionSchema }),\n z.object({ ...base, type: z.literal('approval.pending'), approval: ApprovalSchema }),\n z.object({ ...base, type: z.literal('approval.resolved'), approval: ApprovalSchema }),\n z.object({ ...base, type: z.literal('routine.run'), run: RoutineRunSchema }),\n z.object({ ...base, type: z.literal('usage.tick'), inputTokens: z.number(), outputTokens: z.number(), model: z.string() }),\n z.object({ ...base, type: z.literal('notify'), title: z.string(), body: z.string(), level: z.enum(['info', 'warn', 'error']) }),\n z.object({ ...base, type: z.literal('secret.request'), requestId: z.string(), name: z.string(), reason: z.string() }),\n z.object({ ...base, type: z.literal('thread.updated'), threadId2: z.string() }),\n]);\nexport type ServerEvent = z.infer<typeof ServerEventSchema>;\nexport type ServerEventType = ServerEvent['type'];\n\n/* ------------------------- screencast input (client \u2192 server) ------------------------- */\n\n/**\n * Human input forwarded over the screencast websocket while a screen is taken over.\n *\n * Coordinates are **normalised** (0\u20131, fractions of the rendered frame) rather than pixels: the\n * screencast is capped at 1280px wide and the browser then scales the image to fit the pane, so\n * the client cannot know the page's real viewport and the server cannot know the client's. Each\n * side converts against what it does know.\n *\n * The daemon dispatches these only while `takeOver()` is active for that bot \u2014 see\n * `docs/SECURITY.md`. Input is a human acting as themselves, so it does not pass the Permission\n * Gateway; the gateway governs what *bots* do.\n */\nexport const ScreencastInputSchema = z.discriminatedUnion('kind', [\n z.object({\n kind: z.literal('mouse'),\n action: z.enum(['move', 'down', 'up', 'wheel']),\n x: z.number().min(0).max(1),\n y: z.number().min(0).max(1),\n button: z.enum(['left', 'middle', 'right']).default('left'),\n clickCount: z.number().int().min(0).max(3).default(1),\n /** Wheel deltas, in CSS pixels. Only read for `action: 'wheel'`. */\n deltaX: z.number().default(0),\n deltaY: z.number().default(0),\n }),\n z.object({\n kind: z.literal('key'),\n action: z.enum(['down', 'up']),\n /** A KeyboardEvent.key value \u2014 Playwright's keyboard maps these to the right key codes. */\n key: z.string().min(1).max(32),\n }),\n z.object({\n kind: z.literal('text'),\n /** Committed text (IME, paste, or a printable keypress), inserted verbatim. */\n text: z.string().min(1).max(4096),\n }),\n]);\nexport type ScreencastInput = z.infer<typeof ScreencastInputSchema>;\n\n/** Frames the client may send on the screencast socket. */\nexport const ScreencastClientFrameSchema = z.object({\n type: z.literal('input'),\n input: ScreencastInputSchema,\n});\nexport type ScreencastClientFrame = z.infer<typeof ScreencastClientFrameSchema>;\n", "import { z } from 'zod';\n\nexport const BotStateSchema = z.enum([\n 'idle',\n 'queued',\n 'running',\n 'waiting_approval',\n 'waiting_input',\n 'interrupted',\n]);\nexport type BotState = z.infer<typeof BotStateSchema>;\n\nexport const AttentionSchema = z.enum(['none', 'unread', 'needs_attention']);\nexport type Attention = z.infer<typeof AttentionSchema>;\n\n/**\n * Model tiers a Bot can run on, ordered most to least capable \u2014 this is also the order the UI\n * renders them in, so both pickers stay consistent without repeating the list.\n *\n * Each value is a `claude` CLI model alias, passed through verbatim by `resolveModel()`. Adding a\n * tier here means adding an alias the CLI accepts (`claude --model`), not an API model ID.\n */\nexport const MODEL_TIERS = ['fable', 'opus', 'sonnet', 'haiku'] as const;\nexport const ModelTierSchema = z.enum(MODEL_TIERS);\nexport type ModelTier = z.infer<typeof ModelTierSchema>;\n\nexport const BotSchema = z.object({\n id: z.string(),\n slug: z.string().regex(/^[a-z0-9][a-z0-9-]*$/),\n name: z.string().min(1).max(60),\n title: z.string().max(120).default(''),\n description: z.string().max(8000).default(''),\n avatarEmoji: z.string().max(8).default('\uD83E\uDD16'),\n modelTier: ModelTierSchema.default('sonnet'),\n pinned: z.boolean().default(false),\n hidden: z.boolean().default(false),\n notifications: z.boolean().default(true),\n sessionId: z.string().nullable().default(null),\n state: BotStateSchema.default('idle'),\n attention: AttentionSchema.default('none'),\n threadId: z.string().nullable().default(null),\n createdAt: z.number(),\n deletedAt: z.number().nullable().default(null),\n});\nexport type Bot = z.infer<typeof BotSchema>;\n\nexport const ThreadKindSchema = z.enum(['dm', 'group']);\nexport type ThreadKind = z.infer<typeof ThreadKindSchema>;\n\nexport const ThreadSchema = z.object({\n id: z.string(),\n kind: ThreadKindSchema,\n title: z.string().default(''),\n memberBotIds: z.array(z.string()).default([]),\n pinned: z.boolean().default(false),\n hidden: z.boolean().default(false),\n lastReadAt: z.number().default(0),\n createdAt: z.number(),\n});\nexport type Thread = z.infer<typeof ThreadSchema>;\n\n/** Cards render structured, non-prose content inside a message. */\nexport const CardSchema = z.discriminatedUnion('type', [\n z.object({\n type: z.literal('tool'),\n toolName: z.string(),\n summary: z.string(),\n input: z.unknown().optional(),\n result: z.string().optional(),\n status: z.enum(['running', 'ok', 'error', 'denied']),\n }),\n z.object({\n type: z.literal('file'),\n path: z.string(),\n name: z.string(),\n mime: z.string(),\n bytes: z.number(),\n action: z.enum(['created', 'modified']).default('created'),\n }),\n z.object({ type: z.literal('approval'), approvalId: z.string() }),\n z.object({ type: z.literal('handoff'), fromBotId: z.string(), toBotId: z.string(), note: z.string() }),\n z.object({ type: z.literal('error'), message: z.string() }),\n]);\nexport type Card = z.infer<typeof CardSchema>;\n\nexport const AuthorKindSchema = z.enum(['user', 'bot', 'system']);\nexport type AuthorKind = z.infer<typeof AuthorKindSchema>;\n\nexport const MessageSchema = z.object({\n id: z.string(),\n threadId: z.string(),\n authorKind: AuthorKindSchema,\n authorBotId: z.string().nullable().default(null),\n replyToId: z.string().nullable().default(null),\n contentMd: z.string().default(''),\n cards: z.array(CardSchema).default([]),\n streaming: z.boolean().default(false),\n createdAt: z.number(),\n});\nexport type Message = z.infer<typeof MessageSchema>;\n\nexport const AttachmentSchema = z.object({\n id: z.string(),\n messageId: z.string().nullable(),\n path: z.string(),\n name: z.string(),\n mime: z.string(),\n bytes: z.number(),\n createdAt: z.number(),\n});\nexport type Attachment = z.infer<typeof AttachmentSchema>;\n\nexport const ApprovalStatusSchema = z.enum(['pending', 'allowed', 'denied', 'expired']);\nexport type ApprovalStatus = z.infer<typeof ApprovalStatusSchema>;\n\nexport const ApprovalSchema = z.object({\n id: z.string(),\n botId: z.string(),\n threadId: z.string(),\n toolName: z.string(),\n inputSummary: z.string(),\n rawInput: z.unknown(),\n status: ApprovalStatusSchema.default('pending'),\n decidedBy: z.enum(['user', 'rule', 'auto_review']).nullable().default(null),\n reason: z.string().default(''),\n ruleId: z.string().nullable().default(null),\n createdAt: z.number(),\n decidedAt: z.number().nullable().default(null),\n});\nexport type Approval = z.infer<typeof ApprovalSchema>;\n\nexport const RuleKindSchema = z.enum(['require', 'allow']);\nexport type RuleKind = z.infer<typeof RuleKindSchema>;\n\nexport const RuleSchema = z.object({\n id: z.string(),\n kind: RuleKindSchema,\n /** Glob over tool name, e.g. \"Bash\", \"browser_*\", \"*\" */\n toolPattern: z.string().default('*'),\n /** Optional regex tested against the serialized tool input. */\n inputPattern: z.string().default(''),\n scopeNote: z.string().default(''),\n builtin: z.boolean().default(false),\n enabled: z.boolean().default(true),\n createdAt: z.number(),\n});\nexport type Rule = z.infer<typeof RuleSchema>;\n\nexport const SkillSchema = z.object({\n id: z.string(),\n slug: z.string(),\n name: z.string(),\n description: z.string().default(''),\n path: z.string(),\n source: z.enum(['user', 'taught', 'imported']).default('user'),\n createdAt: z.number(),\n});\nexport type Skill = z.infer<typeof SkillSchema>;\n\nexport const RoutineSchema = z.object({\n id: z.string(),\n botId: z.string(),\n name: z.string().min(1),\n cronExpr: z.string(),\n timezone: z.string().default('UTC'),\n instructionMd: z.string(),\n enabled: z.boolean().default(true),\n lastRunAt: z.number().nullable().default(null),\n nextRunAt: z.number().nullable().default(null),\n createdAt: z.number(),\n});\nexport type Routine = z.infer<typeof RoutineSchema>;\n\nexport const RoutineRunSchema = z.object({\n id: z.string(),\n routineId: z.string(),\n startedAt: z.number(),\n finishedAt: z.number().nullable().default(null),\n status: z.enum(['running', 'ok', 'failed', 'interrupted']),\n summary: z.string().default(''),\n threadId: z.string().nullable().default(null),\n isTest: z.boolean().default(false),\n});\nexport type RoutineRun = z.infer<typeof RoutineRunSchema>;\n\nexport const MailboxEntrySchema = z.object({\n id: z.string(),\n fromBotId: z.string(),\n toBotId: z.string(),\n contentMd: z.string(),\n hops: z.number().default(1),\n delivered: z.boolean().default(false),\n createdAt: z.number(),\n});\nexport type MailboxEntry = z.infer<typeof MailboxEntrySchema>;\n\nexport const UsageRowSchema = z.object({\n id: z.string(),\n botId: z.string(),\n turnId: z.string(),\n model: z.string(),\n inputTokens: z.number().default(0),\n outputTokens: z.number().default(0),\n cacheReadTokens: z.number().default(0),\n costEstimate: z.number().default(0),\n createdAt: z.number(),\n});\nexport type UsageRow = z.infer<typeof UsageRowSchema>;\n\nexport const TurnOriginSchema = z.enum(['user', 'bot', 'routine', 'system']);\nexport type TurnOrigin = z.infer<typeof TurnOriginSchema>;\n", "import { z } from 'zod';\nimport {\n BotSchema, ThreadSchema, MessageSchema, ApprovalSchema, RuleSchema,\n SkillSchema, RoutineSchema, RoutineRunSchema, UsageRowSchema, ModelTierSchema,\n} from './entities.js';\n\nexport const CreateBotRequest = z.object({\n name: z.string().min(1).max(60),\n title: z.string().max(120).optional(),\n description: z.string().max(8000).optional(),\n avatarEmoji: z.string().max(8).optional(),\n modelTier: ModelTierSchema.optional(),\n});\nexport type CreateBotRequest = z.infer<typeof CreateBotRequest>;\n\nexport const UpdateBotRequest = CreateBotRequest.partial().extend({\n pinned: z.boolean().optional(),\n hidden: z.boolean().optional(),\n notifications: z.boolean().optional(),\n});\nexport type UpdateBotRequest = z.infer<typeof UpdateBotRequest>;\n\nexport const CreateThreadRequest = z.object({\n kind: z.enum(['dm', 'group']),\n title: z.string().optional(),\n memberBotIds: z.array(z.string()),\n});\nexport type CreateThreadRequest = z.infer<typeof CreateThreadRequest>;\n\nexport const PostMessageRequest = z.object({\n contentMd: z.string(),\n attachmentIds: z.array(z.string()).optional(),\n replyToId: z.string().nullable().optional(),\n /** explicit @-mention targets resolved by the client */\n mentionBotIds: z.array(z.string()).optional(),\n mentionEveryone: z.boolean().optional(),\n});\nexport type PostMessageRequest = z.infer<typeof PostMessageRequest>;\n\nexport const ApprovalDecisionRequest = z.object({\n decision: z.enum(['allow', 'deny']),\n alwaysRule: z\n .object({ toolPattern: z.string(), inputPattern: z.string().default(''), scopeNote: z.string().default('') })\n .optional(),\n});\nexport type ApprovalDecisionRequest = z.infer<typeof ApprovalDecisionRequest>;\n\nexport const CreateRuleRequest = z.object({\n kind: z.enum(['require', 'allow']),\n toolPattern: z.string().min(1),\n inputPattern: z.string().default(''),\n scopeNote: z.string().default(''),\n});\nexport type CreateRuleRequest = z.infer<typeof CreateRuleRequest>;\n\nexport const CreateRoutineRequest = z.object({\n botId: z.string(),\n name: z.string().min(1),\n cronExpr: z.string().min(1),\n timezone: z.string().optional(),\n instructionMd: z.string().min(1),\n enabled: z.boolean().optional(),\n});\nexport type CreateRoutineRequest = z.infer<typeof CreateRoutineRequest>;\n\nexport const CreateSkillRequest = z.object({\n name: z.string().min(1),\n description: z.string().default(''),\n bodyMd: z.string().min(1),\n source: z.enum(['user', 'taught', 'imported']).optional(),\n});\nexport type CreateSkillRequest = z.infer<typeof CreateSkillRequest>;\n\n/**\n * Field types, declared once and without defaults. `SettingsSchema` layers the\n * defaults on for reads; `SettingsPatchSchema` deliberately leaves them off.\n */\nconst settingsFields = {\n timezone: z.string(),\n maxConcurrentSessions: z.number().min(1).max(8),\n autoReviewEnabled: z.boolean(),\n theme: z.enum(['system', 'light', 'dark']),\n localExecution: z.enum(['ask', 'always', 'never']),\n dailyTokenBudget: z.number(),\n notificationsEnabled: z.boolean(),\n billingMode: z.enum(['subscription', 'api']),\n computerMode: z.enum(['host', 'container']),\n};\n\nexport const SettingsSchema = z.object({\n timezone: settingsFields.timezone.default('UTC'),\n maxConcurrentSessions: settingsFields.maxConcurrentSessions.default(2),\n autoReviewEnabled: settingsFields.autoReviewEnabled.default(true),\n theme: settingsFields.theme.default('system'),\n localExecution: settingsFields.localExecution.default('ask'),\n dailyTokenBudget: settingsFields.dailyTokenBudget.default(0),\n notificationsEnabled: settingsFields.notificationsEnabled.default(true),\n billingMode: settingsFields.billingMode.default('subscription'),\n computerMode: settingsFields.computerMode.default('host'),\n});\nexport type Settings = z.infer<typeof SettingsSchema>;\n\n/**\n * Body schema for `PATCH /api/settings`. It must NOT carry defaults: parsing a\n * one-field patch through a defaulted schema yields a complete object, and\n * persisting that would reset every setting the client didn't mention \u2014 including\n * `localExecution`, which is a security control (see docs/SECURITY.md).\n */\nexport const SettingsPatchSchema = z.object(settingsFields).partial();\nexport type SettingsPatch = z.infer<typeof SettingsPatchSchema>;\n\nexport const SearchResultSchema = z.object({\n kind: z.enum(['message', 'file', 'routine', 'bot']),\n id: z.string(),\n threadId: z.string().nullable(),\n botId: z.string().nullable(),\n title: z.string(),\n snippet: z.string(),\n createdAt: z.number(),\n});\nexport type SearchResult = z.infer<typeof SearchResultSchema>;\n\nexport type ApiBot = z.infer<typeof BotSchema>;\nexport type ApiThread = z.infer<typeof ThreadSchema>;\nexport type ApiMessage = z.infer<typeof MessageSchema>;\nexport type ApiApproval = z.infer<typeof ApprovalSchema>;\nexport type ApiRule = z.infer<typeof RuleSchema>;\nexport type ApiSkill = z.infer<typeof SkillSchema>;\nexport type ApiRoutine = z.infer<typeof RoutineSchema>;\nexport type ApiRoutineRun = z.infer<typeof RoutineRunSchema>;\nexport type ApiUsageRow = z.infer<typeof UsageRowSchema>;\n\nexport interface RosterEntry { bot: ApiBot; thread: ApiThread | null; lastMessageAt: number }\nexport interface ThreadWithMessages { thread: ApiThread; messages: ApiMessage[] }\nexport interface UsageSummary {\n totals: { inputTokens: number; outputTokens: number; cacheReadTokens: number };\n byBot: Array<{ botId: string; botName: string; inputTokens: number; outputTokens: number }>;\n byDay: Array<{ day: string; inputTokens: number; outputTokens: number }>;\n byModel: Array<{ model: string; inputTokens: number; outputTokens: number }>;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["z", "z", "z", "z"]
|
|
7
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __antbotCreateRequire } from 'node:module';
|
|
2
2
|
const require = __antbotCreateRequire(import.meta.url);
|
|
3
3
|
|
|
4
|
-
//
|
|
4
|
+
// daemon/src/util/log.ts
|
|
5
5
|
var order = { debug: 10, info: 20, warn: 30, error: 40 };
|
|
6
6
|
var min = order[process.env.ANTBOT_LOG_LEVEL ?? "info"] ?? 20;
|
|
7
7
|
function emit(level, scope, msg, extra) {
|
|
@@ -21,4 +21,4 @@ var logger = (scope) => ({
|
|
|
21
21
|
export {
|
|
22
22
|
logger
|
|
23
23
|
};
|
|
24
|
-
//# sourceMappingURL=chunk-
|
|
24
|
+
//# sourceMappingURL=chunk-CNCHYZVD.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../
|
|
3
|
+
"sources": ["../../daemon/src/util/log.ts"],
|
|
4
4
|
"sourcesContent": ["type Level = 'debug' | 'info' | 'warn' | 'error';\nconst order: Record<Level, number> = { debug: 10, info: 20, warn: 30, error: 40 };\nconst min = order[(process.env.ANTBOT_LOG_LEVEL as Level) ?? 'info'] ?? 20;\n\nfunction emit(level: Level, scope: string, msg: string, extra?: unknown) {\n if (order[level] < min) return;\n const line = `${new Date().toISOString()} ${level.toUpperCase().padEnd(5)} [${scope}] ${msg}`;\n if (level === 'error') console.error(line, extra ?? '');\n else if (level === 'warn') console.warn(line, extra ?? '');\n else console.log(line, extra ?? '');\n}\n\nexport const logger = (scope: string) => ({\n debug: (m: string, e?: unknown) => emit('debug', scope, m, e),\n info: (m: string, e?: unknown) => emit('info', scope, m, e),\n warn: (m: string, e?: unknown) => emit('warn', scope, m, e),\n error: (m: string, e?: unknown) => emit('error', scope, m, e),\n});\n"],
|
|
5
5
|
"mappings": ";;;;AACA,IAAM,QAA+B,EAAE,OAAO,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,GAAG;AAChF,IAAM,MAAM,MAAO,QAAQ,IAAI,oBAA8B,MAAM,KAAK;AAExE,SAAS,KAAK,OAAc,OAAe,KAAa,OAAiB;AACvE,MAAI,MAAM,KAAK,IAAI,IAAK;AACxB,QAAM,OAAO,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC,IAAI,MAAM,YAAY,EAAE,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,GAAG;AAC3F,MAAI,UAAU,QAAS,SAAQ,MAAM,MAAM,SAAS,EAAE;AAAA,WAC7C,UAAU,OAAQ,SAAQ,KAAK,MAAM,SAAS,EAAE;AAAA,MACpD,SAAQ,IAAI,MAAM,SAAS,EAAE;AACpC;AAEO,IAAM,SAAS,CAAC,WAAmB;AAAA,EACxC,OAAO,CAAC,GAAW,MAAgB,KAAK,SAAS,OAAO,GAAG,CAAC;AAAA,EAC5D,MAAM,CAAC,GAAW,MAAgB,KAAK,QAAQ,OAAO,GAAG,CAAC;AAAA,EAC1D,MAAM,CAAC,GAAW,MAAgB,KAAK,QAAQ,OAAO,GAAG,CAAC;AAAA,EAC1D,OAAO,CAAC,GAAW,MAAgB,KAAK,SAAS,OAAO,GAAG,CAAC;AAC9D;",
|
|
6
6
|
"names": []
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __antbotCreateRequire } from 'node:module';
|
|
2
2
|
const require = __antbotCreateRequire(import.meta.url);
|
|
3
3
|
|
|
4
|
-
//
|
|
4
|
+
// daemon/src/util/locate.ts
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
function nodeLocateDeps(here, resolve) {
|
|
@@ -27,14 +27,14 @@ function readPackageVersion(here, exists, read) {
|
|
|
27
27
|
}
|
|
28
28
|
function webDistCandidates(deps) {
|
|
29
29
|
const out = [];
|
|
30
|
-
const resolved = deps.resolve("@antbot/
|
|
30
|
+
const resolved = deps.resolve("@antbot/ui/package.json");
|
|
31
31
|
if (resolved) out.push(path.join(path.dirname(resolved), "dist"));
|
|
32
32
|
const pkg = findPackageRoot(deps.here, deps.exists);
|
|
33
33
|
if (pkg) {
|
|
34
34
|
out.push(path.join(pkg, "web", "dist"));
|
|
35
|
-
out.push(path.resolve(pkg, "..", "
|
|
35
|
+
out.push(path.resolve(pkg, "..", "ui", "dist"));
|
|
36
36
|
}
|
|
37
|
-
out.push(path.resolve(deps.cwd, "
|
|
37
|
+
out.push(path.resolve(deps.cwd, "ui", "dist"));
|
|
38
38
|
return out;
|
|
39
39
|
}
|
|
40
40
|
function findWebDist(deps) {
|
|
@@ -45,7 +45,7 @@ function bundledSkillsCandidates(deps) {
|
|
|
45
45
|
const pkg = findPackageRoot(deps.here, deps.exists);
|
|
46
46
|
if (pkg) {
|
|
47
47
|
out.push(path.join(pkg, "skills"));
|
|
48
|
-
out.push(path.resolve(pkg, "..", "
|
|
48
|
+
out.push(path.resolve(pkg, "..", "skills"));
|
|
49
49
|
}
|
|
50
50
|
out.push(path.resolve(deps.cwd, "skills"));
|
|
51
51
|
return out;
|
|
@@ -61,4 +61,4 @@ export {
|
|
|
61
61
|
findWebDist,
|
|
62
62
|
findBundledSkillsDir
|
|
63
63
|
};
|
|
64
|
-
//# sourceMappingURL=chunk-
|
|
64
|
+
//# sourceMappingURL=chunk-GYWJUW4E.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../
|
|
4
|
-
"sourcesContent": ["// Finding the assets ant-bot ships with \u2014 the built web UI and the bundled skills directory.\n//\n// These lookups used to count `..` segments up from `import.meta.url`, which encodes two guesses\n// at once: the repo layout, and how deep the compiler happens to put the calling module. Both are\n// wrong from an installed package, and both fail *silently* \u2014 `findWebDist` returns null and the\n// daemon serves no UI, `defaultBundledSkillsDir` points at nothing and no skills sync. Walking up\n// to the nearest package.json instead is depth-independent, so bundling or moving a source file\n// cannot quietly break them.\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface LocateDeps {\n /** Directory of the calling module. */\n here: string;\n cwd: string;\n exists: (p: string) => boolean;\n /** Resolves a bare specifier to an absolute path; returns null when it is not installed. */\n resolve: (specifier: string) => string | null;\n}\n\nexport function nodeLocateDeps(here: string, resolve: (s: string) => string | null): LocateDeps {\n return { here, cwd: process.cwd(), exists: (p) => fs.existsSync(p), resolve };\n}\n\n/**\n * The nearest ancestor of `from` (inclusive) holding a package.json. Returns null at the\n * filesystem root, which callers treat as \"fall through to the other candidates\".\n */\nexport function findPackageRoot(from: string, exists: (p: string) => boolean): string | null {\n let dir = path.resolve(from);\n for (;;) {\n if (exists(path.join(dir, 'package.json'))) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/**\n * The version of the package this module was loaded from. In the published build the CLI and the\n * daemon are one package, so `antbot --version` and `GET /api/health` necessarily agree; in a\n * checkout they read their own workspace package.json, which `version.test.ts` pins to the root.\n */\nexport function readPackageVersion(\n here: string,\n exists: (p: string) => boolean,\n read: (p: string) => string,\n): string {\n const root = findPackageRoot(here, exists);\n if (!root) return '0.0.0';\n try {\n return (JSON.parse(read(path.join(root, 'package.json'))) as { version?: string }).version ?? '0.0.0';\n } catch {\n return '0.0.0';\n }\n}\n\n/**\n * Candidates for the built web UI, most specific first. `pkg` is `
|
|
5
|
-
"mappings": ";;;;AAQA,OAAO,QAAQ;AACf,OAAO,UAAU;AAWV,SAAS,eAAe,MAAc,SAAmD;AAC9F,SAAO,EAAE,MAAM,KAAK,QAAQ,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG,QAAQ;AAC9E;AAMO,SAAS,gBAAgB,MAAc,QAA+C;AAC3F,MAAI,MAAM,KAAK,QAAQ,IAAI;AAC3B,aAAS;AACP,QAAI,OAAO,KAAK,KAAK,KAAK,cAAc,CAAC,EAAG,QAAO;AACnD,UAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACF;AAOO,SAAS,mBACd,MACA,QACA,MACQ;AACR,QAAM,OAAO,gBAAgB,MAAM,MAAM;AACzC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,WAAQ,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC,CAAC,EAA2B,WAAW;AAAA,EAChG,QAAQ;AACN,WAAO;AAAA,EACT;AACF;
|
|
3
|
+
"sources": ["../../daemon/src/util/locate.ts"],
|
|
4
|
+
"sourcesContent": ["// Finding the assets ant-bot ships with \u2014 the built web UI and the bundled skills directory.\n//\n// These lookups used to count `..` segments up from `import.meta.url`, which encodes two guesses\n// at once: the repo layout, and how deep the compiler happens to put the calling module. Both are\n// wrong from an installed package, and both fail *silently* \u2014 `findWebDist` returns null and the\n// daemon serves no UI, `defaultBundledSkillsDir` points at nothing and no skills sync. Walking up\n// to the nearest package.json instead is depth-independent, so bundling or moving a source file\n// cannot quietly break them.\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface LocateDeps {\n /** Directory of the calling module. */\n here: string;\n cwd: string;\n exists: (p: string) => boolean;\n /** Resolves a bare specifier to an absolute path; returns null when it is not installed. */\n resolve: (specifier: string) => string | null;\n}\n\nexport function nodeLocateDeps(here: string, resolve: (s: string) => string | null): LocateDeps {\n return { here, cwd: process.cwd(), exists: (p) => fs.existsSync(p), resolve };\n}\n\n/**\n * The nearest ancestor of `from` (inclusive) holding a package.json. Returns null at the\n * filesystem root, which callers treat as \"fall through to the other candidates\".\n */\nexport function findPackageRoot(from: string, exists: (p: string) => boolean): string | null {\n let dir = path.resolve(from);\n for (;;) {\n if (exists(path.join(dir, 'package.json'))) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/**\n * The version of the package this module was loaded from. In the published build the CLI and the\n * daemon are one package, so `antbot --version` and `GET /api/health` necessarily agree; in a\n * checkout they read their own workspace package.json, which `version.test.ts` pins to the root.\n */\nexport function readPackageVersion(\n here: string,\n exists: (p: string) => boolean,\n read: (p: string) => string,\n): string {\n const root = findPackageRoot(here, exists);\n if (!root) return '0.0.0';\n try {\n return (JSON.parse(read(path.join(root, 'package.json'))) as { version?: string }).version ?? '0.0.0';\n } catch {\n return '0.0.0';\n }\n}\n\n/**\n * Candidates for the built web UI, most specific first. `pkg` is the `daemon/` directory in a\n * checkout and the installed package root otherwise, so `pkg/web/dist` covers the shipped layout\n * and `pkg/../ui/dist` covers the sibling workspace package \u2014 neither depends on compile depth.\n *\n * The sibling name is `ui`, not `web`: those are workspace *directories*, and they are the one\n * thing here that a repo reorganisation moves. A rename must update this list and its tests.\n */\nexport function webDistCandidates(deps: LocateDeps): string[] {\n const out: string[] = [];\n const resolved = deps.resolve('@antbot/ui/package.json');\n if (resolved) out.push(path.join(path.dirname(resolved), 'dist'));\n\n const pkg = findPackageRoot(deps.here, deps.exists);\n if (pkg) {\n out.push(path.join(pkg, 'web', 'dist'));\n out.push(path.resolve(pkg, '..', 'ui', 'dist'));\n }\n out.push(path.resolve(deps.cwd, 'ui', 'dist'));\n return out;\n}\n\n/** The built web UI, or null when it has not been built (the daemon then runs API-only). */\nexport function findWebDist(deps: LocateDeps): string | null {\n return webDistCandidates(deps).find((c) => deps.exists(path.join(c, 'index.html'))) ?? null;\n}\n\n/**\n * Candidates for the skills directory ant-bot ships. In a checkout `pkg` is the `daemon/`\n * directory, so the repo root is one level up; in the installed package the directory sits beside\n * the code. (This was two levels up while the workspace lived under `packages/`.)\n */\nexport function bundledSkillsCandidates(deps: LocateDeps): string[] {\n const out: string[] = [];\n const pkg = findPackageRoot(deps.here, deps.exists);\n if (pkg) {\n out.push(path.join(pkg, 'skills'));\n out.push(path.resolve(pkg, '..', 'skills'));\n }\n out.push(path.resolve(deps.cwd, 'skills'));\n return out;\n}\n\n/**\n * The skills directory ant-bot ships with. Unlike `findWebDist` this never returns null: the\n * caller (`syncBundledSkills`) already treats a missing directory as \"nothing to sync\", and a\n * concrete path makes the failure legible in a log.\n */\nexport function findBundledSkillsDir(deps: LocateDeps): string {\n const candidates = bundledSkillsCandidates(deps);\n return candidates.find((c) => deps.exists(c)) ?? candidates[0]!;\n}\n"],
|
|
5
|
+
"mappings": ";;;;AAQA,OAAO,QAAQ;AACf,OAAO,UAAU;AAWV,SAAS,eAAe,MAAc,SAAmD;AAC9F,SAAO,EAAE,MAAM,KAAK,QAAQ,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG,QAAQ;AAC9E;AAMO,SAAS,gBAAgB,MAAc,QAA+C;AAC3F,MAAI,MAAM,KAAK,QAAQ,IAAI;AAC3B,aAAS;AACP,QAAI,OAAO,KAAK,KAAK,KAAK,cAAc,CAAC,EAAG,QAAO;AACnD,UAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACF;AAOO,SAAS,mBACd,MACA,QACA,MACQ;AACR,QAAM,OAAO,gBAAgB,MAAM,MAAM;AACzC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,WAAQ,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC,CAAC,EAA2B,WAAW;AAAA,EAChG,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAUO,SAAS,kBAAkB,MAA4B;AAC5D,QAAM,MAAgB,CAAC;AACvB,QAAM,WAAW,KAAK,QAAQ,yBAAyB;AACvD,MAAI,SAAU,KAAI,KAAK,KAAK,KAAK,KAAK,QAAQ,QAAQ,GAAG,MAAM,CAAC;AAEhE,QAAM,MAAM,gBAAgB,KAAK,MAAM,KAAK,MAAM;AAClD,MAAI,KAAK;AACP,QAAI,KAAK,KAAK,KAAK,KAAK,OAAO,MAAM,CAAC;AACtC,QAAI,KAAK,KAAK,QAAQ,KAAK,MAAM,MAAM,MAAM,CAAC;AAAA,EAChD;AACA,MAAI,KAAK,KAAK,QAAQ,KAAK,KAAK,MAAM,MAAM,CAAC;AAC7C,SAAO;AACT;AAGO,SAAS,YAAY,MAAiC;AAC3D,SAAO,kBAAkB,IAAI,EAAE,KAAK,CAAC,MAAM,KAAK,OAAO,KAAK,KAAK,GAAG,YAAY,CAAC,CAAC,KAAK;AACzF;AAOO,SAAS,wBAAwB,MAA4B;AAClE,QAAM,MAAgB,CAAC;AACvB,QAAM,MAAM,gBAAgB,KAAK,MAAM,KAAK,MAAM;AAClD,MAAI,KAAK;AACP,QAAI,KAAK,KAAK,KAAK,KAAK,QAAQ,CAAC;AACjC,QAAI,KAAK,KAAK,QAAQ,KAAK,MAAM,QAAQ,CAAC;AAAA,EAC5C;AACA,MAAI,KAAK,KAAK,QAAQ,KAAK,KAAK,QAAQ,CAAC;AACzC,SAAO;AACT;AAOO,SAAS,qBAAqB,MAA0B;AAC7D,QAAM,aAAa,wBAAwB,IAAI;AAC/C,SAAO,WAAW,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,KAAK,WAAW,CAAC;AAC/D;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,9 +2,9 @@ import { createRequire as __antbotCreateRequire } from 'node:module';
|
|
|
2
2
|
const require = __antbotCreateRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
parseFrontmatter
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-MSSHR6SW.js";
|
|
6
6
|
|
|
7
|
-
//
|
|
7
|
+
// daemon/src/skills/install.ts
|
|
8
8
|
import fs from "node:fs";
|
|
9
9
|
import os from "node:os";
|
|
10
10
|
import path from "node:path";
|
|
@@ -284,4 +284,4 @@ export {
|
|
|
284
284
|
stage,
|
|
285
285
|
renderManifest
|
|
286
286
|
};
|
|
287
|
-
//# sourceMappingURL=chunk-
|
|
287
|
+
//# sourceMappingURL=chunk-JCZBDGBA.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../
|
|
3
|
+
"sources": ["../../daemon/src/skills/install.ts"],
|
|
4
4
|
"sourcesContent": ["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { spawn } from 'node:child_process';\n\n/**\n * Installing a skill means adding instructions that later steer a bot, and possibly\n * scripts that run with the same access as any bot command. Every source is therefore\n * resolved explicitly rather than guessed at, everything lands under the skills\n * directory, and the caller is handed a manifest of exactly what arrived.\n */\n\nexport type SkillSource =\n | { kind: 'git'; url: string; ref?: string; subdir?: string }\n | { kind: 'path'; path: string }\n | { kind: 'url'; url: string };\n\nconst SCRIPT_EXTENSIONS = new Set([\n '.sh', '.bash', '.zsh', '.fish', '.py', '.rb', '.pl', '.js', '.mjs', '.cjs',\n '.ts', '.ps1', '.bat', '.cmd', '.exe', '.bin',\n]);\n\n/** A file worth warning about: it can be executed, not merely read. */\nexport function isExecutableFile(relPath: string, mode: number): boolean {\n if (SCRIPT_EXTENSIONS.has(path.extname(relPath).toLowerCase())) return true;\n return (mode & 0o111) !== 0;\n}\n\nexport interface FileStat {\n relPath: string;\n bytes: number;\n mode: number;\n}\n\nexport interface SkillManifest {\n files: FileStat[];\n executables: string[];\n totalBytes: number;\n}\n\nexport function classifyFiles(files: FileStat[]): SkillManifest {\n return {\n files,\n executables: files.filter((f) => isExecutableFile(f.relPath, f.mode)).map((f) => f.relPath),\n totalBytes: files.reduce((n, f) => n + f.bytes, 0),\n };\n}\n\nconst GITHUB_TREE = /^(?:https?:\\/\\/)?(?:www\\.)?github\\.com\\/([^/]+)\\/([^/#]+?)(?:\\.git)?\\/(?:tree|blob)\\/([^/]+)(?:\\/(.*))?$/;\nconst GITHUB_REPO = /^(?:https?:\\/\\/)?(?:www\\.)?github\\.com\\/([^/]+)\\/([^/#]+?)(?:\\.git)?$/;\nconst OWNER_REPO = /^([A-Za-z0-9][\\w.-]*)\\/([\\w.-]+)$/;\n\n/**\n * Turn a user-supplied spec into an explicit source.\n *\n * Accepts: `owner/repo`, `github.com/owner/repo`, a full https/ssh git URL, a GitHub\n * `/tree/<ref>/<subdir>` link, a local path, or a direct link to a raw `SKILL.md`.\n * Anything else throws rather than being guessed at.\n */\nexport function parseSkillSource(rawSpec: string): SkillSource {\n const spec = rawSpec.trim();\n if (!spec) throw new Error('A skill source is required.');\n\n // Local paths first \u2014 an explicit path prefix is unambiguous.\n if (spec.startsWith('./') || spec.startsWith('../') || spec.startsWith('/') || spec.startsWith('~')) {\n const expanded = spec.startsWith('~') ? path.join(os.homedir(), spec.slice(1)) : spec;\n return { kind: 'path', path: expanded };\n }\n\n if (spec.startsWith('git@') || spec.startsWith('ssh://') || spec.endsWith('.git')) {\n const [url, ref] = splitRef(spec);\n return { kind: 'git', url, ref, subdir: undefined };\n }\n\n const tree = GITHUB_TREE.exec(spec);\n if (tree) {\n const [, owner, repo, ref, subdir] = tree;\n // A `/blob/<ref>/<dir>/SKILL.md` link is what GitHub's UI hands you, and it is the most\n // natural thing to paste. Point it at the containing directory: a subdir naming a file\n // finds no skill directory and would fail with a confusing \"No SKILL.md found\".\n const dir = subdir ? subdir.replace(/(^|\\/)SKILL\\.md$/i, '') : '';\n return { kind: 'git', url: `https://github.com/${owner}/${repo}`, ref, subdir: dir || undefined };\n }\n\n const [base, ref] = splitRef(spec);\n\n const repoMatch = GITHUB_REPO.exec(base);\n if (repoMatch) {\n const [, owner, repo] = repoMatch;\n return { kind: 'git', url: `https://github.com/${owner}/${repo}`, ref, subdir: undefined };\n }\n\n if (/^https?:\\/\\//.test(base)) {\n if (/\\/SKILL\\.md$/i.test(base)) return { kind: 'url', url: base };\n throw new Error(\n `Unsupported URL: ${base}\\nSupported: a git repository, or a direct link ending in /SKILL.md.`,\n );\n }\n\n const ownerRepo = OWNER_REPO.exec(base);\n if (ownerRepo) {\n const [, owner, repo] = ownerRepo;\n return { kind: 'git', url: `https://github.com/${owner}/${repo}`, ref, subdir: undefined };\n }\n\n throw new Error(\n `Could not understand skill source \"${rawSpec}\".\\n` +\n 'Try: owner/repo, github.com/owner/repo, a git URL, a local path, or a URL ending in /SKILL.md.',\n );\n}\n\n/**\n * One line describing what installing `source` would pull in, for an approval card.\n * The distinction that matters is scope: one named skill, or every skill in a repository.\n * Never throws \u2014 an unparseable source is described verbatim so the card still renders.\n */\nexport function describeSkillSource(rawSpec: string): string {\n let parsed: SkillSource;\n try {\n parsed = parseSkillSource(rawSpec);\n } catch {\n return `Install skill from ${rawSpec}`;\n }\n const where = (u: string): string => u.replace(/^https?:\\/\\//, '');\n switch (parsed.kind) {\n case 'url':\n return `Install one skill from ${where(parsed.url)}`;\n case 'path':\n return `Install skill(s) from the local path ${parsed.path}`;\n case 'git': {\n const ref = parsed.ref ? `#${parsed.ref}` : '';\n return parsed.subdir\n ? `Install \"${parsed.subdir}\" from ${where(parsed.url)}${ref}`\n : `Install EVERY skill in ${where(parsed.url)}${ref} (whole repository)`;\n }\n }\n}\n\nfunction splitRef(spec: string): [string, string | undefined] {\n const hash = spec.lastIndexOf('#');\n if (hash === -1) return [spec, undefined];\n return [spec.slice(0, hash), spec.slice(hash + 1) || undefined];\n}\n\n/* ------------------------------- filesystem helpers ------------------------------- */\n\n/** Every file under `root`, relative-pathed, skipping VCS metadata. */\nexport function walkFiles(root: string, rel = ''): FileStat[] {\n const out: FileStat[] = [];\n const dir = path.join(root, rel);\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (entry.name === '.git' || entry.name === 'node_modules') continue;\n const childRel = rel ? path.join(rel, entry.name) : entry.name;\n const full = path.join(root, childRel);\n if (entry.isSymbolicLink()) continue; // never follow links out of the tree\n if (entry.isDirectory()) out.push(...walkFiles(root, childRel));\n else if (entry.isFile()) {\n const st = fs.statSync(full);\n out.push({ relPath: childRel, bytes: st.size, mode: st.mode });\n }\n }\n return out;\n}\n\n/** Directories containing a SKILL.md, anywhere under `root`. A repo may hold many. */\nexport function findSkillDirs(root: string): string[] {\n const found: string[] = [];\n const visit = (dir: string, depth: number): void => {\n if (depth > 5) return;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n if (entries.some((e) => e.isFile() && e.name.toLowerCase() === 'skill.md')) {\n found.push(dir);\n return; // a skill directory owns its whole subtree\n }\n for (const e of entries) {\n if (!e.isDirectory() || e.name === '.git' || e.name === 'node_modules') continue;\n visit(path.join(dir, e.name), depth + 1);\n }\n };\n visit(root, 0);\n return found.sort();\n}\n\nexport function copyTree(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src, { withFileTypes: true })) {\n if (entry.name === '.git' || entry.name === 'node_modules') continue;\n if (entry.isSymbolicLink()) continue;\n const s = path.join(src, entry.name);\n const d = path.join(dest, entry.name);\n if (entry.isDirectory()) copyTree(s, d);\n else if (entry.isFile()) fs.copyFileSync(s, d);\n }\n}\n\nexport function runGit(args: string[], cwd?: string, timeoutMs = 120_000): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn('git', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });\n let stderr = '';\n const timer = setTimeout(() => {\n child.kill('SIGKILL');\n reject(new Error(`git ${args[0]} timed out after ${timeoutMs / 1000}s`));\n }, timeoutMs);\n child.stderr?.on('data', (d) => (stderr += String(d)));\n child.on('error', (err) => {\n clearTimeout(timer);\n reject(new Error(`git is required to install from a repository: ${err.message}`));\n });\n child.on('close', (code) => {\n clearTimeout(timer);\n if (code === 0) resolve();\n else reject(new Error(`git ${args[0]} failed: ${stderr.trim().split('\\n').slice(-3).join(' ')}`));\n });\n });\n}\n\n/* ---------------------------------- staging ---------------------------------- */\n\nimport { parseFrontmatter } from './skills.js';\n\nexport interface StagedSkill {\n /** Name from the SKILL.md frontmatter \u2014 what the SDK's Skill tool matches on. */\n name: string;\n description: string;\n /** Directory holding SKILL.md and any supporting files, ready to copy in. */\n dir: string;\n manifest: SkillManifest;\n}\n\n/** Hard cap so a mis-typed source cannot fill the disk. */\nexport const MAX_SKILL_BYTES = 10 * 1024 * 1024;\n\nfunction readStaged(dir: string): StagedSkill {\n const file = path.join(dir, 'SKILL.md');\n const raw = fs.readFileSync(file, 'utf8');\n const { name, description } = parseFrontmatter(raw);\n if (!name.trim()) {\n throw new Error(\n `${file} has no \\`name\\` in its frontmatter. A skill needs:\\n---\\nname: my-skill\\ndescription: what it does\\n---`,\n );\n }\n const manifest = classifyFiles(walkFiles(dir));\n if (manifest.totalBytes > MAX_SKILL_BYTES) {\n throw new Error(\n `Skill \"${name}\" is ${(manifest.totalBytes / 1048576).toFixed(1)} MB; the limit is ${MAX_SKILL_BYTES / 1048576} MB.`,\n );\n }\n return { name: name.trim(), description: description.trim(), dir, manifest };\n}\n\n/** Collect every skill under a local path. Accepts a skill dir, a SKILL.md, or a pack of skills. */\nexport async function stageFromPath(source: { kind: 'path'; path: string }): Promise<StagedSkill[]> {\n const target = path.resolve(source.path);\n if (!fs.existsSync(target)) throw new Error(`Path not found: ${target}`);\n\n const stat = fs.statSync(target);\n if (stat.isFile()) {\n if (path.basename(target).toLowerCase() !== 'skill.md')\n throw new Error(`Expected a directory or a SKILL.md file, got ${target}`);\n return [readStaged(path.dirname(target))];\n }\n\n const dirs = findSkillDirs(target);\n if (!dirs.length) throw new Error(`No SKILL.md found under ${target}`);\n return dirs.map(readStaged);\n}\n\n/** Clone a repo shallowly into a temp dir and stage the skills inside it. */\nexport async function stageFromGit(\n source: { kind: 'git'; url: string; ref?: string; subdir?: string },\n tmpRoot = os.tmpdir(),\n): Promise<{ staged: StagedSkill[]; cleanup: () => void }> {\n const dir = fs.mkdtempSync(path.join(tmpRoot, 'antbot-skill-git-'));\n const cleanup = (): void => fs.rmSync(dir, { recursive: true, force: true });\n try {\n const args = ['clone', '--depth', '1', '--quiet'];\n if (source.ref) args.push('--branch', source.ref);\n args.push(source.url, dir);\n await runGit(args);\n\n const root = source.subdir ? path.join(dir, source.subdir) : dir;\n if (!fs.existsSync(root)) throw new Error(`\"${source.subdir}\" does not exist in ${source.url}`);\n\n const dirs = findSkillDirs(root);\n if (!dirs.length) throw new Error(`No SKILL.md found in ${source.url}${source.subdir ? `/${source.subdir}` : ''}`);\n return { staged: dirs.map(readStaged), cleanup };\n } catch (err) {\n cleanup();\n throw err;\n }\n}\n\n/** Fetch a single raw SKILL.md into a temp dir. */\nexport async function stageFromUrl(\n source: { kind: 'url'; url: string },\n tmpRoot = os.tmpdir(),\n fetchImpl: typeof fetch = fetch,\n): Promise<{ staged: StagedSkill[]; cleanup: () => void }> {\n const dir = fs.mkdtempSync(path.join(tmpRoot, 'antbot-skill-url-'));\n const cleanup = (): void => fs.rmSync(dir, { recursive: true, force: true });\n try {\n const res = await fetchImpl(source.url, { redirect: 'follow' });\n if (!res.ok) throw new Error(`Fetching ${source.url} failed: HTTP ${res.status}`);\n const body = await res.text();\n if (body.length > MAX_SKILL_BYTES) throw new Error(`${source.url} is larger than the ${MAX_SKILL_BYTES / 1048576} MB limit.`);\n fs.writeFileSync(path.join(dir, 'SKILL.md'), body);\n return { staged: [readStaged(dir)], cleanup };\n } catch (err) {\n cleanup();\n throw err;\n }\n}\n\n/** Resolve any source to staged skills plus a cleanup for whatever temp state it created. */\nexport async function stage(source: SkillSource): Promise<{ staged: StagedSkill[]; cleanup: () => void }> {\n if (source.kind === 'path') return { staged: await stageFromPath(source), cleanup: () => {} };\n if (source.kind === 'git') return stageFromGit(source);\n return stageFromUrl(source);\n}\n\n/** Human-readable summary of what an install put on disk. */\nexport function renderManifest(skill: StagedSkill, installedAt: string): string {\n const lines = [`\u2713 Installed '${skill.name}'`, ''];\n const width = Math.max(...skill.manifest.files.map((f) => f.relPath.length), 10);\n for (const f of [...skill.manifest.files].sort((a, b) => a.relPath.localeCompare(b.relPath))) {\n const size = f.bytes < 1024 ? `${f.bytes} B` : `${(f.bytes / 1024).toFixed(1)} KB`;\n const flag = isExecutableFile(f.relPath, f.mode) ? ' \u26A0 executable' : '';\n lines.push(` ${f.relPath.padEnd(width)} ${size.padStart(8)}${flag}`);\n }\n if (skill.manifest.executables.length) {\n const n = skill.manifest.executables.length;\n lines.push(\n '',\n `\u26A0 This skill ships ${n} ${n === 1 ? 'script' : 'scripts'}. Scripts run with the same access`,\n ' as any bot command. Review before assigning:',\n ` ${installedAt}`,\n );\n }\n return lines.join('\\n');\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,aAAa;AActB,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AAAA,EAAO;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EACrE;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AACzC,CAAC;AAGM,SAAS,iBAAiB,SAAiB,MAAuB;AACvE,MAAI,kBAAkB,IAAI,KAAK,QAAQ,OAAO,EAAE,YAAY,CAAC,EAAG,QAAO;AACvE,UAAQ,OAAO,QAAW;AAC5B;AAcO,SAAS,cAAc,OAAkC;AAC9D,SAAO;AAAA,IACL;AAAA,IACA,aAAa,MAAM,OAAO,CAAC,MAAM,iBAAiB,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO;AAAA,IAC1F,YAAY,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC;AAAA,EACnD;AACF;AAEA,IAAM,cAAc;AACpB,IAAM,cAAc;AACpB,IAAM,aAAa;AASZ,SAAS,iBAAiB,SAA8B;AAC7D,QAAM,OAAO,QAAQ,KAAK;AAC1B,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,6BAA6B;AAGxD,MAAI,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,KAAK,KAAK,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,GAAG;AACnG,UAAM,WAAW,KAAK,WAAW,GAAG,IAAI,KAAK,KAAK,GAAG,QAAQ,GAAG,KAAK,MAAM,CAAC,CAAC,IAAI;AACjF,WAAO,EAAE,MAAM,QAAQ,MAAM,SAAS;AAAA,EACxC;AAEA,MAAI,KAAK,WAAW,MAAM,KAAK,KAAK,WAAW,QAAQ,KAAK,KAAK,SAAS,MAAM,GAAG;AACjF,UAAM,CAAC,KAAKA,IAAG,IAAI,SAAS,IAAI;AAChC,WAAO,EAAE,MAAM,OAAO,KAAK,KAAAA,MAAK,QAAQ,OAAU;AAAA,EACpD;AAEA,QAAM,OAAO,YAAY,KAAK,IAAI;AAClC,MAAI,MAAM;AACR,UAAM,CAAC,EAAE,OAAO,MAAMA,MAAK,MAAM,IAAI;AAIrC,UAAM,MAAM,SAAS,OAAO,QAAQ,qBAAqB,EAAE,IAAI;AAC/D,WAAO,EAAE,MAAM,OAAO,KAAK,sBAAsB,KAAK,IAAI,IAAI,IAAI,KAAAA,MAAK,QAAQ,OAAO,OAAU;AAAA,EAClG;AAEA,QAAM,CAAC,MAAM,GAAG,IAAI,SAAS,IAAI;AAEjC,QAAM,YAAY,YAAY,KAAK,IAAI;AACvC,MAAI,WAAW;AACb,UAAM,CAAC,EAAE,OAAO,IAAI,IAAI;AACxB,WAAO,EAAE,MAAM,OAAO,KAAK,sBAAsB,KAAK,IAAI,IAAI,IAAI,KAAK,QAAQ,OAAU;AAAA,EAC3F;AAEA,MAAI,eAAe,KAAK,IAAI,GAAG;AAC7B,QAAI,gBAAgB,KAAK,IAAI,EAAG,QAAO,EAAE,MAAM,OAAO,KAAK,KAAK;AAChE,UAAM,IAAI;AAAA,MACR,oBAAoB,IAAI;AAAA;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,YAAY,WAAW,KAAK,IAAI;AACtC,MAAI,WAAW;AACb,UAAM,CAAC,EAAE,OAAO,IAAI,IAAI;AACxB,WAAO,EAAE,MAAM,OAAO,KAAK,sBAAsB,KAAK,IAAI,IAAI,IAAI,KAAK,QAAQ,OAAU;AAAA,EAC3F;AAEA,QAAM,IAAI;AAAA,IACR,sCAAsC,OAAO;AAAA;AAAA,EAE/C;AACF;AAOO,SAAS,oBAAoB,SAAyB;AAC3D,MAAI;AACJ,MAAI;AACF,aAAS,iBAAiB,OAAO;AAAA,EACnC,QAAQ;AACN,WAAO,sBAAsB,OAAO;AAAA,EACtC;AACA,QAAM,QAAQ,CAAC,MAAsB,EAAE,QAAQ,gBAAgB,EAAE;AACjE,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO,0BAA0B,MAAM,OAAO,GAAG,CAAC;AAAA,IACpD,KAAK;AACH,aAAO,wCAAwC,OAAO,IAAI;AAAA,IAC5D,KAAK,OAAO;AACV,YAAM,MAAM,OAAO,MAAM,IAAI,OAAO,GAAG,KAAK;AAC5C,aAAO,OAAO,SACV,YAAY,OAAO,MAAM,UAAU,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,KAC1D,0BAA0B,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG;AAAA,IACvD;AAAA,EACF;AACF;AAEA,SAAS,SAAS,MAA4C;AAC5D,QAAM,OAAO,KAAK,YAAY,GAAG;AACjC,MAAI,SAAS,GAAI,QAAO,CAAC,MAAM,MAAS;AACxC,SAAO,CAAC,KAAK,MAAM,GAAG,IAAI,GAAG,KAAK,MAAM,OAAO,CAAC,KAAK,MAAS;AAChE;AAKO,SAAS,UAAU,MAAc,MAAM,IAAgB;AAC5D,QAAM,MAAkB,CAAC;AACzB,QAAM,MAAM,KAAK,KAAK,MAAM,GAAG;AAC/B,aAAW,SAAS,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAChE,QAAI,MAAM,SAAS,UAAU,MAAM,SAAS,eAAgB;AAC5D,UAAM,WAAW,MAAM,KAAK,KAAK,KAAK,MAAM,IAAI,IAAI,MAAM;AAC1D,UAAM,OAAO,KAAK,KAAK,MAAM,QAAQ;AACrC,QAAI,MAAM,eAAe,EAAG;AAC5B,QAAI,MAAM,YAAY,EAAG,KAAI,KAAK,GAAG,UAAU,MAAM,QAAQ,CAAC;AAAA,aACrD,MAAM,OAAO,GAAG;AACvB,YAAM,KAAK,GAAG,SAAS,IAAI;AAC3B,UAAI,KAAK,EAAE,SAAS,UAAU,OAAO,GAAG,MAAM,MAAM,GAAG,KAAK,CAAC;AAAA,IAC/D;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,cAAc,MAAwB;AACpD,QAAM,QAAkB,CAAC;AACzB,QAAM,QAAQ,CAAC,KAAa,UAAwB;AAClD,QAAI,QAAQ,EAAG;AACf,QAAI;AACJ,QAAI;AACF,gBAAU,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACvD,QAAQ;AACN;AAAA,IACF;AACA,QAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,KAAK,YAAY,MAAM,UAAU,GAAG;AAC1E,YAAM,KAAK,GAAG;AACd;AAAA,IACF;AACA,eAAW,KAAK,SAAS;AACvB,UAAI,CAAC,EAAE,YAAY,KAAK,EAAE,SAAS,UAAU,EAAE,SAAS,eAAgB;AACxE,YAAM,KAAK,KAAK,KAAK,EAAE,IAAI,GAAG,QAAQ,CAAC;AAAA,IACzC;AAAA,EACF;AACA,QAAM,MAAM,CAAC;AACb,SAAO,MAAM,KAAK;AACpB;AAEO,SAAS,SAAS,KAAa,MAAoB;AACxD,KAAG,UAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACtC,aAAW,SAAS,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAChE,QAAI,MAAM,SAAS,UAAU,MAAM,SAAS,eAAgB;AAC5D,QAAI,MAAM,eAAe,EAAG;AAC5B,UAAM,IAAI,KAAK,KAAK,KAAK,MAAM,IAAI;AACnC,UAAM,IAAI,KAAK,KAAK,MAAM,MAAM,IAAI;AACpC,QAAI,MAAM,YAAY,EAAG,UAAS,GAAG,CAAC;AAAA,aAC7B,MAAM,OAAO,EAAG,IAAG,aAAa,GAAG,CAAC;AAAA,EAC/C;AACF;AAEO,SAAS,OAAO,MAAgB,KAAc,YAAY,MAAwB;AACvF,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,QAAQ,MAAM,OAAO,MAAM,EAAE,KAAK,OAAO,CAAC,UAAU,QAAQ,MAAM,EAAE,CAAC;AAC3E,QAAI,SAAS;AACb,UAAM,QAAQ,WAAW,MAAM;AAC7B,YAAM,KAAK,SAAS;AACpB,aAAO,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC,oBAAoB,YAAY,GAAI,GAAG,CAAC;AAAA,IACzE,GAAG,SAAS;AACZ,UAAM,QAAQ,GAAG,QAAQ,CAAC,MAAO,UAAU,OAAO,CAAC,CAAE;AACrD,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,mBAAa,KAAK;AAClB,aAAO,IAAI,MAAM,iDAAiD,IAAI,OAAO,EAAE,CAAC;AAAA,IAClF,CAAC;AACD,UAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,mBAAa,KAAK;AAClB,UAAI,SAAS,EAAG,SAAQ;AAAA,UACnB,QAAO,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC,YAAY,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC;AAAA,IAClG,CAAC;AAAA,EACH,CAAC;AACH;AAgBO,IAAM,kBAAkB,KAAK,OAAO;AAE3C,SAAS,WAAW,KAA0B;AAC5C,QAAM,OAAO,KAAK,KAAK,KAAK,UAAU;AACtC,QAAM,MAAM,GAAG,aAAa,MAAM,MAAM;AACxC,QAAM,EAAE,MAAM,YAAY,IAAI,iBAAiB,GAAG;AAClD,MAAI,CAAC,KAAK,KAAK,GAAG;AAChB,UAAM,IAAI;AAAA,MACR,GAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,IACT;AAAA,EACF;AACA,QAAM,WAAW,cAAc,UAAU,GAAG,CAAC;AAC7C,MAAI,SAAS,aAAa,iBAAiB;AACzC,UAAM,IAAI;AAAA,MACR,UAAU,IAAI,SAAS,SAAS,aAAa,SAAS,QAAQ,CAAC,CAAC,qBAAqB,kBAAkB,OAAO;AAAA,IAChH;AAAA,EACF;AACA,SAAO,EAAE,MAAM,KAAK,KAAK,GAAG,aAAa,YAAY,KAAK,GAAG,KAAK,SAAS;AAC7E;AAGA,eAAsB,cAAc,QAAgE;AAClG,QAAM,SAAS,KAAK,QAAQ,OAAO,IAAI;AACvC,MAAI,CAAC,GAAG,WAAW,MAAM,EAAG,OAAM,IAAI,MAAM,mBAAmB,MAAM,EAAE;AAEvE,QAAM,OAAO,GAAG,SAAS,MAAM;AAC/B,MAAI,KAAK,OAAO,GAAG;AACjB,QAAI,KAAK,SAAS,MAAM,EAAE,YAAY,MAAM;AAC1C,YAAM,IAAI,MAAM,gDAAgD,MAAM,EAAE;AAC1E,WAAO,CAAC,WAAW,KAAK,QAAQ,MAAM,CAAC,CAAC;AAAA,EAC1C;AAEA,QAAM,OAAO,cAAc,MAAM;AACjC,MAAI,CAAC,KAAK,OAAQ,OAAM,IAAI,MAAM,2BAA2B,MAAM,EAAE;AACrE,SAAO,KAAK,IAAI,UAAU;AAC5B;AAGA,eAAsB,aACpB,QACA,UAAU,GAAG,OAAO,GACqC;AACzD,QAAM,MAAM,GAAG,YAAY,KAAK,KAAK,SAAS,mBAAmB,CAAC;AAClE,QAAM,UAAU,MAAY,GAAG,OAAO,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC3E,MAAI;AACF,UAAM,OAAO,CAAC,SAAS,WAAW,KAAK,SAAS;AAChD,QAAI,OAAO,IAAK,MAAK,KAAK,YAAY,OAAO,GAAG;AAChD,SAAK,KAAK,OAAO,KAAK,GAAG;AACzB,UAAM,OAAO,IAAI;AAEjB,UAAM,OAAO,OAAO,SAAS,KAAK,KAAK,KAAK,OAAO,MAAM,IAAI;AAC7D,QAAI,CAAC,GAAG,WAAW,IAAI,EAAG,OAAM,IAAI,MAAM,IAAI,OAAO,MAAM,uBAAuB,OAAO,GAAG,EAAE;AAE9F,UAAM,OAAO,cAAc,IAAI;AAC/B,QAAI,CAAC,KAAK,OAAQ,OAAM,IAAI,MAAM,wBAAwB,OAAO,GAAG,GAAG,OAAO,SAAS,IAAI,OAAO,MAAM,KAAK,EAAE,EAAE;AACjH,WAAO,EAAE,QAAQ,KAAK,IAAI,UAAU,GAAG,QAAQ;AAAA,EACjD,SAAS,KAAK;AACZ,YAAQ;AACR,UAAM;AAAA,EACR;AACF;AAGA,eAAsB,aACpB,QACA,UAAU,GAAG,OAAO,GACpB,YAA0B,OAC+B;AACzD,QAAM,MAAM,GAAG,YAAY,KAAK,KAAK,SAAS,mBAAmB,CAAC;AAClE,QAAM,UAAU,MAAY,GAAG,OAAO,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC3E,MAAI;AACF,UAAM,MAAM,MAAM,UAAU,OAAO,KAAK,EAAE,UAAU,SAAS,CAAC;AAC9D,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,YAAY,OAAO,GAAG,iBAAiB,IAAI,MAAM,EAAE;AAChF,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,KAAK,SAAS,gBAAiB,OAAM,IAAI,MAAM,GAAG,OAAO,GAAG,uBAAuB,kBAAkB,OAAO,YAAY;AAC5H,OAAG,cAAc,KAAK,KAAK,KAAK,UAAU,GAAG,IAAI;AACjD,WAAO,EAAE,QAAQ,CAAC,WAAW,GAAG,CAAC,GAAG,QAAQ;AAAA,EAC9C,SAAS,KAAK;AACZ,YAAQ;AACR,UAAM;AAAA,EACR;AACF;AAGA,eAAsB,MAAM,QAA8E;AACxG,MAAI,OAAO,SAAS,OAAQ,QAAO,EAAE,QAAQ,MAAM,cAAc,MAAM,GAAG,SAAS,MAAM;AAAA,EAAC,EAAE;AAC5F,MAAI,OAAO,SAAS,MAAO,QAAO,aAAa,MAAM;AACrD,SAAO,aAAa,MAAM;AAC5B;AAGO,SAAS,eAAe,OAAoB,aAA6B;AAC9E,QAAM,QAAQ,CAAC,qBAAgB,MAAM,IAAI,KAAK,EAAE;AAChD,QAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,QAAQ,MAAM,GAAG,EAAE;AAC/E,aAAW,KAAK,CAAC,GAAG,MAAM,SAAS,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,cAAc,EAAE,OAAO,CAAC,GAAG;AAC5F,UAAM,OAAO,EAAE,QAAQ,OAAO,GAAG,EAAE,KAAK,OAAO,IAAI,EAAE,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC7E,UAAM,OAAO,iBAAiB,EAAE,SAAS,EAAE,IAAI,IAAI,yBAAoB;AACvE,UAAM,KAAK,KAAK,EAAE,QAAQ,OAAO,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,GAAG,IAAI,EAAE;AAAA,EACvE;AACA,MAAI,MAAM,SAAS,YAAY,QAAQ;AACrC,UAAM,IAAI,MAAM,SAAS,YAAY;AACrC,UAAM;AAAA,MACJ;AAAA,MACA,2BAAsB,CAAC,IAAI,MAAM,IAAI,WAAW,SAAS;AAAA,MACzD;AAAA,MACA,KAAK,WAAW;AAAA,IAClB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;",
|
|
6
6
|
"names": ["ref"]
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createRequire as __antbotCreateRequire } from 'node:module';
|
|
2
2
|
const require = __antbotCreateRequire(import.meta.url);
|
|
3
3
|
|
|
4
|
-
//
|
|
4
|
+
// daemon/src/skills/skills.ts
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// daemon/src/util/ids.ts
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
10
|
var newId = () => randomUUID();
|
|
11
11
|
var now = () => Date.now();
|
|
@@ -17,7 +17,7 @@ function slugify(name, existing = /* @__PURE__ */ new Set()) {
|
|
|
17
17
|
return slug;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
//
|
|
20
|
+
// daemon/src/skills/skills.ts
|
|
21
21
|
var SKILL_TEMPLATE = `## When to use it
|
|
22
22
|
|
|
23
23
|
Describe the trigger: what request or situation should make a bot reach for this skill instead
|
|
@@ -165,8 +165,8 @@ var SkillStore = class {
|
|
|
165
165
|
* `allowMultiple` is set, so a caller cannot install a hundred skills by accident.
|
|
166
166
|
*/
|
|
167
167
|
async installFromSource(source, opts = {}) {
|
|
168
|
-
const { stage, copyTree, renderManifest } = await import("./install-
|
|
169
|
-
const parsed = (await import("./install-
|
|
168
|
+
const { stage, copyTree, renderManifest } = await import("./install-KTEW2CW3.js");
|
|
169
|
+
const parsed = (await import("./install-KTEW2CW3.js")).parseSkillSource(source);
|
|
170
170
|
const { staged, cleanup } = await stage(parsed);
|
|
171
171
|
try {
|
|
172
172
|
if (staged.length > 1 && !opts.allowMultiple) {
|
|
@@ -307,4 +307,4 @@ export {
|
|
|
307
307
|
MultipleSkillsError,
|
|
308
308
|
SkillStore
|
|
309
309
|
};
|
|
310
|
-
//# sourceMappingURL=chunk-
|
|
310
|
+
//# sourceMappingURL=chunk-MSSHR6SW.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../daemon/src/skills/skills.ts", "../../daemon/src/util/ids.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Store } from '../db/store.js';\nimport { slugify } from '../util/ids.js';\nimport type { Skill } from '@antbot/contract';\n\n/**\n * A skill is a directory `<skillsDir>/<slug>/SKILL.md` with a YAML-ish frontmatter block\n * (name, description) followed by a markdown body in the 6-part shape from outline \u00A78:\n * when to use it, required inputs and access, sequence of work, how to validate the result,\n * what to return, what requires approval.\n */\n\nexport const SKILL_TEMPLATE = `## When to use it\n\nDescribe the trigger: what request or situation should make a bot reach for this skill instead\nof improvising. Be specific enough that a bot with this skill enabled recognizes the moment.\n\n## Required inputs and access\n\nList what the skill needs before it can run: source systems, connectors/MCP servers, files,\ncredentials, or information the user must supply. Say what happens if something required is\nmissing.\n\n## Sequence of work\n\nWrite the ordered steps the bot should follow. Prefer \"gather \u2192 draft/reconcile \u2192 recommend\"\nover \"act immediately\" \u2014 automate preparation before execution.\n\n## How to validate the result\n\nState how the bot should check its own output before returning it: what to cross-check, what\ncounts as \"current\" data, and what stale-data policy applies. Per outline \u00A78: **if the source\ndata is unavailable, report the failure instead of using old data.**\n\n## What to return\n\nDescribe the shape of the deliverable: a document, a spreadsheet, a draft message, a linked\nwatch list, or a recommendation with evidence. Separate facts found, assumptions, actions\nalready taken, actions waiting for approval, and open questions where relevant.\n\n## What requires approval\n\nName the actions this skill must never take without an explicit human \"go ahead\": sending,\npublishing, purchasing, deleting, overwriting, or any production change. This section should\nnever be empty \u2014 every skill has an approval boundary.\n`;\n\nexport interface WriteSkillInput {\n name: string;\n description?: string;\n bodyMd: string;\n source?: 'user' | 'taught' | 'imported';\n}\n\nexport interface InstalledSkill {\n skill: Skill;\n executables: string[];\n manifestText: string;\n replaced: boolean;\n}\n\nexport interface ParsedSkillFile {\n name: string;\n description: string;\n bodyMd: string;\n}\n\n/** Parse the `---\\nname: \"...\"\\ndescription: \"...\"\\n---\\n<body>` shape. Pure, no I/O. */\nexport function parseFrontmatter(md: string): ParsedSkillFile {\n const m = md.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n if (!m) return { name: '', description: '', bodyMd: md };\n const [, fm, rest] = m;\n const data: Record<string, string> = {};\n const lines = (fm ?? '').split(/\\r?\\n/);\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const idx = line.indexOf(':');\n if (idx === -1 || /^\\s/.test(line)) continue; // continuation lines are consumed below\n const key = line.slice(0, idx).trim();\n let value = line.slice(idx + 1).trim();\n\n // YAML block scalars: `>` folds newlines into spaces, `|` keeps them. Published\n // skills use both for long descriptions, and the description is what the model\n // matches on \u2014 dropping it to a bare \">\" makes the skill invisible.\n const block = /^([>|])([-+]?)$/.exec(value);\n if (block) {\n const folded = block[1] === '>';\n const collected: string[] = [];\n while (i + 1 < lines.length) {\n const next = lines[i + 1]!;\n if (next.trim() !== '' && !/^\\s/.test(next)) break; // next top-level key\n collected.push(next.trim());\n i++;\n }\n while (collected.length && collected[collected.length - 1] === '') collected.pop();\n value = folded\n ? collected.filter((l) => l !== '').join(' ')\n : collected.join('\\n');\n // A folded block separates paragraphs (blank lines) with a newline.\n if (folded && collected.includes('')) {\n value = collected\n .reduce<string[]>((acc, l) => {\n if (l === '') acc.push('');\n else if (acc.length && acc[acc.length - 1] !== '') acc[acc.length - 1] += ` ${l}`;\n else acc[acc.length - 1] = l;\n return acc;\n }, [''])\n .filter((para) => para !== '')\n .join('\\n');\n }\n data[key] = value;\n continue;\n }\n\n if (value.startsWith('\"') && value.endsWith('\"') && value.length >= 2) {\n value = value.slice(1, -1).replace(/\\\\\"/g, '\"');\n }\n data[key] = value;\n }\n return {\n name: data.name ?? '',\n description: data.description ?? '',\n bodyMd: (rest ?? '').replace(/^\\r?\\n/, ''),\n };\n}\n\n/** Render a SKILL.md file from its parts. Pure, no I/O. */\nexport function renderSkillFile(input: { name: string; description: string; bodyMd: string }): string {\n const esc = (s: string): string => s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n return `---\\nname: \"${esc(input.name)}\"\\ndescription: \"${esc(input.description)}\"\\n---\\n\\n${input.bodyMd.trim()}\\n`;\n}\n\n/**\n * Raised when a source resolves to more than one skill and the caller did not opt in.\n * Carries the names so the caller can tell the human (or the model) what to narrow to.\n */\nexport class MultipleSkillsError extends Error {\n constructor(\n readonly source: string,\n readonly names: string[],\n ) {\n super(`\"${source}\" contains ${names.length} skills, not one.`);\n this.name = 'MultipleSkillsError';\n }\n}\n\nexport class SkillStore {\n constructor(\n private store: Store,\n private skillsDir: string,\n ) {}\n\n private slugDir(slug: string): string {\n return path.join(this.skillsDir, slug);\n }\n\n /** Resolve a stored skill path and assert it is inside the skills dir (no path traversal). */\n private assertInsideSkillsDir(candidate: string): string {\n const root = path.resolve(this.skillsDir) + path.sep;\n const resolved = path.resolve(candidate);\n if (resolved !== path.resolve(this.skillsDir) && !resolved.startsWith(root)) {\n throw new Error(`Refusing to touch a skill path outside the skills directory: ${candidate}`);\n }\n return resolved;\n }\n\n /** Create (or overwrite by slug) a skill directory + SKILL.md, and register it. */\n writeSkill(input: WriteSkillInput): Skill {\n const existing = new Set(this.store.listSkills().map((s) => s.slug));\n const slug = slugify(input.name, existing);\n const dir = this.assertInsideSkillsDir(this.slugDir(slug));\n fs.mkdirSync(dir, { recursive: true });\n const content = renderSkillFile({\n name: input.name,\n description: input.description ?? '',\n bodyMd: input.bodyMd,\n });\n fs.writeFileSync(path.join(dir, 'SKILL.md'), content, 'utf8');\n return this.store.createSkill({\n slug,\n name: input.name,\n description: input.description,\n path: dir,\n source: input.source,\n });\n }\n\n /**\n * Install every skill found at `source` and register it. Existing slugs are replaced in\n * place so re-installing upgrades rather than accumulating copies.\n *\n * Throws `MultipleSkillsError` if `source` holds more than one skill unless\n * `allowMultiple` is set, so a caller cannot install a hundred skills by accident.\n */\n async installFromSource(\n source: string,\n opts: { allowMultiple?: boolean } = {},\n ): Promise<InstalledSkill[]> {\n const { stage, copyTree, renderManifest } = await import('./install.js');\n const parsed = (await import('./install.js')).parseSkillSource(source);\n const { staged, cleanup } = await stage(parsed);\n try {\n // Installing a whole monorepo when one skill was wanted is easy to do by accident and\n // tedious to undo, so a multi-skill source has to be asked for explicitly.\n if (staged.length > 1 && !opts.allowMultiple) {\n throw new MultipleSkillsError(source, staged.map((sk) => sk.name));\n }\n const out: InstalledSkill[] = [];\n for (const skill of staged) {\n const existing = this.store.getSkillBySlug(slugify(skill.name, new Set()));\n const others = new Set(this.store.listSkills().map((x) => x.slug));\n if (existing) others.delete(existing.slug);\n const slug = existing?.slug ?? slugify(skill.name, others);\n\n const dir = this.assertInsideSkillsDir(this.slugDir(slug));\n fs.rmSync(dir, { recursive: true, force: true });\n copyTree(skill.dir, dir);\n\n const registered = existing\n ? (this.store.updateSkill?.(existing.id, { name: skill.name, description: skill.description }) ?? existing)\n : this.store.createSkill({\n slug, name: skill.name, description: skill.description, path: dir, source: 'imported',\n });\n\n // Installed skills are held to the same spec as the ones ant-bot ships. This never\n // blocks an install \u2014 a third-party skill with a sloppy frontmatter still works \u2014 but\n // a `name` that does not match its directory makes the skill impossible for a bot to\n // enable, and silence about that is how it stays broken.\n const { validateSkillDir, formatSpecViolations } = await import('./spec.js');\n const specNotes = formatSpecViolations(validateSkillDir(dir));\n\n out.push({\n skill: registered,\n executables: skill.manifest.executables,\n manifestText: renderManifest(skill, dir) + specNotes,\n replaced: Boolean(existing),\n });\n }\n return out;\n } finally {\n cleanup();\n }\n }\n\n /** Read a skill's SKILL.md and return it with the parsed body (frontmatter stripped). */\n readSkill(id: string): (Skill & { bodyMd: string }) | null {\n const skill = this.store.getSkill(id);\n if (!skill) return null;\n const file = path.join(skill.path, 'SKILL.md');\n if (!fs.existsSync(file)) return { ...skill, bodyMd: '' };\n const raw = fs.readFileSync(file, 'utf8');\n const { bodyMd } = parseFrontmatter(raw);\n return { ...skill, bodyMd };\n }\n\n /** Remove a skill's directory and its db row. Guards against a maliciously escaped path. */\n deleteSkill(id: string): void {\n const skill = this.store.getSkill(id);\n if (!skill) return;\n const resolved = this.assertInsideSkillsDir(skill.path);\n fs.rmSync(resolved, { recursive: true, force: true });\n this.store.deleteSkill(id);\n }\n\n /**\n * Bring the registry back in line with what is actually on disk.\n *\n * A row can outlive its directory \u2014 a skill removed by hand, or a layout migration that\n * moved files without rewriting paths \u2014 and the UI then lists skills that cannot load.\n * Rows whose directory moved are repaired in place so bot assignments survive; rows with\n * nothing left on disk are dropped. Returns what it did, for the boot log.\n */\n reconcile(): { repaired: string[]; removed: string[] } {\n const repaired: string[] = [];\n const removed: string[] = [];\n for (const skill of this.store.listSkills()) {\n if (fs.existsSync(path.join(skill.path, 'SKILL.md'))) continue;\n const expected = path.join(this.skillsDir, skill.slug);\n if (fs.existsSync(path.join(expected, 'SKILL.md'))) {\n this.store.updateSkill(skill.id, { path: expected });\n repaired.push(skill.slug);\n } else {\n this.store.deleteSkill(skill.id);\n removed.push(skill.slug);\n }\n }\n return { repaired, removed };\n }\n\n /**\n * Re-read `name`/`description` from disk for the given slugs and update their rows.\n *\n * Registered names are not cosmetic \u2014 `manager.ts` hands them to the SDK as `enabledSkills`,\n * so a row whose name has drifted from its SKILL.md silently stops matching and the skill\n * quietly disappears from every bot that had it enabled. Any writer of a skill file that a\n * row already points at has to call this; `syncFromDisk` cannot, since it only ever looks at\n * slugs the db has never seen. Returns the slugs whose stored metadata actually changed.\n */\n refreshFromDisk(slugs: string[]): string[] {\n const changed: string[] = [];\n for (const slug of slugs) {\n const registered = this.store.getSkillBySlug(slug);\n if (!registered) continue;\n const file = path.join(this.skillsDir, slug, 'SKILL.md');\n if (!fs.existsSync(file)) continue;\n const { name, description } = parseFrontmatter(fs.readFileSync(file, 'utf8'));\n const nextName = name || registered.name;\n if (nextName === registered.name && description === (registered.description ?? '')) continue;\n this.store.updateSkill(registered.id, { name: nextName, description });\n changed.push(slug);\n }\n return changed;\n }\n\n /**\n * Scan the skills dir at boot and register any SKILL.md not yet known to the db, so users\n * can drop skills in by hand. Idempotent: already-registered slugs are left untouched.\n */\n syncFromDisk(): Skill[] {\n if (!fs.existsSync(this.skillsDir)) return [];\n const added: Skill[] = [];\n for (const entry of fs.readdirSync(this.skillsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const slug = entry.name;\n const dir = path.join(this.skillsDir, slug);\n const file = path.join(dir, 'SKILL.md');\n if (!fs.existsSync(file)) continue;\n if (this.store.getSkillBySlug(slug)) continue;\n const raw = fs.readFileSync(file, 'utf8');\n const { name, description } = parseFrontmatter(raw);\n const skill = this.store.createSkill({\n slug,\n name: name || slug,\n description,\n path: dir,\n source: 'imported',\n });\n added.push(skill);\n }\n return added;\n }\n}\n", "import { randomUUID } from 'node:crypto';\nexport const newId = (): string => randomUUID();\nexport const now = (): number => Date.now();\nexport function slugify(name: string, existing: Set<string> = new Set()): string {\n const base =\n name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 40) || 'bot';\n let slug = base;\n let n = 2;\n while (existing.has(slug)) slug = `${base}-${n++}`;\n return slug;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|