arisa 2.3.55 → 3.0.1
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/AGENTS.md +102 -0
- package/README.md +120 -165
- package/bin/arisa.js +2 -643
- package/cli/openai-transcribe/index.js +51 -0
- package/cli/openai-transcribe/package.json +6 -0
- package/cli/openai-transcribe/tool.manifest.json +15 -0
- package/cli/openai-tts/index.js +58 -0
- package/cli/openai-tts/package.json +6 -0
- package/cli/openai-tts/tool.manifest.json +20 -0
- package/cli/web-browser/index.js +146 -0
- package/cli/web-browser/package.json +6 -0
- package/cli/web-browser/tool.manifest.json +8 -0
- package/package.json +26 -44
- package/src/core/agent/agent-manager.js +218 -0
- package/src/core/artifacts/artifact-store.js +102 -0
- package/src/core/config/config-store.js +20 -0
- package/src/core/tools/tool-registry.js +117 -0
- package/src/index.js +27 -0
- package/src/runtime/bootstrap.js +213 -0
- package/src/runtime/create-app.js +22 -0
- package/src/transport/telegram/auth.js +13 -0
- package/src/transport/telegram/bot.js +214 -0
- package/src/transport/telegram/media.js +75 -0
- package/CLAUDE.md +0 -191
- package/SOUL.md +0 -36
- package/scripts/dump-commands.ts +0 -26
- package/scripts/test-secrets.ts +0 -22
- package/src/core/attachments.ts +0 -104
- package/src/core/auth.ts +0 -58
- package/src/core/context.ts +0 -30
- package/src/core/file-detector.ts +0 -39
- package/src/core/format.ts +0 -159
- package/src/core/index.ts +0 -456
- package/src/core/intent.ts +0 -119
- package/src/core/media.ts +0 -144
- package/src/core/onboarding.ts +0 -102
- package/src/core/processor.ts +0 -305
- package/src/core/router.ts +0 -64
- package/src/core/scheduler.ts +0 -193
- package/src/daemon/agent-cli.ts +0 -130
- package/src/daemon/auto-install.ts +0 -158
- package/src/daemon/autofix.ts +0 -116
- package/src/daemon/bridge.ts +0 -166
- package/src/daemon/channels/base.ts +0 -10
- package/src/daemon/channels/telegram.ts +0 -306
- package/src/daemon/claude-login.ts +0 -218
- package/src/daemon/codex-login.ts +0 -172
- package/src/daemon/fallback.ts +0 -73
- package/src/daemon/index.ts +0 -272
- package/src/daemon/lifecycle.ts +0 -313
- package/src/daemon/setup.ts +0 -329
- package/src/shared/ai-cli.ts +0 -165
- package/src/shared/config.ts +0 -137
- package/src/shared/db.ts +0 -304
- package/src/shared/deepbase-secure.ts +0 -39
- package/src/shared/ink-shim.js +0 -14
- package/src/shared/logger.ts +0 -42
- package/src/shared/paths.ts +0 -90
- package/src/shared/ports.ts +0 -120
- package/src/shared/secrets.ts +0 -136
- package/src/shared/types.ts +0 -103
- package/tsconfig.json +0 -19
package/src/shared/paths.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module shared/paths
|
|
3
|
-
* @role Resolve project and runtime data directories with migration-safe defaults.
|
|
4
|
-
* @responsibilities
|
|
5
|
-
* - Resolve project directory (supports ARISA_PROJECT_DIR override)
|
|
6
|
-
* - Resolve runtime data directory (prefers ~/.arisa by default)
|
|
7
|
-
* - Migrate legacy project-local dirs (.tinyclaw/.arisa) into ~/.arisa
|
|
8
|
-
* - Support ARISA_DATA_DIR override for advanced deployments
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { cpSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "fs";
|
|
12
|
-
import { homedir } from "os";
|
|
13
|
-
import { isAbsolute, join, resolve } from "path";
|
|
14
|
-
|
|
15
|
-
const DEFAULT_PROJECT_DIR = join(import.meta.dir, "..", "..");
|
|
16
|
-
const PROJECT_DIR = process.env.ARISA_PROJECT_DIR
|
|
17
|
-
? resolve(process.env.ARISA_PROJECT_DIR)
|
|
18
|
-
: DEFAULT_PROJECT_DIR;
|
|
19
|
-
|
|
20
|
-
const HOME_DATA_DIR = join(homedir(), ".arisa");
|
|
21
|
-
const PROJECT_ARISA_DIR = join(PROJECT_DIR, ".arisa");
|
|
22
|
-
const LEGACY_DATA_DIR = join(PROJECT_DIR, ".tinyclaw");
|
|
23
|
-
|
|
24
|
-
function samePath(a: string, b: string): boolean {
|
|
25
|
-
return resolve(a) === resolve(b);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function hasFiles(dir: string): boolean {
|
|
29
|
-
try {
|
|
30
|
-
return existsSync(dir) && readdirSync(dir).length > 0;
|
|
31
|
-
} catch {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function moveOrMerge(sourceDir: string, targetDir: string): void {
|
|
37
|
-
if (!existsSync(sourceDir) || samePath(sourceDir, targetDir)) return;
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
if (!existsSync(targetDir)) {
|
|
41
|
-
mkdirSync(resolve(targetDir, ".."), { recursive: true });
|
|
42
|
-
renameSync(sourceDir, targetDir);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Merge source into target and drop source afterward.
|
|
47
|
-
cpSync(sourceDir, targetDir, { recursive: true, force: false, errorOnExist: false });
|
|
48
|
-
rmSync(sourceDir, { recursive: true, force: true });
|
|
49
|
-
} catch {
|
|
50
|
-
// Do not crash startup if migration has a filesystem issue.
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function resolveOverrideDataDir(): string | null {
|
|
55
|
-
const override = process.env.ARISA_DATA_DIR?.trim();
|
|
56
|
-
if (!override) return null;
|
|
57
|
-
return isAbsolute(override) ? override : resolve(PROJECT_DIR, override);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function resolveDataDir(): string {
|
|
61
|
-
const overrideDir = resolveOverrideDataDir();
|
|
62
|
-
if (overrideDir) {
|
|
63
|
-
return overrideDir;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// One-time migration from local runtime dirs to ~/.arisa.
|
|
67
|
-
if (!hasFiles(HOME_DATA_DIR)) {
|
|
68
|
-
if (hasFiles(PROJECT_ARISA_DIR)) {
|
|
69
|
-
moveOrMerge(PROJECT_ARISA_DIR, HOME_DATA_DIR);
|
|
70
|
-
} else if (hasFiles(LEGACY_DATA_DIR)) {
|
|
71
|
-
moveOrMerge(LEGACY_DATA_DIR, HOME_DATA_DIR);
|
|
72
|
-
}
|
|
73
|
-
} else {
|
|
74
|
-
// If ~/.arisa already exists, still merge any local leftovers into it.
|
|
75
|
-
if (hasFiles(PROJECT_ARISA_DIR)) moveOrMerge(PROJECT_ARISA_DIR, HOME_DATA_DIR);
|
|
76
|
-
if (hasFiles(LEGACY_DATA_DIR)) moveOrMerge(LEGACY_DATA_DIR, HOME_DATA_DIR);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (!existsSync(HOME_DATA_DIR)) {
|
|
80
|
-
mkdirSync(HOME_DATA_DIR, { recursive: true });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return HOME_DATA_DIR;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export const projectDir = PROJECT_DIR;
|
|
87
|
-
export const preferredDataDir = HOME_DATA_DIR;
|
|
88
|
-
export const projectLocalDataDir = PROJECT_ARISA_DIR;
|
|
89
|
-
export const legacyDataDir = LEGACY_DATA_DIR;
|
|
90
|
-
export const dataDir = resolveDataDir();
|
package/src/shared/ports.ts
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module shared/ports
|
|
3
|
-
* @role Process cleanup via PID files + /proc scan, retry-aware Bun.serve.
|
|
4
|
-
* @effects Reads/writes runtime pid files, kills processes via SIGKILL
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { existsSync, readFileSync, readdirSync, writeFileSync, unlinkSync, mkdirSync, chmodSync } from "fs";
|
|
8
|
-
import { join, dirname } from "path";
|
|
9
|
-
import { dataDir } from "./paths";
|
|
10
|
-
|
|
11
|
-
const ARISA_DIR = dataDir;
|
|
12
|
-
|
|
13
|
-
function pidPath(name: string): string {
|
|
14
|
-
return join(ARISA_DIR, `${name}.pid`);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Patterns to match in /proc cmdline for each process type
|
|
18
|
-
const CMDLINE_PATTERNS: Record<string, string> = {
|
|
19
|
-
daemon: "daemon/index.ts",
|
|
20
|
-
core: "core/index.ts",
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Kill previous instances of a named process, then write our PID.
|
|
25
|
-
* Uses PID file + /proc scan for robustness in containers.
|
|
26
|
-
*/
|
|
27
|
-
export function claimProcess(name: string): void {
|
|
28
|
-
const myPid = process.pid;
|
|
29
|
-
|
|
30
|
-
// 1. Kill from PID file
|
|
31
|
-
const path = pidPath(name);
|
|
32
|
-
if (existsSync(path)) {
|
|
33
|
-
try {
|
|
34
|
-
const oldPid = parseInt(readFileSync(path, "utf8").trim(), 10);
|
|
35
|
-
if (oldPid && oldPid !== myPid) {
|
|
36
|
-
try { process.kill(oldPid, "SIGKILL"); } catch {}
|
|
37
|
-
}
|
|
38
|
-
} catch {}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// 2. Scan /proc for any matching processes (Linux containers)
|
|
42
|
-
const pattern = CMDLINE_PATTERNS[name];
|
|
43
|
-
if (pattern) {
|
|
44
|
-
killByPattern(pattern, myPid);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 3. Write our PID
|
|
48
|
-
if (!existsSync(dirname(path))) mkdirSync(dirname(path), { recursive: true });
|
|
49
|
-
writeFileSync(path, String(myPid));
|
|
50
|
-
|
|
51
|
-
// 4. Brief pause to let OS release resources
|
|
52
|
-
Bun.sleepSync(200);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Scan /proc cmdline and kill processes matching a pattern (Linux only).
|
|
56
|
-
function killByPattern(pattern: string, excludePid: number): void {
|
|
57
|
-
try {
|
|
58
|
-
if (!existsSync("/proc")) return;
|
|
59
|
-
const dirs = readdirSync("/proc").filter((d) => /^\d+$/.test(d));
|
|
60
|
-
for (const pid of dirs) {
|
|
61
|
-
const numPid = Number(pid);
|
|
62
|
-
if (numPid === excludePid) continue;
|
|
63
|
-
try {
|
|
64
|
-
const cmdline = readFileSync(`/proc/${pid}/cmdline`, "utf8");
|
|
65
|
-
if (cmdline.includes(pattern)) {
|
|
66
|
-
process.kill(numPid, "SIGKILL");
|
|
67
|
-
}
|
|
68
|
-
} catch {}
|
|
69
|
-
}
|
|
70
|
-
} catch {}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Remove our PID file on clean shutdown.
|
|
75
|
-
*/
|
|
76
|
-
export function releaseProcess(name: string): void {
|
|
77
|
-
try { unlinkSync(pidPath(name)); } catch {}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Remove a Unix socket file if it exists (stale leftover from crash).
|
|
82
|
-
*/
|
|
83
|
-
export function cleanupSocket(socketPath: string): void {
|
|
84
|
-
try { unlinkSync(socketPath); } catch {}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Bun.serve() with retry — handles both TCP ports and Unix sockets.
|
|
89
|
-
* For Unix sockets, cleans up stale socket file before first attempt.
|
|
90
|
-
*/
|
|
91
|
-
export async function serveWithRetry(
|
|
92
|
-
options: Parameters<typeof Bun.serve>[0],
|
|
93
|
-
retries = 5,
|
|
94
|
-
): Promise<ReturnType<typeof Bun.serve>> {
|
|
95
|
-
const socketPath = (options as any).unix as string | undefined;
|
|
96
|
-
|
|
97
|
-
// Pre-clean stale Unix socket from a previous crash
|
|
98
|
-
if (socketPath) cleanupSocket(socketPath);
|
|
99
|
-
|
|
100
|
-
for (let i = 0; i < retries; i++) {
|
|
101
|
-
try {
|
|
102
|
-
const server = Bun.serve(options);
|
|
103
|
-
// Make Unix sockets world-accessible so Core (arisa) and Daemon (root)
|
|
104
|
-
// can connect to each other's sockets regardless of ownership.
|
|
105
|
-
if (socketPath) try { chmodSync(socketPath, 0o777); } catch {}
|
|
106
|
-
return server;
|
|
107
|
-
} catch (e: any) {
|
|
108
|
-
if (e?.code !== "EADDRINUSE" || i === retries - 1) throw e;
|
|
109
|
-
if (socketPath) {
|
|
110
|
-
console.log(`[ports] Socket ${socketPath} busy, cleaning up and retrying (${i + 1}/${retries})...`);
|
|
111
|
-
cleanupSocket(socketPath);
|
|
112
|
-
} else {
|
|
113
|
-
const port = (options as any).port ?? "?";
|
|
114
|
-
console.log(`[ports] Port ${port} busy, retrying (${i + 1}/${retries})...`);
|
|
115
|
-
}
|
|
116
|
-
await new Promise((r) => setTimeout(r, 1000));
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
throw new Error("unreachable");
|
|
120
|
-
}
|
package/src/shared/secrets.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module shared/secrets
|
|
3
|
-
* @role Encrypted secrets storage using DeepbaseSecure
|
|
4
|
-
* @responsibilities
|
|
5
|
-
* - Generate/load encryption key
|
|
6
|
-
* - Store API keys encrypted at rest
|
|
7
|
-
* - Provide type-safe getters for secrets
|
|
8
|
-
* @dependencies DeepbaseSecure, crypto-js
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { join } from "path";
|
|
12
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, renameSync } from "fs";
|
|
13
|
-
import CryptoJS from "crypto-js";
|
|
14
|
-
import { DeepbaseSecure } from "./deepbase-secure";
|
|
15
|
-
import { dataDir } from "./paths";
|
|
16
|
-
|
|
17
|
-
const ARISA_DIR = dataDir;
|
|
18
|
-
const ENCRYPTION_KEY_PATH = join(ARISA_DIR, ".encryption_key");
|
|
19
|
-
const SECRETS_DB_PATH = join(ARISA_DIR, "db");
|
|
20
|
-
|
|
21
|
-
// Ensure runtime data and db dirs exist
|
|
22
|
-
mkdirSync(join(ARISA_DIR, "db"), { recursive: true });
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Load or generate encryption key
|
|
26
|
-
*/
|
|
27
|
-
function getEncryptionKey(): string {
|
|
28
|
-
if (existsSync(ENCRYPTION_KEY_PATH)) {
|
|
29
|
-
return readFileSync(ENCRYPTION_KEY_PATH, "utf8").trim();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Generate random 256-bit key
|
|
33
|
-
const key = CryptoJS.lib.WordArray.random(256 / 8).toString(CryptoJS.enc.Hex);
|
|
34
|
-
writeFileSync(ENCRYPTION_KEY_PATH, key, { mode: 0o600 });
|
|
35
|
-
return key;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const encryptionKey = getEncryptionKey();
|
|
39
|
-
let secretsDb = createSecretsDb();
|
|
40
|
-
|
|
41
|
-
function createSecretsDb(): DeepbaseSecure {
|
|
42
|
-
return new DeepbaseSecure({
|
|
43
|
-
path: SECRETS_DB_PATH,
|
|
44
|
-
name: "secrets",
|
|
45
|
-
encryptionKey,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Initialize connection
|
|
50
|
-
let connectionPromise: Promise<void> | null = null;
|
|
51
|
-
let recoveredOnce = false;
|
|
52
|
-
|
|
53
|
-
function looksCorrupted(err: unknown): boolean {
|
|
54
|
-
const msg = err instanceof Error ? `${err.message}\n${err.stack || ""}` : String(err);
|
|
55
|
-
return /Malformed UTF-8 data|Unexpected token|JSON|decrypt|invalid/i.test(msg);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function backupCorruptSecretsDb(): void {
|
|
59
|
-
try {
|
|
60
|
-
const timestamp = Date.now();
|
|
61
|
-
for (const file of readdirSync(SECRETS_DB_PATH)) {
|
|
62
|
-
if (!file.startsWith("secrets")) continue;
|
|
63
|
-
const src = join(SECRETS_DB_PATH, file);
|
|
64
|
-
const dst = join(SECRETS_DB_PATH, `${file}.corrupt.${timestamp}`);
|
|
65
|
-
try {
|
|
66
|
-
renameSync(src, dst);
|
|
67
|
-
} catch {
|
|
68
|
-
// Best-effort backup; ignore per-file failures.
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
} catch {
|
|
72
|
-
// Ignore backup errors; recovery will still retry with a fresh DB handle.
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function ensureConnected(): Promise<void> {
|
|
77
|
-
if (!connectionPromise) {
|
|
78
|
-
connectionPromise = (async () => {
|
|
79
|
-
try {
|
|
80
|
-
await secretsDb.connect();
|
|
81
|
-
} catch (err) {
|
|
82
|
-
if (!recoveredOnce && looksCorrupted(err)) {
|
|
83
|
-
recoveredOnce = true;
|
|
84
|
-
console.warn("[secrets] Encrypted secrets DB looks corrupted; backing up and recreating it.");
|
|
85
|
-
backupCorruptSecretsDb();
|
|
86
|
-
secretsDb = createSecretsDb();
|
|
87
|
-
await secretsDb.connect();
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
throw err;
|
|
91
|
-
}
|
|
92
|
-
})().catch((err) => {
|
|
93
|
-
connectionPromise = null;
|
|
94
|
-
throw err;
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
await connectionPromise;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Get a secret by key
|
|
102
|
-
*/
|
|
103
|
-
export async function getSecret(key: string): Promise<string | undefined> {
|
|
104
|
-
try {
|
|
105
|
-
await ensureConnected();
|
|
106
|
-
return await secretsDb.get("secrets", key);
|
|
107
|
-
} catch (err) {
|
|
108
|
-
console.warn(`[secrets] Could not read ${key} from encrypted DB: ${err}`);
|
|
109
|
-
return undefined;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Set a secret by key
|
|
115
|
-
*/
|
|
116
|
-
export async function setSecret(key: string, value: string): Promise<void> {
|
|
117
|
-
await ensureConnected();
|
|
118
|
-
await secretsDb.set("secrets", key, value);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Delete a secret by key
|
|
123
|
-
*/
|
|
124
|
-
export async function deleteSecret(key: string): Promise<void> {
|
|
125
|
-
await ensureConnected();
|
|
126
|
-
await secretsDb.del("secrets", key);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Type-safe getters for known secrets
|
|
131
|
-
*/
|
|
132
|
-
export const secrets = {
|
|
133
|
-
telegram: () => getSecret("TELEGRAM_BOT_TOKEN"),
|
|
134
|
-
openai: () => getSecret("OPENAI_API_KEY"),
|
|
135
|
-
elevenlabs: () => getSecret("ELEVENLABS_API_KEY"),
|
|
136
|
-
};
|
package/src/shared/types.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module shared/types
|
|
3
|
-
* @role Define all shared interfaces for Daemon ↔ Core communication.
|
|
4
|
-
* @responsibilities
|
|
5
|
-
* - IncomingMessage: what a channel adapter produces
|
|
6
|
-
* - CoreRequest/CoreResponse: HTTP payloads between Daemon and Core
|
|
7
|
-
* - SendRequest: Core → Daemon push (scheduler, etc.)
|
|
8
|
-
* - ScheduledTask: persisted task for croner/one-time
|
|
9
|
-
* - ModelConfig: router output
|
|
10
|
-
* @dependencies None
|
|
11
|
-
* @effects None (types only)
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export interface IncomingMessage {
|
|
15
|
-
chatId: string;
|
|
16
|
-
sender: string;
|
|
17
|
-
senderId: string;
|
|
18
|
-
text?: string;
|
|
19
|
-
audio?: { base64: string; filename: string };
|
|
20
|
-
image?: { base64: string; caption?: string };
|
|
21
|
-
document?: { base64: string; filename: string; mimeType: string; caption?: string };
|
|
22
|
-
command?: string;
|
|
23
|
-
messageId?: number;
|
|
24
|
-
timestamp: number;
|
|
25
|
-
replyTo?: {
|
|
26
|
-
messageId?: number;
|
|
27
|
-
text?: string;
|
|
28
|
-
sender: string;
|
|
29
|
-
timestamp: number;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface CoreRequest {
|
|
34
|
-
message: IncomingMessage;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface CoreResponse {
|
|
38
|
-
text: string;
|
|
39
|
-
files?: string[];
|
|
40
|
-
audio?: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface SendRequest {
|
|
44
|
-
chatId: string;
|
|
45
|
-
text: string;
|
|
46
|
-
files?: string[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface ScheduledTask {
|
|
50
|
-
id: string;
|
|
51
|
-
chatId: string;
|
|
52
|
-
sender: string;
|
|
53
|
-
senderId: string;
|
|
54
|
-
type: "once" | "cron";
|
|
55
|
-
origin?: "cron" | "recurring";
|
|
56
|
-
message: string;
|
|
57
|
-
originalMessage: string;
|
|
58
|
-
createdAt: number;
|
|
59
|
-
runAt?: number;
|
|
60
|
-
cron?: string;
|
|
61
|
-
lastRunAt?: number;
|
|
62
|
-
status?: "pending" | "done";
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface AttachmentRecord {
|
|
66
|
-
id: string;
|
|
67
|
-
chatId: string;
|
|
68
|
-
type: "image" | "audio" | "document";
|
|
69
|
-
filename: string;
|
|
70
|
-
relPath: string;
|
|
71
|
-
mimeType?: string;
|
|
72
|
-
sizeBytes: number;
|
|
73
|
-
createdAt: number;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface ModelConfig {
|
|
77
|
-
model: string;
|
|
78
|
-
timeout: number;
|
|
79
|
-
reason: string;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export interface MessageRecord {
|
|
83
|
-
id: string; // "{chatId}_{messageId}"
|
|
84
|
-
chatId: string;
|
|
85
|
-
messageId: number; // Telegram message_id
|
|
86
|
-
direction: "in" | "out";
|
|
87
|
-
sender: string;
|
|
88
|
-
timestamp: number;
|
|
89
|
-
text?: string;
|
|
90
|
-
mediaType?: "image" | "audio" | "document";
|
|
91
|
-
attachmentPath?: string;
|
|
92
|
-
mediaDescription?: string;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export interface Channel {
|
|
96
|
-
name: string;
|
|
97
|
-
connect(): Promise<void>;
|
|
98
|
-
onMessage(handler: (msg: IncomingMessage) => void): void;
|
|
99
|
-
send(chatId: string, text: string, parseMode?: "HTML" | "plain"): Promise<number | undefined>;
|
|
100
|
-
sendFile(chatId: string, filePath: string): Promise<void>;
|
|
101
|
-
sendAudio?(chatId: string, filePath: string): Promise<void>;
|
|
102
|
-
sendTyping(chatId: string): Promise<void>;
|
|
103
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"types": ["bun"],
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"outDir": "./dist",
|
|
12
|
-
"rootDir": "./src",
|
|
13
|
-
"declaration": true,
|
|
14
|
-
"noUnusedLocals": false,
|
|
15
|
-
"noUnusedParameters": false
|
|
16
|
-
},
|
|
17
|
-
"include": ["src/**/*.ts"],
|
|
18
|
-
"exclude": ["node_modules", "dist"]
|
|
19
|
-
}
|