@imenam/mcp-organizer 1.0.3 → 1.0.7
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/README.md +71 -20
- package/dist/shared/schemas/admin-api.schema.d.ts +101 -0
- package/dist/shared/schemas/admin-api.schema.js +39 -0
- package/dist/shared/schemas/agent-api.schema.d.ts +2 -0
- package/dist/shared/schemas/agent-api.schema.js +4 -0
- package/dist/shared/schemas/agent-tools.schema.d.ts +34 -0
- package/dist/shared/schemas/agent-tools.schema.js +2 -0
- package/dist/shared/schemas/api.schema.d.ts +2 -0
- package/dist/shared/schemas/api.schema.js +2 -0
- package/dist/shared/schemas/entities.schema.d.ts +27 -1
- package/dist/shared/schemas/entities.schema.js +21 -2
- package/dist/shared/schemas/notifications-api.schema.d.ts +31 -0
- package/dist/shared/schemas/notifications-api.schema.js +22 -1
- package/dist/src/agent-api/requests.js +2 -1
- package/dist/src/cli/set-admin.d.ts +1 -0
- package/dist/src/cli/set-admin.js +45 -0
- package/dist/src/core/accounts.js +2 -1
- package/dist/src/core/admin.d.ts +24 -0
- package/dist/src/core/admin.js +85 -0
- package/dist/src/core/agent-tokens.d.ts +9 -1
- package/dist/src/core/agent-tokens.js +25 -2
- package/dist/src/core/agent.d.ts +5 -0
- package/dist/src/core/agent.js +23 -0
- package/dist/src/core/migrations.js +369 -344
- package/dist/src/core/notifications.d.ts +7 -1
- package/dist/src/core/notifications.js +32 -1
- package/dist/src/core/requests.d.ts +1 -1
- package/dist/src/core/requests.js +4 -4
- package/dist/src/core/store.d.ts +38 -2
- package/dist/src/core/store.js +161 -38
- package/dist/src/gui-api.d.ts +6 -0
- package/dist/src/gui-api.js +25 -4
- package/dist/src/index.js +8 -1
- package/dist/src/mcp/start.d.ts +1 -1
- package/dist/src/mcp/start.js +1 -1
- package/dist/src/mcp/tools.js +1 -1
- package/dist/src/server/runner.d.ts +51 -0
- package/dist/src/server/runner.js +222 -0
- package/dist/src/server/start.js +8 -0
- package/gui/dist/assets/index-DuoSNpBr.js +70 -0
- package/gui/dist/assets/index-duxL0fvO.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +3 -2
- package/gui/dist/assets/index-BVN0agCc.css +0 -1
- package/gui/dist/assets/index-DI1_kr81.js +0 -70
|
@@ -68,6 +68,7 @@ export declare const SettingsResponseSchema: z.ZodObject<{
|
|
|
68
68
|
notifyAssignEmail: z.ZodBoolean;
|
|
69
69
|
notifyCommentApp: z.ZodBoolean;
|
|
70
70
|
notifyCommentEmail: z.ZodBoolean;
|
|
71
|
+
assistantHistory: z.ZodNumber;
|
|
71
72
|
email: z.ZodObject<{
|
|
72
73
|
enabled: z.ZodBoolean;
|
|
73
74
|
reason: z.ZodNullable<z.ZodString>;
|
|
@@ -83,5 +84,35 @@ export declare const UpdateSettingsRequestSchema: z.ZodObject<{
|
|
|
83
84
|
notifyAssignEmail: z.ZodOptional<z.ZodBoolean>;
|
|
84
85
|
notifyCommentApp: z.ZodOptional<z.ZodBoolean>;
|
|
85
86
|
notifyCommentEmail: z.ZodOptional<z.ZodBoolean>;
|
|
87
|
+
assistantHistory: z.ZodOptional<z.ZodNumber>;
|
|
86
88
|
}, z.core.$strict>;
|
|
87
89
|
export type UpdateSettingsRequest = z.infer<typeof UpdateSettingsRequestSchema>;
|
|
90
|
+
/**
|
|
91
|
+
* Notifications de l'utilisateur dans un espace : `custom` dit si l'espace a ses
|
|
92
|
+
* propres préférences ; sinon, les valeurs renvoyées sont celles du compte.
|
|
93
|
+
*/
|
|
94
|
+
export declare const SpaceNotificationSettingsResponseSchema: z.ZodObject<{
|
|
95
|
+
notifyAssignApp: z.ZodBoolean;
|
|
96
|
+
notifyAssignEmail: z.ZodBoolean;
|
|
97
|
+
notifyCommentApp: z.ZodBoolean;
|
|
98
|
+
notifyCommentEmail: z.ZodBoolean;
|
|
99
|
+
custom: z.ZodBoolean;
|
|
100
|
+
email: z.ZodObject<{
|
|
101
|
+
enabled: z.ZodBoolean;
|
|
102
|
+
reason: z.ZodNullable<z.ZodString>;
|
|
103
|
+
}, z.core.$strip>;
|
|
104
|
+
}, z.core.$strip>;
|
|
105
|
+
export type SpaceNotificationSettingsResponse = z.infer<typeof SpaceNotificationSettingsResponseSchema>;
|
|
106
|
+
/**
|
|
107
|
+
* Personnalise les notifications d'un espace (`custom: true`, avec les préférences
|
|
108
|
+
* à changer ; les autres partent des préférences en vigueur) ou revient à celles
|
|
109
|
+
* du compte (`custom: false`, sans préférence).
|
|
110
|
+
*/
|
|
111
|
+
export declare const UpdateSpaceNotificationSettingsRequestSchema: z.ZodObject<{
|
|
112
|
+
notifyAssignApp: z.ZodOptional<z.ZodBoolean>;
|
|
113
|
+
notifyAssignEmail: z.ZodOptional<z.ZodBoolean>;
|
|
114
|
+
notifyCommentApp: z.ZodOptional<z.ZodBoolean>;
|
|
115
|
+
notifyCommentEmail: z.ZodOptional<z.ZodBoolean>;
|
|
116
|
+
custom: z.ZodBoolean;
|
|
117
|
+
}, z.core.$strict>;
|
|
118
|
+
export type UpdateSpaceNotificationSettingsRequest = z.infer<typeof UpdateSpaceNotificationSettingsRequestSchema>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ActorTypeSchema, NotificationTypeSchema } from "./enums.schema.js";
|
|
3
|
-
import { IdSchema, TimestampSchema } from "./entities.schema.js";
|
|
3
|
+
import { AssistantHistorySchema, IdSchema, NotificationPreferencesSchema, TimestampSchema } from "./entities.schema.js";
|
|
4
4
|
/** Corps des requêtes et des réponses des notifications et des paramètres de la GUI. */
|
|
5
5
|
/** Nombre de notifications renvoyées par défaut, et au plus, par page. */
|
|
6
6
|
export const NOTIFICATIONS_PAGE_SIZE = 20;
|
|
@@ -42,6 +42,8 @@ export const SettingsResponseSchema = z.object({
|
|
|
42
42
|
notifyAssignEmail: z.boolean(),
|
|
43
43
|
notifyCommentApp: z.boolean(),
|
|
44
44
|
notifyCommentEmail: z.boolean(),
|
|
45
|
+
/** Nombre d'échanges précédents transmis à l'agent avec un message de l'assistant. */
|
|
46
|
+
assistantHistory: AssistantHistorySchema,
|
|
45
47
|
/** Envoi des e-mails de notification : `reason` dit pourquoi il n'a pas lieu. */
|
|
46
48
|
email: z.object({ enabled: z.boolean(), reason: z.string().nullable() }),
|
|
47
49
|
/** Dictée vocale : `reason` dit pourquoi elle est indisponible. */
|
|
@@ -53,6 +55,25 @@ export const UpdateSettingsRequestSchema = z
|
|
|
53
55
|
notifyAssignEmail: z.boolean().optional(),
|
|
54
56
|
notifyCommentApp: z.boolean().optional(),
|
|
55
57
|
notifyCommentEmail: z.boolean().optional(),
|
|
58
|
+
assistantHistory: AssistantHistorySchema.optional(),
|
|
56
59
|
})
|
|
57
60
|
.strict()
|
|
58
61
|
.refine((patch) => Object.values(patch).some((value) => value !== undefined), "Aucune modification demandée.");
|
|
62
|
+
/**
|
|
63
|
+
* Notifications de l'utilisateur dans un espace : `custom` dit si l'espace a ses
|
|
64
|
+
* propres préférences ; sinon, les valeurs renvoyées sont celles du compte.
|
|
65
|
+
*/
|
|
66
|
+
export const SpaceNotificationSettingsResponseSchema = NotificationPreferencesSchema.extend({
|
|
67
|
+
custom: z.boolean(),
|
|
68
|
+
/** Envoi des e-mails de notification : `reason` dit pourquoi il n'a pas lieu. */
|
|
69
|
+
email: z.object({ enabled: z.boolean(), reason: z.string().nullable() }),
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* Personnalise les notifications d'un espace (`custom: true`, avec les préférences
|
|
73
|
+
* à changer ; les autres partent des préférences en vigueur) ou revient à celles
|
|
74
|
+
* du compte (`custom: false`, sans préférence).
|
|
75
|
+
*/
|
|
76
|
+
export const UpdateSpaceNotificationSettingsRequestSchema = NotificationPreferencesSchema.partial()
|
|
77
|
+
.extend({ custom: z.boolean() })
|
|
78
|
+
.strict()
|
|
79
|
+
.refine((patch) => patch.custom || [patch.notifyAssignApp, patch.notifyAssignEmail, patch.notifyCommentApp, patch.notifyCommentEmail].every((value) => value === undefined), "Un espace qui suit les préférences du compte n'a pas de préférences propres.");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ClaimRequestBodySchema, ClaimRequestDataSchema, CompleteRequestBodySchema, FailRequestBodySchema, FinishRequestDataSchema, ListRequestsDataSchema, ListRequestsQuerySchema, } from "../../shared/schemas/agent-tools.schema.js";
|
|
2
|
-
import { agentActor, ideaData, memberData, recentIdeas, requestContext, requestData, requestLine, requestOfSpace, spaceData, treeData } from "../core/agent.js";
|
|
2
|
+
import { agentActor, ideaData, memberData, recentIdeas, requestContext, requestData, requestHistory, requestLine, requestOfSpace, spaceData, treeData } from "../core/agent.js";
|
|
3
3
|
import { parseInput, respond } from "./types.js";
|
|
4
4
|
/** Demandes de l'espace du jeton : liste, prise, fin (réussie ou en échec). */
|
|
5
5
|
export const requestRoutes = [
|
|
@@ -28,6 +28,7 @@ export const requestRoutes = [
|
|
|
28
28
|
const request = store.mutate(agentActor(agent, params.requestId), (tx) => tx.claimAgentRequest());
|
|
29
29
|
return respond(ClaimRequestDataSchema, requestContext(store, agent, request), {
|
|
30
30
|
request: requestData(store, agent, request),
|
|
31
|
+
history: requestHistory(store, request).map((previous) => requestData(store, agent, previous)),
|
|
31
32
|
space: spaceData(agent.space),
|
|
32
33
|
members: memberData(store, agent.space),
|
|
33
34
|
tasks: treeData(store, agent.space),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runSetAdmin(argv: string[], dataDir: string): Promise<number>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { setAdmin } from "../core/admin.js";
|
|
2
|
+
import { Store } from "../core/store.js";
|
|
3
|
+
/**
|
|
4
|
+
* Commande `--set-admin <email> [--revoke]` : accorde le rôle
|
|
5
|
+
* d'administrateur du site à un compte actif, ou le lui retire avec
|
|
6
|
+
* `--revoke`. Le dernier administrateur ne peut pas perdre son rôle.
|
|
7
|
+
*/
|
|
8
|
+
const USAGE = "Usage : mcp-organizer --set-admin <email> [--revoke]";
|
|
9
|
+
class UsageError extends Error {
|
|
10
|
+
}
|
|
11
|
+
function parseArgs(argv) {
|
|
12
|
+
const rest = argv.slice(argv.indexOf("--set-admin") + 1);
|
|
13
|
+
const unknown = rest.filter((arg) => arg.startsWith("-") && arg !== "--revoke");
|
|
14
|
+
if (unknown.length > 0)
|
|
15
|
+
throw new UsageError(`Option inconnue : ${unknown.join(", ")}.`);
|
|
16
|
+
const positional = rest.filter((arg) => !arg.startsWith("-"));
|
|
17
|
+
if (positional.length === 0)
|
|
18
|
+
throw new UsageError("--set-admin attend l'adresse e-mail du compte.");
|
|
19
|
+
if (positional.length > 1)
|
|
20
|
+
throw new UsageError(`Une seule adresse à la fois (reçu : ${positional.join(", ")}).`);
|
|
21
|
+
return { email: positional[0], revoke: rest.includes("--revoke") };
|
|
22
|
+
}
|
|
23
|
+
export async function runSetAdmin(argv, dataDir) {
|
|
24
|
+
let args;
|
|
25
|
+
try {
|
|
26
|
+
args = parseArgs(argv);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
process.stderr.write(`${err?.message ?? err}\n${USAGE}\n`);
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
const store = Store.open(dataDir);
|
|
33
|
+
try {
|
|
34
|
+
const user = setAdmin(store, args.email, !args.revoke);
|
|
35
|
+
process.stdout.write(args.revoke ? `${user.email} n'est plus administrateur du site.\n` : `${user.email} (${user.displayName}) est administrateur du site.\n`);
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
process.stderr.write(`${err?.message ?? err}\n`);
|
|
40
|
+
return 1;
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
store.close();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -147,7 +147,8 @@ export async function setAccount(store, input) {
|
|
|
147
147
|
tx.discardUnusedAccessLinks(user.id);
|
|
148
148
|
return { created: false, user };
|
|
149
149
|
}
|
|
150
|
-
|
|
150
|
+
// Le premier compte du site en est l'administrateur.
|
|
151
|
+
const created = tx.createUser({ id: userId, email: normalized, displayName: name, passwordHash, status: "active", isAdmin: tx.store.countUsers() === 0 });
|
|
151
152
|
ensurePersonalSpace(tx, created.id);
|
|
152
153
|
return { created: true, user: created };
|
|
153
154
|
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AdminSpaceView, AdminSpacesResponse, RunQueueResponse, RunnerStatus } from "../../shared/schemas/admin-api.schema.js";
|
|
2
|
+
import type { User } from "../../shared/schemas/entities.schema.js";
|
|
3
|
+
import type { Store } from "./store.js";
|
|
4
|
+
/**
|
|
5
|
+
* Administration du site : rôle d'administrateur des comptes, et
|
|
6
|
+
* autorisation du runner par espace. Seul un administrateur voit tous les
|
|
7
|
+
* comptes et tous les espaces, et décide des espaces où le runner travaille.
|
|
8
|
+
*/
|
|
9
|
+
/** L'utilisateur est administrateur ; sinon, refus. */
|
|
10
|
+
export declare function requireAdmin(store: Store, userId: string): User;
|
|
11
|
+
/** Tous les comptes, chacun avec les espaces dont il est propriétaire, et l'état du runner. */
|
|
12
|
+
export declare function listAdminSpaces(store: Store, userId: string, runner: RunnerStatus): AdminSpacesResponse;
|
|
13
|
+
/** Autorise ou interdit le runner sur un espace. */
|
|
14
|
+
export declare function setRunnerAllowed(store: Store, userId: string, spaceId: string, allowed: boolean): AdminSpaceView;
|
|
15
|
+
/**
|
|
16
|
+
* Fait traiter une fois la file d'un espace par le runner, qu'il y soit
|
|
17
|
+
* autorisé ou non ; refus quand aucune demande n'y attend.
|
|
18
|
+
*/
|
|
19
|
+
export declare function processQueueNow(store: Store, userId: string, spaceId: string, runNow: (spaceId: string) => void): RunQueueResponse;
|
|
20
|
+
/**
|
|
21
|
+
* Accorde ou retire le rôle d'administrateur au compte actif `email`. Le
|
|
22
|
+
* dernier administrateur garde son rôle : le site n'en reste jamais dépourvu.
|
|
23
|
+
*/
|
|
24
|
+
export declare function setAdmin(store: Store, email: string, isAdmin: boolean): User;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { normalizeEmail } from "./accounts.js";
|
|
2
|
+
import { userLabel } from "./agent.js";
|
|
3
|
+
import { ForbiddenError, InvariantError, NotFoundError, OrganizerError } from "./errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* Administration du site : rôle d'administrateur des comptes, et
|
|
6
|
+
* autorisation du runner par espace. Seul un administrateur voit tous les
|
|
7
|
+
* comptes et tous les espaces, et décide des espaces où le runner travaille.
|
|
8
|
+
*/
|
|
9
|
+
/** L'utilisateur est administrateur ; sinon, refus. */
|
|
10
|
+
export function requireAdmin(store, userId) {
|
|
11
|
+
const user = store.getUser(userId);
|
|
12
|
+
if (!user.isAdmin)
|
|
13
|
+
throw new ForbiddenError("Réservé aux administrateurs du site.");
|
|
14
|
+
return user;
|
|
15
|
+
}
|
|
16
|
+
function spaceView(store, space) {
|
|
17
|
+
return {
|
|
18
|
+
id: space.id,
|
|
19
|
+
name: space.name,
|
|
20
|
+
kind: space.kind,
|
|
21
|
+
keyPrefix: space.keyPrefix,
|
|
22
|
+
runnerAllowed: space.runnerAllowed,
|
|
23
|
+
members: store.listMemberships(space.id).map((membership) => {
|
|
24
|
+
const member = store.getUser(membership.userId);
|
|
25
|
+
return { id: member.id, name: userLabel(member), email: member.email };
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Tous les comptes, chacun avec les espaces dont il est propriétaire, et l'état du runner. */
|
|
30
|
+
export function listAdminSpaces(store, userId, runner) {
|
|
31
|
+
requireAdmin(store, userId);
|
|
32
|
+
const spaces = store.listAllSpaces();
|
|
33
|
+
const users = store.listUsers().map((user) => ({
|
|
34
|
+
id: user.id,
|
|
35
|
+
email: user.email,
|
|
36
|
+
displayName: user.displayName,
|
|
37
|
+
status: user.status,
|
|
38
|
+
isAdmin: user.isAdmin,
|
|
39
|
+
spaces: spaces.filter((space) => space.ownerId === user.id).map((space) => spaceView(store, space)),
|
|
40
|
+
}));
|
|
41
|
+
return { users, allowedCount: spaces.filter((space) => space.runnerAllowed).length, spaceCount: spaces.length, runner };
|
|
42
|
+
}
|
|
43
|
+
/** Autorise ou interdit le runner sur un espace. */
|
|
44
|
+
export function setRunnerAllowed(store, userId, spaceId, allowed) {
|
|
45
|
+
return store.mutate({ type: "user", userId }, (tx) => {
|
|
46
|
+
requireAdmin(tx.store, userId);
|
|
47
|
+
if (!tx.store.findSpace(spaceId))
|
|
48
|
+
throw new NotFoundError("Espace introuvable.");
|
|
49
|
+
return spaceView(tx.store, tx.setSpaceRunnerAllowed(spaceId, allowed));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Fait traiter une fois la file d'un espace par le runner, qu'il y soit
|
|
54
|
+
* autorisé ou non ; refus quand aucune demande n'y attend.
|
|
55
|
+
*/
|
|
56
|
+
export function processQueueNow(store, userId, spaceId, runNow) {
|
|
57
|
+
requireAdmin(store, userId);
|
|
58
|
+
const space = store.findSpace(spaceId);
|
|
59
|
+
if (!space)
|
|
60
|
+
throw new NotFoundError("Espace introuvable.");
|
|
61
|
+
const pendingCount = store.countPendingRequestsOfSpace(spaceId);
|
|
62
|
+
if (pendingCount === 0)
|
|
63
|
+
throw new InvariantError(`Aucune demande en attente dans « ${space.name} ».`);
|
|
64
|
+
runNow(spaceId);
|
|
65
|
+
return { pendingCount };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Accorde ou retire le rôle d'administrateur au compte actif `email`. Le
|
|
69
|
+
* dernier administrateur garde son rôle : le site n'en reste jamais dépourvu.
|
|
70
|
+
*/
|
|
71
|
+
export function setAdmin(store, email, isAdmin) {
|
|
72
|
+
const normalized = normalizeEmail(email);
|
|
73
|
+
const target = store.findUserByEmail(normalized);
|
|
74
|
+
if (!target)
|
|
75
|
+
throw new NotFoundError(`Aucun compte pour ${normalized} : créez-le d'abord (--set-user ${normalized}).`);
|
|
76
|
+
return store.mutate({ type: "user", userId: target.id }, (tx) => {
|
|
77
|
+
const user = tx.store.getUser(target.id);
|
|
78
|
+
if (isAdmin && user.status !== "active")
|
|
79
|
+
throw new OrganizerError(`Le compte ${normalized} n'est pas actif : activez-le d'abord (--set-user ${normalized}).`);
|
|
80
|
+
if (!isAdmin && user.isAdmin && tx.store.countAdmins() === 1) {
|
|
81
|
+
throw new InvariantError(`${normalized} est le seul administrateur : désignez-en un autre (--set-admin <email>) avant de lui retirer ce rôle.`);
|
|
82
|
+
}
|
|
83
|
+
return tx.setUserAdmin(user.id, isAdmin);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -7,7 +7,7 @@ export declare function generateAgentToken(): string;
|
|
|
7
7
|
export declare function hashAgentToken(token: string): string;
|
|
8
8
|
/** État d'un jeton à l'instant `now` ; la révocation l'emporte sur l'expiration, l'expiration sur la perte d'accès. */
|
|
9
9
|
export declare function tokenState(store: Store, token: AgentToken, now: Date): TokenState;
|
|
10
|
-
/** Jetons de l'utilisateur : actifs d'abord, puis du plus récent au plus ancien. */
|
|
10
|
+
/** Jetons de l'utilisateur, sans ceux du runner : actifs d'abord, puis du plus récent au plus ancien. */
|
|
11
11
|
export declare function listAgentTokens(store: Store, userId: string, now?: Date): TokenListResponse;
|
|
12
12
|
/**
|
|
13
13
|
* Crée un jeton de l'utilisateur sur un espace dont il est membre ; renvoie
|
|
@@ -15,6 +15,14 @@ export declare function listAgentTokens(store: Store, userId: string, now?: Date
|
|
|
15
15
|
* relié au site `publicUrl`.
|
|
16
16
|
*/
|
|
17
17
|
export declare function createAgentToken(store: Store, userId: string, input: CreateTokenRequest, publicUrl: string, now?: Date): CreatedTokenResponse;
|
|
18
|
+
/** Nom du jeton du runner, affiché dans la page Agent et l'historique. */
|
|
19
|
+
export declare const RUNNER_TOKEN_NAME = "Runner";
|
|
20
|
+
/**
|
|
21
|
+
* Donne une nouvelle valeur au jeton du runner de l'espace, en le créant au
|
|
22
|
+
* nom du propriétaire de l'espace s'il n'existe pas, et la renvoie. L'ancienne
|
|
23
|
+
* valeur est aussitôt refusée.
|
|
24
|
+
*/
|
|
25
|
+
export declare function issueRunnerToken(store: Store, spaceId: string): string;
|
|
18
26
|
/** Révoque un jeton de l'utilisateur ; un jeton d'un autre est introuvable. */
|
|
19
27
|
export declare function revokeAgentToken(store: Store, userId: string, tokenId: string, now?: Date): AgentTokenView;
|
|
20
28
|
/** Jeton résolu par l'API agent : le jeton, son propriétaire et l'espace couvert. */
|
|
@@ -49,9 +49,12 @@ function tokenView(store, token, now) {
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
const STATE_ORDER = { active: 0, inactive: 1, expired: 2, revoked: 3 };
|
|
52
|
-
/** Jetons de l'utilisateur : actifs d'abord, puis du plus récent au plus ancien. */
|
|
52
|
+
/** Jetons de l'utilisateur, sans ceux du runner : actifs d'abord, puis du plus récent au plus ancien. */
|
|
53
53
|
export function listAgentTokens(store, userId, now = new Date()) {
|
|
54
|
-
const tokens = store
|
|
54
|
+
const tokens = store
|
|
55
|
+
.listAgentTokensOf(userId)
|
|
56
|
+
.filter((token) => !token.isRunner)
|
|
57
|
+
.map((token) => tokenView(store, token, now));
|
|
55
58
|
tokens.sort((a, b) => STATE_ORDER[a.state] - STATE_ORDER[b.state] || b.createdAt.localeCompare(a.createdAt));
|
|
56
59
|
return { tokens };
|
|
57
60
|
}
|
|
@@ -74,6 +77,26 @@ export function createAgentToken(store, userId, input, publicUrl, now = new Date
|
|
|
74
77
|
});
|
|
75
78
|
return { token: tokenView(store, token, now), value, mcpJson: mcpJsonText(buildAgentEntry({ url: publicUrl, token: value })) };
|
|
76
79
|
}
|
|
80
|
+
/** Nom du jeton du runner, affiché dans la page Agent et l'historique. */
|
|
81
|
+
export const RUNNER_TOKEN_NAME = "Runner";
|
|
82
|
+
/**
|
|
83
|
+
* Donne une nouvelle valeur au jeton du runner de l'espace, en le créant au
|
|
84
|
+
* nom du propriétaire de l'espace s'il n'existe pas, et la renvoie. L'ancienne
|
|
85
|
+
* valeur est aussitôt refusée.
|
|
86
|
+
*/
|
|
87
|
+
export function issueRunnerToken(store, spaceId) {
|
|
88
|
+
const value = generateAgentToken();
|
|
89
|
+
const prefix = value.slice(0, AGENT_TOKEN_PREFIX.length + PREFIX_RANDOM_CHARS);
|
|
90
|
+
const space = store.getSpace(spaceId);
|
|
91
|
+
store.mutate(asUser(space.ownerId), (tx) => {
|
|
92
|
+
const existing = tx.store.findRunnerToken(spaceId);
|
|
93
|
+
if (existing)
|
|
94
|
+
tx.rotateRunnerToken(existing.id, prefix, hashAgentToken(value));
|
|
95
|
+
else
|
|
96
|
+
tx.createAgentToken({ spaceId, name: RUNNER_TOKEN_NAME, prefix, tokenHash: hashAgentToken(value), expiresAt: null, isRunner: true });
|
|
97
|
+
});
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
77
100
|
/** Révoque un jeton de l'utilisateur ; un jeton d'un autre est introuvable. */
|
|
78
101
|
export function revokeAgentToken(store, userId, tokenId, now = new Date()) {
|
|
79
102
|
const token = store.mutate(asUser(userId), (tx) => {
|
package/dist/src/core/agent.d.ts
CHANGED
|
@@ -44,6 +44,11 @@ export declare function memberLines(store: Store, space: Space): string[];
|
|
|
44
44
|
export declare function ago(iso: string, now?: Date): string;
|
|
45
45
|
/** Résumé d'une demande pour list_requests. */
|
|
46
46
|
export declare function requestLine(store: Store, agent: AgentCaller, request: AgentRequest): string;
|
|
47
|
+
/**
|
|
48
|
+
* Échanges précédents de l'auteur d'un message dans l'espace visé, du plus ancien
|
|
49
|
+
* au plus récent, au nombre fixé dans ses paramètres ; aucun pour les autres types.
|
|
50
|
+
*/
|
|
51
|
+
export declare function requestHistory(store: Store, request: AgentRequest): AgentRequest[];
|
|
47
52
|
/** Contexte complet d'une demande, renvoyé par claim_request. */
|
|
48
53
|
export declare function requestContext(store: Store, agent: AgentCaller, request: AgentRequest): string;
|
|
49
54
|
/** Idées actives récentes de la boîte à idées d'un espace. */
|
package/dist/src/core/agent.js
CHANGED
|
@@ -168,6 +168,23 @@ const KIND_GUIDANCE = {
|
|
|
168
168
|
test_review: "A test review written by a tester of the context task: feed it back into the existing tasks (status, checklist, comments, priorities) or create a task for each problem found.",
|
|
169
169
|
idea_promotion: "Promote the context idea into a well-formed task (clear title, description, type, priority, parent if relevant) with promote_idea.",
|
|
170
170
|
};
|
|
171
|
+
/**
|
|
172
|
+
* Échanges précédents de l'auteur d'un message dans l'espace visé, du plus ancien
|
|
173
|
+
* au plus récent, au nombre fixé dans ses paramètres ; aucun pour les autres types.
|
|
174
|
+
*/
|
|
175
|
+
export function requestHistory(store, request) {
|
|
176
|
+
if (request.kind !== "message")
|
|
177
|
+
return [];
|
|
178
|
+
const limit = store.getUserSettings(request.authorId).assistantHistory;
|
|
179
|
+
return store.listClosedRequestsOfAuthorBefore(request.targetSpaceId, request.authorId, request, limit);
|
|
180
|
+
}
|
|
181
|
+
/** Lignes d'un échange précédent : demande de l'auteur, puis réponse ou raison de l'échec. */
|
|
182
|
+
function historyLines(store, request) {
|
|
183
|
+
const task = request.contextTaskId === null ? null : store.findTask(request.contextTaskId);
|
|
184
|
+
const about = [request.kind !== "message" ? request.kind : null, task ? `context ${taskKey(store, task)}` : null].filter(Boolean).join(", ");
|
|
185
|
+
const answer = request.status === "done" ? `Reply: ${request.reply ?? ""}` : `Failed: ${request.failureReason ?? ""}`;
|
|
186
|
+
return [`- ${ago(request.createdAt)}${about ? ` (${about})` : ""}: ${request.text.trim()}`, ` ${answer.trim()}`];
|
|
187
|
+
}
|
|
171
188
|
/** Contexte complet d'une demande, renvoyé par claim_request. */
|
|
172
189
|
export function requestContext(store, agent, request) {
|
|
173
190
|
const author = store.getUser(request.authorId);
|
|
@@ -201,6 +218,12 @@ export function requestContext(store, agent, request) {
|
|
|
201
218
|
if (idea)
|
|
202
219
|
lines.push(`Context idea: ${idea.id} "${idea.text}".`);
|
|
203
220
|
}
|
|
221
|
+
const history = requestHistory(store, request);
|
|
222
|
+
if (history.length > 0) {
|
|
223
|
+
lines.push("", `Previous exchanges of the author in this space (oldest first, ${history.length} most recent) — use them to understand the message:`);
|
|
224
|
+
for (const previous of history)
|
|
225
|
+
lines.push(...historyLines(store, previous));
|
|
226
|
+
}
|
|
204
227
|
lines.push("", "Text:", request.text, "");
|
|
205
228
|
lines.push(...spaceContextLines(store, target));
|
|
206
229
|
lines.push("", "Next: read with get_task / search_tasks, act with the write tools (pass this request_id), then call complete_request with a short reply in the author's language.");
|