@tleblancureta/proto 0.1.2 → 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/core-web/src/ProtoApp.tsx +30 -20
- package/core-web/src/components/admin/AdminPanel.tsx +285 -0
- package/core-web/src/components/admin/SystemTab.tsx +167 -0
- package/core-web/src/components/shell/Toolbar.tsx +11 -1
- package/core-web/src/index.ts +1 -0
- package/dist/core-gateway/auth.d.ts +7 -0
- package/dist/core-gateway/auth.d.ts.map +1 -0
- package/dist/core-gateway/auth.js +12 -0
- package/dist/core-gateway/auth.js.map +1 -0
- package/dist/core-gateway/claude-runner.d.ts +10 -0
- package/dist/core-gateway/claude-runner.d.ts.map +1 -0
- package/dist/core-gateway/claude-runner.js +206 -0
- package/dist/core-gateway/claude-runner.js.map +1 -0
- package/dist/core-gateway/config.d.ts +33 -0
- package/dist/core-gateway/config.d.ts.map +1 -0
- package/dist/core-gateway/config.js +84 -0
- package/dist/core-gateway/config.js.map +1 -0
- package/dist/core-gateway/email-sender.d.ts +36 -0
- package/dist/core-gateway/email-sender.d.ts.map +1 -0
- package/dist/core-gateway/email-sender.js +121 -0
- package/dist/core-gateway/email-sender.js.map +1 -0
- package/dist/core-gateway/mail-ingester.d.ts +3 -0
- package/dist/core-gateway/mail-ingester.d.ts.map +1 -0
- package/dist/core-gateway/mail-ingester.js +294 -0
- package/dist/core-gateway/mail-ingester.js.map +1 -0
- package/dist/core-gateway/mail-router.d.ts +18 -0
- package/dist/core-gateway/mail-router.d.ts.map +1 -0
- package/dist/core-gateway/mail-router.js +37 -0
- package/dist/core-gateway/mail-router.js.map +1 -0
- package/dist/core-gateway/mail-threads.d.ts +78 -0
- package/dist/core-gateway/mail-threads.d.ts.map +1 -0
- package/dist/core-gateway/mail-threads.js +100 -0
- package/dist/core-gateway/mail-threads.js.map +1 -0
- package/dist/core-gateway/rate-limiter.d.ts +9 -0
- package/dist/core-gateway/rate-limiter.d.ts.map +1 -0
- package/dist/core-gateway/rate-limiter.js +13 -0
- package/dist/core-gateway/rate-limiter.js.map +1 -0
- package/dist/core-gateway/registry.d.ts +14 -0
- package/dist/core-gateway/registry.d.ts.map +1 -0
- package/dist/core-gateway/registry.js +83 -0
- package/dist/core-gateway/registry.js.map +1 -0
- package/dist/core-gateway/routes/admin.d.ts +3 -0
- package/dist/core-gateway/routes/admin.d.ts.map +1 -0
- package/dist/core-gateway/routes/admin.js +91 -0
- package/dist/core-gateway/routes/admin.js.map +1 -0
- package/dist/core-gateway/routes/chat.d.ts +9 -0
- package/dist/core-gateway/routes/chat.d.ts.map +1 -0
- package/dist/core-gateway/routes/chat.js +149 -0
- package/dist/core-gateway/routes/chat.js.map +1 -0
- package/dist/core-gateway/routes/cron.d.ts +13 -0
- package/dist/core-gateway/routes/cron.d.ts.map +1 -0
- package/dist/core-gateway/routes/cron.js +79 -0
- package/dist/core-gateway/routes/cron.js.map +1 -0
- package/dist/core-gateway/routes/gmail.d.ts +8 -0
- package/dist/core-gateway/routes/gmail.d.ts.map +1 -0
- package/dist/core-gateway/routes/gmail.js +57 -0
- package/dist/core-gateway/routes/gmail.js.map +1 -0
- package/dist/core-gateway/routes/health.d.ts +3 -0
- package/dist/core-gateway/routes/health.d.ts.map +1 -0
- package/dist/core-gateway/routes/health.js +7 -0
- package/dist/core-gateway/routes/health.js.map +1 -0
- package/dist/core-gateway/routes/upload.d.ts +7 -0
- package/dist/core-gateway/routes/upload.d.ts.map +1 -0
- package/dist/core-gateway/routes/upload.js +31 -0
- package/dist/core-gateway/routes/upload.js.map +1 -0
- package/dist/core-gateway/scheduler.d.ts +68 -0
- package/dist/core-gateway/scheduler.d.ts.map +1 -0
- package/dist/core-gateway/scheduler.js +252 -0
- package/dist/core-gateway/scheduler.js.map +1 -0
- package/dist/core-gateway/server.d.ts +17 -0
- package/dist/core-gateway/server.d.ts.map +1 -0
- package/dist/core-gateway/server.js +45 -0
- package/dist/core-gateway/server.js.map +1 -0
- package/dist/core-gateway/session.d.ts +18 -0
- package/dist/core-gateway/session.d.ts.map +1 -0
- package/dist/core-gateway/session.js +178 -0
- package/dist/core-gateway/session.js.map +1 -0
- package/dist/core-gateway/skills.d.ts +4 -0
- package/dist/core-gateway/skills.d.ts.map +1 -0
- package/dist/core-gateway/skills.js +100 -0
- package/dist/core-gateway/skills.js.map +1 -0
- package/dist/core-gateway/supabase.d.ts +3 -0
- package/dist/core-gateway/supabase.d.ts.map +1 -0
- package/dist/core-gateway/supabase.js +18 -0
- package/dist/core-gateway/supabase.js.map +1 -0
- package/dist/core-web/src/ProtoApp.d.ts.map +1 -1
- package/dist/core-web/src/ProtoApp.js +5 -3
- package/dist/core-web/src/ProtoApp.js.map +1 -1
- package/dist/core-web/src/components/admin/AdminPanel.d.ts +7 -0
- package/dist/core-web/src/components/admin/AdminPanel.d.ts.map +1 -0
- package/dist/core-web/src/components/admin/AdminPanel.js +112 -0
- package/dist/core-web/src/components/admin/AdminPanel.js.map +1 -0
- package/dist/core-web/src/components/admin/SystemTab.d.ts +2 -0
- package/dist/core-web/src/components/admin/SystemTab.d.ts.map +1 -0
- package/dist/core-web/src/components/admin/SystemTab.js +25 -0
- package/dist/core-web/src/components/admin/SystemTab.js.map +1 -0
- package/dist/core-web/src/components/shell/Toolbar.d.ts.map +1 -1
- package/dist/core-web/src/components/shell/Toolbar.js +4 -2
- package/dist/core-web/src/components/shell/Toolbar.js.map +1 -1
- package/dist/core-web/src/index.d.ts +1 -0
- package/dist/core-web/src/index.d.ts.map +1 -1
- package/dist/core-web/src/index.js +1 -0
- package/dist/core-web/src/index.js.map +1 -1
- package/dist/gateway.d.ts +3 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +3 -0
- package/dist/gateway.js.map +1 -0
- package/package.json +22 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads skill + agent definitions from the filesystem.
|
|
3
|
+
* Skills live in skills/<name>/SKILL.md, agents in agents/<name>.md.
|
|
4
|
+
* Parsed once at import time and cached in module scope.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
|
|
7
|
+
import { join, basename } from 'node:path';
|
|
8
|
+
import yaml from 'yaml';
|
|
9
|
+
import { config, resolveAppPath } from './config.js';
|
|
10
|
+
// ── Skill loader ──
|
|
11
|
+
function parseSkillFrontmatter(filePath) {
|
|
12
|
+
try {
|
|
13
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
14
|
+
if (!raw.startsWith('---'))
|
|
15
|
+
return null;
|
|
16
|
+
const parts = raw.split('---');
|
|
17
|
+
if (parts.length < 3)
|
|
18
|
+
return null;
|
|
19
|
+
const meta = yaml.parse(parts[1]) || {};
|
|
20
|
+
const name = meta.name;
|
|
21
|
+
if (!name)
|
|
22
|
+
return null;
|
|
23
|
+
return {
|
|
24
|
+
name,
|
|
25
|
+
description: meta.description ?? null,
|
|
26
|
+
mcp_tools: meta['mcp-tools'] ?? [],
|
|
27
|
+
depends: Array.isArray(meta.depends) ? meta.depends : [],
|
|
28
|
+
filePath,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
console.warn(`[registry] Failed to parse ${filePath}:`, err);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function discoverSkills() {
|
|
37
|
+
const dir = resolveAppPath(config.skills_dir);
|
|
38
|
+
if (!existsSync(dir))
|
|
39
|
+
return [];
|
|
40
|
+
const skills = [];
|
|
41
|
+
for (const entry of readdirSync(dir)) {
|
|
42
|
+
const entryPath = join(dir, entry);
|
|
43
|
+
if (!statSync(entryPath).isDirectory())
|
|
44
|
+
continue;
|
|
45
|
+
const skillFile = join(entryPath, 'SKILL.md');
|
|
46
|
+
if (!existsSync(skillFile))
|
|
47
|
+
continue;
|
|
48
|
+
const skill = parseSkillFrontmatter(skillFile);
|
|
49
|
+
if (skill)
|
|
50
|
+
skills.push(skill);
|
|
51
|
+
}
|
|
52
|
+
return skills;
|
|
53
|
+
}
|
|
54
|
+
// ── Agent loader ──
|
|
55
|
+
function discoverAgents() {
|
|
56
|
+
const dir = resolveAppPath(config.agents_dir);
|
|
57
|
+
if (!existsSync(dir))
|
|
58
|
+
return [];
|
|
59
|
+
const agents = [];
|
|
60
|
+
for (const entry of readdirSync(dir)) {
|
|
61
|
+
if (!entry.endsWith('.md'))
|
|
62
|
+
continue;
|
|
63
|
+
agents.push({
|
|
64
|
+
name: basename(entry, '.md'),
|
|
65
|
+
filePath: join(dir, entry),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return agents;
|
|
69
|
+
}
|
|
70
|
+
// ── Cached at module level (read once at startup) ──
|
|
71
|
+
let _skills = null;
|
|
72
|
+
let _agents = null;
|
|
73
|
+
export function loadSkills() {
|
|
74
|
+
if (!_skills)
|
|
75
|
+
_skills = discoverSkills();
|
|
76
|
+
return _skills;
|
|
77
|
+
}
|
|
78
|
+
export function loadAgents() {
|
|
79
|
+
if (!_agents)
|
|
80
|
+
_agents = discoverAgents();
|
|
81
|
+
return _agents;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../core-gateway/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../core-gateway/routes/admin.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAIhC,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,IAAI,QAe5C"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin metadata endpoint — exposes registered tools, entities, workflows,
|
|
3
|
+
* and skills for the Proto admin panel.
|
|
4
|
+
*
|
|
5
|
+
* Reads the app directory (PROTO_APP_ROOT) to extract metadata without
|
|
6
|
+
* executing tool handlers.
|
|
7
|
+
*/
|
|
8
|
+
import { readdirSync, existsSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { pathToFileURL } from 'node:url';
|
|
11
|
+
import { resolveAppPath } from '../config.js';
|
|
12
|
+
import { loadSkills } from '../registry.js';
|
|
13
|
+
export function registerAdminRoutes(app) {
|
|
14
|
+
app.get('/admin/meta', async (c) => {
|
|
15
|
+
const [tools, entities, workflows] = await Promise.all([
|
|
16
|
+
discoverToolMeta(),
|
|
17
|
+
discoverEntityMeta(),
|
|
18
|
+
discoverWorkflowMeta(),
|
|
19
|
+
]);
|
|
20
|
+
const skills = loadSkills().map(s => ({
|
|
21
|
+
name: s.name,
|
|
22
|
+
description: s.description,
|
|
23
|
+
mcp_tools: s.mcp_tools,
|
|
24
|
+
}));
|
|
25
|
+
return c.json({ tools, entities, workflows, skills });
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async function discoverToolMeta() {
|
|
29
|
+
const dir = resolveAppPath('app/tools');
|
|
30
|
+
if (!existsSync(dir))
|
|
31
|
+
return [];
|
|
32
|
+
const files = readdirSync(dir).filter(f => (f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js');
|
|
33
|
+
const tools = [];
|
|
34
|
+
for (const file of files) {
|
|
35
|
+
try {
|
|
36
|
+
const mod = await import(pathToFileURL(join(dir, file)).href);
|
|
37
|
+
const defs = mod.default;
|
|
38
|
+
if (!Array.isArray(defs))
|
|
39
|
+
continue;
|
|
40
|
+
for (const t of defs) {
|
|
41
|
+
if (t && typeof t.name === 'string') {
|
|
42
|
+
tools.push({ name: t.name, description: t.description || '' });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Skip files that fail to import
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return tools;
|
|
51
|
+
}
|
|
52
|
+
async function discoverEntityMeta() {
|
|
53
|
+
const dir = resolveAppPath('app/entities');
|
|
54
|
+
if (!existsSync(dir))
|
|
55
|
+
return [];
|
|
56
|
+
const files = readdirSync(dir).filter(f => (f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js');
|
|
57
|
+
const entities = [];
|
|
58
|
+
for (const file of files) {
|
|
59
|
+
try {
|
|
60
|
+
const mod = await import(pathToFileURL(join(dir, file)).href);
|
|
61
|
+
const def = mod.default;
|
|
62
|
+
if (def && typeof def.name === 'string') {
|
|
63
|
+
entities.push({ name: def.name, table: def.table || '' });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch { }
|
|
67
|
+
}
|
|
68
|
+
return entities;
|
|
69
|
+
}
|
|
70
|
+
async function discoverWorkflowMeta() {
|
|
71
|
+
const dir = resolveAppPath('app/workflows');
|
|
72
|
+
if (!existsSync(dir))
|
|
73
|
+
return [];
|
|
74
|
+
const files = readdirSync(dir).filter(f => (f.endsWith('.ts') || f.endsWith('.js')) && !f.startsWith('_'));
|
|
75
|
+
const workflows = [];
|
|
76
|
+
for (const file of files) {
|
|
77
|
+
try {
|
|
78
|
+
const mod = await import(pathToFileURL(join(dir, file)).href);
|
|
79
|
+
const def = mod.default;
|
|
80
|
+
if (def && typeof def.name === 'string') {
|
|
81
|
+
const phases = Array.isArray(def.phases)
|
|
82
|
+
? def.phases.map((p) => typeof p === 'string' ? p : p.name || '').filter(Boolean)
|
|
83
|
+
: [];
|
|
84
|
+
workflows.push({ name: def.name, entityTable: def.entityTable || '', phases });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch { }
|
|
88
|
+
}
|
|
89
|
+
return workflows;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../../../core-gateway/routes/admin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
type UpgradeWebSocket = (handler: (c: any) => any) => any;
|
|
3
|
+
/**
|
|
4
|
+
* Chat routes: WebSocket streaming (primary), REST /chat + /chat/stream
|
|
5
|
+
* (legacy), and /reset for Claude CLI session invalidation.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerChatRoutes(app: Hono, upgradeWebSocket: UpgradeWebSocket): void;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=chat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../core-gateway/routes/chat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAQhC,KAAK,gBAAgB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,GAAG,KAAK,GAAG,CAAA;AAEzD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,EAAE,gBAAgB,EAAE,gBAAgB,QAmG/E"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { streamSSE } from 'hono/streaming';
|
|
2
|
+
import { chatRequestSchema } from '@tleblancureta/proto/shared';
|
|
3
|
+
import { verifySecret } from '../auth.js';
|
|
4
|
+
import { runClaude, streamClaude } from '../claude-runner.js';
|
|
5
|
+
import { checkRateLimit } from '../rate-limiter.js';
|
|
6
|
+
import { INTERNAL_SECRET } from '../config.js';
|
|
7
|
+
/**
|
|
8
|
+
* Chat routes: WebSocket streaming (primary), REST /chat + /chat/stream
|
|
9
|
+
* (legacy), and /reset for Claude CLI session invalidation.
|
|
10
|
+
*/
|
|
11
|
+
export function registerChatRoutes(app, upgradeWebSocket) {
|
|
12
|
+
// --- WebSocket ---
|
|
13
|
+
app.get('/ws', upgradeWebSocket(() => {
|
|
14
|
+
let authenticated = false;
|
|
15
|
+
return {
|
|
16
|
+
onMessage(event, ws) {
|
|
17
|
+
try {
|
|
18
|
+
const data = JSON.parse(event.data.toString());
|
|
19
|
+
// First message must be auth
|
|
20
|
+
if (!authenticated) {
|
|
21
|
+
if (data.type === 'auth' && data.secret === INTERNAL_SECRET) {
|
|
22
|
+
authenticated = true;
|
|
23
|
+
ws.send(JSON.stringify({ type: 'auth', status: 'ok' }));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
ws.send(JSON.stringify({ type: 'error', message: 'Unauthorized' }));
|
|
27
|
+
ws.close(4001, 'Unauthorized');
|
|
28
|
+
}
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (data.type === 'chat') {
|
|
32
|
+
handleWsChat(data, ws);
|
|
33
|
+
}
|
|
34
|
+
else if (data.type === 'ping') {
|
|
35
|
+
ws.send(JSON.stringify({ type: 'pong' }));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
ws.send(JSON.stringify({ type: 'error', message: err.message }));
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
onClose() { },
|
|
43
|
+
onError() { },
|
|
44
|
+
};
|
|
45
|
+
}));
|
|
46
|
+
// --- REST /reset ---
|
|
47
|
+
app.post('/reset', verifySecret, async (c) => {
|
|
48
|
+
const body = await c.req.json().catch(() => ({}));
|
|
49
|
+
const companyId = body?.company_id;
|
|
50
|
+
const sessionKey = body?.session_key;
|
|
51
|
+
if (!companyId)
|
|
52
|
+
return c.json({ error: 'company_id required' }, 400);
|
|
53
|
+
try {
|
|
54
|
+
const { join, resolve } = await import('node:path');
|
|
55
|
+
const { existsSync, rmSync } = await import('node:fs');
|
|
56
|
+
const dataRoot = process.env.DATA_DIR || '/data';
|
|
57
|
+
const slug = sessionKey ? `${companyId}/${sessionKey}` : companyId;
|
|
58
|
+
const sessionDir = resolve(dataRoot, 'sessions', slug);
|
|
59
|
+
const file = join(sessionDir, '.claude-session-id');
|
|
60
|
+
if (existsSync(file))
|
|
61
|
+
rmSync(file, { force: true });
|
|
62
|
+
return c.json({ ok: true });
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
return c.json({ error: err.message || 'reset failed' }, 500);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
// --- REST /chat ---
|
|
69
|
+
app.post('/chat', async (c) => {
|
|
70
|
+
const body = await c.req.json();
|
|
71
|
+
const parsed = chatRequestSchema.safeParse(body);
|
|
72
|
+
if (!parsed.success)
|
|
73
|
+
return c.json({ error: parsed.error.format() }, 400);
|
|
74
|
+
const { allowed, retryAfterMs } = checkRateLimit(parsed.data.company_id);
|
|
75
|
+
if (!allowed) {
|
|
76
|
+
const retryMin = Math.ceil((retryAfterMs || 0) / 60000);
|
|
77
|
+
return c.json({ error: `Rate limit exceeded. Try again in ${retryMin} minutes.` }, 429);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const result = await runClaude(parsed.data);
|
|
81
|
+
return c.json(result);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
if (err.message?.includes('timed out'))
|
|
85
|
+
return c.json({ error: 'Claude Code session timed out' }, 504);
|
|
86
|
+
return c.json({ error: err.message || 'Claude Code error' }, 502);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
// --- REST /chat/stream (SSE) ---
|
|
90
|
+
app.post('/chat/stream', async (c) => {
|
|
91
|
+
const body = await c.req.json();
|
|
92
|
+
const parsed = chatRequestSchema.safeParse(body);
|
|
93
|
+
if (!parsed.success)
|
|
94
|
+
return c.json({ error: parsed.error.format() }, 400);
|
|
95
|
+
const { allowed, retryAfterMs } = checkRateLimit(parsed.data.company_id);
|
|
96
|
+
if (!allowed) {
|
|
97
|
+
const retryMin = Math.ceil((retryAfterMs || 0) / 60000);
|
|
98
|
+
return c.json({ error: `Rate limit exceeded. Try again in ${retryMin} minutes.` }, 429);
|
|
99
|
+
}
|
|
100
|
+
return streamSSE(c, async (stream) => {
|
|
101
|
+
try {
|
|
102
|
+
for await (const event of streamClaude(parsed.data)) {
|
|
103
|
+
await stream.writeSSE({ data: JSON.stringify(event) });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
await stream.writeSSE({ data: JSON.stringify({ type: 'error', message: err.message }) });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function safeSend(ws, data) {
|
|
113
|
+
try {
|
|
114
|
+
ws.send(data);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return false; // socket closed
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async function handleWsChat(data, ws) {
|
|
122
|
+
const parsed = chatRequestSchema.safeParse(data);
|
|
123
|
+
if (!parsed.success) {
|
|
124
|
+
safeSend(ws, JSON.stringify({ type: 'error', message: 'Invalid request' }));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const { allowed, retryAfterMs } = checkRateLimit(parsed.data.company_id);
|
|
128
|
+
if (!allowed) {
|
|
129
|
+
const retryMin = Math.ceil((retryAfterMs || 0) / 60000);
|
|
130
|
+
safeSend(ws, JSON.stringify({ type: 'error', message: `Rate limit. Retry in ${retryMin} min` }));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
for await (const event of streamClaude(parsed.data)) {
|
|
135
|
+
if (!safeSend(ws, JSON.stringify(event))) {
|
|
136
|
+
// Client disconnected — break out so the generator can clean up
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
// Push shell refresh on tool_result and result
|
|
140
|
+
if (event.type === 'tool_result' || event.type === 'result') {
|
|
141
|
+
safeSend(ws, JSON.stringify({ type: 'shell_refresh' }));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
safeSend(ws, JSON.stringify({ type: 'error', message: err.message }));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../core-gateway/routes/chat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* Cron control surface. Three responsibilities:
|
|
4
|
+
* /cron/tick — internal; called by pg_cron every minute
|
|
5
|
+
* /cron/trigger — manual; run a task right now ("run now" button)
|
|
6
|
+
* /cron/list — inspect tasks + next_run_at (debug / admin UI)
|
|
7
|
+
*
|
|
8
|
+
* Task CRUD is owned by the MCP tools (agent-facing) + direct DB access
|
|
9
|
+
* from the web frontend via supabase-js with RLS. The gateway only owns
|
|
10
|
+
* the dispatch layer.
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerCronRoutes(app: Hono): void;
|
|
13
|
+
//# sourceMappingURL=cron.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../../../core-gateway/routes/cron.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAMhC;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,QA+D3C"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { verifySecret } from '../auth.js';
|
|
2
|
+
import { getSupabase } from '../supabase.js';
|
|
3
|
+
import { tick, dispatchTask, recalcNextRun, computeNextRun } from '../scheduler.js';
|
|
4
|
+
import { isValidCronExpr } from '@tleblancureta/proto/shared';
|
|
5
|
+
/**
|
|
6
|
+
* Cron control surface. Three responsibilities:
|
|
7
|
+
* /cron/tick — internal; called by pg_cron every minute
|
|
8
|
+
* /cron/trigger — manual; run a task right now ("run now" button)
|
|
9
|
+
* /cron/list — inspect tasks + next_run_at (debug / admin UI)
|
|
10
|
+
*
|
|
11
|
+
* Task CRUD is owned by the MCP tools (agent-facing) + direct DB access
|
|
12
|
+
* from the web frontend via supabase-js with RLS. The gateway only owns
|
|
13
|
+
* the dispatch layer.
|
|
14
|
+
*/
|
|
15
|
+
export function registerCronRoutes(app) {
|
|
16
|
+
// --- pg_cron webhook ---
|
|
17
|
+
app.post('/cron/tick', verifySecret, async (c) => {
|
|
18
|
+
const result = await tick();
|
|
19
|
+
return c.json({ ok: true, ...result });
|
|
20
|
+
});
|
|
21
|
+
// --- Manual trigger ---
|
|
22
|
+
app.post('/cron/trigger', verifySecret, async (c) => {
|
|
23
|
+
const body = await c.req.json().catch(() => ({}));
|
|
24
|
+
const taskId = body?.task_id;
|
|
25
|
+
const triggeredBy = body?.triggered_by || 'manual';
|
|
26
|
+
if (!taskId)
|
|
27
|
+
return c.json({ error: 'task_id required' }, 400);
|
|
28
|
+
const db = getSupabase();
|
|
29
|
+
const { data, error } = await db
|
|
30
|
+
.from('scheduled_tasks')
|
|
31
|
+
.select('*')
|
|
32
|
+
.eq('id', taskId)
|
|
33
|
+
.single();
|
|
34
|
+
if (error || !data)
|
|
35
|
+
return c.json({ error: 'task not found' }, 404);
|
|
36
|
+
// Dispatch in background — don't block the HTTP response
|
|
37
|
+
dispatchTask(data, { trigger: 'manual', triggeredBy }).catch(err => console.error('[cron] manual dispatch error', err));
|
|
38
|
+
return c.json({ ok: true, task_id: taskId, trigger: 'manual' });
|
|
39
|
+
});
|
|
40
|
+
// --- List tasks + next runs (debug / admin) ---
|
|
41
|
+
app.get('/cron/list', verifySecret, async (c) => {
|
|
42
|
+
const companyId = c.req.query('company_id');
|
|
43
|
+
const db = getSupabase();
|
|
44
|
+
let q = db
|
|
45
|
+
.from('scheduled_tasks')
|
|
46
|
+
.select('id, company_id, name, cron_expr, timezone, enabled, next_run_at, last_run_at, last_run_status')
|
|
47
|
+
.order('next_run_at', { ascending: true, nullsFirst: false });
|
|
48
|
+
if (companyId)
|
|
49
|
+
q = q.eq('company_id', companyId);
|
|
50
|
+
const { data, error } = await q;
|
|
51
|
+
if (error)
|
|
52
|
+
return c.json({ error: error.message }, 500);
|
|
53
|
+
return c.json({ tasks: data || [] });
|
|
54
|
+
});
|
|
55
|
+
// --- Recompute next_run for a task (called after CRUD in MCP tools) ---
|
|
56
|
+
app.post('/cron/recalc', verifySecret, async (c) => {
|
|
57
|
+
const body = await c.req.json().catch(() => ({}));
|
|
58
|
+
const taskId = body?.task_id;
|
|
59
|
+
if (!taskId)
|
|
60
|
+
return c.json({ error: 'task_id required' }, 400);
|
|
61
|
+
const next = await recalcNextRun(taskId);
|
|
62
|
+
return c.json({ ok: true, next_run_at: next?.toISOString() ?? null });
|
|
63
|
+
});
|
|
64
|
+
// --- Validate a cron expression (used by frontend form) ---
|
|
65
|
+
app.post('/cron/validate', verifySecret, async (c) => {
|
|
66
|
+
const body = await c.req.json().catch(() => ({}));
|
|
67
|
+
const expr = body?.cron_expr;
|
|
68
|
+
const tz = body?.timezone || 'America/Santiago';
|
|
69
|
+
if (!expr)
|
|
70
|
+
return c.json({ error: 'cron_expr required' }, 400);
|
|
71
|
+
if (!isValidCronExpr(expr))
|
|
72
|
+
return c.json({ valid: false, error: 'invalid format' });
|
|
73
|
+
const next = computeNextRun(expr, tz);
|
|
74
|
+
if (!next)
|
|
75
|
+
return c.json({ valid: false, error: 'unparseable' });
|
|
76
|
+
return c.json({ valid: true, next_run_at: next.toISOString() });
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=cron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.js","sourceRoot":"","sources":["../../../core-gateway/routes/cron.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* Gmail OAuth flow:
|
|
4
|
+
* - GET /gmail/auth → returns the Google consent URL (frontend opens it).
|
|
5
|
+
* - POST /gmail/callback → exchanges code for tokens, stores in Supabase.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerGmailRoutes(app: Hono): void;
|
|
8
|
+
//# sourceMappingURL=gmail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../../core-gateway/routes/gmail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,IAAI,QA2D5C"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gmail OAuth flow:
|
|
3
|
+
* - GET /gmail/auth → returns the Google consent URL (frontend opens it).
|
|
4
|
+
* - POST /gmail/callback → exchanges code for tokens, stores in Supabase.
|
|
5
|
+
*/
|
|
6
|
+
export function registerGmailRoutes(app) {
|
|
7
|
+
app.get('/gmail/auth', async (c) => {
|
|
8
|
+
const { google } = await import('googleapis');
|
|
9
|
+
const clientId = process.env.GMAIL_CLIENT_ID;
|
|
10
|
+
const clientSecret = process.env.GMAIL_CLIENT_SECRET;
|
|
11
|
+
const redirectUri = process.env.GMAIL_REDIRECT_URI || `${c.req.header('origin') || 'http://localhost:3001'}/gmail/callback`;
|
|
12
|
+
if (!clientId || !clientSecret)
|
|
13
|
+
return c.json({ error: 'Gmail not configured' }, 500);
|
|
14
|
+
const oauth2 = new google.auth.OAuth2(clientId, clientSecret, redirectUri);
|
|
15
|
+
const url = oauth2.generateAuthUrl({
|
|
16
|
+
access_type: 'offline',
|
|
17
|
+
prompt: 'consent',
|
|
18
|
+
scope: [
|
|
19
|
+
'https://www.googleapis.com/auth/gmail.readonly',
|
|
20
|
+
'https://www.googleapis.com/auth/gmail.send',
|
|
21
|
+
],
|
|
22
|
+
state: c.req.query('user_id') || '',
|
|
23
|
+
});
|
|
24
|
+
return c.json({ url });
|
|
25
|
+
});
|
|
26
|
+
app.post('/gmail/callback', async (c) => {
|
|
27
|
+
const { google } = await import('googleapis');
|
|
28
|
+
const { code, user_id } = await c.req.json();
|
|
29
|
+
const clientId = process.env.GMAIL_CLIENT_ID;
|
|
30
|
+
const clientSecret = process.env.GMAIL_CLIENT_SECRET;
|
|
31
|
+
const redirectUri = process.env.GMAIL_REDIRECT_URI || 'http://localhost:3001/gmail/callback';
|
|
32
|
+
if (!clientId || !clientSecret)
|
|
33
|
+
return c.json({ error: 'Gmail not configured' }, 500);
|
|
34
|
+
const oauth2 = new google.auth.OAuth2(clientId, clientSecret, redirectUri);
|
|
35
|
+
try {
|
|
36
|
+
const { tokens } = await oauth2.getToken(code);
|
|
37
|
+
oauth2.setCredentials(tokens);
|
|
38
|
+
const gmail = google.gmail({ version: 'v1', auth: oauth2 });
|
|
39
|
+
const profile = await gmail.users.getProfile({ userId: 'me' });
|
|
40
|
+
const { createClient } = await import('@supabase/supabase-js');
|
|
41
|
+
const db = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE_KEY);
|
|
42
|
+
await db.from('gmail_tokens').upsert({
|
|
43
|
+
user_id,
|
|
44
|
+
access_token: tokens.access_token,
|
|
45
|
+
refresh_token: tokens.refresh_token,
|
|
46
|
+
expiry_date: tokens.expiry_date,
|
|
47
|
+
email: profile.data.emailAddress,
|
|
48
|
+
updated_at: new Date().toISOString(),
|
|
49
|
+
});
|
|
50
|
+
return c.json({ email: profile.data.emailAddress, connected: true });
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return c.json({ error: err.message }, 400);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=gmail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gmail.js","sourceRoot":"","sources":["../../../core-gateway/routes/gmail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../core-gateway/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAGhC,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,QAI7C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../core-gateway/routes/health.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,MAAM,UAAU,oBAAoB,CAAC,GAAS;IAC5C,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7B,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IACjE,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* Upload route: persists uploaded files to the per-session data dir so the
|
|
4
|
+
* Claude CLI subprocess can read them back. Files auto-delete after 5min.
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerUploadRoutes(app: Hono): void;
|
|
7
|
+
//# sourceMappingURL=upload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../core-gateway/routes/upload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,QAyB7C"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upload route: persists uploaded files to the per-session data dir so the
|
|
3
|
+
* Claude CLI subprocess can read them back. Files auto-delete after 5min.
|
|
4
|
+
*/
|
|
5
|
+
export function registerUploadRoutes(app) {
|
|
6
|
+
app.post('/upload', async (c) => {
|
|
7
|
+
const body = await c.req.parseBody();
|
|
8
|
+
const file = body['file'];
|
|
9
|
+
const companyId = body['company_id'];
|
|
10
|
+
const sessionKey = body['session_key'] || 'web';
|
|
11
|
+
if (!file || !companyId)
|
|
12
|
+
return c.json({ error: 'file and company_id required' }, 400);
|
|
13
|
+
const dataRoot = process.env.DATA_DIR || '/data';
|
|
14
|
+
const sessionDir = `${dataRoot}/sessions/${companyId}/${sessionKey}`;
|
|
15
|
+
const { mkdirSync, writeFileSync } = await import('node:fs');
|
|
16
|
+
mkdirSync(sessionDir, { recursive: true });
|
|
17
|
+
const filename = `${Date.now()}-${file.name}`;
|
|
18
|
+
const filepath = `${sessionDir}/${filename}`;
|
|
19
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
20
|
+
writeFileSync(filepath, buffer);
|
|
21
|
+
setTimeout(async () => {
|
|
22
|
+
try {
|
|
23
|
+
const { unlinkSync } = await import('node:fs');
|
|
24
|
+
unlinkSync(filepath);
|
|
25
|
+
}
|
|
26
|
+
catch { }
|
|
27
|
+
}, 30 * 60 * 1000);
|
|
28
|
+
return c.json({ path: filepath, filename });
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../../core-gateway/routes/upload.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAS;IAC5C,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,CAAA;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAS,CAAA;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAW,CAAA;QAC9C,MAAM,UAAU,GAAI,IAAI,CAAC,aAAa,CAAY,IAAI,KAAK,CAAA;QAE3D,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,EAAE,GAAG,CAAC,CAAA;QAEtF,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAA;QAChD,MAAM,UAAU,GAAG,GAAG,QAAQ,aAAa,SAAS,IAAI,UAAU,EAAE,CAAA;QACpE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAA;QAC5D,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAE1C,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAA;QAC7C,MAAM,QAAQ,GAAG,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAA;QAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACpD,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QAE/B,UAAU,CAAC,KAAK,IAAI,EAAE;YACpB,IAAI,CAAC;gBAAC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;gBAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACvF,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QAElB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;AACJ,CAAC"}
|