oficina-opencode 2.0.1 → 2.1.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/README.md +164 -14
- package/commands/oficina.md +22 -9
- package/dist/core/atomic.d.ts +85 -0
- package/dist/core/atomic.d.ts.map +1 -0
- package/dist/core/atomic.js +186 -0
- package/dist/core/atomic.js.map +1 -0
- package/dist/core/bus.d.ts +76 -56
- package/dist/core/bus.d.ts.map +1 -1
- package/dist/core/bus.js +141 -100
- package/dist/core/bus.js.map +1 -1
- package/dist/core/catalog.d.ts +27 -0
- package/dist/core/catalog.d.ts.map +1 -1
- package/dist/core/catalog.js +41 -6
- package/dist/core/catalog.js.map +1 -1
- package/dist/core/cost.d.ts +275 -0
- package/dist/core/cost.d.ts.map +1 -0
- package/dist/core/cost.js +724 -0
- package/dist/core/cost.js.map +1 -0
- package/dist/core/docsync.d.ts +124 -0
- package/dist/core/docsync.d.ts.map +1 -0
- package/dist/core/docsync.js +191 -0
- package/dist/core/docsync.js.map +1 -0
- package/dist/core/evidence.d.ts +314 -0
- package/dist/core/evidence.d.ts.map +1 -0
- package/dist/core/evidence.js +602 -0
- package/dist/core/evidence.js.map +1 -0
- package/dist/core/fsx.d.ts.map +1 -1
- package/dist/core/fsx.js +7 -1
- package/dist/core/fsx.js.map +1 -1
- package/dist/core/gates.d.ts +9 -2
- package/dist/core/gates.d.ts.map +1 -1
- package/dist/core/gates.js +19 -3
- package/dist/core/gates.js.map +1 -1
- package/dist/core/ids.d.ts +48 -0
- package/dist/core/ids.d.ts.map +1 -0
- package/dist/core/ids.js +87 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/leases.d.ts +45 -0
- package/dist/core/leases.d.ts.map +1 -1
- package/dist/core/leases.js +85 -17
- package/dist/core/leases.js.map +1 -1
- package/dist/core/office.d.ts +72 -1
- package/dist/core/office.d.ts.map +1 -1
- package/dist/core/office.js +173 -6
- package/dist/core/office.js.map +1 -1
- package/dist/core/paths.d.ts +11 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +28 -4
- package/dist/core/paths.js.map +1 -1
- package/dist/core/recovery.d.ts +87 -0
- package/dist/core/recovery.d.ts.map +1 -0
- package/dist/core/recovery.js +325 -0
- package/dist/core/recovery.js.map +1 -0
- package/dist/core/sandbox.d.ts +179 -0
- package/dist/core/sandbox.d.ts.map +1 -0
- package/dist/core/sandbox.js +546 -0
- package/dist/core/sandbox.js.map +1 -0
- package/dist/core/state.d.ts +7 -0
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/state.js +15 -1
- package/dist/core/state.js.map +1 -1
- package/dist/core/stores.d.ts +65 -0
- package/dist/core/stores.d.ts.map +1 -0
- package/dist/core/stores.js +115 -0
- package/dist/core/stores.js.map +1 -0
- package/dist/core/tripwire.d.ts +87 -0
- package/dist/core/tripwire.d.ts.map +1 -0
- package/dist/core/tripwire.js +203 -0
- package/dist/core/tripwire.js.map +1 -0
- package/dist/core/types.d.ts +33 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +1 -0
- package/dist/core/types.js.map +1 -1
- package/dist/hooks/scopeGuard.d.ts +86 -13
- package/dist/hooks/scopeGuard.d.ts.map +1 -1
- package/dist/hooks/scopeGuard.js +296 -62
- package/dist/hooks/scopeGuard.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +185 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +158 -0
- package/dist/tools/index.js.map +1 -1
- package/docs/COMPATIBILITY.md +98 -0
- package/docs/GARANTIAS.md +190 -0
- package/docs/PLAN-V2.1.md +144 -0
- package/docs/QUE-ES.md +15 -0
- package/docs/catalog-facts.json +27 -0
- package/package.json +6 -2
- package/skills/oficina/SKILL.md +191 -69
- package/skills/oficina/reference/mesh.md +11 -2
package/dist/core/bus.d.ts
CHANGED
|
@@ -1,25 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* - Polling, no push: cada agente globa su inbox. Compatible con subagentes.
|
|
13
|
-
* - Ack: el receptor deja rastro de qué leyó.
|
|
14
|
-
* - TTL: un mensaje vencido es invisible para lectores nuevos, sigue en el log.
|
|
15
|
-
* - Idempotency key: un pedido con la misma key no se duplica.
|
|
16
|
-
* - Broadcast: `to: ["*"]` llega al pool; el primero que toma el lease gana.
|
|
17
|
-
*/
|
|
18
|
-
import type { BusMessage, MessageKind, MessagePriority } from "./types.js";
|
|
19
|
-
export interface BusOptions {
|
|
20
|
-
ttlSec?: number;
|
|
21
|
-
clock?: () => number;
|
|
22
|
-
}
|
|
1
|
+
export declare const CHANNELS: {
|
|
2
|
+
/** Del comando al flujo. */
|
|
3
|
+
readonly command: "coord-command";
|
|
4
|
+
/** Del arquitecto a los coordinadores. */
|
|
5
|
+
readonly arch: "coord-arch";
|
|
6
|
+
/** Del flujo al comando. */
|
|
7
|
+
readonly flow: "coord-flow";
|
|
8
|
+
/** Entre pares. */
|
|
9
|
+
readonly peer: "peer";
|
|
10
|
+
};
|
|
11
|
+
export type ChannelId = (typeof CHANNELS)[keyof typeof CHANNELS];
|
|
23
12
|
export interface SendInput {
|
|
24
13
|
from: string;
|
|
25
14
|
to: string[];
|
|
@@ -33,41 +22,72 @@ export interface SendInput {
|
|
|
33
22
|
idempotencyKey?: string | null;
|
|
34
23
|
hops?: number;
|
|
35
24
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
25
|
+
export interface BusOptions {
|
|
26
|
+
ttlSec?: number;
|
|
27
|
+
clock?: () => number;
|
|
28
|
+
}
|
|
29
|
+
export type MessageKind = "HELP_REQUEST" | "HELP_ACCEPT" | "HELP_DECLINE" | "HELP_PARTIAL" | "HELP_QUESTION" | "QUESTION" | "ANSWER" | "SPAWN_REQUEST" | "SPAWN_APPROVED" | "SPAWN_REJECTED" | "CLAIM" | "RELEASE" | "STATUS" | "NOTICE";
|
|
30
|
+
export type MessagePriority = "low" | "normal" | "high" | "critical";
|
|
31
|
+
export interface BusMessage {
|
|
32
|
+
id: string;
|
|
33
|
+
seq: number;
|
|
34
|
+
from: string;
|
|
35
|
+
to: string[];
|
|
36
|
+
kind: MessageKind;
|
|
37
|
+
subject: string;
|
|
38
|
+
body: Record<string, unknown>;
|
|
39
|
+
replyTo: string | null;
|
|
40
|
+
inReplyTo: string | null;
|
|
41
|
+
ttlSec: number;
|
|
42
|
+
createdAt: string;
|
|
43
|
+
priority: MessagePriority;
|
|
44
|
+
idempotencyKey: string | null;
|
|
45
|
+
hops: number;
|
|
46
|
+
}
|
|
47
|
+
export interface BusAck {
|
|
48
|
+
messageId: string;
|
|
49
|
+
agentId: string;
|
|
50
|
+
ackedAt: string;
|
|
51
51
|
}
|
|
52
52
|
export declare class Bus {
|
|
53
53
|
private readonly paths;
|
|
54
54
|
private readonly ttlDefault;
|
|
55
55
|
private readonly clock;
|
|
56
|
-
constructor(paths:
|
|
56
|
+
constructor(paths: {
|
|
57
|
+
busDir: string;
|
|
58
|
+
inboxDir: string;
|
|
59
|
+
}, options?: BusOptions);
|
|
57
60
|
private channelDir;
|
|
58
|
-
private
|
|
61
|
+
private ackDir;
|
|
59
62
|
/**
|
|
60
63
|
* Próximo `seq` de un canal.
|
|
61
64
|
*
|
|
62
65
|
* Se deriva de los archivos existentes, no de un contador en memoria: así
|
|
63
|
-
*
|
|
66
|
+
* el estado sobrevive a un reinicio.
|
|
67
|
+
*
|
|
68
|
+
* OJO: derivarlo NO lo hace atomico por sí solo. Dos emisores
|
|
69
|
+
* concurrentes podian leer el mismo `max + 1` y dejar dos mensajes con el
|
|
70
|
+
* mismo seq. La asignacion real esta en `send`, que hace la asignacion Y
|
|
71
|
+
* la escritura bajo el mismo lock.
|
|
64
72
|
*/
|
|
65
73
|
private nextSeq;
|
|
74
|
+
private listChannelFiles;
|
|
66
75
|
/**
|
|
67
76
|
* Publica un mensaje.
|
|
68
77
|
*
|
|
69
78
|
* Si ya existe un mensaje vivo con la misma `idempotencyKey` en el canal,
|
|
70
79
|
* no se publica un duplicado: se devuelve el existente.
|
|
80
|
+
*
|
|
81
|
+
* ## Atomicidad
|
|
82
|
+
*
|
|
83
|
+
* Todo el critical path (chequeo de idempotencia, asignacion de seq y
|
|
84
|
+
* escritura) ocurre **bajo un lock de canal**. Sin eso:
|
|
85
|
+
*
|
|
86
|
+
* - Dos emisores concurrentes con la misma `idempotencyKey` pasaban los
|
|
87
|
+
* dos el chequeo "existe?" y creaban dos mensajes. La idempotencia era
|
|
88
|
+
* decorativa.
|
|
89
|
+
* - Dos emisores concurrentes calculaban el mismo `seq` y dejaban dos
|
|
90
|
+
* mensajes con el mismo numero, rompiendo el orden del canal.
|
|
71
91
|
*/
|
|
72
92
|
send(channel: string, input: SendInput): Promise<BusMessage>;
|
|
73
93
|
/** Busca un mensaje vivo por su idempotency key en un canal. */
|
|
@@ -76,30 +96,30 @@ export declare class Bus {
|
|
|
76
96
|
readChannel(channel: string): Promise<BusMessage[]>;
|
|
77
97
|
/** ¿El mensaje venció? */
|
|
78
98
|
isExpired(message: BusMessage): boolean;
|
|
79
|
-
/** ¿El mensaje
|
|
99
|
+
/** ¿El mensaje es para este agente? */
|
|
80
100
|
isAddressedTo(message: BusMessage, agentId: string): boolean;
|
|
81
101
|
/**
|
|
82
|
-
* Recibe
|
|
102
|
+
* Recibe mensajes dirigidos al agente.
|
|
83
103
|
*
|
|
84
|
-
* Los
|
|
104
|
+
* Los yaodrivenados por el agente se filtran: no puede auto-confirmarse.
|
|
85
105
|
*/
|
|
86
106
|
receive(agentId: string, channels?: string[]): Promise<BusMessage[]>;
|
|
87
|
-
/** Ids que
|
|
107
|
+
/** Ids que este agente ya acknowledgeo. */
|
|
88
108
|
ackedIds(agentId: string): Promise<Set<string>>;
|
|
89
|
-
/**
|
|
109
|
+
/**
|
|
110
|
+
* Confirma un mensaje.
|
|
111
|
+
*
|
|
112
|
+
* El `messageId` se sanitiza: venia del modelo y se usaba crudo como
|
|
113
|
+
* nombre de archivo.
|
|
114
|
+
*/
|
|
90
115
|
ack(agentId: string, messageId: string): Promise<void>;
|
|
91
|
-
/**
|
|
116
|
+
/** Confirma varios mensajes. */
|
|
92
117
|
ackMany(agentId: string, messageIds: string[]): Promise<void>;
|
|
93
|
-
/** ¿Quién
|
|
118
|
+
/** ¿Quién confirmo este mensaje? */
|
|
94
119
|
ackedBy(messageId: string): Promise<string[]>;
|
|
95
|
-
/**
|
|
120
|
+
/** ¿En qué canal está un mensaje? */
|
|
96
121
|
channelOf(messageId: string): Promise<string | undefined>;
|
|
97
|
-
/**
|
|
98
|
-
* Publica un pedido de ayuda.
|
|
99
|
-
*
|
|
100
|
-
* La idempotency key deriva de card + agente + motivo, así dos intentos del
|
|
101
|
-
* mismo pedido no generan un storm en el pool.
|
|
102
|
-
*/
|
|
122
|
+
/** Pide ayuda a uno o varios agentes. */
|
|
103
123
|
requestHelp(input: {
|
|
104
124
|
from: string;
|
|
105
125
|
to: string[];
|
|
@@ -118,7 +138,7 @@ export declare class Bus {
|
|
|
118
138
|
inReplyTo: string;
|
|
119
139
|
hops?: number;
|
|
120
140
|
}): Promise<BusMessage>;
|
|
121
|
-
/**
|
|
141
|
+
/** Pide ayuda a todos los pares. */
|
|
122
142
|
broadcastHelp(input: {
|
|
123
143
|
from: string;
|
|
124
144
|
cardId: string;
|
|
@@ -126,7 +146,7 @@ export declare class Bus {
|
|
|
126
146
|
whyMe: string;
|
|
127
147
|
hops?: number;
|
|
128
148
|
}): Promise<BusMessage>;
|
|
129
|
-
/**
|
|
149
|
+
/** Estadísticas por canal. */
|
|
130
150
|
stats(): Promise<Record<string, number>>;
|
|
131
151
|
}
|
|
132
152
|
//# sourceMappingURL=bus.d.ts.map
|
package/dist/core/bus.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/core/bus.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/core/bus.ts"],"names":[],"mappings":"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"}
|
package/dist/core/bus.js
CHANGED
|
@@ -1,30 +1,26 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bus de mensajes append-only sobre disco.
|
|
3
|
-
*
|
|
4
|
-
* Por qué disco y no memoria: los subagentes de OpenCode son procesos
|
|
5
|
-
* aislados. No comparten heap. Un bus en memoria sería un bus de una sola
|
|
6
|
-
* sesión. El disco es el único bus que sobrevive, que es compartible entre
|
|
7
|
-
* harnesses, y que es auditable después.
|
|
8
|
-
*
|
|
9
|
-
* Semántica:
|
|
10
|
-
* - Append-only: los mensajes nunca se borran. `seq` es monótono por canal.
|
|
11
|
-
* - Escritura atómica: tmp + rename. Nunca hay un JSON partido en el read.
|
|
12
|
-
* - Polling, no push: cada agente globa su inbox. Compatible con subagentes.
|
|
13
|
-
* - Ack: el receptor deja rastro de qué leyó.
|
|
14
|
-
* - TTL: un mensaje vencido es invisible para lectores nuevos, sigue en el log.
|
|
15
|
-
* - Idempotency key: un pedido con la misma key no se duplica.
|
|
16
|
-
* - Broadcast: `to: ["*"]` llega al pool; el primero que toma el lease gana.
|
|
17
|
-
*/
|
|
18
|
-
import path from "node:path";
|
|
19
1
|
import fs from "node:fs/promises";
|
|
20
|
-
import
|
|
21
|
-
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { withLock } from "./atomic.js";
|
|
4
|
+
import { safeId } from "./ids.js";
|
|
5
|
+
import { nowIso, readJson, shortId, stableHash, writeJsonAtomic } from "./fsx.js";
|
|
6
|
+
import { logger } from "./log.js";
|
|
7
|
+
const log = logger("oficina:bus");
|
|
22
8
|
export const CHANNELS = {
|
|
9
|
+
/** Del comando al flujo. */
|
|
23
10
|
command: "coord-command",
|
|
11
|
+
/** Del arquitecto a los coordinadores. */
|
|
24
12
|
arch: "coord-arch",
|
|
13
|
+
/** Del flujo al comando. */
|
|
25
14
|
flow: "coord-flow",
|
|
15
|
+
/** Entre pares. */
|
|
26
16
|
peer: "peer",
|
|
27
17
|
};
|
|
18
|
+
const PRIORITY_ORDER = {
|
|
19
|
+
critical: 0,
|
|
20
|
+
high: 1,
|
|
21
|
+
normal: 2,
|
|
22
|
+
low: 3,
|
|
23
|
+
};
|
|
28
24
|
export class Bus {
|
|
29
25
|
paths;
|
|
30
26
|
ttlDefault;
|
|
@@ -37,17 +33,22 @@ export class Bus {
|
|
|
37
33
|
channelDir(channel) {
|
|
38
34
|
return path.join(this.paths.busDir, channel);
|
|
39
35
|
}
|
|
40
|
-
|
|
36
|
+
ackDir(agentId) {
|
|
41
37
|
return path.join(this.paths.inboxDir, agentId);
|
|
42
38
|
}
|
|
43
39
|
/**
|
|
44
40
|
* Próximo `seq` de un canal.
|
|
45
41
|
*
|
|
46
42
|
* Se deriva de los archivos existentes, no de un contador en memoria: así
|
|
47
|
-
*
|
|
43
|
+
* el estado sobrevive a un reinicio.
|
|
44
|
+
*
|
|
45
|
+
* OJO: derivarlo NO lo hace atomico por sí solo. Dos emisores
|
|
46
|
+
* concurrentes podian leer el mismo `max + 1` y dejar dos mensajes con el
|
|
47
|
+
* mismo seq. La asignacion real esta en `send`, que hace la asignacion Y
|
|
48
|
+
* la escritura bajo el mismo lock.
|
|
48
49
|
*/
|
|
49
50
|
async nextSeq(channel) {
|
|
50
|
-
const files = await
|
|
51
|
+
const files = await this.listChannelFiles(channel);
|
|
51
52
|
let max = 0;
|
|
52
53
|
for (const f of files) {
|
|
53
54
|
const m = /^(\d{4,})-/.exec(f);
|
|
@@ -59,38 +60,60 @@ export class Bus {
|
|
|
59
60
|
}
|
|
60
61
|
return max + 1;
|
|
61
62
|
}
|
|
63
|
+
async listChannelFiles(channel) {
|
|
64
|
+
try {
|
|
65
|
+
const entries = await fs.readdir(this.channelDir(channel));
|
|
66
|
+
return entries.filter((e) => e.endsWith(".json"));
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
62
72
|
/**
|
|
63
73
|
* Publica un mensaje.
|
|
64
74
|
*
|
|
65
75
|
* Si ya existe un mensaje vivo con la misma `idempotencyKey` en el canal,
|
|
66
76
|
* no se publica un duplicado: se devuelve el existente.
|
|
77
|
+
*
|
|
78
|
+
* ## Atomicidad
|
|
79
|
+
*
|
|
80
|
+
* Todo el critical path (chequeo de idempotencia, asignacion de seq y
|
|
81
|
+
* escritura) ocurre **bajo un lock de canal**. Sin eso:
|
|
82
|
+
*
|
|
83
|
+
* - Dos emisores concurrentes con la misma `idempotencyKey` pasaban los
|
|
84
|
+
* dos el chequeo "existe?" y creaban dos mensajes. La idempotencia era
|
|
85
|
+
* decorativa.
|
|
86
|
+
* - Dos emisores concurrentes calculaban el mismo `seq` y dejaban dos
|
|
87
|
+
* mensajes con el mismo numero, rompiendo el orden del canal.
|
|
67
88
|
*/
|
|
68
89
|
async send(channel, input) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
return withChannelLock(this.channelDir(channel), async () => {
|
|
91
|
+
if (input.idempotencyKey) {
|
|
92
|
+
const existing = await this.findByIdempotencyKey(channel, input.idempotencyKey);
|
|
93
|
+
if (existing)
|
|
94
|
+
return existing;
|
|
95
|
+
}
|
|
96
|
+
const seq = await this.nextSeq(channel);
|
|
97
|
+
const message = {
|
|
98
|
+
id: shortId("m"),
|
|
99
|
+
seq,
|
|
100
|
+
from: input.from,
|
|
101
|
+
to: input.to,
|
|
102
|
+
kind: input.kind,
|
|
103
|
+
subject: input.subject,
|
|
104
|
+
body: input.body ?? {},
|
|
105
|
+
replyTo: input.replyTo ?? null,
|
|
106
|
+
inReplyTo: input.inReplyTo ?? null,
|
|
107
|
+
ttlSec: input.ttlSec ?? this.ttlDefault,
|
|
108
|
+
createdAt: nowIso(this.clock),
|
|
109
|
+
priority: input.priority ?? "normal",
|
|
110
|
+
idempotencyKey: input.idempotencyKey ?? null,
|
|
111
|
+
hops: input.hops ?? 0,
|
|
112
|
+
};
|
|
113
|
+
const file = path.join(this.channelDir(channel), `${String(seq).padStart(4, "0")}-${message.id}.json`);
|
|
114
|
+
await writeJsonAtomic(file, message);
|
|
115
|
+
return message;
|
|
116
|
+
});
|
|
94
117
|
}
|
|
95
118
|
/** Busca un mensaje vivo por su idempotency key en un canal. */
|
|
96
119
|
async findByIdempotencyKey(channel, key) {
|
|
@@ -102,22 +125,20 @@ export class Bus {
|
|
|
102
125
|
}
|
|
103
126
|
/** Lee todos los mensajes de un canal, ordenados por seq. */
|
|
104
127
|
async readChannel(channel) {
|
|
105
|
-
const
|
|
106
|
-
const files = (await listFiles(dir)).filter((f) => f.endsWith(".json")).sort();
|
|
128
|
+
const files = (await this.listChannelFiles(channel)).sort();
|
|
107
129
|
const out = [];
|
|
108
130
|
for (const f of files) {
|
|
109
|
-
const
|
|
110
|
-
if (
|
|
111
|
-
out.push(
|
|
131
|
+
const message = await readJson(path.join(this.channelDir(channel), f));
|
|
132
|
+
if (message)
|
|
133
|
+
out.push(message);
|
|
112
134
|
}
|
|
113
135
|
return out.sort((a, b) => a.seq - b.seq);
|
|
114
136
|
}
|
|
115
137
|
/** ¿El mensaje venció? */
|
|
116
138
|
isExpired(message) {
|
|
117
|
-
|
|
118
|
-
return age > message.ttlSec * 1000;
|
|
139
|
+
return this.clock() - Date.parse(message.createdAt) > message.ttlSec * 1000;
|
|
119
140
|
}
|
|
120
|
-
/** ¿El mensaje
|
|
141
|
+
/** ¿El mensaje es para este agente? */
|
|
121
142
|
isAddressedTo(message, agentId) {
|
|
122
143
|
if (message.from === agentId)
|
|
123
144
|
return false;
|
|
@@ -126,9 +147,9 @@ export class Bus {
|
|
|
126
147
|
return message.to.includes(agentId);
|
|
127
148
|
}
|
|
128
149
|
/**
|
|
129
|
-
* Recibe
|
|
150
|
+
* Recibe mensajes dirigidos al agente.
|
|
130
151
|
*
|
|
131
|
-
* Los
|
|
152
|
+
* Los yaodrivenados por el agente se filtran: no puede auto-confirmarse.
|
|
132
153
|
*/
|
|
133
154
|
async receive(agentId, channels = [CHANNELS.peer]) {
|
|
134
155
|
const acked = await this.ackedIds(agentId);
|
|
@@ -145,71 +166,82 @@ export class Bus {
|
|
|
145
166
|
}
|
|
146
167
|
}
|
|
147
168
|
return out.sort((a, b) => {
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
|
|
169
|
+
const pa = PRIORITY_ORDER[a.priority] ?? 2;
|
|
170
|
+
const pb = PRIORITY_ORDER[b.priority] ?? 2;
|
|
171
|
+
if (pa !== pb)
|
|
172
|
+
return pa - pb;
|
|
173
|
+
return a.seq - b.seq;
|
|
151
174
|
});
|
|
152
175
|
}
|
|
153
|
-
/** Ids que
|
|
176
|
+
/** Ids que este agente ya acknowledgeo. */
|
|
154
177
|
async ackedIds(agentId) {
|
|
155
|
-
const dir = this.
|
|
156
|
-
const files = await listFiles(dir);
|
|
178
|
+
const dir = this.ackDir(agentId);
|
|
157
179
|
const out = new Set();
|
|
180
|
+
let files;
|
|
181
|
+
try {
|
|
182
|
+
files = await fs.readdir(dir);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
158
187
|
for (const f of files) {
|
|
159
188
|
if (!f.endsWith(".ack"))
|
|
160
189
|
continue;
|
|
161
|
-
|
|
162
|
-
if (ack)
|
|
163
|
-
out.add(ack.messageId);
|
|
190
|
+
out.add(f.slice(0, -".ack".length));
|
|
164
191
|
}
|
|
165
192
|
return out;
|
|
166
193
|
}
|
|
167
|
-
/**
|
|
194
|
+
/**
|
|
195
|
+
* Confirma un mensaje.
|
|
196
|
+
*
|
|
197
|
+
* El `messageId` se sanitiza: venia del modelo y se usaba crudo como
|
|
198
|
+
* nombre de archivo.
|
|
199
|
+
*/
|
|
168
200
|
async ack(agentId, messageId) {
|
|
169
|
-
const
|
|
201
|
+
const safe = safeId(messageId);
|
|
202
|
+
if (!safe) {
|
|
203
|
+
log.warn("ack con messageId no seguro, ignorado", { agentId, messageId });
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const dir = this.ackDir(agentId);
|
|
170
207
|
await fs.mkdir(dir, { recursive: true });
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
agentId,
|
|
174
|
-
ackedAt: nowIso(this.clock),
|
|
175
|
-
});
|
|
208
|
+
const ack = { messageId: safe, agentId, ackedAt: nowIso(this.clock) };
|
|
209
|
+
await writeJsonAtomic(path.join(dir, `${safe}.ack`), ack);
|
|
176
210
|
}
|
|
177
|
-
/**
|
|
211
|
+
/** Confirma varios mensajes. */
|
|
178
212
|
async ackMany(agentId, messageIds) {
|
|
179
213
|
for (const id of messageIds)
|
|
180
214
|
await this.ack(agentId, id);
|
|
181
215
|
}
|
|
182
|
-
/** ¿Quién
|
|
216
|
+
/** ¿Quién confirmo este mensaje? */
|
|
183
217
|
async ackedBy(messageId) {
|
|
184
|
-
const dir = this.paths.inboxDir;
|
|
185
|
-
const agents = await listFiles(dir);
|
|
186
218
|
const out = [];
|
|
219
|
+
let agents;
|
|
220
|
+
try {
|
|
221
|
+
agents = await fs.readdir(this.paths.inboxDir);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return out;
|
|
225
|
+
}
|
|
187
226
|
for (const agent of agents) {
|
|
188
|
-
const
|
|
189
|
-
if (
|
|
190
|
-
out.push(
|
|
227
|
+
const acks = await this.ackedIds(agent);
|
|
228
|
+
if (acks.has(messageId))
|
|
229
|
+
out.push(agent);
|
|
191
230
|
}
|
|
192
231
|
return out;
|
|
193
232
|
}
|
|
194
|
-
/**
|
|
233
|
+
/** ¿En qué canal está un mensaje? */
|
|
195
234
|
async channelOf(messageId) {
|
|
196
|
-
const channels =
|
|
235
|
+
const channels = Object.values(CHANNELS);
|
|
197
236
|
for (const channel of channels) {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
237
|
+
for (const message of await this.readChannel(channel)) {
|
|
238
|
+
if (message.id === messageId)
|
|
239
|
+
return channel;
|
|
240
|
+
}
|
|
201
241
|
}
|
|
202
242
|
return undefined;
|
|
203
243
|
}
|
|
204
|
-
|
|
205
|
-
// Protocolo de ayuda
|
|
206
|
-
// ───────────────────────────────────────────────────────────────────────────
|
|
207
|
-
/**
|
|
208
|
-
* Publica un pedido de ayuda.
|
|
209
|
-
*
|
|
210
|
-
* La idempotency key deriva de card + agente + motivo, así dos intentos del
|
|
211
|
-
* mismo pedido no generan un storm en el pool.
|
|
212
|
-
*/
|
|
244
|
+
/** Pide ayuda a uno o varios agentes. */
|
|
213
245
|
async requestHelp(input) {
|
|
214
246
|
return this.send(CHANNELS.peer, {
|
|
215
247
|
from: input.from,
|
|
@@ -217,8 +249,8 @@ export class Bus {
|
|
|
217
249
|
kind: "HELP_REQUEST",
|
|
218
250
|
subject: input.cardId,
|
|
219
251
|
body: { need: input.need, why_me: input.whyMe },
|
|
220
|
-
idempotencyKey: `help:${input.cardId}:${input.from}:${stableHash(input.need)}`,
|
|
221
252
|
hops: input.hops ?? 0,
|
|
253
|
+
idempotencyKey: `help:${input.cardId}:${input.from}:${stableHash(input.need)}`,
|
|
222
254
|
});
|
|
223
255
|
}
|
|
224
256
|
/** Responde un pedido de ayuda. */
|
|
@@ -233,18 +265,27 @@ export class Bus {
|
|
|
233
265
|
hops: input.hops ?? 0,
|
|
234
266
|
});
|
|
235
267
|
}
|
|
236
|
-
/**
|
|
268
|
+
/** Pide ayuda a todos los pares. */
|
|
237
269
|
async broadcastHelp(input) {
|
|
238
270
|
return this.requestHelp({ ...input, to: ["*"] });
|
|
239
271
|
}
|
|
240
|
-
/**
|
|
272
|
+
/** Estadísticas por canal. */
|
|
241
273
|
async stats() {
|
|
242
|
-
const channels = await listFiles(this.paths.busDir);
|
|
243
274
|
const out = {};
|
|
244
|
-
for (const channel of
|
|
275
|
+
for (const channel of Object.values(CHANNELS)) {
|
|
245
276
|
out[channel] = (await this.readChannel(channel)).length;
|
|
246
277
|
}
|
|
247
278
|
return out;
|
|
248
279
|
}
|
|
249
280
|
}
|
|
281
|
+
/* ────────────────────────────────────────────────────────────────────────────
|
|
282
|
+
* Helpers locales
|
|
283
|
+
* ──────────────────────────────────────────────────────────────────────────── */
|
|
284
|
+
/** Lock de canal: serializa las publicaciones de un canal. */
|
|
285
|
+
function withChannelLock(channelDir, fn) {
|
|
286
|
+
return withLock(path.join(channelDir, ".channel.lock"), fn, {
|
|
287
|
+
timeoutMs: 10_000,
|
|
288
|
+
staleMs: 30_000,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
250
291
|
//# sourceMappingURL=bus.js.map
|
package/dist/core/bus.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bus.js","sourceRoot":"","sources":["../../src/core/bus.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"bus.js","sourceRoot":"","sources":["../../src/core/bus.ts"],"names":[],"mappings":"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"}
|