@hua-labs/tap 0.5.0 → 0.5.2
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 +24 -12
- package/dist/bridges/codex-app-server-bridge.d.mts +236 -5
- package/dist/bridges/codex-app-server-bridge.mjs +1168 -722
- package/dist/bridges/codex-app-server-bridge.mjs.map +1 -1
- package/dist/bridges/codex-bridge-runner.d.mts +2 -1
- package/dist/bridges/codex-bridge-runner.mjs +10 -2
- package/dist/bridges/codex-bridge-runner.mjs.map +1 -1
- package/dist/bridges/gemini-ide-companion-runner.mjs +0 -0
- package/dist/cli.mjs +415 -219
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +225 -82
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-server.mjs +267 -19
- package/dist/mcp-server.mjs.map +1 -1
- package/package.json +3 -2
package/dist/mcp-server.mjs
CHANGED
|
@@ -128,6 +128,7 @@ __export(tap_utils_exports, {
|
|
|
128
128
|
debug: () => debug,
|
|
129
129
|
demoteAgentName: () => demoteAgentName,
|
|
130
130
|
getAgentId: () => getAgentId,
|
|
131
|
+
getAgentIdentitySnapshot: () => getAgentIdentitySnapshot,
|
|
131
132
|
getAgentName: () => getAgentName,
|
|
132
133
|
getLastActivityTime: () => getLastActivityTime,
|
|
133
134
|
getLatestReviewDir: () => getLatestReviewDir,
|
|
@@ -137,6 +138,7 @@ __export(tap_utils_exports, {
|
|
|
137
138
|
isForMe: () => isForMe,
|
|
138
139
|
isIdLocked: () => isIdLocked,
|
|
139
140
|
isNameConfirmed: () => isNameConfirmed,
|
|
141
|
+
loadStateInstances: () => loadStateInstances,
|
|
140
142
|
normalizeSources: () => normalizeSources,
|
|
141
143
|
parseFilename: () => parseFilename,
|
|
142
144
|
parseFrontmatter: () => parseFrontmatter,
|
|
@@ -149,7 +151,7 @@ __export(tap_utils_exports, {
|
|
|
149
151
|
updateActivityTime: () => updateActivityTime
|
|
150
152
|
});
|
|
151
153
|
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
152
|
-
import { join, resolve } from "path";
|
|
154
|
+
import { basename, join, resolve } from "path";
|
|
153
155
|
function isConcreteIdentity(value) {
|
|
154
156
|
return !isPlaceholderAgentValue(value);
|
|
155
157
|
}
|
|
@@ -181,9 +183,70 @@ function resolveSingleCodexBootstrap() {
|
|
|
181
183
|
agentName: typeof instance.agentName === "string" && !isPlaceholderAgentValue(instance.agentName) ? instance.agentName : null
|
|
182
184
|
};
|
|
183
185
|
}
|
|
184
|
-
function
|
|
186
|
+
function resolveRuntimeInstanceId() {
|
|
187
|
+
const bridgeInstanceId = process.env.TAP_BRIDGE_INSTANCE_ID;
|
|
188
|
+
if (isConcreteIdentity(bridgeInstanceId)) {
|
|
189
|
+
return normalizeAgentId(bridgeInstanceId);
|
|
190
|
+
}
|
|
185
191
|
const envId = process.env.TAP_AGENT_ID;
|
|
186
|
-
if (isConcreteIdentity(envId))
|
|
192
|
+
if (isConcreteIdentity(envId)) {
|
|
193
|
+
return normalizeAgentId(envId);
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
function resolveRuntimeStateDir() {
|
|
198
|
+
const runtimeStateDir = process.env.TAP_RUNTIME_STATE_DIR;
|
|
199
|
+
if (!runtimeStateDir) return null;
|
|
200
|
+
return resolve(runtimeStateDir);
|
|
201
|
+
}
|
|
202
|
+
function resolveRuntimeStateInstanceId() {
|
|
203
|
+
const runtimeStateDir = resolveRuntimeStateDir();
|
|
204
|
+
if (!runtimeStateDir) return null;
|
|
205
|
+
const dirName = basename(runtimeStateDir);
|
|
206
|
+
if (!dirName.startsWith(BRIDGE_RUNTIME_STATE_DIR_PREFIX)) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
const instanceId = dirName.slice(BRIDGE_RUNTIME_STATE_DIR_PREFIX.length).trim();
|
|
210
|
+
if (!instanceId) return null;
|
|
211
|
+
return normalizeAgentId(instanceId);
|
|
212
|
+
}
|
|
213
|
+
function resolveRuntimeStateDisplayName() {
|
|
214
|
+
const runtimeStateDir = resolveRuntimeStateDir();
|
|
215
|
+
if (!runtimeStateDir) return null;
|
|
216
|
+
try {
|
|
217
|
+
const heartbeatPath = join(runtimeStateDir, "heartbeat.json");
|
|
218
|
+
if (existsSync(heartbeatPath)) {
|
|
219
|
+
const heartbeat = JSON.parse(readFileSync(heartbeatPath, "utf-8"));
|
|
220
|
+
const heartbeatAgent = heartbeat.agent ?? void 0;
|
|
221
|
+
if (isConcreteIdentity(heartbeatAgent)) {
|
|
222
|
+
return heartbeatAgent;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} catch {
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const agentNamePath = join(runtimeStateDir, "agent-name.txt");
|
|
229
|
+
if (!existsSync(agentNamePath)) return null;
|
|
230
|
+
const agentName = readFileSync(agentNamePath, "utf-8").trim();
|
|
231
|
+
return isConcreteIdentity(agentName) ? agentName : null;
|
|
232
|
+
} catch {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function resolveRuntimeDisplayName() {
|
|
237
|
+
const envName = process.env.TAP_AGENT_NAME;
|
|
238
|
+
if (isConcreteIdentity(envName)) return envName;
|
|
239
|
+
const codexName = process.env.CODEX_TAP_AGENT_NAME;
|
|
240
|
+
if (isConcreteIdentity(codexName)) return codexName;
|
|
241
|
+
const runtimeName = resolveRuntimeStateDisplayName();
|
|
242
|
+
if (runtimeName) return runtimeName;
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
function resolveInitialId(stateBootstrap2) {
|
|
246
|
+
const runtimeInstanceId = resolveRuntimeInstanceId();
|
|
247
|
+
if (runtimeInstanceId) return runtimeInstanceId;
|
|
248
|
+
const runtimeStateInstanceId = resolveRuntimeStateInstanceId();
|
|
249
|
+
if (runtimeStateInstanceId) return runtimeStateInstanceId;
|
|
187
250
|
const envName = process.env.TAP_AGENT_NAME;
|
|
188
251
|
if (isConcreteIdentity(envName)) return normalizeAgentId(envName);
|
|
189
252
|
return stateBootstrap2?.agentId ?? "unknown";
|
|
@@ -202,10 +265,25 @@ function resolveNameFromState(agentId, stateBootstrap2) {
|
|
|
202
265
|
return null;
|
|
203
266
|
}
|
|
204
267
|
}
|
|
268
|
+
function refreshUnknownIdentity() {
|
|
269
|
+
if (_idLocked) return;
|
|
270
|
+
const nextBootstrap = resolveSingleCodexBootstrap();
|
|
271
|
+
const nextId = resolveInitialId(nextBootstrap);
|
|
272
|
+
if (nextId === "unknown") return;
|
|
273
|
+
_agentId = nextId;
|
|
274
|
+
_idLocked = true;
|
|
275
|
+
const nextName = resolveNameFromState(nextId, nextBootstrap) ?? resolveRuntimeDisplayName();
|
|
276
|
+
if (nextName && !isPlaceholderAgentValue(nextName)) {
|
|
277
|
+
_agentName = nextName;
|
|
278
|
+
_nameConfirmed = true;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
205
281
|
function getAgentId() {
|
|
282
|
+
refreshUnknownIdentity();
|
|
206
283
|
return _agentId;
|
|
207
284
|
}
|
|
208
285
|
function getAgentName() {
|
|
286
|
+
refreshUnknownIdentity();
|
|
209
287
|
return _agentName;
|
|
210
288
|
}
|
|
211
289
|
function resolveKnownInstanceId(agentId, displayName) {
|
|
@@ -226,8 +304,31 @@ function resolveKnownInstanceId(agentId, displayName) {
|
|
|
226
304
|
return matches.length === 1 ? matches[0][0] : null;
|
|
227
305
|
}
|
|
228
306
|
function resolveCurrentInstanceId() {
|
|
307
|
+
refreshUnknownIdentity();
|
|
229
308
|
return resolveKnownInstanceId(_agentId, _agentName);
|
|
230
309
|
}
|
|
310
|
+
function getAgentIdentitySnapshot() {
|
|
311
|
+
refreshUnknownIdentity();
|
|
312
|
+
const bootstrap = resolveSingleCodexBootstrap();
|
|
313
|
+
return {
|
|
314
|
+
agentId: _agentId,
|
|
315
|
+
agentName: _agentName,
|
|
316
|
+
idLocked: _idLocked,
|
|
317
|
+
nameConfirmed: _nameConfirmed,
|
|
318
|
+
runtimeEnv: {
|
|
319
|
+
bridgeInstanceId: process.env.TAP_BRIDGE_INSTANCE_ID ?? null,
|
|
320
|
+
agentId: process.env.TAP_AGENT_ID ?? null,
|
|
321
|
+
agentName: process.env.TAP_AGENT_NAME ?? null,
|
|
322
|
+
codexTapAgentName: process.env.CODEX_TAP_AGENT_NAME ?? null,
|
|
323
|
+
commsDir: process.env.TAP_COMMS_DIR ?? null,
|
|
324
|
+
stateDir: process.env.TAP_STATE_DIR ?? null,
|
|
325
|
+
runtimeStateDir: process.env.TAP_RUNTIME_STATE_DIR ?? null,
|
|
326
|
+
repoRoot: process.env.TAP_REPO_ROOT ?? null
|
|
327
|
+
},
|
|
328
|
+
bootstrap,
|
|
329
|
+
resolvedCurrentInstanceId: resolveKnownInstanceId(_agentId, _agentName)
|
|
330
|
+
};
|
|
331
|
+
}
|
|
231
332
|
function buildHeartbeatConnectHash(instanceId, agentId) {
|
|
232
333
|
return instanceId ? `instance:${instanceId}` : `session:${agentId}`;
|
|
233
334
|
}
|
|
@@ -333,6 +434,7 @@ function canonicalizeAgentId2(id) {
|
|
|
333
434
|
return canonicalizeAgentId(id);
|
|
334
435
|
}
|
|
335
436
|
function isForMe(to) {
|
|
437
|
+
refreshUnknownIdentity();
|
|
336
438
|
return matchesAgentRecipient(to, _agentId, _agentName);
|
|
337
439
|
}
|
|
338
440
|
function normalizeSources(value) {
|
|
@@ -375,7 +477,7 @@ function getRecentSenders() {
|
|
|
375
477
|
}
|
|
376
478
|
return senders;
|
|
377
479
|
}
|
|
378
|
-
var RAW_COMMS_DIR, COMMS_DIR, INBOX_DIR, REVIEWS_DIR, FINDINGS_DIR, RECEIPTS_DIR, RECEIPTS_PATH, RECEIPTS_LOCK, HEARTBEATS_PATH, HEARTBEATS_LOCK, ARCHIVE_DIR, DB_PATH, SERVER_START, stateBootstrap, _agentId, _agentName, _idLocked, _nameConfirmed, _lastActivityTime;
|
|
480
|
+
var RAW_COMMS_DIR, COMMS_DIR, INBOX_DIR, REVIEWS_DIR, FINDINGS_DIR, RECEIPTS_DIR, RECEIPTS_PATH, RECEIPTS_LOCK, HEARTBEATS_PATH, HEARTBEATS_LOCK, ARCHIVE_DIR, DB_PATH, SERVER_START, BRIDGE_RUNTIME_STATE_DIR_PREFIX, stateBootstrap, _agentId, _agentName, _idLocked, _nameConfirmed, _lastActivityTime;
|
|
379
481
|
var init_tap_utils = __esm({
|
|
380
482
|
"packages/tap-plugin/channels/tap-utils.ts"() {
|
|
381
483
|
"use strict";
|
|
@@ -399,9 +501,10 @@ var init_tap_utils = __esm({
|
|
|
399
501
|
ARCHIVE_DIR = join(COMMS_DIR, "archive");
|
|
400
502
|
DB_PATH = join(COMMS_DIR, "tap.db");
|
|
401
503
|
SERVER_START = Date.now();
|
|
504
|
+
BRIDGE_RUNTIME_STATE_DIR_PREFIX = "codex-app-server-bridge-";
|
|
402
505
|
stateBootstrap = resolveSingleCodexBootstrap();
|
|
403
506
|
_agentId = resolveInitialId(stateBootstrap);
|
|
404
|
-
_agentName = resolveNameFromState(_agentId, stateBootstrap) ?? (
|
|
507
|
+
_agentName = resolveNameFromState(_agentId, stateBootstrap) ?? resolveRuntimeDisplayName() ?? "unknown";
|
|
405
508
|
_idLocked = _agentId !== "unknown";
|
|
406
509
|
_nameConfirmed = !isPlaceholderAgentValue(_agentName);
|
|
407
510
|
_lastActivityTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -661,7 +764,6 @@ var init_tap_io = __esm({
|
|
|
661
764
|
|
|
662
765
|
// packages/tap-plugin/channels/tap-comms.ts
|
|
663
766
|
init_tap_identity();
|
|
664
|
-
init_tap_utils();
|
|
665
767
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
666
768
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
667
769
|
import {
|
|
@@ -671,6 +773,80 @@ import {
|
|
|
671
773
|
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
672
774
|
import { join as join7 } from "path";
|
|
673
775
|
|
|
776
|
+
// packages/tap-plugin/channels/tap-peer-dm-rate-limit.ts
|
|
777
|
+
init_tap_identity();
|
|
778
|
+
var PEER_DM_WINDOW_MS = 5 * 60 * 1e3;
|
|
779
|
+
var PEER_DM_MAX_MESSAGES = 3;
|
|
780
|
+
function normalizeAddress(value) {
|
|
781
|
+
return value?.trim() ?? "";
|
|
782
|
+
}
|
|
783
|
+
function matchesTowerAddress(value, towerName, towerId) {
|
|
784
|
+
const normalizedValue = normalizeAddress(value);
|
|
785
|
+
const normalizedTower = normalizeAddress(towerName);
|
|
786
|
+
const normalizedTowerId = normalizeAddress(towerId);
|
|
787
|
+
if (!normalizedValue) return false;
|
|
788
|
+
return !!normalizedTower && (normalizedValue === normalizedTower || sameRoutingAddress(normalizedValue, normalizedTower)) || !!normalizedTowerId && (normalizedValue === normalizedTowerId || sameRoutingAddress(normalizedValue, normalizedTowerId));
|
|
789
|
+
}
|
|
790
|
+
function resolveTargetAddress(route) {
|
|
791
|
+
const candidate = normalizeAddress(route.resolvedTo) || normalizeAddress(route.to);
|
|
792
|
+
return isBroadcastRecipient(candidate) ? "broadcast" : canonicalizeAgentId(candidate);
|
|
793
|
+
}
|
|
794
|
+
function isPeerDmRateLimitExempt(route) {
|
|
795
|
+
if (isBroadcastRecipient(normalizeAddress(route.to)) || isBroadcastRecipient(normalizeAddress(route.resolvedTo))) {
|
|
796
|
+
return true;
|
|
797
|
+
}
|
|
798
|
+
const towerName = normalizeAddress(route.towerName);
|
|
799
|
+
const towerId = normalizeAddress(route.towerId);
|
|
800
|
+
if (!towerName && !towerId) return false;
|
|
801
|
+
return matchesTowerAddress(route.fromId, towerName, towerId) || matchesTowerAddress(route.fromName, towerName, towerId) || matchesTowerAddress(route.to, towerName, towerId) || matchesTowerAddress(route.resolvedTo, towerName, towerId);
|
|
802
|
+
}
|
|
803
|
+
function pruneHistory(entries, nowMs, windowMs) {
|
|
804
|
+
if (!entries?.length) return [];
|
|
805
|
+
return entries.filter((timestamp) => nowMs - timestamp <= windowMs);
|
|
806
|
+
}
|
|
807
|
+
function getPeerDmRateLimitKey(route) {
|
|
808
|
+
if (isPeerDmRateLimitExempt(route)) {
|
|
809
|
+
return null;
|
|
810
|
+
}
|
|
811
|
+
const from = canonicalizeAgentId(normalizeAddress(route.fromId));
|
|
812
|
+
const to = resolveTargetAddress(route);
|
|
813
|
+
if (!from || !to || to === "broadcast") {
|
|
814
|
+
return null;
|
|
815
|
+
}
|
|
816
|
+
return `${from}->${to}`;
|
|
817
|
+
}
|
|
818
|
+
function checkPeerDmRateLimit(store, route, nowMs = Date.now(), maxMessages = PEER_DM_MAX_MESSAGES, windowMs = PEER_DM_WINDOW_MS) {
|
|
819
|
+
const key = getPeerDmRateLimitKey(route);
|
|
820
|
+
const target = resolveTargetAddress(route);
|
|
821
|
+
if (!key) {
|
|
822
|
+
return {
|
|
823
|
+
allowed: true,
|
|
824
|
+
exempt: true,
|
|
825
|
+
key: null,
|
|
826
|
+
target,
|
|
827
|
+
recentCount: 0
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
const recent = pruneHistory(store.get(key), nowMs, windowMs);
|
|
831
|
+
return {
|
|
832
|
+
allowed: recent.length < maxMessages,
|
|
833
|
+
exempt: false,
|
|
834
|
+
key,
|
|
835
|
+
target,
|
|
836
|
+
recentCount: recent.length
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
function recordPeerDm(store, route, nowMs = Date.now(), windowMs = PEER_DM_WINDOW_MS) {
|
|
840
|
+
const key = getPeerDmRateLimitKey(route);
|
|
841
|
+
if (!key) return;
|
|
842
|
+
const recent = pruneHistory(store.get(key), nowMs, windowMs);
|
|
843
|
+
recent.push(nowMs);
|
|
844
|
+
store.set(key, recent);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// packages/tap-plugin/channels/tap-comms.ts
|
|
848
|
+
init_tap_utils();
|
|
849
|
+
|
|
674
850
|
// packages/tap-plugin/channels/tap-claims.ts
|
|
675
851
|
init_tap_utils();
|
|
676
852
|
import {
|
|
@@ -1555,6 +1731,18 @@ seedStartupFiles("inbox");
|
|
|
1555
1731
|
seedStartupFiles("reviews");
|
|
1556
1732
|
seedStartupFiles("findings");
|
|
1557
1733
|
var ONBOARDING_TEASER_LINES = 10;
|
|
1734
|
+
var peerDmHistory = /* @__PURE__ */ new Map();
|
|
1735
|
+
function loadTowerNameFromConfig() {
|
|
1736
|
+
const repoRoot = process.env.TAP_REPO_ROOT ?? ".";
|
|
1737
|
+
try {
|
|
1738
|
+
const cfgPath = join7(repoRoot, "tap-config.json");
|
|
1739
|
+
if (!existsSync8(cfgPath)) return null;
|
|
1740
|
+
const cfg = JSON.parse(readFileSync7(cfgPath, "utf-8"));
|
|
1741
|
+
return cfg.towerName?.trim() || null;
|
|
1742
|
+
} catch {
|
|
1743
|
+
return null;
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1558
1746
|
function loadOnboardingTeaser() {
|
|
1559
1747
|
const commsDir = process.env.TAP_COMMS_DIR;
|
|
1560
1748
|
if (!commsDir) return "";
|
|
@@ -1782,6 +1970,11 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
1782
1970
|
name: "tap_onboard",
|
|
1783
1971
|
description: "Get the full onboarding guide for this project. Returns welcome.md + any additional onboarding docs from commsDir/onboarding/.",
|
|
1784
1972
|
inputSchema: { type: "object", properties: {} }
|
|
1973
|
+
},
|
|
1974
|
+
{
|
|
1975
|
+
name: "tap_identity_probe",
|
|
1976
|
+
description: "Dump the current MCP-side identity/runtime env snapshot seen by tap tools.",
|
|
1977
|
+
inputSchema: { type: "object", properties: {} }
|
|
1785
1978
|
}
|
|
1786
1979
|
]
|
|
1787
1980
|
}));
|
|
@@ -1974,13 +2167,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
1974
2167
|
}
|
|
1975
2168
|
if (oldName === "unknown" || oldName === "unnamed") {
|
|
1976
2169
|
try {
|
|
1977
|
-
const
|
|
1978
|
-
let towerName = null;
|
|
1979
|
-
const cfgPath = join7(repoRoot, "tap-config.json");
|
|
1980
|
-
if (existsSync8(cfgPath)) {
|
|
1981
|
-
const cfg = JSON.parse(readFileSync7(cfgPath, "utf-8"));
|
|
1982
|
-
towerName = cfg.towerName ?? null;
|
|
1983
|
-
}
|
|
2170
|
+
const towerName = loadTowerNameFromConfig();
|
|
1984
2171
|
let runtime = process.env.TAP_BRIDGE_RUNTIME ?? null;
|
|
1985
2172
|
if (!runtime && stateDir) {
|
|
1986
2173
|
try {
|
|
@@ -2082,7 +2269,9 @@ Recent active names: ${activeList}`;
|
|
|
2082
2269
|
}
|
|
2083
2270
|
const cc = normalizeRecipientList(rawCc, [to]);
|
|
2084
2271
|
const recipientWarnings = [];
|
|
2272
|
+
const towerName = loadTowerNameFromConfig();
|
|
2085
2273
|
const store = loadHeartbeats();
|
|
2274
|
+
const resolvedTowerId = towerName ? resolvePreferredRecipient(store, towerName).target : null;
|
|
2086
2275
|
const knownAgents = /* @__PURE__ */ new Set();
|
|
2087
2276
|
for (const [key, hb] of Object.entries(store)) {
|
|
2088
2277
|
if (!isPlaceholderAgentValue(key)) knownAgents.add(key);
|
|
@@ -2112,10 +2301,57 @@ Recent active names: ${activeList}`;
|
|
|
2112
2301
|
}
|
|
2113
2302
|
}
|
|
2114
2303
|
}
|
|
2304
|
+
const resolvedCc = cc?.map((recipient) => ({
|
|
2305
|
+
original: recipient,
|
|
2306
|
+
resolved: isBroadcastRecipient(recipient) ? recipient : resolveRecipient2(recipient).target
|
|
2307
|
+
}));
|
|
2115
2308
|
const now = /* @__PURE__ */ new Date();
|
|
2309
|
+
const nowMs = now.getTime();
|
|
2116
2310
|
const date = now.toISOString().slice(0, 10).replace(/-/g, "");
|
|
2117
2311
|
const fromId = getAgentId();
|
|
2118
2312
|
const fromName = getAgentName();
|
|
2313
|
+
const rateLimitRoutes = /* @__PURE__ */ new Map();
|
|
2314
|
+
const primaryRoute = {
|
|
2315
|
+
fromId,
|
|
2316
|
+
fromName,
|
|
2317
|
+
to,
|
|
2318
|
+
resolvedTo,
|
|
2319
|
+
towerName,
|
|
2320
|
+
towerId: resolvedTowerId
|
|
2321
|
+
};
|
|
2322
|
+
const primaryCheck = checkPeerDmRateLimit(peerDmHistory, primaryRoute, nowMs);
|
|
2323
|
+
if (!primaryCheck.exempt && primaryCheck.key) {
|
|
2324
|
+
rateLimitRoutes.set(primaryCheck.key, primaryRoute);
|
|
2325
|
+
}
|
|
2326
|
+
for (const recipient of resolvedCc ?? []) {
|
|
2327
|
+
const route = {
|
|
2328
|
+
fromId,
|
|
2329
|
+
fromName,
|
|
2330
|
+
to: recipient.original,
|
|
2331
|
+
resolvedTo: recipient.resolved,
|
|
2332
|
+
towerName,
|
|
2333
|
+
towerId: resolvedTowerId
|
|
2334
|
+
};
|
|
2335
|
+
const check = checkPeerDmRateLimit(peerDmHistory, route, nowMs);
|
|
2336
|
+
if (check.exempt || !check.key) continue;
|
|
2337
|
+
rateLimitRoutes.set(check.key, route);
|
|
2338
|
+
}
|
|
2339
|
+
for (const route of rateLimitRoutes.values()) {
|
|
2340
|
+
const check = checkPeerDmRateLimit(peerDmHistory, route, nowMs);
|
|
2341
|
+
if (!check.allowed) {
|
|
2342
|
+
return {
|
|
2343
|
+
content: [
|
|
2344
|
+
{
|
|
2345
|
+
type: "text",
|
|
2346
|
+
text: `Rate limited: too many messages between ${fromId}\u2192${check.target}. Route through tower instead.`
|
|
2347
|
+
}
|
|
2348
|
+
]
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
for (const route of rateLimitRoutes.values()) {
|
|
2353
|
+
recordPeerDm(peerDmHistory, route, nowMs);
|
|
2354
|
+
}
|
|
2119
2355
|
const filename = `${date}-${fromId}-${resolvedTo}-${subject}.md`;
|
|
2120
2356
|
const filepath = join7(INBOX_DIR, filename);
|
|
2121
2357
|
const ccHeader = cc?.length ? `> CC: ${cc.join(", ")}
|
|
@@ -2145,12 +2381,14 @@ Recent active names: ${activeList}`;
|
|
|
2145
2381
|
const sent = [`Sent to ${to}: ${filename}`];
|
|
2146
2382
|
if (cc?.length) {
|
|
2147
2383
|
const writtenFiles = /* @__PURE__ */ new Set([filename]);
|
|
2148
|
-
for (const recipient of
|
|
2384
|
+
for (const recipient of resolvedCc ?? []) {
|
|
2149
2385
|
try {
|
|
2150
|
-
const resolvedRecipient =
|
|
2386
|
+
const resolvedRecipient = recipient.resolved;
|
|
2151
2387
|
const ccFilename = `${date}-${fromId}-${resolvedRecipient}-${subject}.md`;
|
|
2152
2388
|
if (writtenFiles.has(ccFilename)) {
|
|
2153
|
-
sent.push(
|
|
2389
|
+
sent.push(
|
|
2390
|
+
`CC to ${recipient.original}: skipped (resolves to same target)`
|
|
2391
|
+
);
|
|
2154
2392
|
continue;
|
|
2155
2393
|
}
|
|
2156
2394
|
writtenFiles.add(ccFilename);
|
|
@@ -2160,7 +2398,7 @@ Recent active names: ${activeList}`;
|
|
|
2160
2398
|
`from: ${fromId}`,
|
|
2161
2399
|
`from_name: ${fromName}`,
|
|
2162
2400
|
`to: ${resolvedRecipient}`,
|
|
2163
|
-
`to_name: ${recipient}`,
|
|
2401
|
+
`to_name: ${recipient.original}`,
|
|
2164
2402
|
`subject: ${subject}`,
|
|
2165
2403
|
`sent_at: ${now.toISOString()}`,
|
|
2166
2404
|
"---",
|
|
@@ -2181,10 +2419,10 @@ ${content}`,
|
|
|
2181
2419
|
"inbox",
|
|
2182
2420
|
Date.now()
|
|
2183
2421
|
);
|
|
2184
|
-
sent.push(`CC to ${recipient}: ${ccFilename}`);
|
|
2422
|
+
sent.push(`CC to ${recipient.original}: ${ccFilename}`);
|
|
2185
2423
|
} catch (err) {
|
|
2186
2424
|
sent.push(
|
|
2187
|
-
`CC to ${recipient}: FAILED (${err instanceof Error ? err.message : String(err)})`
|
|
2425
|
+
`CC to ${recipient.original}: FAILED (${err instanceof Error ? err.message : String(err)})`
|
|
2188
2426
|
);
|
|
2189
2427
|
}
|
|
2190
2428
|
}
|
|
@@ -2534,6 +2772,16 @@ ${content}`);
|
|
|
2534
2772
|
content: [{ type: "text", text: prefix + docs.join("\n\n---\n\n") }]
|
|
2535
2773
|
};
|
|
2536
2774
|
}
|
|
2775
|
+
if (req.params.name === "tap_identity_probe") {
|
|
2776
|
+
return {
|
|
2777
|
+
content: [
|
|
2778
|
+
{
|
|
2779
|
+
type: "text",
|
|
2780
|
+
text: JSON.stringify(getAgentIdentitySnapshot(), null, 2)
|
|
2781
|
+
}
|
|
2782
|
+
]
|
|
2783
|
+
};
|
|
2784
|
+
}
|
|
2537
2785
|
throw new Error(`unknown tool: ${req.params.name}`);
|
|
2538
2786
|
});
|
|
2539
2787
|
await mcp.connect(new StdioServerTransport());
|