@hua-labs/tap 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -9
- package/dist/bridges/codex-app-server-auth-gateway.d.mts +9 -1
- package/dist/bridges/codex-app-server-auth-gateway.mjs +183 -14
- package/dist/bridges/codex-app-server-auth-gateway.mjs.map +1 -1
- package/dist/bridges/codex-app-server-bridge.d.mts +224 -5
- package/dist/bridges/codex-app-server-bridge.mjs +1138 -687
- package/dist/bridges/codex-app-server-bridge.mjs.map +1 -1
- package/dist/bridges/codex-bridge-runner.mjs +17 -2
- package/dist/bridges/codex-bridge-runner.mjs.map +1 -1
- package/dist/cli.mjs +703 -95
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +502 -57
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-server.mjs +327 -70
- package/dist/mcp-server.mjs.map +1 -1
- package/package.json +4 -3
- package/LICENSE +0 -21
package/dist/mcp-server.mjs
CHANGED
|
@@ -6807,6 +6807,88 @@ var require_dist = __commonJS({
|
|
|
6807
6807
|
}
|
|
6808
6808
|
});
|
|
6809
6809
|
|
|
6810
|
+
// ../tap-plugin/channels/tap-identity.ts
|
|
6811
|
+
function trimAddress(value) {
|
|
6812
|
+
return value?.trim() ?? "";
|
|
6813
|
+
}
|
|
6814
|
+
function canonicalizeAgentId(value) {
|
|
6815
|
+
return trimAddress(value).replace(/-/g, "_");
|
|
6816
|
+
}
|
|
6817
|
+
function isBroadcastRecipient(value) {
|
|
6818
|
+
return BROADCAST_RECIPIENTS.has(trimAddress(value));
|
|
6819
|
+
}
|
|
6820
|
+
function isPlaceholderAgentValue(value) {
|
|
6821
|
+
const normalized = trimAddress(value);
|
|
6822
|
+
return !normalized || PLACEHOLDER_AGENT_VALUES.has(normalized);
|
|
6823
|
+
}
|
|
6824
|
+
function sameRoutingAddress(left, right) {
|
|
6825
|
+
const normalizedLeft = trimAddress(left);
|
|
6826
|
+
const normalizedRight = trimAddress(right);
|
|
6827
|
+
if (!normalizedLeft || !normalizedRight) {
|
|
6828
|
+
return false;
|
|
6829
|
+
}
|
|
6830
|
+
if (isBroadcastRecipient(normalizedLeft) && isBroadcastRecipient(normalizedRight)) {
|
|
6831
|
+
return true;
|
|
6832
|
+
}
|
|
6833
|
+
return normalizedLeft === normalizedRight || canonicalizeAgentId(normalizedLeft) === canonicalizeAgentId(normalizedRight);
|
|
6834
|
+
}
|
|
6835
|
+
function matchesAgentRecipient(recipient, agentId, agentName) {
|
|
6836
|
+
const normalizedRecipient = trimAddress(recipient);
|
|
6837
|
+
if (!normalizedRecipient) {
|
|
6838
|
+
return false;
|
|
6839
|
+
}
|
|
6840
|
+
return isBroadcastRecipient(normalizedRecipient) || sameRoutingAddress(normalizedRecipient, agentId) || normalizedRecipient === trimAddress(agentName);
|
|
6841
|
+
}
|
|
6842
|
+
function isOwnMessageAddress(sender, agentId, agentName) {
|
|
6843
|
+
const normalizedSender = trimAddress(sender);
|
|
6844
|
+
if (!normalizedSender) {
|
|
6845
|
+
return false;
|
|
6846
|
+
}
|
|
6847
|
+
return sameRoutingAddress(normalizedSender, agentId) || normalizedSender === trimAddress(agentName);
|
|
6848
|
+
}
|
|
6849
|
+
function normalizeRecipientList(rawRecipients, exclude = []) {
|
|
6850
|
+
let recipients;
|
|
6851
|
+
if (rawRecipients == null) {
|
|
6852
|
+
recipients = void 0;
|
|
6853
|
+
} else if (typeof rawRecipients === "string") {
|
|
6854
|
+
const trimmed = trimAddress(rawRecipients);
|
|
6855
|
+
recipients = trimmed ? [trimmed] : void 0;
|
|
6856
|
+
} else if (Array.isArray(rawRecipients)) {
|
|
6857
|
+
const valid = rawRecipients.filter(
|
|
6858
|
+
(value) => typeof value === "string" && trimAddress(value).length > 0
|
|
6859
|
+
).map((value) => trimAddress(value));
|
|
6860
|
+
recipients = valid.length > 0 ? valid : void 0;
|
|
6861
|
+
} else {
|
|
6862
|
+
recipients = void 0;
|
|
6863
|
+
}
|
|
6864
|
+
if (!recipients) {
|
|
6865
|
+
return void 0;
|
|
6866
|
+
}
|
|
6867
|
+
const filtered = [];
|
|
6868
|
+
for (const recipient of recipients) {
|
|
6869
|
+
if (exclude.some((value) => sameRoutingAddress(value, recipient))) {
|
|
6870
|
+
continue;
|
|
6871
|
+
}
|
|
6872
|
+
if (filtered.some((value) => sameRoutingAddress(value, recipient))) {
|
|
6873
|
+
continue;
|
|
6874
|
+
}
|
|
6875
|
+
filtered.push(recipient);
|
|
6876
|
+
}
|
|
6877
|
+
return filtered.length > 0 ? filtered : void 0;
|
|
6878
|
+
}
|
|
6879
|
+
var BROADCAST_RECIPIENTS, PLACEHOLDER_AGENT_VALUES;
|
|
6880
|
+
var init_tap_identity = __esm({
|
|
6881
|
+
"../tap-plugin/channels/tap-identity.ts"() {
|
|
6882
|
+
"use strict";
|
|
6883
|
+
BROADCAST_RECIPIENTS = /* @__PURE__ */ new Set(["\uC804\uCCB4", "all"]);
|
|
6884
|
+
PLACEHOLDER_AGENT_VALUES = /* @__PURE__ */ new Set([
|
|
6885
|
+
"unknown",
|
|
6886
|
+
"unnamed",
|
|
6887
|
+
"<set-per-session>"
|
|
6888
|
+
]);
|
|
6889
|
+
}
|
|
6890
|
+
});
|
|
6891
|
+
|
|
6810
6892
|
// ../tap-plugin/channels/tap-utils.ts
|
|
6811
6893
|
var tap_utils_exports = {};
|
|
6812
6894
|
__export(tap_utils_exports, {
|
|
@@ -6822,6 +6904,7 @@ __export(tap_utils_exports, {
|
|
|
6822
6904
|
RECEIPTS_PATH: () => RECEIPTS_PATH,
|
|
6823
6905
|
REVIEWS_DIR: () => REVIEWS_DIR,
|
|
6824
6906
|
SERVER_START: () => SERVER_START,
|
|
6907
|
+
canonicalizeAgentId: () => canonicalizeAgentId2,
|
|
6825
6908
|
debug: () => debug,
|
|
6826
6909
|
getAgentId: () => getAgentId,
|
|
6827
6910
|
getAgentName: () => getAgentName,
|
|
@@ -6835,30 +6918,63 @@ __export(tap_utils_exports, {
|
|
|
6835
6918
|
isNameConfirmed: () => isNameConfirmed,
|
|
6836
6919
|
normalizeSources: () => normalizeSources,
|
|
6837
6920
|
parseFilename: () => parseFilename,
|
|
6921
|
+
parseFrontmatter: () => parseFrontmatter,
|
|
6922
|
+
parseMessageRoute: () => parseMessageRoute,
|
|
6838
6923
|
setAgentName: () => setAgentName,
|
|
6839
6924
|
stripBom: () => stripBom,
|
|
6925
|
+
stripFrontmatter: () => stripFrontmatter,
|
|
6840
6926
|
updateActivityTime: () => updateActivityTime
|
|
6841
6927
|
});
|
|
6842
6928
|
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
6843
6929
|
import { join, resolve } from "path";
|
|
6844
|
-
function
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
return envName.replace(/-/g, "_");
|
|
6850
|
-
return "unknown";
|
|
6930
|
+
function isConcreteIdentity(value) {
|
|
6931
|
+
return !isPlaceholderAgentValue(value);
|
|
6932
|
+
}
|
|
6933
|
+
function normalizeAgentId(value) {
|
|
6934
|
+
return canonicalizeAgentId(value);
|
|
6851
6935
|
}
|
|
6852
|
-
function
|
|
6936
|
+
function loadStateInstances() {
|
|
6853
6937
|
const stateDir = process.env.TAP_STATE_DIR;
|
|
6854
|
-
|
|
6855
|
-
if (!stateDir || !agentId) return null;
|
|
6938
|
+
if (!stateDir) return null;
|
|
6856
6939
|
try {
|
|
6857
6940
|
const statePath = join(stateDir, "state.json");
|
|
6858
6941
|
if (!existsSync(statePath)) return null;
|
|
6859
6942
|
const state = JSON.parse(readFileSync(statePath, "utf-8"));
|
|
6860
|
-
|
|
6861
|
-
|
|
6943
|
+
return state.instances ?? null;
|
|
6944
|
+
} catch {
|
|
6945
|
+
return null;
|
|
6946
|
+
}
|
|
6947
|
+
}
|
|
6948
|
+
function resolveSingleCodexBootstrap() {
|
|
6949
|
+
const instances = loadStateInstances();
|
|
6950
|
+
if (!instances) return null;
|
|
6951
|
+
const installedCodexInstances = Object.entries(instances).filter(
|
|
6952
|
+
([, instance2]) => instance2?.runtime === "codex" && instance2?.installed
|
|
6953
|
+
);
|
|
6954
|
+
if (installedCodexInstances.length !== 1) return null;
|
|
6955
|
+
const [instanceId, instance] = installedCodexInstances[0];
|
|
6956
|
+
return {
|
|
6957
|
+
agentId: normalizeAgentId(instanceId),
|
|
6958
|
+
agentName: typeof instance.agentName === "string" && !isPlaceholderAgentValue(instance.agentName) ? instance.agentName : null
|
|
6959
|
+
};
|
|
6960
|
+
}
|
|
6961
|
+
function resolveInitialId(stateBootstrap2) {
|
|
6962
|
+
const envId = process.env.TAP_AGENT_ID;
|
|
6963
|
+
if (isConcreteIdentity(envId)) return normalizeAgentId(envId);
|
|
6964
|
+
const envName = process.env.TAP_AGENT_NAME;
|
|
6965
|
+
if (isConcreteIdentity(envName)) return normalizeAgentId(envName);
|
|
6966
|
+
return stateBootstrap2?.agentId ?? "unknown";
|
|
6967
|
+
}
|
|
6968
|
+
function resolveNameFromState(agentId, stateBootstrap2) {
|
|
6969
|
+
if (agentId === "unknown") return null;
|
|
6970
|
+
if (stateBootstrap2?.agentId === agentId && stateBootstrap2.agentName) {
|
|
6971
|
+
return stateBootstrap2.agentName;
|
|
6972
|
+
}
|
|
6973
|
+
try {
|
|
6974
|
+
const instances = loadStateInstances();
|
|
6975
|
+
if (!instances) return null;
|
|
6976
|
+
const instance = instances[agentId] ?? instances[agentId.replace(/_/g, "-")];
|
|
6977
|
+
return typeof instance?.agentName === "string" && !isPlaceholderAgentValue(instance.agentName) ? instance.agentName : null;
|
|
6862
6978
|
} catch {
|
|
6863
6979
|
return null;
|
|
6864
6980
|
}
|
|
@@ -6876,7 +6992,7 @@ function setAgentName(name) {
|
|
|
6876
6992
|
_agentName = name;
|
|
6877
6993
|
_nameConfirmed = true;
|
|
6878
6994
|
if (!_idLocked) {
|
|
6879
|
-
_agentId = name
|
|
6995
|
+
_agentId = canonicalizeAgentId(name);
|
|
6880
6996
|
_idLocked = true;
|
|
6881
6997
|
}
|
|
6882
6998
|
}
|
|
@@ -6895,6 +7011,35 @@ function debug(message) {
|
|
|
6895
7011
|
function stripBom(text) {
|
|
6896
7012
|
return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
6897
7013
|
}
|
|
7014
|
+
function parseFrontmatter(content) {
|
|
7015
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
7016
|
+
if (!match) return null;
|
|
7017
|
+
const fields = {};
|
|
7018
|
+
for (const line of match[1].split("\n")) {
|
|
7019
|
+
const kv = line.match(/^(\w+):\s*(.+)$/);
|
|
7020
|
+
if (kv) fields[kv[1]] = kv[2].trim();
|
|
7021
|
+
}
|
|
7022
|
+
if (!fields.from || !fields.to) return null;
|
|
7023
|
+
return {
|
|
7024
|
+
from: fields.from,
|
|
7025
|
+
from_name: fields.from_name,
|
|
7026
|
+
to: fields.to,
|
|
7027
|
+
to_name: fields.to_name,
|
|
7028
|
+
subject: fields.subject ?? "",
|
|
7029
|
+
sent_at: fields.sent_at,
|
|
7030
|
+
type: fields.type
|
|
7031
|
+
};
|
|
7032
|
+
}
|
|
7033
|
+
function stripFrontmatter(content) {
|
|
7034
|
+
return content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n*/, "");
|
|
7035
|
+
}
|
|
7036
|
+
function parseMessageRoute(filename, content) {
|
|
7037
|
+
if (content) {
|
|
7038
|
+
const fm = parseFrontmatter(content);
|
|
7039
|
+
if (fm) return { from: fm.from, to: fm.to, subject: fm.subject };
|
|
7040
|
+
}
|
|
7041
|
+
return parseFilename(filename);
|
|
7042
|
+
}
|
|
6898
7043
|
function parseFilename(filename) {
|
|
6899
7044
|
const withoutExt = filename.replace(/\.md$/, "");
|
|
6900
7045
|
const dateMatch = withoutExt.match(/^(\d{8})-(.+)$/);
|
|
@@ -6916,8 +7061,11 @@ function parseFilename(filename) {
|
|
|
6916
7061
|
}
|
|
6917
7062
|
return null;
|
|
6918
7063
|
}
|
|
7064
|
+
function canonicalizeAgentId2(id) {
|
|
7065
|
+
return canonicalizeAgentId(id);
|
|
7066
|
+
}
|
|
6919
7067
|
function isForMe(to) {
|
|
6920
|
-
return to
|
|
7068
|
+
return matchesAgentRecipient(to, _agentId, _agentName);
|
|
6921
7069
|
}
|
|
6922
7070
|
function normalizeSources(value) {
|
|
6923
7071
|
if (!Array.isArray(value) || value.length === 0) {
|
|
@@ -6959,10 +7107,11 @@ function getRecentSenders() {
|
|
|
6959
7107
|
}
|
|
6960
7108
|
return senders;
|
|
6961
7109
|
}
|
|
6962
|
-
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,
|
|
7110
|
+
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;
|
|
6963
7111
|
var init_tap_utils = __esm({
|
|
6964
7112
|
"../tap-plugin/channels/tap-utils.ts"() {
|
|
6965
7113
|
"use strict";
|
|
7114
|
+
init_tap_identity();
|
|
6966
7115
|
RAW_COMMS_DIR = process.env.TAP_COMMS_DIR;
|
|
6967
7116
|
if (!RAW_COMMS_DIR) {
|
|
6968
7117
|
console.error(
|
|
@@ -6982,11 +7131,11 @@ var init_tap_utils = __esm({
|
|
|
6982
7131
|
ARCHIVE_DIR = join(COMMS_DIR, "archive");
|
|
6983
7132
|
DB_PATH = join(COMMS_DIR, "tap.db");
|
|
6984
7133
|
SERVER_START = Date.now();
|
|
6985
|
-
|
|
6986
|
-
_agentId = resolveInitialId();
|
|
6987
|
-
_agentName = resolveNameFromState() ?? (
|
|
7134
|
+
stateBootstrap = resolveSingleCodexBootstrap();
|
|
7135
|
+
_agentId = resolveInitialId(stateBootstrap);
|
|
7136
|
+
_agentName = resolveNameFromState(_agentId, stateBootstrap) ?? (isConcreteIdentity(process.env.TAP_AGENT_NAME) ? process.env.TAP_AGENT_NAME : "unknown");
|
|
6988
7137
|
_idLocked = _agentId !== "unknown";
|
|
6989
|
-
_nameConfirmed =
|
|
7138
|
+
_nameConfirmed = !isPlaceholderAgentValue(_agentName);
|
|
6990
7139
|
_lastActivityTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
6991
7140
|
}
|
|
6992
7141
|
});
|
|
@@ -7018,7 +7167,37 @@ import {
|
|
|
7018
7167
|
unlinkSync,
|
|
7019
7168
|
writeFileSync
|
|
7020
7169
|
} from "fs";
|
|
7170
|
+
import { createHash } from "crypto";
|
|
7021
7171
|
import { join as join2 } from "path";
|
|
7172
|
+
function getBridgeProcessedDirs() {
|
|
7173
|
+
const now = Date.now();
|
|
7174
|
+
if (now - _bridgeDirsCachedAt < BRIDGE_DIR_CACHE_TTL_MS) {
|
|
7175
|
+
return _bridgeProcessedDirs;
|
|
7176
|
+
}
|
|
7177
|
+
_bridgeDirsCachedAt = now;
|
|
7178
|
+
if (!REPO_ROOT) {
|
|
7179
|
+
_bridgeProcessedDirs = [];
|
|
7180
|
+
return _bridgeProcessedDirs;
|
|
7181
|
+
}
|
|
7182
|
+
const tmpDir = join2(REPO_ROOT, ".tmp");
|
|
7183
|
+
if (!existsSync2(tmpDir)) {
|
|
7184
|
+
_bridgeProcessedDirs = [];
|
|
7185
|
+
return _bridgeProcessedDirs;
|
|
7186
|
+
}
|
|
7187
|
+
try {
|
|
7188
|
+
_bridgeProcessedDirs = readdirSync2(tmpDir).filter((d) => d.startsWith("codex-app-server-bridge")).map((d) => join2(tmpDir, d, "processed")).filter((p) => existsSync2(p));
|
|
7189
|
+
} catch {
|
|
7190
|
+
_bridgeProcessedDirs = [];
|
|
7191
|
+
}
|
|
7192
|
+
return _bridgeProcessedDirs;
|
|
7193
|
+
}
|
|
7194
|
+
function isBridgeProcessed(filePath, mtimeMs) {
|
|
7195
|
+
const dirs = getBridgeProcessedDirs();
|
|
7196
|
+
if (dirs.length === 0) return false;
|
|
7197
|
+
const markerId = createHash("sha1").update(`${filePath}|${mtimeMs}`).digest("hex");
|
|
7198
|
+
const markerFile = `${markerId}.done`;
|
|
7199
|
+
return dirs.some((dir) => existsSync2(join2(dir, markerFile)));
|
|
7200
|
+
}
|
|
7022
7201
|
function acquireLock(lockPath, retries = 3, delayMs = 100) {
|
|
7023
7202
|
for (let attempt = 0; attempt < retries; attempt++) {
|
|
7024
7203
|
try {
|
|
@@ -7148,6 +7327,10 @@ function getUnreadItems(options) {
|
|
|
7148
7327
|
continue;
|
|
7149
7328
|
}
|
|
7150
7329
|
if (effectiveSinceMs && mtime < effectiveSinceMs) continue;
|
|
7330
|
+
if (isBridgeProcessed(fullPath, mtime)) {
|
|
7331
|
+
readFiles.add(key);
|
|
7332
|
+
continue;
|
|
7333
|
+
}
|
|
7151
7334
|
let content;
|
|
7152
7335
|
try {
|
|
7153
7336
|
content = stripBom(readFileSync2(fullPath, "utf-8"));
|
|
@@ -7158,13 +7341,17 @@ function getUnreadItems(options) {
|
|
|
7158
7341
|
let to = "all";
|
|
7159
7342
|
let subject = filename.replace(/\.md$/, "");
|
|
7160
7343
|
if (source === "inbox") {
|
|
7161
|
-
const
|
|
7344
|
+
const fm = parseFrontmatter(content);
|
|
7345
|
+
const parsed = fm ? { from: fm.from, to: fm.to, subject: fm.subject } : parseFilename(filename);
|
|
7162
7346
|
if (!parsed || !isForMe(parsed.to)) continue;
|
|
7163
|
-
if (parsed.from
|
|
7347
|
+
if (isOwnMessageAddress(parsed.from, getAgentId(), getAgentName()))
|
|
7164
7348
|
continue;
|
|
7165
|
-
from = resolveAgentLabel(parsed.from, heartbeatStore);
|
|
7166
|
-
to = resolveAgentLabel(parsed.to, heartbeatStore);
|
|
7349
|
+
from = resolveAgentLabel(fm?.from_name ?? parsed.from, heartbeatStore);
|
|
7350
|
+
to = resolveAgentLabel(fm?.to_name ?? parsed.to, heartbeatStore);
|
|
7167
7351
|
subject = parsed.subject;
|
|
7352
|
+
if (fm && includeContent) {
|
|
7353
|
+
content = stripFrontmatter(content);
|
|
7354
|
+
}
|
|
7168
7355
|
}
|
|
7169
7356
|
const item = {
|
|
7170
7357
|
source,
|
|
@@ -7189,13 +7376,18 @@ function getUnreadItems(options) {
|
|
|
7189
7376
|
}
|
|
7190
7377
|
return items;
|
|
7191
7378
|
}
|
|
7192
|
-
var startupFiles, readFiles;
|
|
7379
|
+
var startupFiles, readFiles, REPO_ROOT, BRIDGE_DIR_CACHE_TTL_MS, _bridgeProcessedDirs, _bridgeDirsCachedAt;
|
|
7193
7380
|
var init_tap_io = __esm({
|
|
7194
7381
|
"../tap-plugin/channels/tap-io.ts"() {
|
|
7195
7382
|
"use strict";
|
|
7196
7383
|
init_tap_utils();
|
|
7384
|
+
init_tap_identity();
|
|
7197
7385
|
startupFiles = /* @__PURE__ */ new Set();
|
|
7198
7386
|
readFiles = /* @__PURE__ */ new Set();
|
|
7387
|
+
REPO_ROOT = process.env.TAP_REPO_ROOT ?? null;
|
|
7388
|
+
BRIDGE_DIR_CACHE_TTL_MS = 3e4;
|
|
7389
|
+
_bridgeProcessedDirs = [];
|
|
7390
|
+
_bridgeDirsCachedAt = 0;
|
|
7199
7391
|
}
|
|
7200
7392
|
});
|
|
7201
7393
|
|
|
@@ -21209,6 +21401,7 @@ var StdioServerTransport = class {
|
|
|
21209
21401
|
};
|
|
21210
21402
|
|
|
21211
21403
|
// ../tap-plugin/channels/tap-comms.ts
|
|
21404
|
+
init_tap_identity();
|
|
21212
21405
|
init_tap_utils();
|
|
21213
21406
|
init_tap_io();
|
|
21214
21407
|
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -21416,6 +21609,7 @@ init_tap_utils();
|
|
|
21416
21609
|
import { existsSync as existsSync4, readFileSync as readFileSync4, statSync as statSync4, watch } from "fs";
|
|
21417
21610
|
import { join as join4 } from "path";
|
|
21418
21611
|
init_tap_io();
|
|
21612
|
+
init_tap_identity();
|
|
21419
21613
|
var notifiedFiles = /* @__PURE__ */ new Set();
|
|
21420
21614
|
var recentEvents = /* @__PURE__ */ new Map();
|
|
21421
21615
|
var inFlightFiles = /* @__PURE__ */ new Set();
|
|
@@ -21454,7 +21648,7 @@ async function waitForFileReady(filepath) {
|
|
|
21454
21648
|
function isOwnMessageArtifact(source, filename, parsed) {
|
|
21455
21649
|
const agentId = getAgentId();
|
|
21456
21650
|
const agentName = getAgentName();
|
|
21457
|
-
if (parsed && (parsed.from
|
|
21651
|
+
if (parsed && isOwnMessageAddress(parsed.from, agentId, agentName)) {
|
|
21458
21652
|
return true;
|
|
21459
21653
|
}
|
|
21460
21654
|
if (source === "reviews") {
|
|
@@ -21476,9 +21670,6 @@ async function processWatchFile(dir, source, filename, mcp2) {
|
|
|
21476
21670
|
const key = getSourceKey(source, filename);
|
|
21477
21671
|
if (notifiedFiles.has(key) || inFlightFiles.has(key) || readFiles.has(key))
|
|
21478
21672
|
return false;
|
|
21479
|
-
const parsed = parseFilename(filename);
|
|
21480
|
-
if (source === "inbox" && (!parsed || !isForMe(parsed.to))) return false;
|
|
21481
|
-
if (isOwnMessageArtifact(source, filename, parsed)) return false;
|
|
21482
21673
|
inFlightFiles.add(key);
|
|
21483
21674
|
try {
|
|
21484
21675
|
const filepath = join4(dir, filename);
|
|
@@ -21488,6 +21679,15 @@ async function processWatchFile(dir, source, filename, mcp2) {
|
|
|
21488
21679
|
return false;
|
|
21489
21680
|
}
|
|
21490
21681
|
if (!file2) return false;
|
|
21682
|
+
let parsed = null;
|
|
21683
|
+
if (source === "inbox") {
|
|
21684
|
+
const fm = parseFrontmatter(file2.content);
|
|
21685
|
+
parsed = fm ? { from: fm.from, to: fm.to, subject: fm.subject } : parseFilename(filename);
|
|
21686
|
+
} else {
|
|
21687
|
+
parsed = parseFilename(filename);
|
|
21688
|
+
}
|
|
21689
|
+
if (source === "inbox" && (!parsed || !isForMe(parsed.to))) return false;
|
|
21690
|
+
if (isOwnMessageArtifact(source, filename, parsed)) return false;
|
|
21491
21691
|
const rawFrom = parsed?.from || source;
|
|
21492
21692
|
const rawTo = parsed?.to || "all";
|
|
21493
21693
|
const from = parsed ? resolveAgentLabel(parsed.from) : source;
|
|
@@ -21579,7 +21779,7 @@ import { readdirSync as readdirSync5, renameSync as renameSync2, statSync as sta
|
|
|
21579
21779
|
// ../tap-plugin/channels/tap-poll-fallback.ts
|
|
21580
21780
|
init_tap_utils();
|
|
21581
21781
|
import { existsSync as existsSync5, readdirSync as readdirSync4, statSync as statSync5 } from "fs";
|
|
21582
|
-
var POLL_INTERVAL_MS = 3e4;
|
|
21782
|
+
var POLL_INTERVAL_MS = process.platform === "win32" ? 1e4 : 3e4;
|
|
21583
21783
|
var POLL_SOURCES = ["inbox", "reviews"];
|
|
21584
21784
|
var recoveredCount = 0;
|
|
21585
21785
|
var pollCycles = 0;
|
|
@@ -21657,8 +21857,8 @@ function loadOnboardingTeaser() {
|
|
|
21657
21857
|
const commsDir = process.env.TAP_COMMS_DIR;
|
|
21658
21858
|
if (!commsDir) return "";
|
|
21659
21859
|
const stateDir = process.env.TAP_STATE_DIR;
|
|
21660
|
-
const agentId =
|
|
21661
|
-
if (stateDir && agentId) {
|
|
21860
|
+
const agentId = getAgentId();
|
|
21861
|
+
if (stateDir && agentId !== "unknown") {
|
|
21662
21862
|
try {
|
|
21663
21863
|
const markerPath = join5(stateDir, "onboarded.json");
|
|
21664
21864
|
if (existsSync6(markerPath)) {
|
|
@@ -21673,7 +21873,7 @@ function loadOnboardingTeaser() {
|
|
|
21673
21873
|
if (!existsSync6(welcomePath)) return "";
|
|
21674
21874
|
const content = readFileSync5(welcomePath, "utf-8");
|
|
21675
21875
|
const lines = content.split("\n").slice(0, ONBOARDING_TEASER_LINES);
|
|
21676
|
-
if (stateDir && agentId) {
|
|
21876
|
+
if (stateDir && agentId !== "unknown") {
|
|
21677
21877
|
try {
|
|
21678
21878
|
const markerPath = join5(stateDir, "onboarded.json");
|
|
21679
21879
|
let store = {};
|
|
@@ -21883,11 +22083,22 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
21883
22083
|
}
|
|
21884
22084
|
]
|
|
21885
22085
|
}));
|
|
22086
|
+
function prunePhantomHeartbeats(store) {
|
|
22087
|
+
let removed = 0;
|
|
22088
|
+
for (const key of Object.keys(store)) {
|
|
22089
|
+
if (!store[key].id) {
|
|
22090
|
+
delete store[key];
|
|
22091
|
+
removed++;
|
|
22092
|
+
}
|
|
22093
|
+
}
|
|
22094
|
+
return removed;
|
|
22095
|
+
}
|
|
21886
22096
|
function persistActivity(id, name) {
|
|
21887
22097
|
const locked = acquireLock(HEARTBEATS_LOCK);
|
|
21888
22098
|
if (!locked) return;
|
|
21889
22099
|
try {
|
|
21890
22100
|
const store = loadHeartbeats();
|
|
22101
|
+
prunePhantomHeartbeats(store);
|
|
21891
22102
|
const existing = store[id];
|
|
21892
22103
|
store[id] = {
|
|
21893
22104
|
id,
|
|
@@ -22119,38 +22330,14 @@ Recent active names: ${activeList}`;
|
|
|
22119
22330
|
]
|
|
22120
22331
|
};
|
|
22121
22332
|
}
|
|
22122
|
-
|
|
22123
|
-
if (rawCc == null) {
|
|
22124
|
-
cc = void 0;
|
|
22125
|
-
} else if (typeof rawCc === "string") {
|
|
22126
|
-
const trimmed = rawCc.trim();
|
|
22127
|
-
cc = trimmed ? [trimmed] : void 0;
|
|
22128
|
-
} else if (Array.isArray(rawCc)) {
|
|
22129
|
-
const valid = rawCc.filter(
|
|
22130
|
-
(v) => typeof v === "string" && v.trim().length > 0
|
|
22131
|
-
).map((v) => v.trim());
|
|
22132
|
-
cc = valid.length > 0 ? valid : void 0;
|
|
22133
|
-
} else {
|
|
22134
|
-
cc = void 0;
|
|
22135
|
-
}
|
|
22136
|
-
if (cc) {
|
|
22137
|
-
const seen = /* @__PURE__ */ new Set([to]);
|
|
22138
|
-
cc = cc.filter((r) => {
|
|
22139
|
-
if (seen.has(r)) return false;
|
|
22140
|
-
seen.add(r);
|
|
22141
|
-
return true;
|
|
22142
|
-
});
|
|
22143
|
-
if (cc.length === 0) cc = void 0;
|
|
22144
|
-
}
|
|
22145
|
-
const broadcastNames = /* @__PURE__ */ new Set(["\uC804\uCCB4", "all"]);
|
|
22333
|
+
const cc = normalizeRecipientList(rawCc, [to]);
|
|
22146
22334
|
const recipientWarnings = [];
|
|
22147
22335
|
const store = loadHeartbeats();
|
|
22148
22336
|
const knownAgents = /* @__PURE__ */ new Set();
|
|
22149
22337
|
const displayNameCount = /* @__PURE__ */ new Map();
|
|
22150
|
-
const placeholders = /* @__PURE__ */ new Set(["unknown", "unnamed", "<set-per-session>"]);
|
|
22151
22338
|
for (const [key, hb] of Object.entries(store)) {
|
|
22152
|
-
if (!
|
|
22153
|
-
if (
|
|
22339
|
+
if (!isPlaceholderAgentValue(key)) knownAgents.add(key);
|
|
22340
|
+
if (!isPlaceholderAgentValue(hb.agent)) {
|
|
22154
22341
|
knownAgents.add(hb.agent);
|
|
22155
22342
|
const ids = displayNameCount.get(hb.agent) ?? [];
|
|
22156
22343
|
ids.push(key);
|
|
@@ -22159,7 +22346,7 @@ Recent active names: ${activeList}`;
|
|
|
22159
22346
|
}
|
|
22160
22347
|
const knownList = [...knownAgents].filter((n) => n !== "unknown").join(", ");
|
|
22161
22348
|
let resolvedTo = to;
|
|
22162
|
-
if (!
|
|
22349
|
+
if (!isBroadcastRecipient(to)) {
|
|
22163
22350
|
if (!knownAgents.has(to)) {
|
|
22164
22351
|
recipientWarnings.push(
|
|
22165
22352
|
`\u26A0\uFE0F WARNING: "${to}" is not a known agent. Check spelling. Known: ${knownList}`
|
|
@@ -22176,7 +22363,7 @@ Recent active names: ${activeList}`;
|
|
|
22176
22363
|
}
|
|
22177
22364
|
if (cc?.length) {
|
|
22178
22365
|
for (const recipient of cc) {
|
|
22179
|
-
if (
|
|
22366
|
+
if (isBroadcastRecipient(recipient)) continue;
|
|
22180
22367
|
if (!knownAgents.has(recipient)) {
|
|
22181
22368
|
recipientWarnings.push(
|
|
22182
22369
|
`\u26A0\uFE0F WARNING: CC "${recipient}" is not a known agent. Known: ${knownList}`
|
|
@@ -22191,7 +22378,8 @@ Recent active names: ${activeList}`;
|
|
|
22191
22378
|
}
|
|
22192
22379
|
}
|
|
22193
22380
|
}
|
|
22194
|
-
const
|
|
22381
|
+
const now = /* @__PURE__ */ new Date();
|
|
22382
|
+
const date4 = now.toISOString().slice(0, 10).replace(/-/g, "");
|
|
22195
22383
|
const fromId = getAgentId();
|
|
22196
22384
|
const fromName = getAgentName();
|
|
22197
22385
|
const filename = `${date4}-${fromId}-${resolvedTo}-${subject}.md`;
|
|
@@ -22199,7 +22387,19 @@ Recent active names: ${activeList}`;
|
|
|
22199
22387
|
const ccHeader = cc?.length ? `> CC: ${cc.join(", ")}
|
|
22200
22388
|
|
|
22201
22389
|
` : "";
|
|
22202
|
-
|
|
22390
|
+
const frontmatter = [
|
|
22391
|
+
"---",
|
|
22392
|
+
"type: inbox",
|
|
22393
|
+
`from: ${fromId}`,
|
|
22394
|
+
`from_name: ${fromName}`,
|
|
22395
|
+
`to: ${resolvedTo}`,
|
|
22396
|
+
`to_name: ${to}`,
|
|
22397
|
+
`subject: ${subject}`,
|
|
22398
|
+
`sent_at: ${now.toISOString()}`,
|
|
22399
|
+
"---",
|
|
22400
|
+
""
|
|
22401
|
+
].join("\n");
|
|
22402
|
+
writeFileSync2(filepath, frontmatter + ccHeader + content, "utf-8");
|
|
22203
22403
|
dbInsertMessage(
|
|
22204
22404
|
filename,
|
|
22205
22405
|
fromName,
|
|
@@ -22213,16 +22413,28 @@ Recent active names: ${activeList}`;
|
|
|
22213
22413
|
const writtenFiles = /* @__PURE__ */ new Set([filename]);
|
|
22214
22414
|
for (const recipient of cc) {
|
|
22215
22415
|
try {
|
|
22216
|
-
const resolvedRecipient =
|
|
22416
|
+
const resolvedRecipient = isBroadcastRecipient(recipient) ? recipient : resolveToMostRecent2(recipient);
|
|
22217
22417
|
const ccFilename = `${date4}-${fromId}-${resolvedRecipient}-${subject}.md`;
|
|
22218
22418
|
if (writtenFiles.has(ccFilename)) {
|
|
22219
22419
|
sent.push(`CC to ${recipient}: skipped (resolves to same target)`);
|
|
22220
22420
|
continue;
|
|
22221
22421
|
}
|
|
22222
22422
|
writtenFiles.add(ccFilename);
|
|
22423
|
+
const ccFrontmatter = [
|
|
22424
|
+
"---",
|
|
22425
|
+
"type: inbox",
|
|
22426
|
+
`from: ${fromId}`,
|
|
22427
|
+
`from_name: ${fromName}`,
|
|
22428
|
+
`to: ${resolvedRecipient}`,
|
|
22429
|
+
`to_name: ${recipient}`,
|
|
22430
|
+
`subject: ${subject}`,
|
|
22431
|
+
`sent_at: ${now.toISOString()}`,
|
|
22432
|
+
"---",
|
|
22433
|
+
""
|
|
22434
|
+
].join("\n");
|
|
22223
22435
|
writeFileSync2(
|
|
22224
22436
|
join5(INBOX_DIR, ccFilename),
|
|
22225
|
-
`> CC from message to ${to}
|
|
22437
|
+
ccFrontmatter + `> CC from message to ${to}
|
|
22226
22438
|
|
|
22227
22439
|
${content}`,
|
|
22228
22440
|
"utf-8"
|
|
@@ -22248,11 +22460,27 @@ ${content}`,
|
|
|
22248
22460
|
}
|
|
22249
22461
|
if (req.params.name === "tap_broadcast") {
|
|
22250
22462
|
const { subject, content } = req.params.arguments;
|
|
22251
|
-
const
|
|
22463
|
+
const now = /* @__PURE__ */ new Date();
|
|
22464
|
+
const date4 = now.toISOString().slice(0, 10).replace(/-/g, "");
|
|
22252
22465
|
const broadcastId = getAgentId();
|
|
22253
22466
|
const broadcastName = getAgentName();
|
|
22254
22467
|
const filename = `${date4}-${broadcastId}-\uC804\uCCB4-${subject}.md`;
|
|
22255
|
-
|
|
22468
|
+
const broadcastFrontmatter = [
|
|
22469
|
+
"---",
|
|
22470
|
+
"type: inbox",
|
|
22471
|
+
`from: ${broadcastId}`,
|
|
22472
|
+
`from_name: ${broadcastName}`,
|
|
22473
|
+
"to: \uC804\uCCB4",
|
|
22474
|
+
`subject: ${subject}`,
|
|
22475
|
+
`sent_at: ${now.toISOString()}`,
|
|
22476
|
+
"---",
|
|
22477
|
+
""
|
|
22478
|
+
].join("\n");
|
|
22479
|
+
writeFileSync2(
|
|
22480
|
+
join5(INBOX_DIR, filename),
|
|
22481
|
+
broadcastFrontmatter + content,
|
|
22482
|
+
"utf-8"
|
|
22483
|
+
);
|
|
22256
22484
|
dbInsertMessage(
|
|
22257
22485
|
filename,
|
|
22258
22486
|
broadcastName,
|
|
@@ -22309,9 +22537,30 @@ ${content}`,
|
|
|
22309
22537
|
releaseLock(RECEIPTS_LOCK);
|
|
22310
22538
|
}
|
|
22311
22539
|
}
|
|
22540
|
+
function buildHudLine() {
|
|
22541
|
+
const hbStore = loadHeartbeats();
|
|
22542
|
+
const aliveWindow = Date.now() - 10 * 60 * 1e3;
|
|
22543
|
+
let agentCount = 0;
|
|
22544
|
+
for (const hb of Object.values(hbStore)) {
|
|
22545
|
+
if (!hb.id) continue;
|
|
22546
|
+
const t = new Date(hb.lastActivity ?? hb.timestamp ?? 0).getTime();
|
|
22547
|
+
if (t >= aliveWindow && hb.status !== "signing-off") agentCount++;
|
|
22548
|
+
}
|
|
22549
|
+
const unreadItems = getUnreadItems({
|
|
22550
|
+
sources: ["inbox"],
|
|
22551
|
+
limit: 100,
|
|
22552
|
+
includeContent: false,
|
|
22553
|
+
markRead: false
|
|
22554
|
+
});
|
|
22555
|
+
const unreadCount = unreadItems.length;
|
|
22556
|
+
const unreadDisplay = unreadCount >= 100 ? "99+" : String(unreadCount);
|
|
22557
|
+
const status = agentCount > 0 ? "\u{1F7E2}" : "\u26AA";
|
|
22558
|
+
return `[tap] ${status} ${agentCount} agents | \u{1F4E8} ${unreadDisplay} unread`;
|
|
22559
|
+
}
|
|
22312
22560
|
if (req.params.name === "tap_stats") {
|
|
22313
22561
|
const hours = typeof req.params.arguments?.hours === "number" ? req.params.arguments.hours : 24;
|
|
22314
22562
|
const cutoff = Date.now() - hours * 60 * 60 * 1e3;
|
|
22563
|
+
const hud = buildHudLine();
|
|
22315
22564
|
const dbResult = dbGetStats(cutoff);
|
|
22316
22565
|
if (dbResult) {
|
|
22317
22566
|
return {
|
|
@@ -22319,7 +22568,7 @@ ${content}`,
|
|
|
22319
22568
|
{
|
|
22320
22569
|
type: "text",
|
|
22321
22570
|
text: JSON.stringify(
|
|
22322
|
-
{ hours, ...dbResult, source: "sqlite" },
|
|
22571
|
+
{ hours, ...dbResult, source: "sqlite", hud },
|
|
22323
22572
|
null,
|
|
22324
22573
|
2
|
|
22325
22574
|
)
|
|
@@ -22342,7 +22591,7 @@ ${content}`,
|
|
|
22342
22591
|
const parsed = parseFilename2(filename);
|
|
22343
22592
|
if (!parsed) continue;
|
|
22344
22593
|
sent[parsed.from] = (sent[parsed.from] || 0) + 1;
|
|
22345
|
-
if (parsed.to
|
|
22594
|
+
if (isBroadcastRecipient(parsed.to)) broadcasts++;
|
|
22346
22595
|
else received[parsed.to] = (received[parsed.to] || 0) + 1;
|
|
22347
22596
|
}
|
|
22348
22597
|
}
|
|
@@ -22357,7 +22606,14 @@ ${content}`,
|
|
|
22357
22606
|
{
|
|
22358
22607
|
type: "text",
|
|
22359
22608
|
text: JSON.stringify(
|
|
22360
|
-
{
|
|
22609
|
+
{
|
|
22610
|
+
hours,
|
|
22611
|
+
sent,
|
|
22612
|
+
received,
|
|
22613
|
+
broadcasts,
|
|
22614
|
+
totalReceipts: receiptCount,
|
|
22615
|
+
hud
|
|
22616
|
+
},
|
|
22361
22617
|
null,
|
|
22362
22618
|
2
|
|
22363
22619
|
)
|
|
@@ -22405,6 +22661,7 @@ ${content}`,
|
|
|
22405
22661
|
const store = loadHeartbeats();
|
|
22406
22662
|
const agents = [];
|
|
22407
22663
|
for (const [agentId, hb] of Object.entries(store)) {
|
|
22664
|
+
if (!hb.id) continue;
|
|
22408
22665
|
const actTime = new Date(hb.lastActivity).getTime();
|
|
22409
22666
|
if (actTime < cutoff) continue;
|
|
22410
22667
|
const alive = hb.status !== "signing-off";
|