synomem 0.1.1 → 0.3.0
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/ARCHITECTURE.md +2 -2
- package/CHANGELOG.md +37 -0
- package/README.md +26 -13
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +379 -51
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +131 -17
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +489 -76
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +8 -8
- package/dist/import.d.ts +356 -13
- package/dist/import.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +213 -31
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp-server.js +54 -8
- package/dist/mcp-server.js.map +1 -1
- package/dist/ports/repository.d.ts +21 -1
- package/dist/ports/repository.d.ts.map +1 -1
- package/dist/projections.d.ts +26 -1
- package/dist/projections.d.ts.map +1 -1
- package/dist/projections.js +208 -44
- package/dist/projections.js.map +1 -1
- package/dist/remote.d.ts +82 -9
- package/dist/remote.d.ts.map +1 -1
- package/dist/remote.js +53 -2
- package/dist/remote.js.map +1 -1
- package/dist/schemas.d.ts +476 -21
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +204 -26
- package/dist/schemas.js.map +1 -1
- package/dist/service.d.ts +82 -10
- package/dist/service.d.ts.map +1 -1
- package/dist/skill-install.d.ts +8 -2
- package/dist/skill-install.d.ts.map +1 -1
- package/dist/skill-install.js +6 -11
- package/dist/skill-install.js.map +1 -1
- package/dist/storage.d.ts +51 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +366 -36
- package/dist/storage.js.map +1 -1
- package/dist/types.d.ts +310 -38
- package/dist/types.d.ts.map +1 -1
- package/docs/cli.md +53 -20
- package/docs/examples.md +4 -4
- package/docs/mcp.md +12 -4
- package/docs/skill.md +10 -7
- package/docs/storage-format.md +4 -4
- package/openapi/synomem-v1.yaml +24 -24
- package/package.json +1 -1
- package/skills/synomem/SKILL.md +24 -8
- package/skills/synomem/agents/openai.yaml +1 -1
- package/skills/synomem/references/examples.md +1 -1
- package/src/cli.ts +610 -95
- package/src/client.ts +587 -79
- package/src/config.ts +8 -8
- package/src/index.ts +11 -1
- package/src/mcp/index.ts +265 -30
- package/src/mcp-server.ts +58 -8
- package/src/ports/repository.ts +21 -0
- package/src/projections.ts +209 -44
- package/src/remote.ts +166 -8
- package/src/schemas.ts +211 -26
- package/src/service.ts +85 -7
- package/src/skill-install.ts +14 -17
- package/src/storage.ts +472 -34
- package/src/types.ts +332 -39
package/src/schemas.ts
CHANGED
|
@@ -24,6 +24,30 @@ export const agentIdSchema = z
|
|
|
24
24
|
.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, 'Use lowercase ASCII letters, digits, and hyphens')
|
|
25
25
|
.refine((id) => !reservedIds.has(id), 'Reserved agent ID');
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* An alias as written, folded to the canonical lowercase form.
|
|
29
|
+
*
|
|
30
|
+
* People type `Mike` and `mike` interchangeably, so accepting either and
|
|
31
|
+
* storing one keeps a single alias from being claimed twice in two casings.
|
|
32
|
+
*/
|
|
33
|
+
export const agentAliasSchema = z
|
|
34
|
+
.string()
|
|
35
|
+
.trim()
|
|
36
|
+
.min(1)
|
|
37
|
+
.max(63)
|
|
38
|
+
.regex(/^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$/, 'Use ASCII letters, digits, and hyphens')
|
|
39
|
+
.transform((alias) => alias.toLowerCase())
|
|
40
|
+
.refine((alias) => !reservedIds.has(alias), 'Reserved agent ID');
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A name offered for lookup, which may be an ID or an alias in any casing.
|
|
44
|
+
*
|
|
45
|
+
* Lookups are deliberately more permissive than writes: rejecting `Mycroft`
|
|
46
|
+
* for its capital letter would tell the caller nothing useful about whether
|
|
47
|
+
* that agent exists.
|
|
48
|
+
*/
|
|
49
|
+
export const agentLookupSchema = z.string().trim().min(1).max(100);
|
|
50
|
+
|
|
27
51
|
export const actorSchema = z.object({
|
|
28
52
|
kind: z.enum(['human', 'agent', 'system']),
|
|
29
53
|
id: agentIdSchema,
|
|
@@ -88,7 +112,7 @@ export const evidenceSchema = z
|
|
|
88
112
|
export const profileSchema = z.object({
|
|
89
113
|
id: agentIdSchema,
|
|
90
114
|
displayName: z.string().trim().min(1).max(200),
|
|
91
|
-
aliases: z.array(
|
|
115
|
+
aliases: z.array(agentAliasSchema).max(50).optional(),
|
|
92
116
|
description: z.string().trim().max(2000).optional(),
|
|
93
117
|
createdAt: z.string().datetime({ offset: true }),
|
|
94
118
|
metadata: metadataSchema.optional(),
|
|
@@ -97,6 +121,21 @@ export const profileSchema = z.object({
|
|
|
97
121
|
export const createAgentSchema = profileSchema.omit({ createdAt: true });
|
|
98
122
|
export const updateAgentSchema = createAgentSchema.omit({ id: true }).partial();
|
|
99
123
|
|
|
124
|
+
/**
|
|
125
|
+
* A runtime binding is a claim about where an agent runs, so the fields stay
|
|
126
|
+
* deliberately loose: Synomem should record a runtime it has never heard of
|
|
127
|
+
* rather than reject an install it cannot classify.
|
|
128
|
+
*/
|
|
129
|
+
export const bindRuntimeSchema = z
|
|
130
|
+
.object({
|
|
131
|
+
agentId: z.string().trim().min(1).max(100),
|
|
132
|
+
runtime: z.string().trim().min(1).max(100),
|
|
133
|
+
profile: z.string().trim().min(1).max(100).optional(),
|
|
134
|
+
installationId: z.string().trim().min(1).max(100).optional(),
|
|
135
|
+
capabilities: metadataSchema.optional(),
|
|
136
|
+
})
|
|
137
|
+
.strict();
|
|
138
|
+
|
|
100
139
|
const baseEventSchema = z.object({
|
|
101
140
|
schemaVersion: z.literal(1),
|
|
102
141
|
id: z.string().regex(/^[0-9A-HJKMNP-TV-Z]{26}$/),
|
|
@@ -218,7 +257,48 @@ const noteArchivedSchema = baseEventSchema.extend({
|
|
|
218
257
|
noteId: z.string().length(26),
|
|
219
258
|
});
|
|
220
259
|
|
|
221
|
-
|
|
260
|
+
/**
|
|
261
|
+
* Post events. A post carries no recipient, assignee or visibility: it is
|
|
262
|
+
* addressed to the workspace, and workspace membership is the audience. Adding
|
|
263
|
+
* a visibility field would create a second, weaker way to hide a record.
|
|
264
|
+
*/
|
|
265
|
+
const postFields = {
|
|
266
|
+
title: z
|
|
267
|
+
.string()
|
|
268
|
+
.trim()
|
|
269
|
+
.min(1)
|
|
270
|
+
.max(200)
|
|
271
|
+
.regex(/^[^\r\n]+$/),
|
|
272
|
+
body: z.string().trim().min(1).max(32_000),
|
|
273
|
+
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
274
|
+
};
|
|
275
|
+
const postCreatedSchema = baseEventSchema.extend({
|
|
276
|
+
type: z.literal('post.created'),
|
|
277
|
+
...postFields,
|
|
278
|
+
replyTo: z.string().length(26).optional(),
|
|
279
|
+
});
|
|
280
|
+
const postEditedSchema = baseEventSchema.extend({
|
|
281
|
+
type: z.literal('post.edited'),
|
|
282
|
+
postId: z.string().length(26),
|
|
283
|
+
...postFields,
|
|
284
|
+
});
|
|
285
|
+
const postArchivedSchema = baseEventSchema.extend({
|
|
286
|
+
type: z.literal('post.archived'),
|
|
287
|
+
postId: z.string().length(26),
|
|
288
|
+
reason: z.string().trim().min(1).max(2000).optional(),
|
|
289
|
+
});
|
|
290
|
+
const postAcknowledgedSchema = baseEventSchema.extend({
|
|
291
|
+
type: z.literal('post.acknowledged'),
|
|
292
|
+
postId: z.string().length(26),
|
|
293
|
+
note: z.string().trim().min(1).max(2000).optional(),
|
|
294
|
+
});
|
|
295
|
+
const postAcknowledgmentWithdrawnSchema = baseEventSchema.extend({
|
|
296
|
+
type: z.literal('post.acknowledgment.withdrawn'),
|
|
297
|
+
postId: z.string().length(26),
|
|
298
|
+
reason: z.string().trim().min(1).max(2000).optional(),
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const taskDueSchema = z.discriminatedUnion('kind', [
|
|
222
302
|
z.object({
|
|
223
303
|
kind: z.literal('date'),
|
|
224
304
|
date: z
|
|
@@ -247,7 +327,7 @@ const todoDueSchema = z.discriminatedUnion('kind', [
|
|
|
247
327
|
}, 'Use a valid IANA time-zone identifier'),
|
|
248
328
|
}),
|
|
249
329
|
]);
|
|
250
|
-
const
|
|
330
|
+
const taskFields = {
|
|
251
331
|
title: z
|
|
252
332
|
.string()
|
|
253
333
|
.trim()
|
|
@@ -256,15 +336,64 @@ const todoFields = {
|
|
|
256
336
|
.regex(/^[^\r\n]+$/),
|
|
257
337
|
description: z.string().trim().max(16_000).optional(),
|
|
258
338
|
priority: z.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)]),
|
|
259
|
-
due:
|
|
339
|
+
due: taskDueSchema.optional(),
|
|
260
340
|
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
261
341
|
visibility: z.enum(['private', 'workspace', 'public']),
|
|
262
342
|
};
|
|
263
|
-
const
|
|
264
|
-
type: z.literal('
|
|
343
|
+
const taskCreatedSchema = baseEventSchema.extend({
|
|
344
|
+
type: z.literal('task.created'),
|
|
265
345
|
assigneeAgentId: agentIdSchema,
|
|
266
346
|
assigneeDisplayName: z.string().trim().min(1).max(200),
|
|
267
347
|
requiresAcceptance: z.boolean(),
|
|
348
|
+
...taskFields,
|
|
349
|
+
});
|
|
350
|
+
const taskUpdatedSchema = baseEventSchema.extend({
|
|
351
|
+
type: z.literal('task.updated'),
|
|
352
|
+
taskId: z.string().length(26),
|
|
353
|
+
...taskFields,
|
|
354
|
+
});
|
|
355
|
+
const taskCompletedSchema = baseEventSchema.extend({
|
|
356
|
+
type: z.literal('task.completed'),
|
|
357
|
+
taskId: z.string().length(26),
|
|
358
|
+
note: z.string().trim().min(1).max(2000).optional(),
|
|
359
|
+
});
|
|
360
|
+
const taskReopenedSchema = baseEventSchema.extend({
|
|
361
|
+
type: z.literal('task.reopened'),
|
|
362
|
+
taskId: z.string().length(26),
|
|
363
|
+
});
|
|
364
|
+
const taskAcceptedSchema = baseEventSchema.extend({
|
|
365
|
+
type: z.literal('task.accepted'),
|
|
366
|
+
taskId: z.string().length(26),
|
|
367
|
+
// Optional: accepting without comment is a complete answer on its own.
|
|
368
|
+
response: z.string().trim().min(1).max(2000).optional(),
|
|
369
|
+
});
|
|
370
|
+
const taskRejectedSchema = baseEventSchema.extend({
|
|
371
|
+
type: z.literal('task.rejected'),
|
|
372
|
+
taskId: z.string().length(26),
|
|
373
|
+
// Required. A refusal with no reason tells the assigner only that the work
|
|
374
|
+
// will not happen, not whether to reassign it, wait, or change the request.
|
|
375
|
+
response: z.string().trim().min(1).max(2000),
|
|
376
|
+
});
|
|
377
|
+
const taskCanceledSchema = baseEventSchema.extend({
|
|
378
|
+
type: z.literal('task.canceled'),
|
|
379
|
+
taskId: z.string().length(26),
|
|
380
|
+
reason: z.string().trim().min(1).max(2000).optional(),
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* A Todo is owner-only, so it carries no assignee and no acceptance lifecycle.
|
|
385
|
+
* `details` rather than `description` keeps it lexically distinct from a Task in
|
|
386
|
+
* every payload, which makes a mix-up visible in a log rather than silent.
|
|
387
|
+
*/
|
|
388
|
+
const todoFields = {
|
|
389
|
+
title: z.string().trim().min(1).max(200),
|
|
390
|
+
details: z.string().trim().min(1).max(4000).optional(),
|
|
391
|
+
priority: z.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)]),
|
|
392
|
+
due: taskDueSchema.optional(),
|
|
393
|
+
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
394
|
+
};
|
|
395
|
+
const todoCreatedSchema = baseEventSchema.extend({
|
|
396
|
+
type: z.literal('todo.created'),
|
|
268
397
|
...todoFields,
|
|
269
398
|
});
|
|
270
399
|
const todoUpdatedSchema = baseEventSchema.extend({
|
|
@@ -281,22 +410,22 @@ const todoReopenedSchema = baseEventSchema.extend({
|
|
|
281
410
|
type: z.literal('todo.reopened'),
|
|
282
411
|
todoId: z.string().length(26),
|
|
283
412
|
});
|
|
284
|
-
const todoAcceptedSchema = baseEventSchema.extend({
|
|
285
|
-
type: z.literal('todo.accepted'),
|
|
286
|
-
todoId: z.string().length(26),
|
|
287
|
-
});
|
|
288
|
-
const todoRejectedSchema = baseEventSchema.extend({
|
|
289
|
-
type: z.literal('todo.rejected'),
|
|
290
|
-
todoId: z.string().length(26),
|
|
291
|
-
reason: z.string().trim().min(1).max(2000).optional(),
|
|
292
|
-
});
|
|
293
413
|
const todoCanceledSchema = baseEventSchema.extend({
|
|
294
414
|
type: z.literal('todo.canceled'),
|
|
295
415
|
todoId: z.string().length(26),
|
|
296
416
|
reason: z.string().trim().min(1).max(2000).optional(),
|
|
297
417
|
});
|
|
418
|
+
const todoArchivedSchema = baseEventSchema.extend({
|
|
419
|
+
type: z.literal('todo.archived'),
|
|
420
|
+
todoId: z.string().length(26),
|
|
421
|
+
});
|
|
298
422
|
|
|
299
423
|
export const eventSchema = z.discriminatedUnion('type', [
|
|
424
|
+
postCreatedSchema,
|
|
425
|
+
postEditedSchema,
|
|
426
|
+
postArchivedSchema,
|
|
427
|
+
postAcknowledgedSchema,
|
|
428
|
+
postAcknowledgmentWithdrawnSchema,
|
|
300
429
|
kudosGivenSchema,
|
|
301
430
|
acknowledgedSchema,
|
|
302
431
|
revokedSchema,
|
|
@@ -308,13 +437,19 @@ export const eventSchema = z.discriminatedUnion('type', [
|
|
|
308
437
|
noteCreatedSchema,
|
|
309
438
|
noteRevisedSchema,
|
|
310
439
|
noteArchivedSchema,
|
|
440
|
+
taskCreatedSchema,
|
|
441
|
+
taskUpdatedSchema,
|
|
442
|
+
taskCompletedSchema,
|
|
443
|
+
taskReopenedSchema,
|
|
444
|
+
taskAcceptedSchema,
|
|
445
|
+
taskRejectedSchema,
|
|
446
|
+
taskCanceledSchema,
|
|
311
447
|
todoCreatedSchema,
|
|
312
448
|
todoUpdatedSchema,
|
|
313
449
|
todoCompletedSchema,
|
|
314
450
|
todoReopenedSchema,
|
|
315
|
-
todoAcceptedSchema,
|
|
316
|
-
todoRejectedSchema,
|
|
317
451
|
todoCanceledSchema,
|
|
452
|
+
todoArchivedSchema,
|
|
318
453
|
]);
|
|
319
454
|
|
|
320
455
|
const giveKudosInputSchema = kudosGivenSchema
|
|
@@ -388,6 +523,24 @@ export const sendMemoSchema = z
|
|
|
388
523
|
...mutationMetadata,
|
|
389
524
|
})
|
|
390
525
|
.strict();
|
|
526
|
+
export const createPostSchema = z
|
|
527
|
+
.object({
|
|
528
|
+
...postFields,
|
|
529
|
+
replyTo: z.string().length(26).optional(),
|
|
530
|
+
...mutationMetadata,
|
|
531
|
+
})
|
|
532
|
+
.strict();
|
|
533
|
+
export const updatePostSchema = z
|
|
534
|
+
.object({
|
|
535
|
+
postId: z.string().length(26),
|
|
536
|
+
expectedVersion: z.number().int().min(1),
|
|
537
|
+
title: postFields.title.optional(),
|
|
538
|
+
body: postFields.body.optional(),
|
|
539
|
+
tags: postFields.tags,
|
|
540
|
+
idempotencyKey: z.string().trim().min(1).max(200).optional(),
|
|
541
|
+
})
|
|
542
|
+
.strict();
|
|
543
|
+
|
|
391
544
|
export const createNoteSchema = z
|
|
392
545
|
.object({
|
|
393
546
|
ownerAgentId: agentIdSchema.optional(),
|
|
@@ -407,15 +560,44 @@ export const reviseNoteSchema = z
|
|
|
407
560
|
...mutationMetadata,
|
|
408
561
|
})
|
|
409
562
|
.strict();
|
|
410
|
-
export const
|
|
563
|
+
export const createTaskSchema = z
|
|
411
564
|
.object({
|
|
412
565
|
assigneeAgentId: agentIdSchema.optional(),
|
|
566
|
+
title: taskCreatedSchema.shape.title,
|
|
567
|
+
description: taskCreatedSchema.shape.description,
|
|
568
|
+
priority: taskCreatedSchema.shape.priority.optional(),
|
|
569
|
+
due: taskDueSchema.optional(),
|
|
570
|
+
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
571
|
+
visibility: z.enum(['private', 'workspace', 'public']).optional(),
|
|
572
|
+
...mutationMetadata,
|
|
573
|
+
})
|
|
574
|
+
.strict();
|
|
575
|
+
export const updateTaskSchema = z
|
|
576
|
+
.object({
|
|
577
|
+
taskId: z.string().length(26),
|
|
578
|
+
expectedVersion: z.number().int().min(1),
|
|
579
|
+
title: taskCreatedSchema.shape.title.optional(),
|
|
580
|
+
description: taskCreatedSchema.shape.description,
|
|
581
|
+
priority: taskCreatedSchema.shape.priority.optional(),
|
|
582
|
+
due: taskDueSchema.nullable().optional(),
|
|
583
|
+
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
584
|
+
visibility: z.enum(['private', 'workspace', 'public']).optional(),
|
|
585
|
+
...mutationMetadata,
|
|
586
|
+
})
|
|
587
|
+
.strict();
|
|
588
|
+
/**
|
|
589
|
+
* A Todo takes no assignee and no visibility: it belongs to its author and is
|
|
590
|
+
* always private. Omitting those fields from the input — rather than accepting
|
|
591
|
+
* and ignoring them — means an attempt to assign a Todo fails loudly instead of
|
|
592
|
+
* silently producing a private reminder nobody else can see.
|
|
593
|
+
*/
|
|
594
|
+
export const createTodoSchema = z
|
|
595
|
+
.object({
|
|
413
596
|
title: todoCreatedSchema.shape.title,
|
|
414
|
-
|
|
597
|
+
details: todoCreatedSchema.shape.details,
|
|
415
598
|
priority: todoCreatedSchema.shape.priority.optional(),
|
|
416
|
-
due:
|
|
599
|
+
due: taskDueSchema.optional(),
|
|
417
600
|
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
418
|
-
visibility: z.enum(['private', 'workspace', 'public']).optional(),
|
|
419
601
|
...mutationMetadata,
|
|
420
602
|
})
|
|
421
603
|
.strict();
|
|
@@ -424,23 +606,26 @@ export const updateTodoSchema = z
|
|
|
424
606
|
todoId: z.string().length(26),
|
|
425
607
|
expectedVersion: z.number().int().min(1),
|
|
426
608
|
title: todoCreatedSchema.shape.title.optional(),
|
|
427
|
-
|
|
609
|
+
details: todoCreatedSchema.shape.details,
|
|
428
610
|
priority: todoCreatedSchema.shape.priority.optional(),
|
|
429
|
-
due:
|
|
611
|
+
due: taskDueSchema.nullable().optional(),
|
|
430
612
|
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
431
|
-
visibility: z.enum(['private', 'workspace', 'public']).optional(),
|
|
432
613
|
...mutationMetadata,
|
|
433
614
|
})
|
|
434
615
|
.strict();
|
|
616
|
+
|
|
435
617
|
export const itemListInputSchema = z
|
|
436
618
|
.object({
|
|
437
619
|
kinds: z
|
|
438
|
-
.array(z.enum(['kudos', 'memo', 'note', 'todo']))
|
|
439
|
-
.max(
|
|
620
|
+
.array(z.enum(['kudos', 'memo', 'note', 'post', 'task', 'todo']))
|
|
621
|
+
.max(5)
|
|
440
622
|
.optional(),
|
|
441
623
|
participantAgentId: agentIdSchema.optional(),
|
|
442
624
|
actorId: agentIdSchema.optional(),
|
|
443
625
|
actorKind: z.enum(['human', 'agent', 'system']).optional(),
|
|
626
|
+
awaitingResponse: z.boolean().optional(),
|
|
627
|
+
awaitingSince: z.string().datetime({ offset: true }).optional(),
|
|
628
|
+
overdueAsOf: z.string().datetime({ offset: true }).optional(),
|
|
444
629
|
tag: kudosTagSchema.optional(),
|
|
445
630
|
status: z.string().trim().min(1).max(50).optional(),
|
|
446
631
|
pending: z.boolean().optional(),
|
package/src/service.ts
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ActorIdentity,
|
|
3
|
+
AgentDirectoryEntry,
|
|
3
4
|
AgentProfile,
|
|
5
|
+
CreatePostInput,
|
|
6
|
+
PostRecord,
|
|
7
|
+
PostRoster,
|
|
8
|
+
UpdatePostInput,
|
|
9
|
+
AgentResolution,
|
|
10
|
+
AgentRuntimeBinding,
|
|
11
|
+
BindRuntimeInput,
|
|
4
12
|
ChangePage,
|
|
5
13
|
ChangesInput,
|
|
6
14
|
CreateAgentInput,
|
|
7
15
|
CreateNoteInput,
|
|
8
16
|
CreateNoteResult,
|
|
17
|
+
CreateTaskInput,
|
|
9
18
|
CreateTodoInput,
|
|
10
19
|
CreateTodoResult,
|
|
20
|
+
CreateTaskResult,
|
|
11
21
|
DoctorResult,
|
|
12
22
|
GiveKudosInput,
|
|
13
23
|
GiveKudosResult,
|
|
@@ -27,8 +37,10 @@ import type {
|
|
|
27
37
|
ReviseNoteInput,
|
|
28
38
|
SendMemoInput,
|
|
29
39
|
SendMemoResult,
|
|
40
|
+
TaskRecord,
|
|
30
41
|
TodoRecord,
|
|
31
42
|
UpdateAgentInput,
|
|
43
|
+
UpdateTaskInput,
|
|
32
44
|
UpdateTodoInput,
|
|
33
45
|
} from './types.js';
|
|
34
46
|
|
|
@@ -45,7 +57,7 @@ export interface SynomemServiceCapabilities {
|
|
|
45
57
|
projections: {
|
|
46
58
|
writeWinsMarkdown: boolean;
|
|
47
59
|
writeMemoryMarkdown: boolean;
|
|
48
|
-
|
|
60
|
+
writeTasksMarkdown: boolean;
|
|
49
61
|
writeInboxEntries: boolean;
|
|
50
62
|
};
|
|
51
63
|
}
|
|
@@ -66,6 +78,33 @@ export interface SynomemDomainService {
|
|
|
66
78
|
update(id: string, changes: UpdateAgentInput): Promise<AgentProfile>;
|
|
67
79
|
get(idOrAlias: string): Promise<AgentProfile>;
|
|
68
80
|
list(): Promise<AgentProfile[]>;
|
|
81
|
+
resolve(query: string): Promise<AgentResolution>;
|
|
82
|
+
directory(): Promise<AgentDirectoryEntry[]>;
|
|
83
|
+
bindings(idOrAlias: string): Promise<AgentRuntimeBinding[]>;
|
|
84
|
+
bindRuntime(input: BindRuntimeInput): Promise<AgentRuntimeBinding>;
|
|
85
|
+
unbindRuntime(bindingId: string): Promise<boolean>;
|
|
86
|
+
};
|
|
87
|
+
readonly posts: {
|
|
88
|
+
create(input: CreatePostInput): Promise<{
|
|
89
|
+
record: PostRecord;
|
|
90
|
+
created: boolean;
|
|
91
|
+
deduplicated: boolean;
|
|
92
|
+
}>;
|
|
93
|
+
list(input?: Omit<ItemListInput, 'kinds'>): Promise<Page<ItemSummary>>;
|
|
94
|
+
get(id: string): Promise<PostRecord>;
|
|
95
|
+
update(input: UpdatePostInput): Promise<PostRecord>;
|
|
96
|
+
archive(input: {
|
|
97
|
+
postId: string;
|
|
98
|
+
reason?: string;
|
|
99
|
+
idempotencyKey?: string;
|
|
100
|
+
}): Promise<PostRecord>;
|
|
101
|
+
acknowledge(input: {
|
|
102
|
+
postId: string;
|
|
103
|
+
note?: string;
|
|
104
|
+
idempotencyKey?: string;
|
|
105
|
+
}): Promise<PostRecord>;
|
|
106
|
+
withdrawAcknowledgment(input: { postId: string; reason?: string }): Promise<PostRecord>;
|
|
107
|
+
roster(postId: string): Promise<PostRoster>;
|
|
69
108
|
};
|
|
70
109
|
readonly kudos: {
|
|
71
110
|
give(input: GiveKudosInput): Promise<GiveKudosResult>;
|
|
@@ -93,17 +132,43 @@ export interface SynomemDomainService {
|
|
|
93
132
|
revise(input: ReviseNoteInput): Promise<NoteRecord>;
|
|
94
133
|
archive(input: { noteId: string; idempotencyKey?: string }): Promise<NoteRecord>;
|
|
95
134
|
};
|
|
135
|
+
readonly tasks: {
|
|
136
|
+
create(input: CreateTaskInput): Promise<CreateTaskResult>;
|
|
137
|
+
list(input?: Omit<ItemListInput, 'kinds'>): Promise<Page<ItemSummary>>;
|
|
138
|
+
get(id: string): Promise<TaskRecord>;
|
|
139
|
+
update(input: UpdateTaskInput): Promise<TaskRecord>;
|
|
140
|
+
accept(input: {
|
|
141
|
+
taskId: string;
|
|
142
|
+
/** Optional: conditions, timing, or partial capability. */
|
|
143
|
+
response?: string;
|
|
144
|
+
idempotencyKey?: string;
|
|
145
|
+
}): Promise<TaskRecord>;
|
|
146
|
+
reject(input: {
|
|
147
|
+
taskId: string;
|
|
148
|
+
/** Required: a refusal the assigner cannot act on is barely an answer. */
|
|
149
|
+
response: string;
|
|
150
|
+
idempotencyKey?: string;
|
|
151
|
+
}): Promise<TaskRecord>;
|
|
152
|
+
complete(input: {
|
|
153
|
+
taskId: string;
|
|
154
|
+
note?: string;
|
|
155
|
+
idempotencyKey?: string;
|
|
156
|
+
}): Promise<TaskRecord>;
|
|
157
|
+
reopen(input: { taskId: string; idempotencyKey?: string }): Promise<TaskRecord>;
|
|
158
|
+
cancel(input: {
|
|
159
|
+
taskId: string;
|
|
160
|
+
reason?: string;
|
|
161
|
+
idempotencyKey?: string;
|
|
162
|
+
}): Promise<TaskRecord>;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Private self-reminders. No assignee, no acceptance, owner-only reads.
|
|
166
|
+
*/
|
|
96
167
|
readonly todos: {
|
|
97
168
|
create(input: CreateTodoInput): Promise<CreateTodoResult>;
|
|
98
169
|
list(input?: Omit<ItemListInput, 'kinds'>): Promise<Page<ItemSummary>>;
|
|
99
170
|
get(id: string): Promise<TodoRecord>;
|
|
100
171
|
update(input: UpdateTodoInput): Promise<TodoRecord>;
|
|
101
|
-
accept(input: { todoId: string; idempotencyKey?: string }): Promise<TodoRecord>;
|
|
102
|
-
reject(input: {
|
|
103
|
-
todoId: string;
|
|
104
|
-
reason?: string;
|
|
105
|
-
idempotencyKey?: string;
|
|
106
|
-
}): Promise<TodoRecord>;
|
|
107
172
|
complete(input: {
|
|
108
173
|
todoId: string;
|
|
109
174
|
note?: string;
|
|
@@ -115,6 +180,19 @@ export interface SynomemDomainService {
|
|
|
115
180
|
reason?: string;
|
|
116
181
|
idempotencyKey?: string;
|
|
117
182
|
}): Promise<TodoRecord>;
|
|
183
|
+
archive(input: { todoId: string; idempotencyKey?: string }): Promise<TodoRecord>;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Unanswered and overdue discovery. Derived from durable events; never a
|
|
187
|
+
* statement about whether an agent is reachable.
|
|
188
|
+
*/
|
|
189
|
+
readonly discovery: {
|
|
190
|
+
unanswered(
|
|
191
|
+
input?: Omit<ItemListInput, 'awaitingResponse' | 'pending'> & { olderThanHours?: number },
|
|
192
|
+
): Promise<Page<ItemSummary>>;
|
|
193
|
+
overdue(
|
|
194
|
+
input?: Omit<ItemListInput, 'overdueAsOf'> & { asOf?: string },
|
|
195
|
+
): Promise<Page<ItemSummary>>;
|
|
118
196
|
};
|
|
119
197
|
readonly items: {
|
|
120
198
|
list(input?: ItemListInput): Promise<Page<ItemSummary>>;
|
package/src/skill-install.ts
CHANGED
|
@@ -57,8 +57,14 @@ export interface SkillOptions {
|
|
|
57
57
|
apply?: boolean;
|
|
58
58
|
force?: boolean;
|
|
59
59
|
link?: boolean;
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
/**
|
|
61
|
+
* The agent this installation binds to.
|
|
62
|
+
*
|
|
63
|
+
* Only the canonical ID is written into the generated registration command.
|
|
64
|
+
* The display name and kind are read from the agent's profile at startup, so
|
|
65
|
+
* a harness cannot sign another agent's name to work it did.
|
|
66
|
+
*/
|
|
67
|
+
agentId?: string;
|
|
62
68
|
userHome?: string;
|
|
63
69
|
env?: NodeJS.ProcessEnv;
|
|
64
70
|
source?: string;
|
|
@@ -160,19 +166,10 @@ function shellQuote(value: string): string {
|
|
|
160
166
|
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
161
167
|
}
|
|
162
168
|
|
|
163
|
-
function mcpCommand(
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
): string | undefined {
|
|
168
|
-
if (!actorId) return undefined;
|
|
169
|
-
const identity = actorSchema.parse({
|
|
170
|
-
kind: 'agent',
|
|
171
|
-
id: actorId,
|
|
172
|
-
displayName: actorName ?? actorId,
|
|
173
|
-
});
|
|
174
|
-
const name = identity.displayName ?? identity.id;
|
|
175
|
-
const args = ['--actor-id', identity.id, '--actor-kind', 'agent', '--actor-name', name];
|
|
169
|
+
function mcpCommand(runtime: SkillRuntime, agentId?: string): string | undefined {
|
|
170
|
+
if (!agentId) return undefined;
|
|
171
|
+
const identity = actorSchema.parse({ kind: 'agent', id: agentId });
|
|
172
|
+
const args = ['--agent-id', identity.id];
|
|
176
173
|
if (runtime === 'codex') {
|
|
177
174
|
return `codex mcp add synomem -- synomem-mcp ${args.map(shellQuote).join(' ')}`;
|
|
178
175
|
}
|
|
@@ -258,7 +255,7 @@ export function skillStatus(options: SkillOptions = {}): SkillOperationResult {
|
|
|
258
255
|
packageVersion: packageVersion(),
|
|
259
256
|
locations,
|
|
260
257
|
mcpCommands: locations
|
|
261
|
-
.map((location) => mcpCommand(location.runtime, options.
|
|
258
|
+
.map((location) => mcpCommand(location.runtime, options.agentId))
|
|
262
259
|
.filter((value): value is string => Boolean(value)),
|
|
263
260
|
};
|
|
264
261
|
}
|
|
@@ -326,7 +323,7 @@ export function formatSkillResult(
|
|
|
326
323
|
lines.push('', 'Dry run only. Re-run with --yes to apply.');
|
|
327
324
|
if (result.mcpCommands.length) lines.push('', 'MCP registration:', ...result.mcpCommands);
|
|
328
325
|
else if (operation === 'install') {
|
|
329
|
-
lines.push('', 'Tip: add --
|
|
326
|
+
lines.push('', 'Tip: add --agent <agent-id> to print MCP registration commands.');
|
|
330
327
|
}
|
|
331
328
|
return lines.join('\n');
|
|
332
329
|
}
|