@0xmaxma/claude-gateway 1.5.7 → 1.6.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 +22 -0
- package/dist/agent/runner.d.ts +31 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +224 -16
- package/dist/agent/runner.js.map +1 -1
- package/dist/api/apps-router.d.ts.map +1 -1
- package/dist/api/apps-router.js +7 -2
- package/dist/api/apps-router.js.map +1 -1
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +27 -0
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/api/line-webhook-router.d.ts.map +1 -1
- package/dist/api/line-webhook-router.js +68 -0
- package/dist/api/line-webhook-router.js.map +1 -1
- package/dist/api/router.d.ts +2 -0
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +60 -4
- package/dist/api/router.js.map +1 -1
- package/dist/api/share-router.d.ts +11 -0
- package/dist/api/share-router.d.ts.map +1 -0
- package/dist/api/share-router.js +402 -0
- package/dist/api/share-router.js.map +1 -0
- package/dist/apps/installer.d.ts +55 -0
- package/dist/apps/installer.d.ts.map +1 -1
- package/dist/apps/installer.js +136 -1
- package/dist/apps/installer.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +9 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/public-url.d.ts +11 -0
- package/dist/config/public-url.d.ts.map +1 -0
- package/dist/config/public-url.js +41 -0
- package/dist/config/public-url.js.map +1 -0
- package/dist/config/watcher.d.ts.map +1 -1
- package/dist/config/watcher.js +1 -0
- package/dist/config/watcher.js.map +1 -1
- package/dist/history/db.d.ts +14 -0
- package/dist/history/db.d.ts.map +1 -1
- package/dist/history/db.js +48 -4
- package/dist/history/db.js.map +1 -1
- package/dist/history/types.d.ts +5 -0
- package/dist/history/types.d.ts.map +1 -1
- package/dist/session/process.d.ts +3 -0
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +27 -1
- package/dist/session/process.js.map +1 -1
- package/dist/session/store.d.ts +2 -1
- package/dist/session/store.d.ts.map +1 -1
- package/dist/session/store.js +10 -2
- package/dist/session/store.js.map +1 -1
- package/dist/share/session-image-catalog.d.ts +22 -0
- package/dist/share/session-image-catalog.d.ts.map +1 -0
- package/dist/share/session-image-catalog.js +151 -0
- package/dist/share/session-image-catalog.js.map +1 -0
- package/dist/share/share-store.d.ts +137 -0
- package/dist/share/share-store.d.ts.map +1 -0
- package/dist/share/share-store.js +340 -0
- package/dist/share/share-store.js.map +1 -0
- package/dist/types.d.ts +19 -7
- package/dist/types.d.ts.map +1 -1
- package/mcp/instructions.ts +1 -0
- package/mcp/server.ts +2 -0
- package/mcp/tools/agent/handlers.ts +55 -4
- package/mcp/tools/image/module.ts +240 -26
- package/mcp/tools/line/module.ts +186 -0
- package/mcp/tools/share-image/module.ts +120 -0
- package/mcp/tools/shared/share-client.ts +197 -0
- package/package.json +3 -1
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ShareStore = exports.ShareError = exports.ARTIFACT_RETENTION_MS = exports.DEFAULT_MAX_TOTAL_BYTES = exports.DEFAULT_MAX_FILE_BYTES = exports.DEFAULT_MAX_REFS = exports.DEFAULT_SHARE_TTL_SECONDS = exports.MINT_DEDUPE_WINDOW_MS = exports.SHARE_TOKEN_RE = void 0;
|
|
37
|
+
exports.shareLimitsFromEnv = shareLimitsFromEnv;
|
|
38
|
+
exports.detectImageMime = detectImageMime;
|
|
39
|
+
exports.validateShareFile = validateShareFile;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const crypto_1 = require("crypto");
|
|
43
|
+
const node_sqlite_1 = require("node:sqlite");
|
|
44
|
+
const media_store_1 = require("../history/media-store");
|
|
45
|
+
/**
|
|
46
|
+
* Share bridge — SQLite-backed store for short-lived public image shares
|
|
47
|
+
* and private image artifacts (#70, plan §8/§9).
|
|
48
|
+
*
|
|
49
|
+
* The gateway MAIN process is the only owner of this DB: MCP subprocesses go
|
|
50
|
+
* through the authenticated HTTP API (share-router.ts) and never open
|
|
51
|
+
* SQLite themselves. Tokens are bearer capabilities: 24 random bytes,
|
|
52
|
+
* base64url, and ONLY the SHA-256 hash is persisted — the plaintext token
|
|
53
|
+
* exists in the mint response (and a short-lived in-memory dedupe cache) only.
|
|
54
|
+
*/
|
|
55
|
+
/** randomBytes(24) → base64url without padding = 32 chars. */
|
|
56
|
+
exports.SHARE_TOKEN_RE = /^[A-Za-z0-9_-]{32}$/;
|
|
57
|
+
/** Idempotent-mint window (§17.4): a re-mint for the same (agent, session,
|
|
58
|
+
* ref, purpose) within this window returns the SAME token/URL so the
|
|
59
|
+
* provider's duplicate-submit guard (which hashes the image URLs) still
|
|
60
|
+
* dedupes agent retries instead of double-billing. */
|
|
61
|
+
exports.MINT_DEDUPE_WINDOW_MS = 60000;
|
|
62
|
+
exports.DEFAULT_SHARE_TTL_SECONDS = 1800; // 30 min (§3.15)
|
|
63
|
+
exports.DEFAULT_MAX_REFS = 5;
|
|
64
|
+
exports.DEFAULT_MAX_FILE_BYTES = 20 * 1024 * 1024; // 20 MiB
|
|
65
|
+
exports.DEFAULT_MAX_TOTAL_BYTES = 50 * 1024 * 1024; // 50 MiB
|
|
66
|
+
/** Artifacts older than this are pruned opportunistically — far beyond any share
|
|
67
|
+
* TTL (max 24h) and any live session, so removal never breaks an active ref. */
|
|
68
|
+
exports.ARTIFACT_RETENTION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
69
|
+
const ARTIFACT_PRUNE_THROTTLE_MS = 60 * 60 * 1000; // sweep at most once/hour
|
|
70
|
+
function shareLimitsFromEnv() {
|
|
71
|
+
const num = (v, dflt) => {
|
|
72
|
+
const n = Number(v);
|
|
73
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : dflt;
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
maxRefs: num(process.env.IMAGE_SHARE_MAX_REFS, exports.DEFAULT_MAX_REFS),
|
|
77
|
+
maxFileBytes: num(process.env.IMAGE_SHARE_MAX_FILE_BYTES, exports.DEFAULT_MAX_FILE_BYTES),
|
|
78
|
+
maxTotalBytes: num(process.env.IMAGE_SHARE_MAX_TOTAL_BYTES, exports.DEFAULT_MAX_TOTAL_BYTES),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** Typed error with a stable machine-readable code (used for HTTP mapping). */
|
|
82
|
+
class ShareError extends Error {
|
|
83
|
+
constructor(code, message) {
|
|
84
|
+
super(message);
|
|
85
|
+
this.code = code;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.ShareError = ShareError;
|
|
89
|
+
/** Phase-1 formats: PNG / JPEG / WebP only (§11). GIF/SVG/PDF are rejected. */
|
|
90
|
+
function detectImageMime(header) {
|
|
91
|
+
if (header.length >= 3 && header[0] === 0xff && header[1] === 0xd8 && header[2] === 0xff)
|
|
92
|
+
return 'image/jpeg';
|
|
93
|
+
if (header.length >= 8 && header[0] === 0x89 && header[1] === 0x50 && header[2] === 0x4e && header[3] === 0x47)
|
|
94
|
+
return 'image/png';
|
|
95
|
+
if (header.length >= 12 &&
|
|
96
|
+
header[0] === 0x52 && header[1] === 0x49 && header[2] === 0x46 && header[3] === 0x46 &&
|
|
97
|
+
header[8] === 0x57 && header[9] === 0x45 && header[10] === 0x42 && header[11] === 0x50)
|
|
98
|
+
return 'image/webp';
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Validate a local ref (absolute or media-relative path) for sharing (§12):
|
|
103
|
+
* canonicalize, require containment in the agent's media root, reject symlink
|
|
104
|
+
* escapes, require a regular file, validate magic bytes and the per-file cap.
|
|
105
|
+
* Returns only the media-root-relative path — client-supplied absolute paths
|
|
106
|
+
* are never persisted. Throws ShareError with a stable code.
|
|
107
|
+
*/
|
|
108
|
+
function validateShareFile(agentsBaseDir, agentId, ref, maxFileBytes = exports.DEFAULT_MAX_FILE_BYTES) {
|
|
109
|
+
const root = media_store_1.MediaStore.agentMediaRoot(agentsBaseDir, agentId);
|
|
110
|
+
let resolved;
|
|
111
|
+
try {
|
|
112
|
+
if (path.isAbsolute(ref)) {
|
|
113
|
+
// Absolute input (e.g. the path generate_image returned): containment +
|
|
114
|
+
// symlink checks mirror MediaStore.resolvePath.
|
|
115
|
+
const abs = path.resolve(ref);
|
|
116
|
+
if (!abs.startsWith(root + path.sep))
|
|
117
|
+
throw new Error('outside media root');
|
|
118
|
+
resolved = fs.existsSync(abs) ? fs.realpathSync(abs) : abs;
|
|
119
|
+
if (!resolved.startsWith(root + path.sep))
|
|
120
|
+
throw new Error('outside media root');
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
resolved = media_store_1.MediaStore.resolvePath(agentsBaseDir, agentId, ref);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
throw new ShareError('invalid_path', 'path is outside the agent media root');
|
|
128
|
+
}
|
|
129
|
+
let stat;
|
|
130
|
+
try {
|
|
131
|
+
stat = fs.lstatSync(resolved); // realpath already followed links; lstat guards devices/FIFOs
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
throw new ShareError('image_ref_not_found', 'referenced image file does not exist');
|
|
135
|
+
}
|
|
136
|
+
if (!stat.isFile()) {
|
|
137
|
+
throw new ShareError('invalid_path', 'referenced path is not a regular file');
|
|
138
|
+
}
|
|
139
|
+
if (stat.size > maxFileBytes) {
|
|
140
|
+
throw new ShareError('image_too_large', `image exceeds ${maxFileBytes} bytes`);
|
|
141
|
+
}
|
|
142
|
+
const header = Buffer.alloc(12);
|
|
143
|
+
const fd = fs.openSync(resolved, 'r');
|
|
144
|
+
try {
|
|
145
|
+
fs.readSync(fd, header, 0, 12, 0);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
fs.closeSync(fd);
|
|
149
|
+
}
|
|
150
|
+
const mime = detectImageMime(header);
|
|
151
|
+
if (!mime) {
|
|
152
|
+
throw new ShareError('unsupported_image_type', 'only PNG, JPEG and WebP can be shared');
|
|
153
|
+
}
|
|
154
|
+
const relativePath = path.relative(root, resolved);
|
|
155
|
+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
156
|
+
throw new ShareError('invalid_path', 'path is outside the agent media root');
|
|
157
|
+
}
|
|
158
|
+
return { relativePath, size: stat.size, mime };
|
|
159
|
+
}
|
|
160
|
+
class ShareStore {
|
|
161
|
+
constructor(dbPath) {
|
|
162
|
+
/** In-memory idempotent-mint cache: dedupe key → last mint. Plaintext tokens
|
|
163
|
+
* live here only for MINT_DEDUPE_WINDOW_MS, never on disk (§9/§17.4). */
|
|
164
|
+
this.mintCache = new Map();
|
|
165
|
+
/** Last opportunistic artifact-prune timestamp (throttle, see registerArtifact). */
|
|
166
|
+
this.lastArtifactPruneMs = 0;
|
|
167
|
+
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
|
|
168
|
+
this.db = new node_sqlite_1.DatabaseSync(dbPath);
|
|
169
|
+
this.db.exec('PRAGMA journal_mode=WAL');
|
|
170
|
+
this.db.exec('PRAGMA busy_timeout=5000');
|
|
171
|
+
this.db.exec('PRAGMA foreign_keys=ON');
|
|
172
|
+
this.db.exec(`
|
|
173
|
+
CREATE TABLE IF NOT EXISTS image_shares (
|
|
174
|
+
id TEXT PRIMARY KEY,
|
|
175
|
+
token_hash BLOB NOT NULL UNIQUE,
|
|
176
|
+
agent_id TEXT NOT NULL,
|
|
177
|
+
session_id TEXT NOT NULL,
|
|
178
|
+
relative_path TEXT NOT NULL,
|
|
179
|
+
purpose TEXT NOT NULL,
|
|
180
|
+
created_at INTEGER NOT NULL,
|
|
181
|
+
expires_at INTEGER NOT NULL,
|
|
182
|
+
revoked_at INTEGER
|
|
183
|
+
);
|
|
184
|
+
CREATE INDEX IF NOT EXISTS image_shares_expiry ON image_shares(expires_at);
|
|
185
|
+
|
|
186
|
+
CREATE TABLE IF NOT EXISTS image_artifacts (
|
|
187
|
+
id TEXT PRIMARY KEY,
|
|
188
|
+
agent_id TEXT NOT NULL,
|
|
189
|
+
session_id TEXT NOT NULL,
|
|
190
|
+
relative_path TEXT NOT NULL,
|
|
191
|
+
provider TEXT NOT NULL,
|
|
192
|
+
model TEXT NOT NULL,
|
|
193
|
+
task_id TEXT,
|
|
194
|
+
image_index INTEGER NOT NULL DEFAULT 0,
|
|
195
|
+
created_at INTEGER NOT NULL,
|
|
196
|
+
prompt TEXT
|
|
197
|
+
);
|
|
198
|
+
CREATE INDEX IF NOT EXISTS image_artifacts_session_created
|
|
199
|
+
ON image_artifacts(agent_id, session_id, created_at DESC);
|
|
200
|
+
`);
|
|
201
|
+
// DBs created before the `prompt` column existed: CREATE TABLE IF NOT
|
|
202
|
+
// EXISTS leaves them untouched, so add the column in place. Additive and
|
|
203
|
+
// nullable — older rows simply have no prompt.
|
|
204
|
+
const cols = this.db.prepare(`PRAGMA table_info(image_artifacts)`).all();
|
|
205
|
+
if (!cols.some((c) => c.name === 'prompt')) {
|
|
206
|
+
this.db.exec('ALTER TABLE image_artifacts ADD COLUMN prompt TEXT');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// ── artifacts (§8) ────────────────────────────────────────────────────────
|
|
210
|
+
registerArtifact(a) {
|
|
211
|
+
const id = `img_${(0, crypto_1.randomBytes)(9).toString('base64url')}`;
|
|
212
|
+
this.db.prepare(`INSERT INTO image_artifacts (id, agent_id, session_id, relative_path, provider, model, task_id, image_index, created_at, prompt)
|
|
213
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, a.agentId, a.sessionId, a.relativePath, a.provider, a.model, a.taskId ?? null, a.imageIndex ?? 0, Date.now(), a.prompt ?? null);
|
|
214
|
+
this.pruneOldArtifacts();
|
|
215
|
+
return id;
|
|
216
|
+
}
|
|
217
|
+
/** Opportunistic, throttled retention sweep — delete artifacts older than
|
|
218
|
+
* ARTIFACT_RETENTION_MS. Best-effort: a failure here must not fail the insert. */
|
|
219
|
+
pruneOldArtifacts() {
|
|
220
|
+
const now = Date.now();
|
|
221
|
+
if (now - this.lastArtifactPruneMs < ARTIFACT_PRUNE_THROTTLE_MS)
|
|
222
|
+
return;
|
|
223
|
+
this.lastArtifactPruneMs = now;
|
|
224
|
+
try {
|
|
225
|
+
this.db.prepare('DELETE FROM image_artifacts WHERE created_at <= ?').run(now - exports.ARTIFACT_RETENTION_MS);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
/* best-effort */
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** Resolve an artifact bound to the SAME agent AND session — cross-agent or
|
|
232
|
+
* cross-session lookups return null (uniform "not found", §8). */
|
|
233
|
+
resolveArtifact(agentId, sessionId, artifactId) {
|
|
234
|
+
const row = this.db.prepare(`SELECT id, agent_id, session_id, relative_path, provider, model
|
|
235
|
+
FROM image_artifacts WHERE id = ? AND agent_id = ? AND session_id = ?`).get(artifactId, agentId, sessionId);
|
|
236
|
+
if (!row)
|
|
237
|
+
return null;
|
|
238
|
+
return {
|
|
239
|
+
artifactId: row.id,
|
|
240
|
+
agentId: row.agent_id,
|
|
241
|
+
sessionId: row.session_id,
|
|
242
|
+
relativePath: row.relative_path,
|
|
243
|
+
provider: row.provider,
|
|
244
|
+
model: row.model,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/** Newest artifact id registered for (agent, session, relative_path), or null.
|
|
248
|
+
* Read-only reverse lookup for the session image catalog (#72): a path that
|
|
249
|
+
* was produced by generate_image gets the stable `artifact:<id>` ref instead
|
|
250
|
+
* of a raw path. Same agent+session binding as resolveArtifact — a path
|
|
251
|
+
* registered by another agent/session is invisible here. */
|
|
252
|
+
findArtifactByPath(agentId, sessionId, relativePath) {
|
|
253
|
+
const row = this.db.prepare(`SELECT id, prompt FROM image_artifacts
|
|
254
|
+
WHERE agent_id = ? AND session_id = ? AND relative_path = ?
|
|
255
|
+
ORDER BY created_at DESC, rowid DESC LIMIT 1`).get(agentId, sessionId, relativePath);
|
|
256
|
+
return row ? { id: row.id, prompt: row.prompt } : null;
|
|
257
|
+
}
|
|
258
|
+
// ── shares (§9) ───────────────────────────────────────────────────────────
|
|
259
|
+
/**
|
|
260
|
+
* Mint a share. `dedupeRef` is the caller-facing identity of the ref
|
|
261
|
+
* (e.g. "artifact:img_x" or "path:<relative>") — an identical mint for the
|
|
262
|
+
* same (agent, session, ref, purpose) within MINT_DEDUPE_WINDOW_MS returns
|
|
263
|
+
* the SAME token (§17.4) so provider-side dedupe keeps working.
|
|
264
|
+
*/
|
|
265
|
+
mintShare(a) {
|
|
266
|
+
const key = [a.agentId, a.sessionId, a.dedupeRef, a.purpose].join('');
|
|
267
|
+
const now = Date.now();
|
|
268
|
+
const cached = this.mintCache.get(key);
|
|
269
|
+
if (cached && now - cached.mintedAtMs < exports.MINT_DEDUPE_WINDOW_MS && cached.expiresAtMs > now) {
|
|
270
|
+
return { shareId: cached.shareId, token: cached.token, expiresAtMs: cached.expiresAtMs, deduped: true };
|
|
271
|
+
}
|
|
272
|
+
const token = (0, crypto_1.randomBytes)(24).toString('base64url');
|
|
273
|
+
const tokenHash = (0, crypto_1.createHash)('sha256').update(token).digest();
|
|
274
|
+
const shareId = `shr_${(0, crypto_1.randomBytes)(9).toString('base64url')}`;
|
|
275
|
+
const expiresAtMs = now + a.ttlSeconds * 1000;
|
|
276
|
+
this.db.prepare(`INSERT INTO image_shares (id, token_hash, agent_id, session_id, relative_path, purpose, created_at, expires_at)
|
|
277
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(shareId, tokenHash, a.agentId, a.sessionId, a.relativePath, a.purpose, now, expiresAtMs);
|
|
278
|
+
this.mintCache.set(key, { shareId, token, expiresAtMs, deduped: false, mintedAtMs: now });
|
|
279
|
+
this.pruneMintCache(now);
|
|
280
|
+
return { shareId, token, expiresAtMs, deduped: false };
|
|
281
|
+
}
|
|
282
|
+
/** Look up a live (unexpired, unrevoked) share by plaintext token. */
|
|
283
|
+
lookupByToken(token) {
|
|
284
|
+
if (!exports.SHARE_TOKEN_RE.test(token))
|
|
285
|
+
return null;
|
|
286
|
+
const tokenHash = (0, crypto_1.createHash)('sha256').update(token).digest();
|
|
287
|
+
const row = this.db.prepare(`SELECT id, agent_id, session_id, relative_path, purpose
|
|
288
|
+
FROM image_shares
|
|
289
|
+
WHERE token_hash = ? AND revoked_at IS NULL AND expires_at > ?`).get(tokenHash, Date.now());
|
|
290
|
+
if (!row)
|
|
291
|
+
return null;
|
|
292
|
+
return {
|
|
293
|
+
shareId: row.id,
|
|
294
|
+
agentId: row.agent_id,
|
|
295
|
+
sessionId: row.session_id,
|
|
296
|
+
relativePath: row.relative_path,
|
|
297
|
+
purpose: row.purpose,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
getShareOwner(shareId) {
|
|
301
|
+
const row = this.db.prepare(`SELECT agent_id, session_id, purpose FROM image_shares WHERE id = ? AND revoked_at IS NULL`).get(shareId);
|
|
302
|
+
return row ? { agentId: row.agent_id, sessionId: row.session_id, purpose: row.purpose } : null;
|
|
303
|
+
}
|
|
304
|
+
/** Revoke a share by id. Also evicts any idempotency-cache entry pointing at
|
|
305
|
+
* it so a post-revoke mint issues a FRESH token. Returns false when unknown. */
|
|
306
|
+
revokeShare(shareId) {
|
|
307
|
+
const res = this.db.prepare(`UPDATE image_shares SET revoked_at = ? WHERE id = ? AND revoked_at IS NULL`).run(Date.now(), shareId);
|
|
308
|
+
for (const [key, entry] of this.mintCache) {
|
|
309
|
+
if (entry.shareId === shareId)
|
|
310
|
+
this.mintCache.delete(key);
|
|
311
|
+
}
|
|
312
|
+
return Number(res.changes) > 0;
|
|
313
|
+
}
|
|
314
|
+
/** Lazy cleanup — delete expired rows. Safe to call opportunistically. */
|
|
315
|
+
cleanupExpired() {
|
|
316
|
+
try {
|
|
317
|
+
this.db.prepare(`DELETE FROM image_shares WHERE expires_at <= ?`).run(Date.now());
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
/* best-effort */
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
close() {
|
|
324
|
+
try {
|
|
325
|
+
this.db.close();
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
/* already closed */
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
pruneMintCache(now) {
|
|
332
|
+
for (const [key, entry] of this.mintCache) {
|
|
333
|
+
if (now - entry.mintedAtMs >= exports.MINT_DEDUPE_WINDOW_MS || entry.expiresAtMs <= now) {
|
|
334
|
+
this.mintCache.delete(key);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
exports.ShareStore = ShareStore;
|
|
340
|
+
//# sourceMappingURL=share-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share-store.js","sourceRoot":"","sources":["../../src/share/share-store.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -146,13 +146,15 @@ export interface GatewayConfig {
|
|
|
146
146
|
*/
|
|
147
147
|
bind?: string;
|
|
148
148
|
/**
|
|
149
|
-
* Absolute, externally-reachable
|
|
150
|
-
* "https://gateway.example.com"
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
149
|
+
* Absolute, externally-reachable base URL of this gateway, including any
|
|
150
|
+
* reverse-proxy path prefix (e.g. "https://gateway.example.com" or
|
|
151
|
+
* "https://vm.example.com/gateway"). Two consumers: phone-openable links
|
|
152
|
+
* such as the `/cli` webview terminal viewer, and the image-share bridge —
|
|
153
|
+
* its presence is the sole enable switch and source for minting public
|
|
154
|
+
* shared-image URLs. The process cannot infer its own public URL (it binds
|
|
155
|
+
* localhost by default and sits behind a reverse proxy), so the operator
|
|
156
|
+
* sets it explicitly. Unset = features that need a public link are
|
|
157
|
+
* disabled. A trailing slash is trimmed when building links.
|
|
156
158
|
*/
|
|
157
159
|
publicUrl?: string;
|
|
158
160
|
models?: ModelConfig[];
|
|
@@ -233,6 +235,8 @@ export interface SessionMeta {
|
|
|
233
235
|
* can restore the composer selection on reload; the agent's own context is the
|
|
234
236
|
* functional source of truth. Updated whenever a send carries image_params. */
|
|
235
237
|
imageConfig?: ImageParams;
|
|
238
|
+
/** Real model from Claude stream, updated per turn (e.g. "claude-opus-4-8"). */
|
|
239
|
+
model?: string;
|
|
236
240
|
}
|
|
237
241
|
export interface SessionIndex {
|
|
238
242
|
activeSessionId: string;
|
|
@@ -254,6 +258,14 @@ export type ImageParams = {
|
|
|
254
258
|
size?: string;
|
|
255
259
|
aspect_ratio?: string;
|
|
256
260
|
image_ref?: string;
|
|
261
|
+
/**
|
|
262
|
+
* Reference images explicitly selected in the composer, in the order the user
|
|
263
|
+
* picked them. Each entry is a `ref` value from GET /api/v1/image-catalog —
|
|
264
|
+
* either an `artifact:<id>` ref or a media-relative path (the same forms the
|
|
265
|
+
* generate_image `image`/`images` arguments accept). Per-turn only: unlike the
|
|
266
|
+
* rest of ImageParams these are NOT persisted as durable session image config.
|
|
267
|
+
*/
|
|
268
|
+
image_refs?: string[];
|
|
257
269
|
n?: number;
|
|
258
270
|
};
|
|
259
271
|
export type StreamEvent = {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/mcp/instructions.ts
CHANGED
|
@@ -15,6 +15,7 @@ const IMAGE_INSTRUCTION = [
|
|
|
15
15
|
'• RETRY ON FAILURE ONLY: a generate can fail with no_supply / no_credential (pool_eligible does not guarantee a working key). If — AND ONLY IF — a generate returns no_supply, no_credential, or an error, try the NEXT usable model (byok_available ones first), up to every usable model. This retry rule NEVER applies to a successful generate or to sending.',
|
|
16
16
|
'• ONE image, sent ONCE, then STOP: as soon as a generate SUCCEEDS, deliver that single file with your reply tool exactly ONE time (files: ["/abs/path.png"]) and briefly mention the model. Then you are DONE — do NOT generate again, do NOT resend the same image, do NOT call the reply tool again, and do NOT send extra follow-up messages. Sending the image (or any message) repeatedly is a bug.',
|
|
17
17
|
'• Only if there is NO usable model at all (none byok_available AND none pool_eligible), OR every usable model failed to generate, tell the user PLAINLY that image generation isn\'t set up with a working model yet and they need to connect an image-provider key (BYOK). Do NOT invent app-install / MCP-setup steps, and do NOT pretend an image was created.',
|
|
18
|
+
'• REFERRING TO AN EARLIER IMAGE: if the user points at an image from earlier in the chat ("image number 2", "the first image", "the one you just made"), call generate_image with action="list_refs" FIRST and use the "ref" of the item they mean — never count images from your own memory of the conversation. Not remembering any images is NOT evidence there are none: your context may have been reset or compacted while the chat history still has them, so NEVER reply "no images attached / please attach" to such a request before list_refs has returned an empty catalog. If it is ambiguous, or the index they gave does not exist in the catalog, ask them which image instead of guessing.',
|
|
18
19
|
'• NEVER tell the user to install an app or set up an MCP server for images.',
|
|
19
20
|
].join('\n');
|
|
20
21
|
|
package/mcp/server.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { SkillsModule } from './tools/skills/module';
|
|
|
20
20
|
import { AgentModule } from './tools/agent/module';
|
|
21
21
|
import { BrowserModule } from './tools/browser/module';
|
|
22
22
|
import { ImageModule } from './tools/image/module';
|
|
23
|
+
import { ShareImageModule } from './tools/share-image/module';
|
|
23
24
|
import { AppsModule } from './tools/apps/module';
|
|
24
25
|
import { ApiModule } from './tools/api/module';
|
|
25
26
|
import { buildChannelInstructions } from './instructions';
|
|
@@ -42,6 +43,7 @@ const modules: AnyModule[] = [
|
|
|
42
43
|
new AgentModule(),
|
|
43
44
|
new BrowserModule(),
|
|
44
45
|
new ImageModule(),
|
|
46
|
+
new ShareImageModule(),
|
|
45
47
|
new AppsModule(),
|
|
46
48
|
new ApiModule(),
|
|
47
49
|
];
|
|
@@ -16,6 +16,13 @@ export const TELEGRAM_USER_ID_REGEX = /^\d{6,15}$/;
|
|
|
16
16
|
export const DISCORD_USER_ID_REGEX = /^\d{17,19}$/;
|
|
17
17
|
|
|
18
18
|
const FILENAME_SAFE_REGEX = /^[A-Z][A-Z0-9_-]*\.md$/i;
|
|
19
|
+
|
|
20
|
+
// A whole line that is *only* a Markdown code fence, after trimming (which also
|
|
21
|
+
// drops a trailing \r on CRLF input and surrounding spaces). FENCE_LINE_REGEX
|
|
22
|
+
// matches both an opener (```markdown, ```ts) and a bare fence (```);
|
|
23
|
+
// FENCE_CLOSE_REGEX matches only the bare closing fence.
|
|
24
|
+
const FENCE_LINE_REGEX = /^```[\w-]*$/;
|
|
25
|
+
const FENCE_CLOSE_REGEX = /^```$/;
|
|
19
26
|
const STANDARD_STUB_FILES = ['HEARTBEAT.md', 'MEMORY.md', 'SOUL.md', 'USER.md'];
|
|
20
27
|
|
|
21
28
|
// ---------------------------------------------------------------------------
|
|
@@ -115,12 +122,47 @@ export async function verifyDiscordToken(token: string): Promise<{ ok: boolean;
|
|
|
115
122
|
|
|
116
123
|
function firstNonEmptyLine(text: string): string {
|
|
117
124
|
for (const line of text.split('\n')) {
|
|
125
|
+
// Skip pure code-fence lines (```markdown, ```ts, ``` …) so a stray wrapper
|
|
126
|
+
// fence never leaks into a derived value such as the agent description.
|
|
127
|
+
if (FENCE_LINE_REGEX.test(line.trim())) continue;
|
|
118
128
|
const trimmed = line.replace(/^#+\s*/, '').trim();
|
|
119
129
|
if (trimmed) return trimmed;
|
|
120
130
|
}
|
|
121
131
|
return text.trim().slice(0, 80);
|
|
122
132
|
}
|
|
123
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Remove a single outer Markdown code-fence wrapper that a generating LLM may
|
|
136
|
+
* have wrapped whole-document output in (e.g. ```markdown … ```). Only strips
|
|
137
|
+
* when BOTH the first non-empty line is a fence opener (```lang or bare ```) AND
|
|
138
|
+
* the last non-empty line is a bare closing fence (```), so partial/unbalanced
|
|
139
|
+
* fences are left untouched. Inner/legitimate fenced blocks are preserved;
|
|
140
|
+
* unfenced content is returned unchanged.
|
|
141
|
+
*
|
|
142
|
+
* Known limitation (F2): a *legitimate* document whose first non-empty line
|
|
143
|
+
* opens a fenced block and whose last non-empty line closes a different one —
|
|
144
|
+
* two independent blocks with prose stripped away in between — is
|
|
145
|
+
* indistinguishable at the line level from a single outer wrapper, so its outer
|
|
146
|
+
* fences are peeled. This is accepted: real AGENTS.md/SOUL.md content opens with
|
|
147
|
+
* a heading, not a code fence, so the false-positive shape does not occur in
|
|
148
|
+
* practice. See test "AMH-fence-g" which locks this behavior.
|
|
149
|
+
*/
|
|
150
|
+
function stripOuterCodeFence(text: string): string {
|
|
151
|
+
const lines = text.split('\n');
|
|
152
|
+
|
|
153
|
+
let first = 0;
|
|
154
|
+
while (first < lines.length && lines[first].trim() === '') first++;
|
|
155
|
+
let last = lines.length - 1;
|
|
156
|
+
while (last >= 0 && lines[last].trim() === '') last--;
|
|
157
|
+
if (first >= last) return text; // need at least two non-empty lines
|
|
158
|
+
|
|
159
|
+
const isOpener = FENCE_LINE_REGEX.test(lines[first].trim());
|
|
160
|
+
const isCloser = FENCE_CLOSE_REGEX.test(lines[last].trim());
|
|
161
|
+
if (!isOpener || !isCloser) return text; // not a clean wrapper — leave as-is
|
|
162
|
+
|
|
163
|
+
return lines.slice(first + 1, last).join('\n').trim();
|
|
164
|
+
}
|
|
165
|
+
|
|
124
166
|
function envVarName(agentId: string, channel: 'telegram' | 'discord'): string {
|
|
125
167
|
const base = agentId.toUpperCase().replace(/-/g, '_');
|
|
126
168
|
return channel === 'telegram' ? `${base}_BOT_TOKEN` : `${base}_DISCORD_BOT_TOKEN`;
|
|
@@ -215,16 +257,25 @@ export async function createAgent(args: CreateAgentArgs): Promise<string> {
|
|
|
215
257
|
fs.mkdirSync(wsDir, { recursive: true });
|
|
216
258
|
|
|
217
259
|
// 8. Write workspace files
|
|
260
|
+
// AI-generated *_md content is stored verbatim, so strip any outer code-fence
|
|
261
|
+
// wrapper the generating model may have added before it reaches disk AND the
|
|
262
|
+
// firstNonEmptyLine(agentsMdContent) description derivation below.
|
|
263
|
+
// Guard with a typeof check (not `!== undefined`): args is external MCP input
|
|
264
|
+
// cast from `unknown`, so a caller can send `agents_md: null`. A bare null
|
|
265
|
+
// would reach stripOuterCodeFence and throw on `.split`; the typeof gate falls
|
|
266
|
+
// back to the default stub for both null and undefined, matching the prior
|
|
267
|
+
// `??` behavior while still stripping a real string wrapper.
|
|
218
268
|
const agentsMdContent =
|
|
219
|
-
args.agents_md
|
|
220
|
-
|
|
269
|
+
typeof args.agents_md === 'string'
|
|
270
|
+
? stripOuterCodeFence(args.agents_md)
|
|
271
|
+
: `# Agent: ${agentId.charAt(0).toUpperCase() + agentId.slice(1)}\n\n${description}`;
|
|
221
272
|
fs.writeFileSync(path.join(wsDir, 'AGENTS.md'), agentsMdContent, 'utf8');
|
|
222
273
|
|
|
223
274
|
if (args.soul_md) {
|
|
224
|
-
fs.writeFileSync(path.join(wsDir, 'SOUL.md'), args.soul_md, 'utf8');
|
|
275
|
+
fs.writeFileSync(path.join(wsDir, 'SOUL.md'), stripOuterCodeFence(args.soul_md), 'utf8');
|
|
225
276
|
}
|
|
226
277
|
if (args.user_md) {
|
|
227
|
-
fs.writeFileSync(path.join(wsDir, 'USER.md'), args.user_md, 'utf8');
|
|
278
|
+
fs.writeFileSync(path.join(wsDir, 'USER.md'), stripOuterCodeFence(args.user_md), 'utf8');
|
|
228
279
|
}
|
|
229
280
|
|
|
230
281
|
// Write stub files for any standard files not yet present
|