clawless 0.1.2
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/.env.example +48 -0
- package/LICENSE +21 -0
- package/QUICKSTART-SCHEDULER.md +226 -0
- package/QUICKSTART.md +98 -0
- package/README.md +404 -0
- package/SCHEDULER.md +255 -0
- package/TESTING.md +239 -0
- package/acp/clientHelpers.ts +23 -0
- package/acp/tempAcpRunner.ts +320 -0
- package/agent-bridge.config.example.json +19 -0
- package/bin/cli.ts +255 -0
- package/dist/acp/clientHelpers.js +19 -0
- package/dist/acp/tempAcpRunner.js +263 -0
- package/dist/bin/cli.js +217 -0
- package/dist/index.js +1115 -0
- package/dist/messaging/telegramClient.js +109 -0
- package/dist/scheduler/cronScheduler.js +272 -0
- package/dist/scheduler/scheduledJobHandler.js +34 -0
- package/dist/utils/error.js +12 -0
- package/dist/utils/telegramMarkdown.js +128 -0
- package/ecosystem.config.json +23 -0
- package/index.ts +1272 -0
- package/messaging/telegramClient.ts +132 -0
- package/package.json +43 -0
- package/scheduler/cronScheduler.ts +355 -0
- package/scheduler/scheduledJobHandler.ts +55 -0
- package/scripts/callback-health.sh +6 -0
- package/scripts/callback-post-chat.sh +25 -0
- package/scripts/callback-post.sh +19 -0
- package/scripts/gemini-scheduler-examples.sh +162 -0
- package/scripts/test-scheduler.sh +78 -0
- package/tsconfig.json +23 -0
- package/utils/error.ts +12 -0
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
const ENV_KEY_MAP = {
|
|
7
|
+
telegramToken: 'TELEGRAM_TOKEN',
|
|
8
|
+
typingIntervalMs: 'TYPING_INTERVAL_MS',
|
|
9
|
+
geminiCommand: 'GEMINI_COMMAND',
|
|
10
|
+
geminiApprovalMode: 'GEMINI_APPROVAL_MODE',
|
|
11
|
+
geminiModel: 'GEMINI_MODEL',
|
|
12
|
+
acpPermissionStrategy: 'ACP_PERMISSION_STRATEGY',
|
|
13
|
+
geminiTimeoutMs: 'GEMINI_TIMEOUT_MS',
|
|
14
|
+
geminiNoOutputTimeoutMs: 'GEMINI_NO_OUTPUT_TIMEOUT_MS',
|
|
15
|
+
geminiKillGraceMs: 'GEMINI_KILL_GRACE_MS',
|
|
16
|
+
maxResponseLength: 'MAX_RESPONSE_LENGTH',
|
|
17
|
+
acpStreamStdout: 'ACP_STREAM_STDOUT',
|
|
18
|
+
acpDebugStream: 'ACP_DEBUG_STREAM',
|
|
19
|
+
heartbeatIntervalMs: 'HEARTBEAT_INTERVAL_MS',
|
|
20
|
+
callbackHost: 'CALLBACK_HOST',
|
|
21
|
+
callbackPort: 'CALLBACK_PORT',
|
|
22
|
+
callbackAuthToken: 'CALLBACK_AUTH_TOKEN',
|
|
23
|
+
callbackMaxBodyBytes: 'CALLBACK_MAX_BODY_BYTES',
|
|
24
|
+
agentBridgeHome: 'AGENT_BRIDGE_HOME',
|
|
25
|
+
memoryFilePath: 'MEMORY_FILE_PATH',
|
|
26
|
+
memoryMaxChars: 'MEMORY_MAX_CHARS',
|
|
27
|
+
schedulesFilePath: 'SCHEDULES_FILE_PATH',
|
|
28
|
+
};
|
|
29
|
+
const DEFAULT_CONFIG_PATH = path.join(os.homedir(), '.gemini-bridge', 'config.json');
|
|
30
|
+
const DEFAULT_AGENT_BRIDGE_HOME = path.join(os.homedir(), '.gemini-bridge');
|
|
31
|
+
const DEFAULT_MEMORY_FILE_PATH = path.join(DEFAULT_AGENT_BRIDGE_HOME, 'MEMORY.md');
|
|
32
|
+
const DEFAULT_CONFIG_TEMPLATE = {
|
|
33
|
+
telegramToken: 'your_telegram_bot_token_here',
|
|
34
|
+
typingIntervalMs: 4000,
|
|
35
|
+
geminiCommand: 'gemini',
|
|
36
|
+
geminiApprovalMode: 'yolo',
|
|
37
|
+
geminiModel: '',
|
|
38
|
+
acpPermissionStrategy: 'allow_once',
|
|
39
|
+
geminiTimeoutMs: 900000,
|
|
40
|
+
geminiNoOutputTimeoutMs: 60000,
|
|
41
|
+
geminiKillGraceMs: 5000,
|
|
42
|
+
maxResponseLength: 4000,
|
|
43
|
+
acpStreamStdout: false,
|
|
44
|
+
acpDebugStream: false,
|
|
45
|
+
heartbeatIntervalMs: 60000,
|
|
46
|
+
callbackHost: 'localhost',
|
|
47
|
+
callbackPort: 8788,
|
|
48
|
+
callbackAuthToken: '',
|
|
49
|
+
callbackMaxBodyBytes: 65536,
|
|
50
|
+
agentBridgeHome: '~/.gemini-bridge',
|
|
51
|
+
memoryFilePath: '~/.gemini-bridge/MEMORY.md',
|
|
52
|
+
memoryMaxChars: 12000,
|
|
53
|
+
schedulesFilePath: '~/.gemini-bridge/schedules.json',
|
|
54
|
+
};
|
|
55
|
+
function printHelp() {
|
|
56
|
+
console.log(`gemini-bridge
|
|
57
|
+
|
|
58
|
+
Usage:
|
|
59
|
+
gemini-bridge [--config <path>]
|
|
60
|
+
|
|
61
|
+
Options:
|
|
62
|
+
--config <path> Path to JSON config file (default: ~/.gemini-bridge/config.json)
|
|
63
|
+
-h, --help Show this help message
|
|
64
|
+
|
|
65
|
+
Config precedence:
|
|
66
|
+
1) Existing environment variables
|
|
67
|
+
2) Values from config file
|
|
68
|
+
`);
|
|
69
|
+
}
|
|
70
|
+
function parseArgs(argv) {
|
|
71
|
+
const result = {
|
|
72
|
+
configPath: process.env.GEMINI_BRIDGE_CONFIG || process.env.AGENT_BRIDGE_CONFIG || DEFAULT_CONFIG_PATH,
|
|
73
|
+
help: false,
|
|
74
|
+
};
|
|
75
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
76
|
+
const arg = argv[index];
|
|
77
|
+
if (arg === '-h' || arg === '--help') {
|
|
78
|
+
result.help = true;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (arg === '--config') {
|
|
82
|
+
const value = argv[index + 1];
|
|
83
|
+
if (!value) {
|
|
84
|
+
throw new Error('--config requires a file path');
|
|
85
|
+
}
|
|
86
|
+
result.configPath = value;
|
|
87
|
+
index += 1;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
function toEnvValue(value) {
|
|
95
|
+
if (value === null || value === undefined) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
if (typeof value === 'string') {
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
return String(value);
|
|
102
|
+
}
|
|
103
|
+
function resolveEnvKey(configKey) {
|
|
104
|
+
if (configKey in ENV_KEY_MAP) {
|
|
105
|
+
return ENV_KEY_MAP[configKey];
|
|
106
|
+
}
|
|
107
|
+
const looksLikeEnvKey = /^[A-Z0-9_]+$/.test(configKey);
|
|
108
|
+
if (looksLikeEnvKey) {
|
|
109
|
+
return configKey;
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
function applyConfigToEnv(configData) {
|
|
114
|
+
if (!configData || typeof configData !== 'object' || Array.isArray(configData)) {
|
|
115
|
+
throw new Error('Config file must contain a JSON object at the top level');
|
|
116
|
+
}
|
|
117
|
+
for (const [configKey, rawValue] of Object.entries(configData)) {
|
|
118
|
+
const envKey = resolveEnvKey(configKey);
|
|
119
|
+
if (!envKey) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (process.env[envKey] !== undefined) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const envValue = toEnvValue(rawValue);
|
|
126
|
+
if (envValue !== undefined) {
|
|
127
|
+
process.env[envKey] = envValue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function resolveConfigPath(configPath) {
|
|
132
|
+
if (!configPath || configPath === '~') {
|
|
133
|
+
return os.homedir();
|
|
134
|
+
}
|
|
135
|
+
if (configPath.startsWith('~/')) {
|
|
136
|
+
return path.join(os.homedir(), configPath.slice(2));
|
|
137
|
+
}
|
|
138
|
+
return path.resolve(process.cwd(), configPath);
|
|
139
|
+
}
|
|
140
|
+
function ensureConfigFile(configPath) {
|
|
141
|
+
const absolutePath = resolveConfigPath(configPath);
|
|
142
|
+
if (fs.existsSync(absolutePath)) {
|
|
143
|
+
return { created: false, path: absolutePath };
|
|
144
|
+
}
|
|
145
|
+
fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
|
|
146
|
+
fs.writeFileSync(absolutePath, `${JSON.stringify(DEFAULT_CONFIG_TEMPLATE, null, 2)}\n`, 'utf8');
|
|
147
|
+
return { created: true, path: absolutePath };
|
|
148
|
+
}
|
|
149
|
+
function ensureMemoryFile(memoryFilePath) {
|
|
150
|
+
const absolutePath = resolveConfigPath(memoryFilePath);
|
|
151
|
+
if (!fs.existsSync(absolutePath)) {
|
|
152
|
+
fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
|
|
153
|
+
const template = [
|
|
154
|
+
'# Agent Bridge Memory',
|
|
155
|
+
'',
|
|
156
|
+
'This file stores durable memory notes for Agent Bridge.',
|
|
157
|
+
'',
|
|
158
|
+
'## Notes',
|
|
159
|
+
'',
|
|
160
|
+
].join('\n');
|
|
161
|
+
fs.writeFileSync(absolutePath, `${template}\n`, 'utf8');
|
|
162
|
+
return { created: true, path: absolutePath };
|
|
163
|
+
}
|
|
164
|
+
return { created: false, path: absolutePath };
|
|
165
|
+
}
|
|
166
|
+
function ensureMemoryFromEnv() {
|
|
167
|
+
const configuredHome = process.env.AGENT_BRIDGE_HOME || DEFAULT_AGENT_BRIDGE_HOME;
|
|
168
|
+
const configuredMemoryPath = process.env.MEMORY_FILE_PATH || path.join(configuredHome, 'MEMORY.md');
|
|
169
|
+
if (!process.env.AGENT_BRIDGE_HOME) {
|
|
170
|
+
process.env.AGENT_BRIDGE_HOME = configuredHome;
|
|
171
|
+
}
|
|
172
|
+
if (!process.env.MEMORY_FILE_PATH) {
|
|
173
|
+
process.env.MEMORY_FILE_PATH = configuredMemoryPath;
|
|
174
|
+
}
|
|
175
|
+
return ensureMemoryFile(process.env.MEMORY_FILE_PATH || DEFAULT_MEMORY_FILE_PATH);
|
|
176
|
+
}
|
|
177
|
+
function logMemoryFileCreation(memoryState) {
|
|
178
|
+
if (memoryState.created) {
|
|
179
|
+
console.log(`[gemini-bridge] Created memory file: ${memoryState.path}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function loadConfigFile(configPath) {
|
|
183
|
+
const absolutePath = resolveConfigPath(configPath);
|
|
184
|
+
if (!fs.existsSync(absolutePath)) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const fileContent = fs.readFileSync(absolutePath, 'utf8');
|
|
188
|
+
const parsed = JSON.parse(fileContent);
|
|
189
|
+
applyConfigToEnv(parsed);
|
|
190
|
+
return absolutePath;
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const args = parseArgs(process.argv.slice(2));
|
|
194
|
+
if (args.help) {
|
|
195
|
+
printHelp();
|
|
196
|
+
process.exit(0);
|
|
197
|
+
}
|
|
198
|
+
const configState = ensureConfigFile(args.configPath);
|
|
199
|
+
const memoryState = ensureMemoryFromEnv();
|
|
200
|
+
logMemoryFileCreation(memoryState);
|
|
201
|
+
if (configState.created) {
|
|
202
|
+
console.log(`[gemini-bridge] Created config template: ${configState.path}`);
|
|
203
|
+
console.log('[gemini-bridge] Fill in placeholder values, then run gemini-bridge again.');
|
|
204
|
+
process.exit(0);
|
|
205
|
+
}
|
|
206
|
+
const loadedConfigPath = loadConfigFile(args.configPath);
|
|
207
|
+
if (loadedConfigPath) {
|
|
208
|
+
console.log(`[gemini-bridge] Loaded config: ${loadedConfigPath}`);
|
|
209
|
+
}
|
|
210
|
+
const postConfigMemoryState = ensureMemoryFromEnv();
|
|
211
|
+
logMemoryFileCreation(postConfigMemoryState);
|
|
212
|
+
await import('../index.js');
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
console.error(`[gemini-bridge] ${error.message}`);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|