@bridge4dev/runner 0.69.1 → 0.70.1
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/dist/index.js +11 -0
- package/dist/journal.d.ts +8 -1
- package/dist/journal.js +5 -1
- package/dist/message-author.d.ts +29 -0
- package/dist/message-author.js +34 -0
- package/dist/protocol.d.ts +86 -0
- package/dist/protocol.js +38 -0
- package/dist/supervisor.js +58 -11
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -397,6 +397,17 @@ function runnerCapabilities(apiUrlOverride) {
|
|
|
397
397
|
* machine in the fleet is up to date.
|
|
398
398
|
*/
|
|
399
399
|
agentOutsideFolder: true,
|
|
400
|
+
/**
|
|
401
|
+
* «Tell the agent who is writing»: the name the API attaches to a message
|
|
402
|
+
* (`author` on `deliver_message` and `session_message`, `promptAuthor` on
|
|
403
|
+
* the descriptor) goes on top of the agent's prompt, never into the feed.
|
|
404
|
+
*
|
|
405
|
+
* Announced for the settings card only, and as a warning rather than a
|
|
406
|
+
* refusal, like `agentOutsideFolder` above it: an older runner drops the
|
|
407
|
+
* field unread and the message still arrives — just unsigned — so a
|
|
408
|
+
* manager can record the decision before the last machine is current.
|
|
409
|
+
*/
|
|
410
|
+
messageAuthors: true,
|
|
400
411
|
/**
|
|
401
412
|
* #137: this runner can read a repository that has no commits yet.
|
|
402
413
|
*
|
package/dist/journal.d.ts
CHANGED
|
@@ -30,6 +30,13 @@ export interface PendingMessage {
|
|
|
30
30
|
* those cannot be recalled, which is correct — they predate the feature.
|
|
31
31
|
*/
|
|
32
32
|
seq?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Who typed it, as DevBridge shows them — present only when the project has
|
|
35
|
+
* «Tell the agent who is writing» switched on. Held with the words so a
|
|
36
|
+
* message that waited out a restart is still signed for the agent when it
|
|
37
|
+
* finally goes (`message-author.ts`).
|
|
38
|
+
*/
|
|
39
|
+
author?: string;
|
|
33
40
|
}
|
|
34
41
|
export interface PendingAttachment {
|
|
35
42
|
id: string;
|
|
@@ -140,7 +147,7 @@ export declare class SessionJournal {
|
|
|
140
147
|
* it is queued in memory, so the ordering is "on disk, then held" — a crash
|
|
141
148
|
* between the two costs a duplicate delivery at worst, never a lost message.
|
|
142
149
|
*/
|
|
143
|
-
appendPending(text: string, attachments?: PendingAttachment[], seq?: number): PendingMessage;
|
|
150
|
+
appendPending(text: string, attachments?: PendingAttachment[], seq?: number, author?: string): PendingMessage;
|
|
144
151
|
/** The message reached an agent — stop replaying it after a restart. */
|
|
145
152
|
resolvePending(id: string): void;
|
|
146
153
|
/**
|
package/dist/journal.js
CHANGED
|
@@ -97,6 +97,7 @@ export class SessionJournal {
|
|
|
97
97
|
text: parsed.text,
|
|
98
98
|
...(parsed.attachments?.length ? { attachments: parsed.attachments } : {}),
|
|
99
99
|
...(typeof parsed.seq === 'number' ? { seq: parsed.seq } : {}),
|
|
100
|
+
...(typeof parsed.author === 'string' ? { author: parsed.author } : {}),
|
|
100
101
|
});
|
|
101
102
|
// Ids are `p<n>`; keep the counter above whatever the file holds so a
|
|
102
103
|
// restarted runner cannot mint an id that is already in flight.
|
|
@@ -157,6 +158,7 @@ export class SessionJournal {
|
|
|
157
158
|
text: record.text,
|
|
158
159
|
...(record.attachments?.length ? { attachments: record.attachments } : {}),
|
|
159
160
|
...(record.seq === undefined ? {} : { seq: record.seq }),
|
|
161
|
+
...(record.author === undefined ? {} : { author: record.author }),
|
|
160
162
|
ts: new Date().toISOString(),
|
|
161
163
|
});
|
|
162
164
|
}
|
|
@@ -294,13 +296,14 @@ export class SessionJournal {
|
|
|
294
296
|
* it is queued in memory, so the ordering is "on disk, then held" — a crash
|
|
295
297
|
* between the two costs a duplicate delivery at worst, never a lost message.
|
|
296
298
|
*/
|
|
297
|
-
appendPending(text, attachments, seq) {
|
|
299
|
+
appendPending(text, attachments, seq, author) {
|
|
298
300
|
const id = `p${this.pendingCounter++}`;
|
|
299
301
|
const record = {
|
|
300
302
|
id,
|
|
301
303
|
text,
|
|
302
304
|
...(attachments?.length ? { attachments } : {}),
|
|
303
305
|
...(seq === undefined ? {} : { seq }),
|
|
306
|
+
...(author === undefined ? {} : { author }),
|
|
304
307
|
};
|
|
305
308
|
this.write({
|
|
306
309
|
kind: 'pending',
|
|
@@ -308,6 +311,7 @@ export class SessionJournal {
|
|
|
308
311
|
text,
|
|
309
312
|
...(attachments?.length ? { attachments } : {}),
|
|
310
313
|
...(seq === undefined ? {} : { seq }),
|
|
314
|
+
...(author === undefined ? {} : { author }),
|
|
311
315
|
ts: new Date().toISOString(),
|
|
312
316
|
});
|
|
313
317
|
this.pendingById.set(id, record);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who typed this — for the agent, not for the feed.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the agent needs it
|
|
5
|
+
*
|
|
6
|
+
* Several people write into one session: the developer, a colleague forwarding
|
|
7
|
+
* a client's email, the platform owner stepping in to help. The runner echoes
|
|
8
|
+
* every message into the feed as `role: 'user'` and the API stamps the author
|
|
9
|
+
* onto that echo for people to see — but the AGENT got the bare words, and
|
|
10
|
+
* could not tell one person from another. A project prompt that says «if Andy
|
|
11
|
+
* writes, do not start development — say you are waiting for Dima» had nothing
|
|
12
|
+
* to go on.
|
|
13
|
+
*
|
|
14
|
+
* ## What it is, and what it is not
|
|
15
|
+
*
|
|
16
|
+
* A line the platform puts on top of the composed prompt, named after the
|
|
17
|
+
* person as DevBridge shows them. The feed never sees it: `acceptUserMessage`
|
|
18
|
+
* echoes the text the person typed, and this runs on the way to the agent, the
|
|
19
|
+
* same place the attachment paths are added. It is a hint to the model, not an
|
|
20
|
+
* access control — the project's real permissions are its roles, and the line
|
|
21
|
+
* carries no authority of its own. The API decides per message whether to send
|
|
22
|
+
* a name at all (the project setting «Tell the agent who is writing»); the
|
|
23
|
+
* runner adds the line whenever one arrives and never invents one.
|
|
24
|
+
*
|
|
25
|
+
* The name comes off the wire and is treated as such: folded onto one line,
|
|
26
|
+
* trimmed, and an empty one means no line at all.
|
|
27
|
+
*/
|
|
28
|
+
export declare function signMessage(text: string, author: string | undefined): string;
|
|
29
|
+
//# sourceMappingURL=message-author.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who typed this — for the agent, not for the feed.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the agent needs it
|
|
5
|
+
*
|
|
6
|
+
* Several people write into one session: the developer, a colleague forwarding
|
|
7
|
+
* a client's email, the platform owner stepping in to help. The runner echoes
|
|
8
|
+
* every message into the feed as `role: 'user'` and the API stamps the author
|
|
9
|
+
* onto that echo for people to see — but the AGENT got the bare words, and
|
|
10
|
+
* could not tell one person from another. A project prompt that says «if Andy
|
|
11
|
+
* writes, do not start development — say you are waiting for Dima» had nothing
|
|
12
|
+
* to go on.
|
|
13
|
+
*
|
|
14
|
+
* ## What it is, and what it is not
|
|
15
|
+
*
|
|
16
|
+
* A line the platform puts on top of the composed prompt, named after the
|
|
17
|
+
* person as DevBridge shows them. The feed never sees it: `acceptUserMessage`
|
|
18
|
+
* echoes the text the person typed, and this runs on the way to the agent, the
|
|
19
|
+
* same place the attachment paths are added. It is a hint to the model, not an
|
|
20
|
+
* access control — the project's real permissions are its roles, and the line
|
|
21
|
+
* carries no authority of its own. The API decides per message whether to send
|
|
22
|
+
* a name at all (the project setting «Tell the agent who is writing»); the
|
|
23
|
+
* runner adds the line whenever one arrives and never invents one.
|
|
24
|
+
*
|
|
25
|
+
* The name comes off the wire and is treated as such: folded onto one line,
|
|
26
|
+
* trimmed, and an empty one means no line at all.
|
|
27
|
+
*/
|
|
28
|
+
export function signMessage(text, author) {
|
|
29
|
+
const name = (author ?? '').replace(/\s+/g, ' ').trim();
|
|
30
|
+
if (name === '')
|
|
31
|
+
return text;
|
|
32
|
+
return `[Message from ${name}]\n\n${text}`;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=message-author.js.map
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { HostLoadFrame } from './host-load.js';
|
|
3
3
|
import type { SessionLimitsFrame } from './session-limits.js';
|
|
4
|
+
/**
|
|
5
|
+
* The longest name the wire accepts for «who typed this». A display name from a
|
|
6
|
+
* profile, not a document — anything longer is not a name, and the field is a
|
|
7
|
+
* nicety: over the limit it is dropped and the message goes on without it.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MESSAGE_AUTHOR_MAX = 200;
|
|
4
10
|
export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
5
11
|
id: z.ZodString;
|
|
6
12
|
kind: z.ZodEnum<["TICKET", "CHAT"]>;
|
|
@@ -71,6 +77,18 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
|
71
77
|
* arrives as `undefined`, which is the same as «auto-update is off».
|
|
72
78
|
*/
|
|
73
79
|
agentLatestVersion: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
80
|
+
/**
|
|
81
|
+
* Who handed over the first message — the person who created the session, as
|
|
82
|
+
* DevBridge shows them. Sent only when the project has «Tell the agent who is
|
|
83
|
+
* writing» switched on and the prompt is not empty; `composeInitialPrompt`
|
|
84
|
+
* puts the name on top of the whole first message (`message-author.ts`).
|
|
85
|
+
*
|
|
86
|
+
* Optional, and absent means «no name»: an older API never sends it, and a
|
|
87
|
+
* project with the setting off gets exactly the first message it always had.
|
|
88
|
+
* `.catch(undefined)` like its neighbours — a bad value costs the signature,
|
|
89
|
+
* never the descriptor, never the `hello_ack` it rides in (QA-100 MAJOR-1).
|
|
90
|
+
*/
|
|
91
|
+
promptAuthor: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
74
92
|
workspace: z.ZodObject<{
|
|
75
93
|
id: z.ZodString;
|
|
76
94
|
path: z.ZodString;
|
|
@@ -277,6 +295,7 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
|
277
295
|
pausedUntil?: string | null | undefined;
|
|
278
296
|
backgroundTasks?: number | undefined;
|
|
279
297
|
agentLatestVersion?: string | undefined;
|
|
298
|
+
promptAuthor?: string | undefined;
|
|
280
299
|
skipAgentPrompt?: boolean | undefined;
|
|
281
300
|
branchHint?: string | undefined;
|
|
282
301
|
branchPlan?: {
|
|
@@ -328,6 +347,7 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
|
328
347
|
pausedUntil?: unknown;
|
|
329
348
|
backgroundTasks?: unknown;
|
|
330
349
|
agentLatestVersion?: unknown;
|
|
350
|
+
promptAuthor?: unknown;
|
|
331
351
|
skipAgentPrompt?: unknown;
|
|
332
352
|
branchHint?: unknown;
|
|
333
353
|
branchPlan?: unknown;
|
|
@@ -362,6 +382,14 @@ export declare const QuestionAnswerShape: {
|
|
|
362
382
|
notes?: string | undefined;
|
|
363
383
|
}>, "many">>;
|
|
364
384
|
readonly text: z.ZodOptional<z.ZodString>;
|
|
385
|
+
/**
|
|
386
|
+
* Who typed `text` — sent only when the project has «Tell the agent who is
|
|
387
|
+
* writing» on. Signs the free text of a «discuss» reply (words a person typed
|
|
388
|
+
* into an open card are a message like any other) and the words rescued when
|
|
389
|
+
* the card turns out to be dead; a pick stays a pick. `.catch(undefined)`
|
|
390
|
+
* like the message author: a bad name costs the signature, not the answer.
|
|
391
|
+
*/
|
|
392
|
+
readonly author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
365
393
|
};
|
|
366
394
|
/** The `answer_question` command's arguments — the shape above on its own. */
|
|
367
395
|
export declare const QuestionAnswerArgsSchema: z.ZodObject<{
|
|
@@ -384,10 +412,19 @@ export declare const QuestionAnswerArgsSchema: z.ZodObject<{
|
|
|
384
412
|
notes?: string | undefined;
|
|
385
413
|
}>, "many">>;
|
|
386
414
|
readonly text: z.ZodOptional<z.ZodString>;
|
|
415
|
+
/**
|
|
416
|
+
* Who typed `text` — sent only when the project has «Tell the agent who is
|
|
417
|
+
* writing» on. Signs the free text of a «discuss» reply (words a person typed
|
|
418
|
+
* into an open card are a message like any other) and the words rescued when
|
|
419
|
+
* the card turns out to be dead; a pick stays a pick. `.catch(undefined)`
|
|
420
|
+
* like the message author: a bad name costs the signature, not the answer.
|
|
421
|
+
*/
|
|
422
|
+
readonly author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
387
423
|
}, "strip", z.ZodTypeAny, {
|
|
388
424
|
action: "answer" | "discuss";
|
|
389
425
|
askId: string;
|
|
390
426
|
text?: string | undefined;
|
|
427
|
+
author?: string | undefined;
|
|
391
428
|
answers?: {
|
|
392
429
|
values: string[];
|
|
393
430
|
questionId: string;
|
|
@@ -398,6 +435,7 @@ export declare const QuestionAnswerArgsSchema: z.ZodObject<{
|
|
|
398
435
|
action: "answer" | "discuss";
|
|
399
436
|
askId: string;
|
|
400
437
|
text?: string | undefined;
|
|
438
|
+
author?: unknown;
|
|
401
439
|
answers?: {
|
|
402
440
|
values: string[];
|
|
403
441
|
questionId: string;
|
|
@@ -432,9 +470,18 @@ export declare const DeliverMessageArgsSchema: z.ZodObject<{
|
|
|
432
470
|
mimeType: string;
|
|
433
471
|
fileSize: number;
|
|
434
472
|
}>, "many">>>;
|
|
473
|
+
/**
|
|
474
|
+
* Who typed it, as DevBridge shows them — present only when the project has
|
|
475
|
+
* «Tell the agent who is writing» switched on. Goes on top of the composed
|
|
476
|
+
* prompt (`message-author.ts`), never into the feed echo. `.catch(undefined)`
|
|
477
|
+
* for the same reason attachments have it: a malformed name must cost the
|
|
478
|
+
* signature, never the sentence the person typed.
|
|
479
|
+
*/
|
|
480
|
+
author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
435
481
|
}, "strip", z.ZodTypeAny, {
|
|
436
482
|
text: string;
|
|
437
483
|
messageId: string;
|
|
484
|
+
author?: string | undefined;
|
|
438
485
|
attachments?: {
|
|
439
486
|
id: string;
|
|
440
487
|
fileName: string;
|
|
@@ -444,6 +491,7 @@ export declare const DeliverMessageArgsSchema: z.ZodObject<{
|
|
|
444
491
|
}, {
|
|
445
492
|
text: string;
|
|
446
493
|
messageId: string;
|
|
494
|
+
author?: unknown;
|
|
447
495
|
attachments?: unknown;
|
|
448
496
|
}>;
|
|
449
497
|
export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
@@ -521,6 +569,18 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
521
569
|
* arrives as `undefined`, which is the same as «auto-update is off».
|
|
522
570
|
*/
|
|
523
571
|
agentLatestVersion: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
572
|
+
/**
|
|
573
|
+
* Who handed over the first message — the person who created the session, as
|
|
574
|
+
* DevBridge shows them. Sent only when the project has «Tell the agent who is
|
|
575
|
+
* writing» switched on and the prompt is not empty; `composeInitialPrompt`
|
|
576
|
+
* puts the name on top of the whole first message (`message-author.ts`).
|
|
577
|
+
*
|
|
578
|
+
* Optional, and absent means «no name»: an older API never sends it, and a
|
|
579
|
+
* project with the setting off gets exactly the first message it always had.
|
|
580
|
+
* `.catch(undefined)` like its neighbours — a bad value costs the signature,
|
|
581
|
+
* never the descriptor, never the `hello_ack` it rides in (QA-100 MAJOR-1).
|
|
582
|
+
*/
|
|
583
|
+
promptAuthor: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
524
584
|
workspace: z.ZodObject<{
|
|
525
585
|
id: z.ZodString;
|
|
526
586
|
path: z.ZodString;
|
|
@@ -727,6 +787,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
727
787
|
pausedUntil?: string | null | undefined;
|
|
728
788
|
backgroundTasks?: number | undefined;
|
|
729
789
|
agentLatestVersion?: string | undefined;
|
|
790
|
+
promptAuthor?: string | undefined;
|
|
730
791
|
skipAgentPrompt?: boolean | undefined;
|
|
731
792
|
branchHint?: string | undefined;
|
|
732
793
|
branchPlan?: {
|
|
@@ -778,6 +839,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
778
839
|
pausedUntil?: unknown;
|
|
779
840
|
backgroundTasks?: unknown;
|
|
780
841
|
agentLatestVersion?: unknown;
|
|
842
|
+
promptAuthor?: unknown;
|
|
781
843
|
skipAgentPrompt?: unknown;
|
|
782
844
|
branchHint?: unknown;
|
|
783
845
|
branchPlan?: unknown;
|
|
@@ -827,6 +889,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
827
889
|
pausedUntil?: string | null | undefined;
|
|
828
890
|
backgroundTasks?: number | undefined;
|
|
829
891
|
agentLatestVersion?: string | undefined;
|
|
892
|
+
promptAuthor?: string | undefined;
|
|
830
893
|
skipAgentPrompt?: boolean | undefined;
|
|
831
894
|
branchHint?: string | undefined;
|
|
832
895
|
branchPlan?: {
|
|
@@ -884,6 +947,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
884
947
|
pausedUntil?: unknown;
|
|
885
948
|
backgroundTasks?: unknown;
|
|
886
949
|
agentLatestVersion?: unknown;
|
|
950
|
+
promptAuthor?: unknown;
|
|
887
951
|
skipAgentPrompt?: unknown;
|
|
888
952
|
branchHint?: unknown;
|
|
889
953
|
branchPlan?: unknown;
|
|
@@ -990,6 +1054,18 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
990
1054
|
* arrives as `undefined`, which is the same as «auto-update is off».
|
|
991
1055
|
*/
|
|
992
1056
|
agentLatestVersion: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
1057
|
+
/**
|
|
1058
|
+
* Who handed over the first message — the person who created the session, as
|
|
1059
|
+
* DevBridge shows them. Sent only when the project has «Tell the agent who is
|
|
1060
|
+
* writing» switched on and the prompt is not empty; `composeInitialPrompt`
|
|
1061
|
+
* puts the name on top of the whole first message (`message-author.ts`).
|
|
1062
|
+
*
|
|
1063
|
+
* Optional, and absent means «no name»: an older API never sends it, and a
|
|
1064
|
+
* project with the setting off gets exactly the first message it always had.
|
|
1065
|
+
* `.catch(undefined)` like its neighbours — a bad value costs the signature,
|
|
1066
|
+
* never the descriptor, never the `hello_ack` it rides in (QA-100 MAJOR-1).
|
|
1067
|
+
*/
|
|
1068
|
+
promptAuthor: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
993
1069
|
workspace: z.ZodObject<{
|
|
994
1070
|
id: z.ZodString;
|
|
995
1071
|
path: z.ZodString;
|
|
@@ -1196,6 +1272,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1196
1272
|
pausedUntil?: string | null | undefined;
|
|
1197
1273
|
backgroundTasks?: number | undefined;
|
|
1198
1274
|
agentLatestVersion?: string | undefined;
|
|
1275
|
+
promptAuthor?: string | undefined;
|
|
1199
1276
|
skipAgentPrompt?: boolean | undefined;
|
|
1200
1277
|
branchHint?: string | undefined;
|
|
1201
1278
|
branchPlan?: {
|
|
@@ -1247,6 +1324,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1247
1324
|
pausedUntil?: unknown;
|
|
1248
1325
|
backgroundTasks?: unknown;
|
|
1249
1326
|
agentLatestVersion?: unknown;
|
|
1327
|
+
promptAuthor?: unknown;
|
|
1250
1328
|
skipAgentPrompt?: unknown;
|
|
1251
1329
|
branchHint?: unknown;
|
|
1252
1330
|
branchPlan?: unknown;
|
|
@@ -1295,6 +1373,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1295
1373
|
pausedUntil?: string | null | undefined;
|
|
1296
1374
|
backgroundTasks?: number | undefined;
|
|
1297
1375
|
agentLatestVersion?: string | undefined;
|
|
1376
|
+
promptAuthor?: string | undefined;
|
|
1298
1377
|
skipAgentPrompt?: boolean | undefined;
|
|
1299
1378
|
branchHint?: string | undefined;
|
|
1300
1379
|
branchPlan?: {
|
|
@@ -1349,6 +1428,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1349
1428
|
pausedUntil?: unknown;
|
|
1350
1429
|
backgroundTasks?: unknown;
|
|
1351
1430
|
agentLatestVersion?: unknown;
|
|
1431
|
+
promptAuthor?: unknown;
|
|
1352
1432
|
skipAgentPrompt?: unknown;
|
|
1353
1433
|
branchHint?: unknown;
|
|
1354
1434
|
branchPlan?: unknown;
|
|
@@ -1380,10 +1460,12 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1380
1460
|
mimeType: string;
|
|
1381
1461
|
fileSize: number;
|
|
1382
1462
|
}>, "many">>>;
|
|
1463
|
+
author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
1383
1464
|
}, "strip", z.ZodTypeAny, {
|
|
1384
1465
|
text: string;
|
|
1385
1466
|
sessionId: string;
|
|
1386
1467
|
type: "session_message";
|
|
1468
|
+
author?: string | undefined;
|
|
1387
1469
|
attachments?: {
|
|
1388
1470
|
id: string;
|
|
1389
1471
|
fileName: string;
|
|
@@ -1395,6 +1477,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1395
1477
|
text: string;
|
|
1396
1478
|
sessionId: string;
|
|
1397
1479
|
type: "session_message";
|
|
1480
|
+
author?: unknown;
|
|
1398
1481
|
attachments?: unknown;
|
|
1399
1482
|
messageId?: unknown;
|
|
1400
1483
|
}>, z.ZodObject<{
|
|
@@ -1435,6 +1518,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1435
1518
|
notes?: string | undefined;
|
|
1436
1519
|
}>, "many">>;
|
|
1437
1520
|
text: z.ZodOptional<z.ZodString>;
|
|
1521
|
+
author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
1438
1522
|
type: z.ZodLiteral<"question_answer">;
|
|
1439
1523
|
sessionId: z.ZodString;
|
|
1440
1524
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -1443,6 +1527,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1443
1527
|
action: "answer" | "discuss";
|
|
1444
1528
|
askId: string;
|
|
1445
1529
|
text?: string | undefined;
|
|
1530
|
+
author?: string | undefined;
|
|
1446
1531
|
answers?: {
|
|
1447
1532
|
values: string[];
|
|
1448
1533
|
questionId: string;
|
|
@@ -1455,6 +1540,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1455
1540
|
action: "answer" | "discuss";
|
|
1456
1541
|
askId: string;
|
|
1457
1542
|
text?: string | undefined;
|
|
1543
|
+
author?: unknown;
|
|
1458
1544
|
answers?: {
|
|
1459
1545
|
values: string[];
|
|
1460
1546
|
questionId: string;
|
package/dist/protocol.js
CHANGED
|
@@ -3,6 +3,12 @@ import { AGENT_DB_VALUES, AGENT_VERSION_PATTERN } from './agent-registry.js';
|
|
|
3
3
|
// Wire protocol with the DevBridge API (mirror of
|
|
4
4
|
// packages/api/src/modules/dev-orchestration/dev-orchestration.schema.ts —
|
|
5
5
|
// the API side is the source of truth).
|
|
6
|
+
/**
|
|
7
|
+
* The longest name the wire accepts for «who typed this». A display name from a
|
|
8
|
+
* profile, not a document — anything longer is not a name, and the field is a
|
|
9
|
+
* nicety: over the limit it is dropped and the message goes on without it.
|
|
10
|
+
*/
|
|
11
|
+
export const MESSAGE_AUTHOR_MAX = 200;
|
|
6
12
|
export const SessionDescriptorSchema = z.object({
|
|
7
13
|
id: z.string().uuid(),
|
|
8
14
|
kind: z.enum(['TICKET', 'CHAT']),
|
|
@@ -102,6 +108,18 @@ export const SessionDescriptorSchema = z.object({
|
|
|
102
108
|
.regex(new RegExp(AGENT_VERSION_PATTERN))
|
|
103
109
|
.optional()
|
|
104
110
|
.catch(undefined),
|
|
111
|
+
/**
|
|
112
|
+
* Who handed over the first message — the person who created the session, as
|
|
113
|
+
* DevBridge shows them. Sent only when the project has «Tell the agent who is
|
|
114
|
+
* writing» switched on and the prompt is not empty; `composeInitialPrompt`
|
|
115
|
+
* puts the name on top of the whole first message (`message-author.ts`).
|
|
116
|
+
*
|
|
117
|
+
* Optional, and absent means «no name»: an older API never sends it, and a
|
|
118
|
+
* project with the setting off gets exactly the first message it always had.
|
|
119
|
+
* `.catch(undefined)` like its neighbours — a bad value costs the signature,
|
|
120
|
+
* never the descriptor, never the `hello_ack` it rides in (QA-100 MAJOR-1).
|
|
121
|
+
*/
|
|
122
|
+
promptAuthor: z.string().max(MESSAGE_AUTHOR_MAX).optional().catch(undefined),
|
|
105
123
|
workspace: z.object({
|
|
106
124
|
id: z.string().uuid(),
|
|
107
125
|
path: z.string(),
|
|
@@ -263,6 +281,14 @@ export const QuestionAnswerShape = {
|
|
|
263
281
|
.max(4)
|
|
264
282
|
.optional(),
|
|
265
283
|
text: z.string().max(20_000).optional(),
|
|
284
|
+
/**
|
|
285
|
+
* Who typed `text` — sent only when the project has «Tell the agent who is
|
|
286
|
+
* writing» on. Signs the free text of a «discuss» reply (words a person typed
|
|
287
|
+
* into an open card are a message like any other) and the words rescued when
|
|
288
|
+
* the card turns out to be dead; a pick stays a pick. `.catch(undefined)`
|
|
289
|
+
* like the message author: a bad name costs the signature, not the answer.
|
|
290
|
+
*/
|
|
291
|
+
author: z.string().max(MESSAGE_AUTHOR_MAX).optional().catch(undefined),
|
|
266
292
|
};
|
|
267
293
|
/** The `answer_question` command's arguments — the shape above on its own. */
|
|
268
294
|
export const QuestionAnswerArgsSchema = z.object(QuestionAnswerShape);
|
|
@@ -295,6 +321,14 @@ export const DeliverMessageArgsSchema = z.object({
|
|
|
295
321
|
messageId: z.string().min(1).max(120),
|
|
296
322
|
text: z.string(),
|
|
297
323
|
attachments: MessageAttachmentsSchema,
|
|
324
|
+
/**
|
|
325
|
+
* Who typed it, as DevBridge shows them — present only when the project has
|
|
326
|
+
* «Tell the agent who is writing» switched on. Goes on top of the composed
|
|
327
|
+
* prompt (`message-author.ts`), never into the feed echo. `.catch(undefined)`
|
|
328
|
+
* for the same reason attachments have it: a malformed name must cost the
|
|
329
|
+
* signature, never the sentence the person typed.
|
|
330
|
+
*/
|
|
331
|
+
author: z.string().max(MESSAGE_AUTHOR_MAX).optional().catch(undefined),
|
|
298
332
|
});
|
|
299
333
|
export const GatewayFrameSchema = z.discriminatedUnion('type', [
|
|
300
334
|
z.object({
|
|
@@ -334,6 +368,10 @@ export const GatewayFrameSchema = z.discriminatedUnion('type', [
|
|
|
334
368
|
// fetched with the runner's own token. `.catch` so a malformed entry costs
|
|
335
369
|
// the attachments, never the message the user typed.
|
|
336
370
|
attachments: MessageAttachmentsSchema,
|
|
371
|
+
// Who typed it — the same field `deliver_message` carries, on the legacy
|
|
372
|
+
// door too, so a project with the setting on is not silently unsigned on
|
|
373
|
+
// an API that still sends the frame.
|
|
374
|
+
author: z.string().max(MESSAGE_AUTHOR_MAX).optional().catch(undefined),
|
|
337
375
|
}),
|
|
338
376
|
z.object({
|
|
339
377
|
type: z.literal('permission_answer'),
|
package/dist/supervisor.js
CHANGED
|
@@ -35,6 +35,7 @@ import { countRunningCommands, freshStallState, pickKillCandidate, readScopeProc
|
|
|
35
35
|
import { machineReserveBytes } from './service-unit.js';
|
|
36
36
|
import { sessionLimitsChangedEnough, sessionLimitsHeartbeatDue, SESSION_LIMITS_HEARTBEAT_MS, } from './session-limits.js';
|
|
37
37
|
import { composeMessageWithAttachments, saveAttachments, } from './attachments.js';
|
|
38
|
+
import { signMessage } from './message-author.js';
|
|
38
39
|
import { applyRewind, createCheckpoint, dropCheckpoints, listCheckpoints, MAX_BUSY_SESSIONS, previewRewind, pruneCheckpoints, } from './checkpoints.js';
|
|
39
40
|
import { DeliverMessageArgsSchema, QuestionAnswerArgsSchema } from './protocol.js';
|
|
40
41
|
import { availableModes, MODE_REFUSED_TEXT } from './adapters/types.js';
|
|
@@ -1828,7 +1829,7 @@ export class Supervisor {
|
|
|
1828
1829
|
// command yet. Its outcome goes nowhere because nobody is listening —
|
|
1829
1830
|
// which is the whole defect ticket #299 is about, and why the command
|
|
1830
1831
|
// below exists.
|
|
1831
|
-
this.acceptUserMessage(frame.sessionId, frame.text, frame.attachments, frame.messageId ?? undefined);
|
|
1832
|
+
this.acceptUserMessage(frame.sessionId, frame.text, frame.attachments, frame.messageId ?? undefined, frame.author);
|
|
1832
1833
|
break;
|
|
1833
1834
|
case 'permission_answer': {
|
|
1834
1835
|
const running = this.sessions.get(frame.sessionId);
|
|
@@ -1914,6 +1915,16 @@ export class Supervisor {
|
|
|
1914
1915
|
existing.stopRequested = true;
|
|
1915
1916
|
existing.session?.stop('session_stopped');
|
|
1916
1917
|
}
|
|
1918
|
+
// The descriptor also knows the feed better than this life does (#472).
|
|
1919
|
+
// The API writes lines of its own into a feed this runner numbers: the
|
|
1920
|
+
// refusal service puts «Continuing the session by itself» at the next
|
|
1921
|
+
// free seq and resumes a moment later, while this life is still going
|
|
1922
|
+
// down. The words that come with the resume are echoed by THIS life, and
|
|
1923
|
+
// its counter knew nothing of that line – the echo reused its number and
|
|
1924
|
+
// the API dropped it as a duplicate. Before the `await` below: the words
|
|
1925
|
+
// arrive right behind this frame. A no-op whenever this runner wrote the
|
|
1926
|
+
// last row itself.
|
|
1927
|
+
existing.journal.ensureSeqAbove(descriptor.lastSeq);
|
|
1917
1928
|
// The descriptor is newer than what this session was built from, so its
|
|
1918
1929
|
// clock is too (QA-149 MAJOR-1). Applied on the way out of every early
|
|
1919
1930
|
// return, not just the reconnect one — a descriptor re-sent for any
|
|
@@ -2021,7 +2032,7 @@ export class Supervisor {
|
|
|
2021
2032
|
if (orphaned) {
|
|
2022
2033
|
this.orphanMessages.delete(descriptor.id);
|
|
2023
2034
|
for (const message of orphaned) {
|
|
2024
|
-
this.acceptUserMessage(descriptor.id, message.text, message.attachments, message.messageId);
|
|
2035
|
+
this.acceptUserMessage(descriptor.id, message.text, message.attachments, message.messageId, message.author);
|
|
2025
2036
|
}
|
|
2026
2037
|
}
|
|
2027
2038
|
try {
|
|
@@ -2935,9 +2946,18 @@ export class Supervisor {
|
|
|
2935
2946
|
}
|
|
2936
2947
|
// Keep the journal while offline: the recorded terminal status is what
|
|
2937
2948
|
// reconcile replays after the next reconnect (QA-96 F1).
|
|
2949
|
+
//
|
|
2950
|
+
// …and while a resume is queued behind this life (#472). The next life
|
|
2951
|
+
// opens this same journal, and two things it needs live only here: the
|
|
2952
|
+
// words parked for it (`acceptUserMessage` holds a message that reached a
|
|
2953
|
+
// life already on its way out) and the seq counter. Deleted, the resume
|
|
2954
|
+
// started from an empty file – the platform's «continue» after a refusal
|
|
2955
|
+
// was gone, and «Session resumed» reused a seq the old life had already
|
|
2956
|
+
// sent, so the API dropped it. The session sat idle with nothing on screen.
|
|
2938
2957
|
if (this.ws.connected &&
|
|
2939
2958
|
running.journal.unacked().length === 0 &&
|
|
2940
|
-
isTerminal(running.lastReported)
|
|
2959
|
+
isTerminal(running.lastReported) &&
|
|
2960
|
+
!running.pendingRestart) {
|
|
2941
2961
|
this.journals.closeAndDelete(descriptor.id);
|
|
2942
2962
|
}
|
|
2943
2963
|
// The map just lost an entry, and this is the one place where that happens
|
|
@@ -4293,11 +4313,18 @@ export class Supervisor {
|
|
|
4293
4313
|
// own events reach the feed a microtask later, so the user's words still
|
|
4294
4314
|
// land before the agent's reaction — and on a miss we can hand the text to
|
|
4295
4315
|
// the ordinary delivery path, which does the echo itself.
|
|
4316
|
+
//
|
|
4317
|
+
// The free text of a «discuss» reply is a person's message like any other,
|
|
4318
|
+
// so it is signed for the agent the way `acceptUserMessage` signs one
|
|
4319
|
+
// (`message-author.ts`) — and only for the agent: the echo below stays the
|
|
4320
|
+
// words as typed. A pick (`answer`) is structured and gets no line.
|
|
4296
4321
|
const accepted = running.session?.answerQuestion({
|
|
4297
4322
|
askId: frame.askId,
|
|
4298
4323
|
action: frame.action,
|
|
4299
4324
|
...(frame.answers ? { answers: frame.answers } : {}),
|
|
4300
|
-
...(frame.text !== undefined
|
|
4325
|
+
...(frame.text !== undefined
|
|
4326
|
+
? { text: frame.action === 'discuss' ? signMessage(frame.text, frame.author) : frame.text }
|
|
4327
|
+
: {}),
|
|
4301
4328
|
});
|
|
4302
4329
|
if (accepted) {
|
|
4303
4330
|
running.answeredAsks.add(frame.askId);
|
|
@@ -4372,7 +4399,7 @@ export class Supervisor {
|
|
|
4372
4399
|
this.sendEvent(running, 'system_note', {
|
|
4373
4400
|
text: 'That question is no longer open — sending your reply as an ordinary message instead.',
|
|
4374
4401
|
});
|
|
4375
|
-
this.acceptUserMessage(frame.sessionId, rescued);
|
|
4402
|
+
this.acceptUserMessage(frame.sessionId, rescued, undefined, undefined, frame.author);
|
|
4376
4403
|
return 'not_open';
|
|
4377
4404
|
}
|
|
4378
4405
|
// Nothing to deliver — but the API optimistically flipped the session to
|
|
@@ -4395,7 +4422,14 @@ export class Supervisor {
|
|
|
4395
4422
|
* thrown away, because «I wrote it into a socket» was never an answer to
|
|
4396
4423
|
* «did the runner get it».
|
|
4397
4424
|
*/
|
|
4398
|
-
acceptUserMessage(sessionId, text, attachments, messageId
|
|
4425
|
+
acceptUserMessage(sessionId, text, attachments, messageId,
|
|
4426
|
+
/**
|
|
4427
|
+
* Who typed it, as DevBridge shows them — sent only when the project has
|
|
4428
|
+
* «Tell the agent who is writing» on. Goes on top of the COMPOSED prompt
|
|
4429
|
+
* (`message-author.ts`), the way attachment paths do; the feed echo below
|
|
4430
|
+
* stays the bare text, exactly as the person wrote it.
|
|
4431
|
+
*/
|
|
4432
|
+
author) {
|
|
4399
4433
|
const running = this.sessions.get(sessionId);
|
|
4400
4434
|
if (!running) {
|
|
4401
4435
|
// The API believes this session lives here but the runner lost track of
|
|
@@ -4417,6 +4451,7 @@ export class Supervisor {
|
|
|
4417
4451
|
text,
|
|
4418
4452
|
...(attachments?.length ? { attachments } : {}),
|
|
4419
4453
|
...(messageId ? { messageId } : {}),
|
|
4454
|
+
...(author ? { author } : {}),
|
|
4420
4455
|
});
|
|
4421
4456
|
this.orphanMessages.set(sessionId, queued.slice(-Supervisor.ORPHAN_MESSAGE_CAP));
|
|
4422
4457
|
this.ws.send({ type: 'session_unknown', sessionId });
|
|
@@ -4483,17 +4518,17 @@ export class Supervisor {
|
|
|
4483
4518
|
// check — the outbox flushes on reconnect, and the git service posts its
|
|
4484
4519
|
// own conflict tasks. Held here rather than delivered, so «на паузе»
|
|
4485
4520
|
// means the same thing whichever door the words came through.
|
|
4486
|
-
this.queueMessage(running, running.journal.appendPending(text, attachments, originSeq));
|
|
4521
|
+
this.queueMessage(running, running.journal.appendPending(text, attachments, originSeq, author));
|
|
4487
4522
|
return 'accepted';
|
|
4488
4523
|
}
|
|
4489
4524
|
this.enqueueDelivery(running, async () => {
|
|
4490
|
-
const composed = await this.materializeAttachments(running, text, attachments);
|
|
4525
|
+
const composed = signMessage(await this.materializeAttachments(running, text, attachments), author);
|
|
4491
4526
|
if (this.isStale(running)) {
|
|
4492
4527
|
// The session ended while the files downloaded. Park the message on
|
|
4493
4528
|
// disk rather than dropping it — «Продолжить» carries it to the agent.
|
|
4494
4529
|
// Announced like every other queueing decision: a bubble that is
|
|
4495
4530
|
// waiting must say so, whichever door it came through.
|
|
4496
|
-
const parked = running.journal.appendPending(text, attachments, originSeq);
|
|
4531
|
+
const parked = running.journal.appendPending(text, attachments, originSeq, author);
|
|
4497
4532
|
if (parked.seq !== undefined) {
|
|
4498
4533
|
this.sendEvent(running, 'message_queued', { targetSeq: parked.seq });
|
|
4499
4534
|
}
|
|
@@ -5077,7 +5112,10 @@ export class Supervisor {
|
|
|
5077
5112
|
const parts = [];
|
|
5078
5113
|
try {
|
|
5079
5114
|
for (const record of pending) {
|
|
5080
|
-
|
|
5115
|
+
// Each part under its own name: two people who wrote while the
|
|
5116
|
+
// session was held go to the agent together, and the agent must
|
|
5117
|
+
// still be able to tell which words are whose.
|
|
5118
|
+
parts.push(signMessage(await this.materializeAttachments(running, record.text, record.attachments), record.author));
|
|
5081
5119
|
}
|
|
5082
5120
|
}
|
|
5083
5121
|
catch (error) {
|
|
@@ -6507,7 +6545,7 @@ export class Supervisor {
|
|
|
6507
6545
|
error: parsed.error.issues[0]?.message ?? 'malformed message',
|
|
6508
6546
|
});
|
|
6509
6547
|
}
|
|
6510
|
-
const outcome = this.acceptUserMessage(sessionId, parsed.data.text, parsed.data.attachments, parsed.data.messageId);
|
|
6548
|
+
const outcome = this.acceptUserMessage(sessionId, parsed.data.text, parsed.data.attachments, parsed.data.messageId, parsed.data.author);
|
|
6511
6549
|
// `ok` is about the RELAY, like the answer above: `unknown_session` is
|
|
6512
6550
|
// the one case the API can fix by asking again after it has re-sent
|
|
6513
6551
|
// the descriptor, so it is the one case reported as a failure.
|
|
@@ -8219,6 +8257,15 @@ export function carryOnMessage(refusedWhole) {
|
|
|
8219
8257
|
* prompt beside `CLAUDE.md` — which is read last and therefore overrides ours.
|
|
8220
8258
|
*/
|
|
8221
8259
|
export function composeInitialPrompt(descriptor) {
|
|
8260
|
+
const body = composeInitialBody(descriptor);
|
|
8261
|
+
// Signed like every later message (`message-author.ts`): the API names the
|
|
8262
|
+
// creator only when the project has «Tell the agent who is writing» on. The
|
|
8263
|
+
// name goes above the assignment too — handing a ticket over is that
|
|
8264
|
+
// person's act. An empty first message stays empty: there is nothing to sign
|
|
8265
|
+
// and the agent is meant to boot and wait.
|
|
8266
|
+
return body === '' ? body : signMessage(body, descriptor.promptAuthor);
|
|
8267
|
+
}
|
|
8268
|
+
function composeInitialBody(descriptor) {
|
|
8222
8269
|
// A free chat may carry tickets as CONTEXT. Assigning them would put an agent
|
|
8223
8270
|
// nobody asked onto somebody else's ticket (session 13).
|
|
8224
8271
|
if (descriptor.kind === 'CHAT' || descriptor.tickets.length === 0)
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const RUNNER_VERSION = "0.
|
|
1
|
+
export declare const RUNNER_VERSION = "0.70.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
package/package.json
CHANGED