110 lines
3.5 KiB
TypeScript
110 lines
3.5 KiB
TypeScript
import os from 'os';
|
|
import path from 'path';
|
|
|
|
import type { AgentType } from './types.js';
|
|
import { readEnvFile } from './env.js';
|
|
|
|
const envConfig = readEnvFile([
|
|
'ASSISTANT_NAME',
|
|
'ASSISTANT_HAS_OWN_NUMBER',
|
|
'SERVICE_ID',
|
|
'SERVICE_AGENT_TYPE',
|
|
'SESSION_COMMAND_ALLOWED_SENDERS',
|
|
'SESSION_COMMAND_USER_IDS',
|
|
'USAGE_DASHBOARD',
|
|
]);
|
|
|
|
export const ASSISTANT_NAME =
|
|
process.env.ASSISTANT_NAME || envConfig.ASSISTANT_NAME || 'Andy';
|
|
export const ASSISTANT_HAS_OWN_NUMBER =
|
|
(process.env.ASSISTANT_HAS_OWN_NUMBER ||
|
|
envConfig.ASSISTANT_HAS_OWN_NUMBER) === 'true';
|
|
const ASSISTANT_SLUG = ASSISTANT_NAME.trim().toLowerCase();
|
|
const rawServiceAgentType =
|
|
process.env.SERVICE_AGENT_TYPE || envConfig.SERVICE_AGENT_TYPE;
|
|
export const SERVICE_ID =
|
|
process.env.SERVICE_ID || envConfig.SERVICE_ID || ASSISTANT_SLUG;
|
|
export const SERVICE_AGENT_TYPE: AgentType =
|
|
rawServiceAgentType === 'codex' || rawServiceAgentType === 'claude-code'
|
|
? rawServiceAgentType
|
|
: ASSISTANT_SLUG === 'codex'
|
|
? 'codex'
|
|
: 'claude-code';
|
|
export const POLL_INTERVAL = 2000;
|
|
export const SCHEDULER_POLL_INTERVAL = 60000;
|
|
|
|
const PROJECT_ROOT = process.cwd();
|
|
const HOME_DIR = process.env.HOME || os.homedir();
|
|
|
|
export const SENDER_ALLOWLIST_PATH = path.join(
|
|
HOME_DIR,
|
|
'.config',
|
|
'nanoclaw',
|
|
'sender-allowlist.json',
|
|
);
|
|
export const STORE_DIR = path.resolve(
|
|
process.env.NANOCLAW_STORE_DIR || path.join(PROJECT_ROOT, 'store'),
|
|
);
|
|
export const GROUPS_DIR = path.resolve(
|
|
process.env.NANOCLAW_GROUPS_DIR || path.join(PROJECT_ROOT, 'groups'),
|
|
);
|
|
export const DATA_DIR = path.resolve(
|
|
process.env.NANOCLAW_DATA_DIR || path.join(PROJECT_ROOT, 'data'),
|
|
);
|
|
// Shared cache directory (same across both services for dedup)
|
|
export const CACHE_DIR = path.join(PROJECT_ROOT, 'cache');
|
|
|
|
export const AGENT_TIMEOUT = parseInt(
|
|
process.env.AGENT_TIMEOUT || '1800000',
|
|
10,
|
|
);
|
|
export const AGENT_MAX_OUTPUT_SIZE = parseInt(
|
|
process.env.AGENT_MAX_OUTPUT_SIZE || '10485760',
|
|
10,
|
|
); // 10MB default
|
|
export const IPC_POLL_INTERVAL = 1000;
|
|
export const IDLE_TIMEOUT = parseInt(process.env.IDLE_TIMEOUT || '1800000', 10); // 30min default — how long to keep agent alive after last result
|
|
export const MAX_CONCURRENT_AGENTS = Math.max(
|
|
1,
|
|
parseInt(process.env.MAX_CONCURRENT_AGENTS || '5', 10) || 5,
|
|
);
|
|
|
|
function escapeRegex(str: string): string {
|
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
}
|
|
|
|
export const TRIGGER_PATTERN = new RegExp(
|
|
`^@${escapeRegex(ASSISTANT_NAME)}\\b`,
|
|
'i',
|
|
);
|
|
|
|
// Status dashboard: Discord channel ID for live agent status updates
|
|
export const STATUS_CHANNEL_ID = process.env.STATUS_CHANNEL_ID || '';
|
|
export const STATUS_UPDATE_INTERVAL = 10000; // 10s
|
|
export const USAGE_UPDATE_INTERVAL = 300000; // 5 minutes
|
|
export const USAGE_DASHBOARD_ENABLED =
|
|
(process.env.USAGE_DASHBOARD || envConfig.USAGE_DASHBOARD) === 'true';
|
|
|
|
// Timezone for scheduled tasks (cron expressions, etc.)
|
|
// Uses system timezone by default
|
|
export const TIMEZONE =
|
|
process.env.TZ || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
|
|
const rawSessionCommandAllowedSenders =
|
|
process.env.SESSION_COMMAND_ALLOWED_SENDERS ||
|
|
process.env.SESSION_COMMAND_USER_IDS ||
|
|
envConfig.SESSION_COMMAND_ALLOWED_SENDERS ||
|
|
envConfig.SESSION_COMMAND_USER_IDS ||
|
|
'';
|
|
|
|
const SESSION_COMMAND_ALLOWED_SENDERS = new Set(
|
|
rawSessionCommandAllowedSenders
|
|
.split(',')
|
|
.map((value) => value.trim())
|
|
.filter(Boolean),
|
|
);
|
|
|
|
export function isSessionCommandSenderAllowed(sender: string): boolean {
|
|
return SESSION_COMMAND_ALLOWED_SENDERS.has(sender);
|
|
}
|