@tpsdev-ai/cli 0.1.0 → 0.3.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 +46 -60
- package/bin/tps.cjs +22 -0
- package/bin/tps.ts +435 -0
- package/nono-profiles/tps-backup.toml +18 -0
- package/nono-profiles/tps-bootstrap.toml +20 -0
- package/nono-profiles/tps-office-manager.toml +21 -0
- package/nono-profiles/tps-restore.toml +18 -0
- package/nono-profiles/tps-status.toml +19 -0
- package/package.json +19 -15
- package/LICENSE +0 -201
- package/dist/bin/tps.d.ts +0 -3
- package/dist/bin/tps.d.ts.map +0 -1
- package/dist/bin/tps.js +0 -267
- package/dist/bin/tps.js.map +0 -1
- package/dist/src/cli/hire.d.ts +0 -16
- package/dist/src/cli/hire.d.ts.map +0 -1
- package/dist/src/cli/hire.js +0 -176
- package/dist/src/cli/hire.js.map +0 -1
- package/dist/src/cli/office.d.ts +0 -7
- package/dist/src/cli/office.d.ts.map +0 -1
- package/dist/src/cli/office.js +0 -51
- package/dist/src/cli/office.js.map +0 -1
- package/dist/src/cli/review.d.ts +0 -9
- package/dist/src/cli/review.d.ts.map +0 -1
- package/dist/src/cli/review.js +0 -109
- package/dist/src/cli/review.js.map +0 -1
- package/dist/src/cli/roster.d.ts +0 -6
- package/dist/src/cli/roster.d.ts.map +0 -1
- package/dist/src/cli/roster.js +0 -60
- package/dist/src/cli/roster.js.map +0 -1
- package/dist/src/commands/branch.d.ts +0 -14
- package/dist/src/commands/branch.d.ts.map +0 -1
- package/dist/src/commands/branch.js +0 -395
- package/dist/src/commands/branch.js.map +0 -1
- package/dist/src/commands/context.d.ts +0 -9
- package/dist/src/commands/context.d.ts.map +0 -1
- package/dist/src/commands/context.js +0 -57
- package/dist/src/commands/context.js.map +0 -1
- package/dist/src/commands/identity.d.ts +0 -13
- package/dist/src/commands/identity.d.ts.map +0 -1
- package/dist/src/commands/identity.js +0 -231
- package/dist/src/commands/identity.js.map +0 -1
- package/dist/src/commands/mail.d.ts +0 -12
- package/dist/src/commands/mail.d.ts.map +0 -1
- package/dist/src/commands/mail.js +0 -225
- package/dist/src/commands/mail.js.map +0 -1
- package/dist/src/commands/office.d.ts +0 -19
- package/dist/src/commands/office.d.ts.map +0 -1
- package/dist/src/commands/office.js +0 -598
- package/dist/src/commands/office.js.map +0 -1
- package/dist/src/commands/roster.d.ts +0 -10
- package/dist/src/commands/roster.d.ts.map +0 -1
- package/dist/src/commands/roster.js +0 -143
- package/dist/src/commands/roster.js.map +0 -1
- package/dist/src/generators/claude-code.d.ts +0 -17
- package/dist/src/generators/claude-code.d.ts.map +0 -1
- package/dist/src/generators/claude-code.js +0 -80
- package/dist/src/generators/claude-code.js.map +0 -1
- package/dist/src/generators/codex.d.ts +0 -22
- package/dist/src/generators/codex.d.ts.map +0 -1
- package/dist/src/generators/codex.js +0 -78
- package/dist/src/generators/codex.js.map +0 -1
- package/dist/src/generators/ollama.d.ts +0 -18
- package/dist/src/generators/ollama.d.ts.map +0 -1
- package/dist/src/generators/ollama.js +0 -97
- package/dist/src/generators/ollama.js.map +0 -1
- package/dist/src/generators/openclaw.d.ts +0 -15
- package/dist/src/generators/openclaw.d.ts.map +0 -1
- package/dist/src/generators/openclaw.js +0 -103
- package/dist/src/generators/openclaw.js.map +0 -1
- package/dist/src/generators/registry.d.ts +0 -36
- package/dist/src/generators/registry.d.ts.map +0 -1
- package/dist/src/generators/registry.js +0 -99
- package/dist/src/generators/registry.js.map +0 -1
- package/dist/src/schema/manifest.d.ts +0 -140
- package/dist/src/schema/manifest.d.ts.map +0 -1
- package/dist/src/schema/manifest.js +0 -62
- package/dist/src/schema/manifest.js.map +0 -1
- package/dist/src/schema/report.d.ts +0 -166
- package/dist/src/schema/report.d.ts.map +0 -1
- package/dist/src/schema/report.js +0 -90
- package/dist/src/schema/report.js.map +0 -1
- package/dist/src/schema/sanitizer.d.ts +0 -30
- package/dist/src/schema/sanitizer.d.ts.map +0 -1
- package/dist/src/schema/sanitizer.js +0 -97
- package/dist/src/schema/sanitizer.js.map +0 -1
- package/dist/src/soundstage/mock-llm.d.ts +0 -3
- package/dist/src/soundstage/mock-llm.d.ts.map +0 -1
- package/dist/src/soundstage/mock-llm.js +0 -68
- package/dist/src/soundstage/mock-llm.js.map +0 -1
- package/dist/src/utils/agent-info.d.ts +0 -28
- package/dist/src/utils/agent-info.d.ts.map +0 -1
- package/dist/src/utils/agent-info.js +0 -102
- package/dist/src/utils/agent-info.js.map +0 -1
- package/dist/src/utils/archive.d.ts +0 -27
- package/dist/src/utils/archive.d.ts.map +0 -1
- package/dist/src/utils/archive.js +0 -80
- package/dist/src/utils/archive.js.map +0 -1
- package/dist/src/utils/config-inject.d.ts +0 -27
- package/dist/src/utils/config-inject.d.ts.map +0 -1
- package/dist/src/utils/config-inject.js +0 -83
- package/dist/src/utils/config-inject.js.map +0 -1
- package/dist/src/utils/config.d.ts +0 -30
- package/dist/src/utils/config.d.ts.map +0 -1
- package/dist/src/utils/config.js +0 -55
- package/dist/src/utils/config.js.map +0 -1
- package/dist/src/utils/connection-state.d.ts +0 -27
- package/dist/src/utils/connection-state.d.ts.map +0 -1
- package/dist/src/utils/connection-state.js +0 -81
- package/dist/src/utils/connection-state.js.map +0 -1
- package/dist/src/utils/context.d.ts +0 -14
- package/dist/src/utils/context.d.ts.map +0 -1
- package/dist/src/utils/context.js +0 -68
- package/dist/src/utils/context.js.map +0 -1
- package/dist/src/utils/github-webhook.d.ts +0 -3
- package/dist/src/utils/github-webhook.d.ts.map +0 -1
- package/dist/src/utils/github-webhook.js +0 -105
- package/dist/src/utils/github-webhook.js.map +0 -1
- package/dist/src/utils/identity.d.ts +0 -114
- package/dist/src/utils/identity.d.ts.map +0 -1
- package/dist/src/utils/identity.js +0 -341
- package/dist/src/utils/identity.js.map +0 -1
- package/dist/src/utils/internal-mail.d.ts +0 -18
- package/dist/src/utils/internal-mail.d.ts.map +0 -1
- package/dist/src/utils/internal-mail.js +0 -75
- package/dist/src/utils/internal-mail.js.map +0 -1
- package/dist/src/utils/loop-detector.d.ts +0 -27
- package/dist/src/utils/loop-detector.d.ts.map +0 -1
- package/dist/src/utils/loop-detector.js +0 -42
- package/dist/src/utils/loop-detector.js.map +0 -1
- package/dist/src/utils/mail-handler.d.ts +0 -19
- package/dist/src/utils/mail-handler.d.ts.map +0 -1
- package/dist/src/utils/mail-handler.js +0 -94
- package/dist/src/utils/mail-handler.js.map +0 -1
- package/dist/src/utils/mail.d.ts +0 -22
- package/dist/src/utils/mail.d.ts.map +0 -1
- package/dist/src/utils/mail.js +0 -111
- package/dist/src/utils/mail.js.map +0 -1
- package/dist/src/utils/manifest.d.ts +0 -36
- package/dist/src/utils/manifest.d.ts.map +0 -1
- package/dist/src/utils/manifest.js +0 -91
- package/dist/src/utils/manifest.js.map +0 -1
- package/dist/src/utils/noise-ik-transport.d.ts +0 -18
- package/dist/src/utils/noise-ik-transport.d.ts.map +0 -1
- package/dist/src/utils/noise-ik-transport.js +0 -357
- package/dist/src/utils/noise-ik-transport.js.map +0 -1
- package/dist/src/utils/nono.d.ts +0 -72
- package/dist/src/utils/nono.d.ts.map +0 -1
- package/dist/src/utils/nono.js +0 -166
- package/dist/src/utils/nono.js.map +0 -1
- package/dist/src/utils/outbox.d.ts +0 -10
- package/dist/src/utils/outbox.d.ts.map +0 -1
- package/dist/src/utils/outbox.js +0 -29
- package/dist/src/utils/outbox.js.map +0 -1
- package/dist/src/utils/output.d.ts +0 -17
- package/dist/src/utils/output.d.ts.map +0 -1
- package/dist/src/utils/output.js +0 -83
- package/dist/src/utils/output.js.map +0 -1
- package/dist/src/utils/plain-tcp-transport.d.ts +0 -10
- package/dist/src/utils/plain-tcp-transport.d.ts.map +0 -1
- package/dist/src/utils/plain-tcp-transport.js +0 -209
- package/dist/src/utils/plain-tcp-transport.js.map +0 -1
- package/dist/src/utils/provision.d.ts +0 -2
- package/dist/src/utils/provision.d.ts.map +0 -1
- package/dist/src/utils/provision.js +0 -186
- package/dist/src/utils/provision.js.map +0 -1
- package/dist/src/utils/relay.d.ts +0 -30
- package/dist/src/utils/relay.d.ts.map +0 -1
- package/dist/src/utils/relay.js +0 -539
- package/dist/src/utils/relay.js.map +0 -1
- package/dist/src/utils/sandbox.d.ts +0 -37
- package/dist/src/utils/sandbox.d.ts.map +0 -1
- package/dist/src/utils/sandbox.js +0 -126
- package/dist/src/utils/sandbox.js.map +0 -1
- package/dist/src/utils/transport.d.ts +0 -62
- package/dist/src/utils/transport.d.ts.map +0 -1
- package/dist/src/utils/transport.js +0 -75
- package/dist/src/utils/transport.js.map +0 -1
- package/dist/src/utils/wall.d.ts +0 -5
- package/dist/src/utils/wall.d.ts.map +0 -1
- package/dist/src/utils/wall.js +0 -51
- package/dist/src/utils/wall.js.map +0 -1
- package/dist/src/utils/wire-delivery.d.ts +0 -10
- package/dist/src/utils/wire-delivery.d.ts.map +0 -1
- package/dist/src/utils/wire-delivery.js +0 -57
- package/dist/src/utils/wire-delivery.js.map +0 -1
- package/dist/src/utils/wire-frame.d.ts +0 -10
- package/dist/src/utils/wire-frame.d.ts.map +0 -1
- package/dist/src/utils/wire-frame.js +0 -66
- package/dist/src/utils/wire-frame.js.map +0 -1
- package/dist/src/utils/wire-mail.d.ts +0 -54
- package/dist/src/utils/wire-mail.d.ts.map +0 -1
- package/dist/src/utils/wire-mail.js +0 -24
- package/dist/src/utils/wire-mail.js.map +0 -1
- package/dist/src/utils/ws-noise-transport.d.ts +0 -18
- package/dist/src/utils/ws-noise-transport.d.ts.map +0 -1
- package/dist/src/utils/ws-noise-transport.js +0 -356
- package/dist/src/utils/ws-noise-transport.js.map +0 -1
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TPS Identity Primitives — Ed25519 signing + X25519 encryption.
|
|
3
|
-
*
|
|
4
|
-
* Every entity (host or branch) has TWO keypairs derived from one 32-byte seed:
|
|
5
|
-
* - Ed25519 for signing/verification (identity proof)
|
|
6
|
-
* - X25519 for encryption/key exchange (secret delivery, Noise handshake)
|
|
7
|
-
*
|
|
8
|
-
* The private key IS the identity. Lose it → revoke and re-provision.
|
|
9
|
-
* Branch generates its own keys — the host NEVER sees a branch's private key.
|
|
10
|
-
*/
|
|
11
|
-
import * as ed from "@noble/ed25519";
|
|
12
|
-
import { x25519 } from "@noble/curves/ed25519.js";
|
|
13
|
-
import { randomBytes, createHash } from "node:crypto";
|
|
14
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync, statSync, readdirSync, unlinkSync, } from "node:fs";
|
|
15
|
-
import { join } from "node:path";
|
|
16
|
-
import { homedir, hostname } from "node:os";
|
|
17
|
-
// noble/ed25519 v3 needs hashes.sha512 set for sync operations.
|
|
18
|
-
import { hashes } from "@noble/ed25519";
|
|
19
|
-
hashes.sha512 = (message) => {
|
|
20
|
-
return new Uint8Array(createHash("sha512").update(message).digest());
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Compute the fingerprint (SHA-256 hex) of a public key.
|
|
24
|
-
*/
|
|
25
|
-
export function fingerprint(publicKey) {
|
|
26
|
-
return createHash("sha256").update(publicKey).digest("hex");
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Derive X25519 private key from Ed25519 seed.
|
|
30
|
-
* Uses SHA-512 of the seed (same as Ed25519 key expansion) and clamps
|
|
31
|
-
* the first 32 bytes for Curve25519 scalar multiplication.
|
|
32
|
-
* This is the same approach as libsodium's crypto_sign_ed25519_sk_to_curve25519.
|
|
33
|
-
*/
|
|
34
|
-
export function edSeedToX25519Private(seed) {
|
|
35
|
-
const h = createHash("sha512").update(seed).digest();
|
|
36
|
-
const scalar = new Uint8Array(h.slice(0, 32));
|
|
37
|
-
// Clamp for Curve25519
|
|
38
|
-
scalar[0] &= 248;
|
|
39
|
-
scalar[31] &= 127;
|
|
40
|
-
scalar[31] |= 64;
|
|
41
|
-
return scalar;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Generate a new identity keypair (Ed25519 signing + X25519 encryption).
|
|
45
|
-
* Both are derived from a single 32-byte seed.
|
|
46
|
-
*/
|
|
47
|
-
export function generateKeyPair(options) {
|
|
48
|
-
const seed = new Uint8Array(randomBytes(32));
|
|
49
|
-
// Ed25519 signing keypair
|
|
50
|
-
const edPublic = ed.getPublicKey(seed);
|
|
51
|
-
// X25519 encryption keypair (derived from same seed)
|
|
52
|
-
const xPrivate = edSeedToX25519Private(seed);
|
|
53
|
-
const xPublic = x25519.getPublicKey(xPrivate);
|
|
54
|
-
const now = new Date();
|
|
55
|
-
const fp = fingerprint(edPublic);
|
|
56
|
-
return {
|
|
57
|
-
signing: { publicKey: edPublic, privateKey: seed },
|
|
58
|
-
encryption: { publicKey: xPublic, privateKey: xPrivate },
|
|
59
|
-
seed,
|
|
60
|
-
fingerprint: fp,
|
|
61
|
-
createdAt: now.toISOString(),
|
|
62
|
-
expiresAt: options?.expiresIn
|
|
63
|
-
? new Date(now.getTime() + options.expiresIn).toISOString()
|
|
64
|
-
: undefined,
|
|
65
|
-
// Backward compat
|
|
66
|
-
publicKey: edPublic,
|
|
67
|
-
privateKey: seed,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Sign a message with a private key.
|
|
72
|
-
* Returns the 64-byte Ed25519 signature.
|
|
73
|
-
*/
|
|
74
|
-
export function sign(message, privateKey) {
|
|
75
|
-
return ed.sign(message, privateKey);
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Verify a signature against a message and public key.
|
|
79
|
-
*/
|
|
80
|
-
export function verify(message, signature, publicKey) {
|
|
81
|
-
try {
|
|
82
|
-
return ed.verify(signature, message, publicKey);
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
// --- Filesystem storage ---
|
|
89
|
-
function getIdentityDir() {
|
|
90
|
-
return (process.env.TPS_IDENTITY_DIR ||
|
|
91
|
-
join(process.env.HOME || homedir(), ".tps", "identity"));
|
|
92
|
-
}
|
|
93
|
-
function getRegistryDir() {
|
|
94
|
-
return (process.env.TPS_REGISTRY_DIR ||
|
|
95
|
-
join(process.env.HOME || homedir(), ".tps", "registry"));
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Save a keypair to a directory.
|
|
99
|
-
* Private keys get 0600 permissions. Both Ed25519 and X25519 keys stored.
|
|
100
|
-
*/
|
|
101
|
-
export function saveKeyPair(keyPair, dir, prefix = "host") {
|
|
102
|
-
mkdirSync(dir, { recursive: true });
|
|
103
|
-
// Store the master seed (32 bytes — derives both keypairs)
|
|
104
|
-
const seedPath = join(dir, `${prefix}.seed`);
|
|
105
|
-
writeFileSync(seedPath, Buffer.from(keyPair.seed));
|
|
106
|
-
chmodSync(seedPath, 0o600);
|
|
107
|
-
// Ed25519 signing keys
|
|
108
|
-
const keyPath = join(dir, `${prefix}.key`);
|
|
109
|
-
const pubPath = join(dir, `${prefix}.pub`);
|
|
110
|
-
writeFileSync(keyPath, Buffer.from(keyPair.signing.privateKey));
|
|
111
|
-
chmodSync(keyPath, 0o600);
|
|
112
|
-
writeFileSync(pubPath, Buffer.from(keyPair.signing.publicKey));
|
|
113
|
-
// X25519 encryption keys
|
|
114
|
-
const xKeyPath = join(dir, `${prefix}.x25519.key`);
|
|
115
|
-
const xPubPath = join(dir, `${prefix}.x25519.pub`);
|
|
116
|
-
writeFileSync(xKeyPath, Buffer.from(keyPair.encryption.privateKey));
|
|
117
|
-
chmodSync(xKeyPath, 0o600);
|
|
118
|
-
writeFileSync(xPubPath, Buffer.from(keyPair.encryption.publicKey));
|
|
119
|
-
// Write metadata
|
|
120
|
-
const meta = {
|
|
121
|
-
fingerprint: keyPair.fingerprint,
|
|
122
|
-
createdAt: keyPair.createdAt,
|
|
123
|
-
expiresAt: keyPair.expiresAt,
|
|
124
|
-
};
|
|
125
|
-
writeFileSync(join(dir, `${prefix}.meta.json`), JSON.stringify(meta, null, 2), "utf-8");
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Load a keypair from a directory.
|
|
129
|
-
* Supports both new format (with seed + x25519) and legacy (ed25519 only).
|
|
130
|
-
*/
|
|
131
|
-
export function loadKeyPair(dir, prefix = "host") {
|
|
132
|
-
const keyPath = join(dir, `${prefix}.key`);
|
|
133
|
-
const pubPath = join(dir, `${prefix}.pub`);
|
|
134
|
-
const metaPath = join(dir, `${prefix}.meta.json`);
|
|
135
|
-
const seedPath = join(dir, `${prefix}.seed`);
|
|
136
|
-
if (!existsSync(keyPath) || !existsSync(pubPath)) {
|
|
137
|
-
throw new Error(`No keypair found at ${dir}/${prefix}.*`);
|
|
138
|
-
}
|
|
139
|
-
const edPrivate = new Uint8Array(readFileSync(keyPath));
|
|
140
|
-
const edPublic = new Uint8Array(readFileSync(pubPath));
|
|
141
|
-
let meta = {
|
|
142
|
-
fingerprint: fingerprint(edPublic),
|
|
143
|
-
createdAt: new Date().toISOString(),
|
|
144
|
-
};
|
|
145
|
-
if (existsSync(metaPath)) {
|
|
146
|
-
meta = JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
147
|
-
}
|
|
148
|
-
// Load or derive X25519 keys
|
|
149
|
-
const seed = existsSync(seedPath)
|
|
150
|
-
? new Uint8Array(readFileSync(seedPath))
|
|
151
|
-
: edPrivate; // legacy: seed IS the ed25519 private key (32 bytes)
|
|
152
|
-
const xPrivate = edSeedToX25519Private(seed);
|
|
153
|
-
const xPubPath = join(dir, `${prefix}.x25519.pub`);
|
|
154
|
-
const xPublic = existsSync(xPubPath)
|
|
155
|
-
? new Uint8Array(readFileSync(xPubPath))
|
|
156
|
-
: x25519.getPublicKey(xPrivate);
|
|
157
|
-
return {
|
|
158
|
-
signing: { publicKey: edPublic, privateKey: edPrivate },
|
|
159
|
-
encryption: { publicKey: xPublic, privateKey: xPrivate },
|
|
160
|
-
seed,
|
|
161
|
-
fingerprint: meta.fingerprint,
|
|
162
|
-
createdAt: meta.createdAt,
|
|
163
|
-
expiresAt: meta.expiresAt,
|
|
164
|
-
publicKey: edPublic,
|
|
165
|
-
privateKey: edPrivate,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Check if a private key file has safe permissions (0600).
|
|
170
|
-
* Returns true if permissions are restrictive enough.
|
|
171
|
-
*/
|
|
172
|
-
export function checkKeyPermissions(keyPath) {
|
|
173
|
-
try {
|
|
174
|
-
const st = statSync(keyPath);
|
|
175
|
-
const mode = st.mode & 0o777;
|
|
176
|
-
// Allow 0600 or 0400 (read-only)
|
|
177
|
-
return mode === 0o600 || mode === 0o400;
|
|
178
|
-
}
|
|
179
|
-
catch {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
// --- Host identity convenience ---
|
|
184
|
-
/**
|
|
185
|
-
* Initialize host identity (generate keypair if not exists).
|
|
186
|
-
* Returns the keypair (existing or newly generated).
|
|
187
|
-
*/
|
|
188
|
-
export function initHostIdentity(options) {
|
|
189
|
-
const dir = getIdentityDir();
|
|
190
|
-
const keyPath = join(dir, "host.key");
|
|
191
|
-
if (existsSync(keyPath) && !options?.force) {
|
|
192
|
-
return loadKeyPair(dir, "host");
|
|
193
|
-
}
|
|
194
|
-
const kp = generateKeyPair({ expiresIn: options?.expiresIn });
|
|
195
|
-
saveKeyPair(kp, dir, "host");
|
|
196
|
-
return kp;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Load the host identity. Throws if not initialized.
|
|
200
|
-
*/
|
|
201
|
-
export function loadHostIdentity() {
|
|
202
|
-
const dir = getIdentityDir();
|
|
203
|
-
return loadKeyPair(dir, "host");
|
|
204
|
-
}
|
|
205
|
-
export function loadHostIdentityId() {
|
|
206
|
-
const safeHostname = () => hostname().split(".")[0];
|
|
207
|
-
const metaPath = join(getIdentityDir(), "host.meta.json");
|
|
208
|
-
if (existsSync(metaPath)) {
|
|
209
|
-
try {
|
|
210
|
-
const data = JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
211
|
-
return String(data.id || data.hostId || safeHostname());
|
|
212
|
-
}
|
|
213
|
-
catch {
|
|
214
|
-
return safeHostname();
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return safeHostname();
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Register a branch's public keys in the host registry.
|
|
221
|
-
* Branch generates its own keys — only PUBLIC keys are registered here.
|
|
222
|
-
* The host NEVER sees a branch's private key.
|
|
223
|
-
*/
|
|
224
|
-
export function registerBranch(branchId, publicKey, meta, encryptionKey) {
|
|
225
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(branchId)) {
|
|
226
|
-
throw new Error(`Invalid branch ID: "${branchId}". Use only letters, numbers, hyphens, underscores.`);
|
|
227
|
-
}
|
|
228
|
-
const dir = getRegistryDir();
|
|
229
|
-
mkdirSync(dir, { recursive: true });
|
|
230
|
-
const fp = fingerprint(publicKey);
|
|
231
|
-
const fullMeta = {
|
|
232
|
-
fingerprint: fp,
|
|
233
|
-
createdAt: meta?.createdAt || new Date().toISOString(),
|
|
234
|
-
expiresAt: meta?.expiresAt,
|
|
235
|
-
trust: meta?.trust || "standard",
|
|
236
|
-
};
|
|
237
|
-
// Ed25519 signing public key
|
|
238
|
-
writeFileSync(join(dir, `${branchId}.pub`), Buffer.from(publicKey));
|
|
239
|
-
// X25519 encryption public key (if provided)
|
|
240
|
-
if (encryptionKey) {
|
|
241
|
-
writeFileSync(join(dir, `${branchId}.x25519.pub`), Buffer.from(encryptionKey));
|
|
242
|
-
}
|
|
243
|
-
writeFileSync(join(dir, `${branchId}.meta.json`), JSON.stringify(fullMeta, null, 2), "utf-8");
|
|
244
|
-
return { branchId, publicKey, encryptionKey, meta: fullMeta };
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Look up a branch's registered key.
|
|
248
|
-
*/
|
|
249
|
-
export function lookupBranch(branchId) {
|
|
250
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(branchId))
|
|
251
|
-
return null;
|
|
252
|
-
const dir = getRegistryDir();
|
|
253
|
-
const pubPath = join(dir, `${branchId}.pub`);
|
|
254
|
-
if (!existsSync(pubPath))
|
|
255
|
-
return null;
|
|
256
|
-
// Check if revoked
|
|
257
|
-
const revokedPath = join(dir, "revoked", `${branchId}.meta.json`);
|
|
258
|
-
if (existsSync(revokedPath))
|
|
259
|
-
return null;
|
|
260
|
-
const publicKey = new Uint8Array(readFileSync(pubPath));
|
|
261
|
-
const metaPath = join(dir, `${branchId}.meta.json`);
|
|
262
|
-
let meta = {
|
|
263
|
-
fingerprint: fingerprint(publicKey),
|
|
264
|
-
createdAt: new Date().toISOString(),
|
|
265
|
-
};
|
|
266
|
-
if (existsSync(metaPath)) {
|
|
267
|
-
meta = JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
268
|
-
}
|
|
269
|
-
// Load X25519 encryption public key if available
|
|
270
|
-
const xPubPath = join(dir, `${branchId}.x25519.pub`);
|
|
271
|
-
const encryptionKey = existsSync(xPubPath)
|
|
272
|
-
? new Uint8Array(readFileSync(xPubPath))
|
|
273
|
-
: undefined;
|
|
274
|
-
return { branchId, publicKey, encryptionKey, meta };
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Revoke a branch's key. Moves metadata to revoked/ directory.
|
|
278
|
-
*/
|
|
279
|
-
export function revokeBranch(branchId, reason) {
|
|
280
|
-
const dir = getRegistryDir();
|
|
281
|
-
const pubPath = join(dir, `${branchId}.pub`);
|
|
282
|
-
const metaPath = join(dir, `${branchId}.meta.json`);
|
|
283
|
-
if (!existsSync(pubPath)) {
|
|
284
|
-
throw new Error(`No registered key for branch: ${branchId}`);
|
|
285
|
-
}
|
|
286
|
-
const revokedDir = join(dir, "revoked");
|
|
287
|
-
mkdirSync(revokedDir, { recursive: true });
|
|
288
|
-
// Read existing meta, add revocation info
|
|
289
|
-
let meta = {
|
|
290
|
-
fingerprint: "",
|
|
291
|
-
createdAt: new Date().toISOString(),
|
|
292
|
-
};
|
|
293
|
-
if (existsSync(metaPath)) {
|
|
294
|
-
meta = JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
295
|
-
}
|
|
296
|
-
meta.revokedAt = new Date().toISOString();
|
|
297
|
-
meta.revokeReason = reason;
|
|
298
|
-
// Move to revoked
|
|
299
|
-
writeFileSync(join(revokedDir, `${branchId}.meta.json`), JSON.stringify(meta, null, 2), "utf-8");
|
|
300
|
-
// Remove from active registry
|
|
301
|
-
try {
|
|
302
|
-
unlinkSync(pubPath);
|
|
303
|
-
if (existsSync(metaPath))
|
|
304
|
-
unlinkSync(metaPath);
|
|
305
|
-
}
|
|
306
|
-
catch {
|
|
307
|
-
// Best effort cleanup
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Check if a branch key is revoked.
|
|
312
|
-
*/
|
|
313
|
-
export function isRevoked(branchId) {
|
|
314
|
-
const dir = getRegistryDir();
|
|
315
|
-
return existsSync(join(dir, "revoked", `${branchId}.meta.json`));
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Check if a branch key is expired.
|
|
319
|
-
*/
|
|
320
|
-
export function isExpired(meta) {
|
|
321
|
-
if (!meta.expiresAt)
|
|
322
|
-
return false;
|
|
323
|
-
return new Date(meta.expiresAt) < new Date();
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* List all registered (non-revoked) branches.
|
|
327
|
-
*/
|
|
328
|
-
export function listBranches() {
|
|
329
|
-
const dir = getRegistryDir();
|
|
330
|
-
if (!existsSync(dir))
|
|
331
|
-
return [];
|
|
332
|
-
const files = readdirSync(dir);
|
|
333
|
-
return files
|
|
334
|
-
.filter((f) => f.endsWith(".pub") && !f.includes(".x25519."))
|
|
335
|
-
.map((f) => {
|
|
336
|
-
const branchId = f.replace(/\.pub$/, "");
|
|
337
|
-
return lookupBranch(branchId);
|
|
338
|
-
})
|
|
339
|
-
.filter((r) => r !== null);
|
|
340
|
-
}
|
|
341
|
-
//# sourceMappingURL=identity.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/utils/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EACL,UAAU,EACV,SAAS,EACT,YAAY,EACZ,aAAa,EACb,SAAS,EACT,QAAQ,EACR,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAW,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5C,gEAAgE;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,MAAM,CAAC,MAAM,GAAG,CAAC,OAAmB,EAAE,EAAE;IACtC,OAAO,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AACvE,CAAC,CAAC;AAkCF;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,SAAqB;IAC/C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAgB;IACpD,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;IACrD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAC9C,uBAAuB;IACvB,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IACjB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAE/B;IACC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IAE7C,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAEvC,qDAAqD;IACrD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAE9C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEjC,OAAO;QACL,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE;QAClD,UAAU,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE;QACxD,IAAI;QACJ,WAAW,EAAE,EAAE;QACf,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;QAC5B,SAAS,EAAE,OAAO,EAAE,SAAS;YAC3B,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;YAC3D,CAAC,CAAC,SAAS;QACb,kBAAkB;QAClB,SAAS,EAAE,QAAQ;QACnB,UAAU,EAAE,IAAI;KACjB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,OAAmB,EAAE,UAAsB;IAC9D,OAAO,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,MAAM,CACpB,OAAmB,EACnB,SAAqB,EACrB,SAAqB;IAErB,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,6BAA6B;AAE7B,SAAS,cAAc;IACrB,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,CACxD,CAAC;AACJ,CAAC;AAED,SAAS,cAAc;IACrB,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,CACxD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,OAAmB,EACnB,GAAW,EACX,SAAiB,MAAM;IAEvB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpC,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,OAAO,CAAC,CAAC;IAC7C,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAE3B,uBAAuB;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,CAAC;IAC3C,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IAChE,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC1B,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAE/D,yBAAyB;IACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,aAAa,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,aAAa,CAAC,CAAC;IACnD,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;IACpE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3B,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IAEnE,iBAAiB;IACjB,MAAM,IAAI,GAAY;QACpB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC;IACF,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,YAAY,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC1F,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,SAAiB,MAAM;IAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,YAAY,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,OAAO,CAAC,CAAC;IAE7C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,IAAI,MAAM,IAAI,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvD,IAAI,IAAI,GAAY;QAClB,WAAW,EAAE,WAAW,CAAC,QAAQ,CAAC;QAClC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,6BAA6B;IAC7B,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC;QAC/B,CAAC,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC,CAAC,SAAS,CAAC,CAAC,qDAAqD;IAEpE,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,aAAa,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC;QAClC,CAAC,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAElC,OAAO;QACL,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE;QACvD,UAAU,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE;QACxD,IAAI;QACJ,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,QAAQ;QACnB,UAAU,EAAE,SAAS;KACtB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC;QAC7B,iCAAiC;QACjC,OAAO,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,oCAAoC;AAEpC;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAGhC;IACC,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAEtC,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QAC3C,OAAO,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9D,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,OAAO,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE,EAAE,gBAAgB,CAAC,CAAC;IAC1D,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;YACzD,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,YAAY,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IACD,OAAO,YAAY,EAAE,CAAC;AACxB,CAAC;AAWD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,QAAgB,EAChB,SAAqB,EACrB,IAAuB,EACvB,aAA0B;IAE1B,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,uBAAuB,QAAQ,qDAAqD,CACrF,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpC,MAAM,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAY;QACxB,WAAW,EAAE,EAAE;QACf,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACtD,SAAS,EAAE,IAAI,EAAE,SAAS;QAC1B,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,UAAU;KACjC,CAAC;IAEF,6BAA6B;IAC7B,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAEpE,6CAA6C;IAC7C,IAAI,aAAa,EAAE,CAAC;QAClB,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,aAAa,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,aAAa,CACX,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,YAAY,CAAC,EAClC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EACjC,OAAO,CACR,CAAC;IAEF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAChE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,MAAM,CAAC,CAAC;IAE7C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,mBAAmB;IACnB,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,QAAQ,YAAY,CAAC,CAAC;IAClE,IAAI,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,YAAY,CAAC,CAAC;IACpD,IAAI,IAAI,GAAY;QAClB,WAAW,EAAE,WAAW,CAAC,SAAS,CAAC;QACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,iDAAiD;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,aAAa,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,UAAU,CAAC,QAAQ,CAAC;QACxC,CAAC,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,MAAc;IAC3D,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,MAAM,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,YAAY,CAAC,CAAC;IAEpD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACxC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,0CAA0C;IAC1C,IAAI,IAAI,GAAY;QAClB,WAAW,EAAE,EAAE;QACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1C,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;IAE3B,kBAAkB;IAClB,aAAa,CACX,IAAI,CAAC,UAAU,EAAE,GAAG,QAAQ,YAAY,CAAC,EACzC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAC7B,OAAO,CACR,CAAC;IAEF,8BAA8B;IAC9B,IAAI,CAAC;QACH,UAAU,CAAC,OAAO,CAAC,CAAC;QACpB,IAAI,UAAU,CAAC,QAAQ,CAAC;YAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,QAAQ,YAAY,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAa;IACrC,IAAI,CAAC,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAClC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAa,CAAC;IAE3C,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;SACpE,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE;QACjB,MAAM,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACzC,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAuB,EAAsB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export interface InternalMessage {
|
|
2
|
-
id: string;
|
|
3
|
-
from: string;
|
|
4
|
-
to: string;
|
|
5
|
-
body: string;
|
|
6
|
-
timestamp: string;
|
|
7
|
-
read: boolean;
|
|
8
|
-
}
|
|
9
|
-
export declare function internalMailRoot(officeDir: string): string;
|
|
10
|
-
export declare function getInternalInbox(officeDir: string, agent: string): {
|
|
11
|
-
root: string;
|
|
12
|
-
tmp: string;
|
|
13
|
-
fresh: string;
|
|
14
|
-
cur: string;
|
|
15
|
-
};
|
|
16
|
-
export declare function sendInternalMessage(officeDir: string, from: string, to: string, body: string): InternalMessage;
|
|
17
|
-
export declare function checkInternalMessages(officeDir: string, agent: string): InternalMessage[];
|
|
18
|
-
//# sourceMappingURL=internal-mail.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"internal-mail.d.ts","sourceRoot":"","sources":["../../../src/utils/internal-mail.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAUD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1D;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAY5H;AAID,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAoB9G;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAmBzF"}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join, resolve, sep } from "node:path";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import { randomUUID } from "node:crypto";
|
|
5
|
-
import { sanitizeIdentifier } from "../schema/sanitizer.js";
|
|
6
|
-
function assertOfficeDir(officeDir) {
|
|
7
|
-
const resolved = resolve(officeDir);
|
|
8
|
-
const root = resolve(join(process.env.HOME || homedir(), ".tps", "branch-office"));
|
|
9
|
-
if (!resolved.startsWith(root + sep) && resolved !== root) {
|
|
10
|
-
throw new Error(`Office directory out of bounds: ${officeDir}`);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
export function internalMailRoot(officeDir) {
|
|
14
|
-
assertOfficeDir(officeDir);
|
|
15
|
-
const dir = join(officeDir, "mail", "internal");
|
|
16
|
-
mkdirSync(dir, { recursive: true });
|
|
17
|
-
return dir;
|
|
18
|
-
}
|
|
19
|
-
export function getInternalInbox(officeDir, agent) {
|
|
20
|
-
assertOfficeDir(officeDir);
|
|
21
|
-
const safe = sanitizeIdentifier(agent);
|
|
22
|
-
if (!agent || safe !== agent)
|
|
23
|
-
throw new Error(`Invalid agent id: ${agent}`);
|
|
24
|
-
const root = join(internalMailRoot(officeDir), agent);
|
|
25
|
-
const tmp = join(root, "tmp");
|
|
26
|
-
const fresh = join(root, "new");
|
|
27
|
-
const cur = join(root, "cur");
|
|
28
|
-
mkdirSync(tmp, { recursive: true });
|
|
29
|
-
mkdirSync(fresh, { recursive: true });
|
|
30
|
-
mkdirSync(cur, { recursive: true });
|
|
31
|
-
return { root, tmp, fresh, cur };
|
|
32
|
-
}
|
|
33
|
-
const MAX_BODY_BYTES = 64 * 1024;
|
|
34
|
-
export function sendInternalMessage(officeDir, from, to, body) {
|
|
35
|
-
assertOfficeDir(officeDir);
|
|
36
|
-
const safeFrom = sanitizeIdentifier(from);
|
|
37
|
-
const safeTo = sanitizeIdentifier(to);
|
|
38
|
-
if (!from || safeFrom !== from)
|
|
39
|
-
throw new Error(`Invalid agent id: ${from}`);
|
|
40
|
-
if (!to || safeTo !== to)
|
|
41
|
-
throw new Error(`Invalid agent id: ${to}`);
|
|
42
|
-
if (body.includes("\u0000"))
|
|
43
|
-
throw new Error("Message body contains invalid null byte.");
|
|
44
|
-
if (Buffer.byteLength(body, "utf8") > MAX_BODY_BYTES)
|
|
45
|
-
throw new Error("Message body exceeds maximum size (64KB).");
|
|
46
|
-
const inbox = getInternalInbox(officeDir, to);
|
|
47
|
-
const timestamp = new Date().toISOString();
|
|
48
|
-
const id = randomUUID();
|
|
49
|
-
const message = { id, from, to, body, timestamp, read: false };
|
|
50
|
-
const safeTs = timestamp.replace(/[:.]/g, "-");
|
|
51
|
-
const filename = `${safeTs}-${id}.json`;
|
|
52
|
-
writeFileSync(join(inbox.tmp, filename), JSON.stringify(message, null, 2), "utf-8");
|
|
53
|
-
renameSync(join(inbox.tmp, filename), join(inbox.fresh, filename));
|
|
54
|
-
return message;
|
|
55
|
-
}
|
|
56
|
-
export function checkInternalMessages(officeDir, agent) {
|
|
57
|
-
assertOfficeDir(officeDir);
|
|
58
|
-
const safe = sanitizeIdentifier(agent);
|
|
59
|
-
if (!agent || safe !== agent)
|
|
60
|
-
throw new Error(`Invalid agent id: ${agent}`);
|
|
61
|
-
const inbox = getInternalInbox(officeDir, agent);
|
|
62
|
-
const files = readdirSync(inbox.fresh).filter((f) => f.endsWith(".json"));
|
|
63
|
-
const messages = [];
|
|
64
|
-
for (const f of files) {
|
|
65
|
-
const fromPath = join(inbox.fresh, f);
|
|
66
|
-
const toPath = join(inbox.cur, f);
|
|
67
|
-
renameSync(fromPath, toPath);
|
|
68
|
-
const raw = readFileSync(toPath, "utf-8");
|
|
69
|
-
const msg = JSON.parse(raw);
|
|
70
|
-
msg.read = true;
|
|
71
|
-
messages.push(msg);
|
|
72
|
-
}
|
|
73
|
-
return messages.sort((a, b) => (a.timestamp < b.timestamp ? 1 : -1));
|
|
74
|
-
}
|
|
75
|
-
//# sourceMappingURL=internal-mail.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"internal-mail.js","sourceRoot":"","sources":["../../../src/utils/internal-mail.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export interface LoopDetectorOptions {
|
|
2
|
-
/** Max duplicate messages before triggering. Default: 3 */
|
|
3
|
-
threshold?: number;
|
|
4
|
-
/** Time window in ms. Default: 300_000 (5 min) */
|
|
5
|
-
windowMs?: number;
|
|
6
|
-
}
|
|
7
|
-
export declare class LoopDetector {
|
|
8
|
-
private history;
|
|
9
|
-
private readonly threshold;
|
|
10
|
-
private readonly windowMs;
|
|
11
|
-
constructor(opts?: LoopDetectorOptions);
|
|
12
|
-
/** Hash a message body (SHA-256, first 16 hex chars) */
|
|
13
|
-
private hash;
|
|
14
|
-
/** Prune entries outside the time window */
|
|
15
|
-
private prune;
|
|
16
|
-
/**
|
|
17
|
-
* Check if a message body is a duplicate.
|
|
18
|
-
* Returns true if this message should be PAUSED (loop detected).
|
|
19
|
-
* Always records the hash regardless of result.
|
|
20
|
-
*/
|
|
21
|
-
check(body: string): boolean;
|
|
22
|
-
/** Reset all history (e.g., after manual intervention) */
|
|
23
|
-
reset(): void;
|
|
24
|
-
/** Get current duplicate count for a body */
|
|
25
|
-
duplicateCount(body: string): number;
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=loop-detector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loop-detector.d.ts","sourceRoot":"","sources":["../../../src/utils/loop-detector.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,IAAI,GAAE,mBAAwB;IAK1C,wDAAwD;IACxD,OAAO,CAAC,IAAI;IAIZ,4CAA4C;IAC5C,OAAO,CAAC,KAAK;IAKb;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAQ5B,0DAA0D;IAC1D,KAAK,IAAI,IAAI;IAIb,6CAA6C;IAC7C,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAKrC"}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
export class LoopDetector {
|
|
3
|
-
history = [];
|
|
4
|
-
threshold;
|
|
5
|
-
windowMs;
|
|
6
|
-
constructor(opts = {}) {
|
|
7
|
-
this.threshold = opts.threshold ?? 3;
|
|
8
|
-
this.windowMs = opts.windowMs ?? 300_000;
|
|
9
|
-
}
|
|
10
|
-
/** Hash a message body (SHA-256, first 16 hex chars) */
|
|
11
|
-
hash(body) {
|
|
12
|
-
return createHash("sha256").update(body).digest("hex").slice(0, 16);
|
|
13
|
-
}
|
|
14
|
-
/** Prune entries outside the time window */
|
|
15
|
-
prune() {
|
|
16
|
-
const cutoff = Date.now() - this.windowMs;
|
|
17
|
-
this.history = this.history.filter((e) => e.timestamp > cutoff);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Check if a message body is a duplicate.
|
|
21
|
-
* Returns true if this message should be PAUSED (loop detected).
|
|
22
|
-
* Always records the hash regardless of result.
|
|
23
|
-
*/
|
|
24
|
-
check(body) {
|
|
25
|
-
this.prune();
|
|
26
|
-
const h = this.hash(body);
|
|
27
|
-
this.history.push({ hash: h, timestamp: Date.now() });
|
|
28
|
-
const count = this.history.filter((e) => e.hash === h).length;
|
|
29
|
-
return count >= this.threshold;
|
|
30
|
-
}
|
|
31
|
-
/** Reset all history (e.g., after manual intervention) */
|
|
32
|
-
reset() {
|
|
33
|
-
this.history = [];
|
|
34
|
-
}
|
|
35
|
-
/** Get current duplicate count for a body */
|
|
36
|
-
duplicateCount(body) {
|
|
37
|
-
this.prune();
|
|
38
|
-
const h = this.hash(body);
|
|
39
|
-
return this.history.filter((e) => e.hash === h).length;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
//# sourceMappingURL=loop-detector.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loop-detector.js","sourceRoot":"","sources":["../../../src/utils/loop-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAczC,MAAM,OAAO,YAAY;IACf,OAAO,GAAgB,EAAE,CAAC;IACjB,SAAS,CAAS;IAClB,QAAQ,CAAS;IAElC,YAAY,OAA4B,EAAE;QACxC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC;IAC3C,CAAC;IAED,wDAAwD;IAChD,IAAI,CAAC,IAAY;QACvB,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,4CAA4C;IACpC,KAAK;QACX,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC;IAClE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAC9D,OAAO,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC;IACjC,CAAC;IAED,0DAA0D;IAC1D,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;IACpB,CAAC;IAED,6CAA6C;IAC7C,cAAc,CAAC,IAAY;QACzB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,CAAC;CACF"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { AgentManifest } from "./manifest.js";
|
|
2
|
-
export interface HandlerAction {
|
|
3
|
-
type: "reply" | "forward" | "drop" | "inbox";
|
|
4
|
-
body?: string;
|
|
5
|
-
to?: string;
|
|
6
|
-
}
|
|
7
|
-
export interface MailMessage {
|
|
8
|
-
id: string;
|
|
9
|
-
from: string;
|
|
10
|
-
to: string;
|
|
11
|
-
body: string;
|
|
12
|
-
timestamp: string;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Runs the mail handler pipeline for an incoming message.
|
|
16
|
-
* Iterates through manifests in priority order (assumed sorted from discoverManifests).
|
|
17
|
-
*/
|
|
18
|
-
export declare function runHandlerPipeline(msg: MailMessage, manifests: AgentManifest[], registeredAgents: string[]): Promise<HandlerAction>;
|
|
19
|
-
//# sourceMappingURL=mail-handler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mail-handler.d.ts","sourceRoot":"","sources":["../../../src/utils/mail-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,aAAa,EAAE,EAC1B,gBAAgB,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,aAAa,CAAC,CA+FxB"}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { matchesFilter } from "./manifest.js";
|
|
3
|
-
/**
|
|
4
|
-
* Runs the mail handler pipeline for an incoming message.
|
|
5
|
-
* Iterates through manifests in priority order (assumed sorted from discoverManifests).
|
|
6
|
-
*/
|
|
7
|
-
export async function runHandlerPipeline(msg, manifests, registeredAgents) {
|
|
8
|
-
const enabledManifests = manifests.filter((m) => m.capabilities?.mail_handler?.enabled !== false);
|
|
9
|
-
for (const manifest of enabledManifests) {
|
|
10
|
-
if (!matchesFilter(manifest, msg)) {
|
|
11
|
-
continue;
|
|
12
|
-
}
|
|
13
|
-
const handler = manifest.capabilities?.mail_handler;
|
|
14
|
-
const bodyToTest = msg.body.trim().slice(0, 1024);
|
|
15
|
-
// 1. Check routing rules first
|
|
16
|
-
if (manifest.routing) {
|
|
17
|
-
for (const rule of manifest.routing) {
|
|
18
|
-
try {
|
|
19
|
-
const re = new RegExp(rule.pattern);
|
|
20
|
-
if (re.test(bodyToTest)) {
|
|
21
|
-
return { type: "forward", to: rule.to, body: msg.body };
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
catch (err) {
|
|
25
|
-
// Skip invalid regex
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
// 2. Run exec handler if it exists
|
|
30
|
-
if (handler?.exec) {
|
|
31
|
-
const env = {
|
|
32
|
-
...process.env,
|
|
33
|
-
MAIL_ID: msg.id,
|
|
34
|
-
MAIL_FROM: msg.from,
|
|
35
|
-
MAIL_TO: msg.to,
|
|
36
|
-
MAIL_TIMESTAMP: msg.timestamp,
|
|
37
|
-
TPS_AGENT_NAME: manifest.name,
|
|
38
|
-
};
|
|
39
|
-
if (handler.needs_roster) {
|
|
40
|
-
env.TPS_REGISTERED_AGENTS = JSON.stringify(registeredAgents);
|
|
41
|
-
}
|
|
42
|
-
const timeoutMs = (handler.timeout || 30) * 1000;
|
|
43
|
-
try {
|
|
44
|
-
const result = spawnSync(handler.exec, [], {
|
|
45
|
-
input: msg.body,
|
|
46
|
-
env,
|
|
47
|
-
timeout: timeoutMs,
|
|
48
|
-
encoding: "utf8",
|
|
49
|
-
shell: false,
|
|
50
|
-
cwd: manifest.agentDir,
|
|
51
|
-
});
|
|
52
|
-
if (result.error) {
|
|
53
|
-
console.error("[HANDLER] spawnSync error:", result.error);
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if (result.status === 0) {
|
|
57
|
-
const stdout = result.stdout?.trim() || "";
|
|
58
|
-
if (!stdout) {
|
|
59
|
-
return { type: "drop" };
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
const json = JSON.parse(stdout);
|
|
63
|
-
if (json && typeof json === "object" && json.action) {
|
|
64
|
-
return {
|
|
65
|
-
type: json.action,
|
|
66
|
-
body: json.body,
|
|
67
|
-
to: json.to,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch (e) {
|
|
72
|
-
// Not JSON, treat as plain text reply
|
|
73
|
-
}
|
|
74
|
-
return { type: "reply", body: stdout, to: msg.from };
|
|
75
|
-
}
|
|
76
|
-
else if (result.status === 1) {
|
|
77
|
-
// Exit 1: continue to next manifest
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
// Exit 2+: error, log and continue
|
|
82
|
-
console.error(`[HANDLER] error: ${manifest.name} exited with ${result.status}`);
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
catch (err) {
|
|
87
|
-
console.error(`[HANDLER] exception running ${manifest.name}:`, err);
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return { type: "inbox" };
|
|
93
|
-
}
|
|
94
|
-
//# sourceMappingURL=mail-handler.js.map
|