synomem 0.1.0 → 0.2.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 -1
- package/README.md +28 -15
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +311 -70
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +96 -17
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +333 -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 +207 -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 +156 -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 +18 -1
- package/dist/ports/repository.d.ts.map +1 -1
- package/dist/projections.d.ts +18 -1
- package/dist/projections.d.ts.map +1 -1
- package/dist/projections.js +137 -44
- package/dist/projections.js.map +1 -1
- package/dist/remote.d.ts +57 -9
- package/dist/remote.d.ts.map +1 -1
- package/dist/remote.js +43 -2
- package/dist/remote.js.map +1 -1
- package/dist/schemas.d.ts +302 -21
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +142 -26
- package/dist/schemas.js.map +1 -1
- package/dist/service.d.ts +57 -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 +41 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +254 -36
- package/dist/storage.js.map +1 -1
- package/dist/types.d.ts +213 -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 +572 -173
- package/src/client.ts +391 -79
- package/src/config.ts +8 -8
- package/src/index.ts +11 -1
- package/src/mcp/index.ts +189 -30
- package/src/mcp-server.ts +58 -8
- package/src/ports/repository.ts +16 -0
- package/src/projections.ts +139 -44
- package/src/remote.ts +118 -8
- package/src/schemas.ts +147 -26
- package/src/service.ts +59 -7
- package/src/skill-install.ts +14 -17
- package/src/storage.ts +326 -34
- package/src/types.ts +228 -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,7 @@ const noteArchivedSchema = baseEventSchema.extend({
|
|
|
218
257
|
noteId: z.string().length(26),
|
|
219
258
|
});
|
|
220
259
|
|
|
221
|
-
const
|
|
260
|
+
const taskDueSchema = z.discriminatedUnion('kind', [
|
|
222
261
|
z.object({
|
|
223
262
|
kind: z.literal('date'),
|
|
224
263
|
date: z
|
|
@@ -247,7 +286,7 @@ const todoDueSchema = z.discriminatedUnion('kind', [
|
|
|
247
286
|
}, 'Use a valid IANA time-zone identifier'),
|
|
248
287
|
}),
|
|
249
288
|
]);
|
|
250
|
-
const
|
|
289
|
+
const taskFields = {
|
|
251
290
|
title: z
|
|
252
291
|
.string()
|
|
253
292
|
.trim()
|
|
@@ -256,15 +295,64 @@ const todoFields = {
|
|
|
256
295
|
.regex(/^[^\r\n]+$/),
|
|
257
296
|
description: z.string().trim().max(16_000).optional(),
|
|
258
297
|
priority: z.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)]),
|
|
259
|
-
due:
|
|
298
|
+
due: taskDueSchema.optional(),
|
|
260
299
|
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
261
300
|
visibility: z.enum(['private', 'workspace', 'public']),
|
|
262
301
|
};
|
|
263
|
-
const
|
|
264
|
-
type: z.literal('
|
|
302
|
+
const taskCreatedSchema = baseEventSchema.extend({
|
|
303
|
+
type: z.literal('task.created'),
|
|
265
304
|
assigneeAgentId: agentIdSchema,
|
|
266
305
|
assigneeDisplayName: z.string().trim().min(1).max(200),
|
|
267
306
|
requiresAcceptance: z.boolean(),
|
|
307
|
+
...taskFields,
|
|
308
|
+
});
|
|
309
|
+
const taskUpdatedSchema = baseEventSchema.extend({
|
|
310
|
+
type: z.literal('task.updated'),
|
|
311
|
+
taskId: z.string().length(26),
|
|
312
|
+
...taskFields,
|
|
313
|
+
});
|
|
314
|
+
const taskCompletedSchema = baseEventSchema.extend({
|
|
315
|
+
type: z.literal('task.completed'),
|
|
316
|
+
taskId: z.string().length(26),
|
|
317
|
+
note: z.string().trim().min(1).max(2000).optional(),
|
|
318
|
+
});
|
|
319
|
+
const taskReopenedSchema = baseEventSchema.extend({
|
|
320
|
+
type: z.literal('task.reopened'),
|
|
321
|
+
taskId: z.string().length(26),
|
|
322
|
+
});
|
|
323
|
+
const taskAcceptedSchema = baseEventSchema.extend({
|
|
324
|
+
type: z.literal('task.accepted'),
|
|
325
|
+
taskId: z.string().length(26),
|
|
326
|
+
// Optional: accepting without comment is a complete answer on its own.
|
|
327
|
+
response: z.string().trim().min(1).max(2000).optional(),
|
|
328
|
+
});
|
|
329
|
+
const taskRejectedSchema = baseEventSchema.extend({
|
|
330
|
+
type: z.literal('task.rejected'),
|
|
331
|
+
taskId: z.string().length(26),
|
|
332
|
+
// Required. A refusal with no reason tells the assigner only that the work
|
|
333
|
+
// will not happen, not whether to reassign it, wait, or change the request.
|
|
334
|
+
response: z.string().trim().min(1).max(2000),
|
|
335
|
+
});
|
|
336
|
+
const taskCanceledSchema = baseEventSchema.extend({
|
|
337
|
+
type: z.literal('task.canceled'),
|
|
338
|
+
taskId: z.string().length(26),
|
|
339
|
+
reason: z.string().trim().min(1).max(2000).optional(),
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* A Todo is owner-only, so it carries no assignee and no acceptance lifecycle.
|
|
344
|
+
* `details` rather than `description` keeps it lexically distinct from a Task in
|
|
345
|
+
* every payload, which makes a mix-up visible in a log rather than silent.
|
|
346
|
+
*/
|
|
347
|
+
const todoFields = {
|
|
348
|
+
title: z.string().trim().min(1).max(200),
|
|
349
|
+
details: z.string().trim().min(1).max(4000).optional(),
|
|
350
|
+
priority: z.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)]),
|
|
351
|
+
due: taskDueSchema.optional(),
|
|
352
|
+
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
353
|
+
};
|
|
354
|
+
const todoCreatedSchema = baseEventSchema.extend({
|
|
355
|
+
type: z.literal('todo.created'),
|
|
268
356
|
...todoFields,
|
|
269
357
|
});
|
|
270
358
|
const todoUpdatedSchema = baseEventSchema.extend({
|
|
@@ -281,20 +369,15 @@ const todoReopenedSchema = baseEventSchema.extend({
|
|
|
281
369
|
type: z.literal('todo.reopened'),
|
|
282
370
|
todoId: z.string().length(26),
|
|
283
371
|
});
|
|
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
372
|
const todoCanceledSchema = baseEventSchema.extend({
|
|
294
373
|
type: z.literal('todo.canceled'),
|
|
295
374
|
todoId: z.string().length(26),
|
|
296
375
|
reason: z.string().trim().min(1).max(2000).optional(),
|
|
297
376
|
});
|
|
377
|
+
const todoArchivedSchema = baseEventSchema.extend({
|
|
378
|
+
type: z.literal('todo.archived'),
|
|
379
|
+
todoId: z.string().length(26),
|
|
380
|
+
});
|
|
298
381
|
|
|
299
382
|
export const eventSchema = z.discriminatedUnion('type', [
|
|
300
383
|
kudosGivenSchema,
|
|
@@ -308,13 +391,19 @@ export const eventSchema = z.discriminatedUnion('type', [
|
|
|
308
391
|
noteCreatedSchema,
|
|
309
392
|
noteRevisedSchema,
|
|
310
393
|
noteArchivedSchema,
|
|
394
|
+
taskCreatedSchema,
|
|
395
|
+
taskUpdatedSchema,
|
|
396
|
+
taskCompletedSchema,
|
|
397
|
+
taskReopenedSchema,
|
|
398
|
+
taskAcceptedSchema,
|
|
399
|
+
taskRejectedSchema,
|
|
400
|
+
taskCanceledSchema,
|
|
311
401
|
todoCreatedSchema,
|
|
312
402
|
todoUpdatedSchema,
|
|
313
403
|
todoCompletedSchema,
|
|
314
404
|
todoReopenedSchema,
|
|
315
|
-
todoAcceptedSchema,
|
|
316
|
-
todoRejectedSchema,
|
|
317
405
|
todoCanceledSchema,
|
|
406
|
+
todoArchivedSchema,
|
|
318
407
|
]);
|
|
319
408
|
|
|
320
409
|
const giveKudosInputSchema = kudosGivenSchema
|
|
@@ -407,15 +496,44 @@ export const reviseNoteSchema = z
|
|
|
407
496
|
...mutationMetadata,
|
|
408
497
|
})
|
|
409
498
|
.strict();
|
|
410
|
-
export const
|
|
499
|
+
export const createTaskSchema = z
|
|
411
500
|
.object({
|
|
412
501
|
assigneeAgentId: agentIdSchema.optional(),
|
|
502
|
+
title: taskCreatedSchema.shape.title,
|
|
503
|
+
description: taskCreatedSchema.shape.description,
|
|
504
|
+
priority: taskCreatedSchema.shape.priority.optional(),
|
|
505
|
+
due: taskDueSchema.optional(),
|
|
506
|
+
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
507
|
+
visibility: z.enum(['private', 'workspace', 'public']).optional(),
|
|
508
|
+
...mutationMetadata,
|
|
509
|
+
})
|
|
510
|
+
.strict();
|
|
511
|
+
export const updateTaskSchema = z
|
|
512
|
+
.object({
|
|
513
|
+
taskId: z.string().length(26),
|
|
514
|
+
expectedVersion: z.number().int().min(1),
|
|
515
|
+
title: taskCreatedSchema.shape.title.optional(),
|
|
516
|
+
description: taskCreatedSchema.shape.description,
|
|
517
|
+
priority: taskCreatedSchema.shape.priority.optional(),
|
|
518
|
+
due: taskDueSchema.nullable().optional(),
|
|
519
|
+
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
520
|
+
visibility: z.enum(['private', 'workspace', 'public']).optional(),
|
|
521
|
+
...mutationMetadata,
|
|
522
|
+
})
|
|
523
|
+
.strict();
|
|
524
|
+
/**
|
|
525
|
+
* A Todo takes no assignee and no visibility: it belongs to its author and is
|
|
526
|
+
* always private. Omitting those fields from the input — rather than accepting
|
|
527
|
+
* and ignoring them — means an attempt to assign a Todo fails loudly instead of
|
|
528
|
+
* silently producing a private reminder nobody else can see.
|
|
529
|
+
*/
|
|
530
|
+
export const createTodoSchema = z
|
|
531
|
+
.object({
|
|
413
532
|
title: todoCreatedSchema.shape.title,
|
|
414
|
-
|
|
533
|
+
details: todoCreatedSchema.shape.details,
|
|
415
534
|
priority: todoCreatedSchema.shape.priority.optional(),
|
|
416
|
-
due:
|
|
535
|
+
due: taskDueSchema.optional(),
|
|
417
536
|
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
418
|
-
visibility: z.enum(['private', 'workspace', 'public']).optional(),
|
|
419
537
|
...mutationMetadata,
|
|
420
538
|
})
|
|
421
539
|
.strict();
|
|
@@ -424,23 +542,26 @@ export const updateTodoSchema = z
|
|
|
424
542
|
todoId: z.string().length(26),
|
|
425
543
|
expectedVersion: z.number().int().min(1),
|
|
426
544
|
title: todoCreatedSchema.shape.title.optional(),
|
|
427
|
-
|
|
545
|
+
details: todoCreatedSchema.shape.details,
|
|
428
546
|
priority: todoCreatedSchema.shape.priority.optional(),
|
|
429
|
-
due:
|
|
547
|
+
due: taskDueSchema.nullable().optional(),
|
|
430
548
|
tags: z.array(kudosTagSchema).max(20).optional(),
|
|
431
|
-
visibility: z.enum(['private', 'workspace', 'public']).optional(),
|
|
432
549
|
...mutationMetadata,
|
|
433
550
|
})
|
|
434
551
|
.strict();
|
|
552
|
+
|
|
435
553
|
export const itemListInputSchema = z
|
|
436
554
|
.object({
|
|
437
555
|
kinds: z
|
|
438
|
-
.array(z.enum(['kudos', 'memo', 'note', 'todo']))
|
|
439
|
-
.max(
|
|
556
|
+
.array(z.enum(['kudos', 'memo', 'note', 'task', 'todo']))
|
|
557
|
+
.max(5)
|
|
440
558
|
.optional(),
|
|
441
559
|
participantAgentId: agentIdSchema.optional(),
|
|
442
560
|
actorId: agentIdSchema.optional(),
|
|
443
561
|
actorKind: z.enum(['human', 'agent', 'system']).optional(),
|
|
562
|
+
awaitingResponse: z.boolean().optional(),
|
|
563
|
+
awaitingSince: z.string().datetime({ offset: true }).optional(),
|
|
564
|
+
overdueAsOf: z.string().datetime({ offset: true }).optional(),
|
|
444
565
|
tag: kudosTagSchema.optional(),
|
|
445
566
|
status: z.string().trim().min(1).max(50).optional(),
|
|
446
567
|
pending: z.boolean().optional(),
|
package/src/service.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ActorIdentity,
|
|
3
|
+
AgentDirectoryEntry,
|
|
3
4
|
AgentProfile,
|
|
5
|
+
AgentResolution,
|
|
6
|
+
AgentRuntimeBinding,
|
|
7
|
+
BindRuntimeInput,
|
|
4
8
|
ChangePage,
|
|
5
9
|
ChangesInput,
|
|
6
10
|
CreateAgentInput,
|
|
7
11
|
CreateNoteInput,
|
|
8
12
|
CreateNoteResult,
|
|
13
|
+
CreateTaskInput,
|
|
9
14
|
CreateTodoInput,
|
|
10
15
|
CreateTodoResult,
|
|
16
|
+
CreateTaskResult,
|
|
11
17
|
DoctorResult,
|
|
12
18
|
GiveKudosInput,
|
|
13
19
|
GiveKudosResult,
|
|
@@ -27,8 +33,10 @@ import type {
|
|
|
27
33
|
ReviseNoteInput,
|
|
28
34
|
SendMemoInput,
|
|
29
35
|
SendMemoResult,
|
|
36
|
+
TaskRecord,
|
|
30
37
|
TodoRecord,
|
|
31
38
|
UpdateAgentInput,
|
|
39
|
+
UpdateTaskInput,
|
|
32
40
|
UpdateTodoInput,
|
|
33
41
|
} from './types.js';
|
|
34
42
|
|
|
@@ -45,7 +53,7 @@ export interface SynomemServiceCapabilities {
|
|
|
45
53
|
projections: {
|
|
46
54
|
writeWinsMarkdown: boolean;
|
|
47
55
|
writeMemoryMarkdown: boolean;
|
|
48
|
-
|
|
56
|
+
writeTasksMarkdown: boolean;
|
|
49
57
|
writeInboxEntries: boolean;
|
|
50
58
|
};
|
|
51
59
|
}
|
|
@@ -66,6 +74,11 @@ export interface SynomemDomainService {
|
|
|
66
74
|
update(id: string, changes: UpdateAgentInput): Promise<AgentProfile>;
|
|
67
75
|
get(idOrAlias: string): Promise<AgentProfile>;
|
|
68
76
|
list(): Promise<AgentProfile[]>;
|
|
77
|
+
resolve(query: string): Promise<AgentResolution>;
|
|
78
|
+
directory(): Promise<AgentDirectoryEntry[]>;
|
|
79
|
+
bindings(idOrAlias: string): Promise<AgentRuntimeBinding[]>;
|
|
80
|
+
bindRuntime(input: BindRuntimeInput): Promise<AgentRuntimeBinding>;
|
|
81
|
+
unbindRuntime(bindingId: string): Promise<boolean>;
|
|
69
82
|
};
|
|
70
83
|
readonly kudos: {
|
|
71
84
|
give(input: GiveKudosInput): Promise<GiveKudosResult>;
|
|
@@ -93,17 +106,43 @@ export interface SynomemDomainService {
|
|
|
93
106
|
revise(input: ReviseNoteInput): Promise<NoteRecord>;
|
|
94
107
|
archive(input: { noteId: string; idempotencyKey?: string }): Promise<NoteRecord>;
|
|
95
108
|
};
|
|
109
|
+
readonly tasks: {
|
|
110
|
+
create(input: CreateTaskInput): Promise<CreateTaskResult>;
|
|
111
|
+
list(input?: Omit<ItemListInput, 'kinds'>): Promise<Page<ItemSummary>>;
|
|
112
|
+
get(id: string): Promise<TaskRecord>;
|
|
113
|
+
update(input: UpdateTaskInput): Promise<TaskRecord>;
|
|
114
|
+
accept(input: {
|
|
115
|
+
taskId: string;
|
|
116
|
+
/** Optional: conditions, timing, or partial capability. */
|
|
117
|
+
response?: string;
|
|
118
|
+
idempotencyKey?: string;
|
|
119
|
+
}): Promise<TaskRecord>;
|
|
120
|
+
reject(input: {
|
|
121
|
+
taskId: string;
|
|
122
|
+
/** Required: a refusal the assigner cannot act on is barely an answer. */
|
|
123
|
+
response: string;
|
|
124
|
+
idempotencyKey?: string;
|
|
125
|
+
}): Promise<TaskRecord>;
|
|
126
|
+
complete(input: {
|
|
127
|
+
taskId: string;
|
|
128
|
+
note?: string;
|
|
129
|
+
idempotencyKey?: string;
|
|
130
|
+
}): Promise<TaskRecord>;
|
|
131
|
+
reopen(input: { taskId: string; idempotencyKey?: string }): Promise<TaskRecord>;
|
|
132
|
+
cancel(input: {
|
|
133
|
+
taskId: string;
|
|
134
|
+
reason?: string;
|
|
135
|
+
idempotencyKey?: string;
|
|
136
|
+
}): Promise<TaskRecord>;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Private self-reminders. No assignee, no acceptance, owner-only reads.
|
|
140
|
+
*/
|
|
96
141
|
readonly todos: {
|
|
97
142
|
create(input: CreateTodoInput): Promise<CreateTodoResult>;
|
|
98
143
|
list(input?: Omit<ItemListInput, 'kinds'>): Promise<Page<ItemSummary>>;
|
|
99
144
|
get(id: string): Promise<TodoRecord>;
|
|
100
145
|
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
146
|
complete(input: {
|
|
108
147
|
todoId: string;
|
|
109
148
|
note?: string;
|
|
@@ -115,6 +154,19 @@ export interface SynomemDomainService {
|
|
|
115
154
|
reason?: string;
|
|
116
155
|
idempotencyKey?: string;
|
|
117
156
|
}): Promise<TodoRecord>;
|
|
157
|
+
archive(input: { todoId: string; idempotencyKey?: string }): Promise<TodoRecord>;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Unanswered and overdue discovery. Derived from durable events; never a
|
|
161
|
+
* statement about whether an agent is reachable.
|
|
162
|
+
*/
|
|
163
|
+
readonly discovery: {
|
|
164
|
+
unanswered(
|
|
165
|
+
input?: Omit<ItemListInput, 'awaitingResponse' | 'pending'> & { olderThanHours?: number },
|
|
166
|
+
): Promise<Page<ItemSummary>>;
|
|
167
|
+
overdue(
|
|
168
|
+
input?: Omit<ItemListInput, 'overdueAsOf'> & { asOf?: string },
|
|
169
|
+
): Promise<Page<ItemSummary>>;
|
|
118
170
|
};
|
|
119
171
|
readonly items: {
|
|
120
172
|
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
|
}
|