@virtengine/openfleet 0.25.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/.env.example +914 -0
- package/LICENSE +190 -0
- package/README.md +500 -0
- package/agent-endpoint.mjs +918 -0
- package/agent-hook-bridge.mjs +230 -0
- package/agent-hooks.mjs +1188 -0
- package/agent-pool.mjs +2403 -0
- package/agent-prompts.mjs +689 -0
- package/agent-sdk.mjs +141 -0
- package/anomaly-detector.mjs +1195 -0
- package/autofix.mjs +1294 -0
- package/claude-shell.mjs +708 -0
- package/cli.mjs +906 -0
- package/codex-config.mjs +1274 -0
- package/codex-model-profiles.mjs +135 -0
- package/codex-shell.mjs +762 -0
- package/config-doctor.mjs +613 -0
- package/config.mjs +1720 -0
- package/conflict-resolver.mjs +248 -0
- package/container-runner.mjs +450 -0
- package/copilot-shell.mjs +827 -0
- package/daemon-restart-policy.mjs +56 -0
- package/diff-stats.mjs +282 -0
- package/error-detector.mjs +829 -0
- package/fetch-runtime.mjs +34 -0
- package/fleet-coordinator.mjs +838 -0
- package/get-telegram-chat-id.mjs +71 -0
- package/git-safety.mjs +170 -0
- package/github-reconciler.mjs +403 -0
- package/hook-profiles.mjs +651 -0
- package/kanban-adapter.mjs +4491 -0
- package/lib/logger.mjs +645 -0
- package/maintenance.mjs +828 -0
- package/merge-strategy.mjs +1171 -0
- package/monitor.mjs +12207 -0
- package/openfleet.config.example.json +115 -0
- package/openfleet.schema.json +465 -0
- package/package.json +203 -0
- package/postinstall.mjs +187 -0
- package/pr-cleanup-daemon.mjs +978 -0
- package/preflight.mjs +408 -0
- package/prepublish-check.mjs +90 -0
- package/presence.mjs +328 -0
- package/primary-agent.mjs +282 -0
- package/publish.mjs +151 -0
- package/repo-root.mjs +29 -0
- package/restart-controller.mjs +100 -0
- package/review-agent.mjs +557 -0
- package/rotate-agent-logs.sh +133 -0
- package/sdk-conflict-resolver.mjs +973 -0
- package/session-tracker.mjs +880 -0
- package/setup.mjs +3937 -0
- package/shared-knowledge.mjs +410 -0
- package/shared-state-manager.mjs +841 -0
- package/shared-workspace-cli.mjs +199 -0
- package/shared-workspace-registry.mjs +537 -0
- package/shared-workspaces.json +18 -0
- package/startup-service.mjs +1070 -0
- package/sync-engine.mjs +1063 -0
- package/task-archiver.mjs +801 -0
- package/task-assessment.mjs +550 -0
- package/task-claims.mjs +924 -0
- package/task-complexity.mjs +581 -0
- package/task-executor.mjs +5111 -0
- package/task-store.mjs +753 -0
- package/telegram-bot.mjs +9281 -0
- package/telegram-sentinel.mjs +2010 -0
- package/ui/app.js +867 -0
- package/ui/app.legacy.js +1464 -0
- package/ui/app.monolith.js +2488 -0
- package/ui/components/charts.js +226 -0
- package/ui/components/chat-view.js +567 -0
- package/ui/components/command-palette.js +587 -0
- package/ui/components/diff-viewer.js +190 -0
- package/ui/components/forms.js +327 -0
- package/ui/components/kanban-board.js +451 -0
- package/ui/components/session-list.js +305 -0
- package/ui/components/shared.js +473 -0
- package/ui/index.html +70 -0
- package/ui/modules/api.js +297 -0
- package/ui/modules/icons.js +461 -0
- package/ui/modules/router.js +81 -0
- package/ui/modules/settings-schema.js +261 -0
- package/ui/modules/state.js +679 -0
- package/ui/modules/telegram.js +331 -0
- package/ui/modules/utils.js +270 -0
- package/ui/styles/animations.css +140 -0
- package/ui/styles/base.css +98 -0
- package/ui/styles/components.css +1915 -0
- package/ui/styles/kanban.css +286 -0
- package/ui/styles/layout.css +809 -0
- package/ui/styles/sessions.css +827 -0
- package/ui/styles/variables.css +188 -0
- package/ui/styles.css +141 -0
- package/ui/styles.monolith.css +1046 -0
- package/ui/tabs/agents.js +1417 -0
- package/ui/tabs/chat.js +74 -0
- package/ui/tabs/control.js +887 -0
- package/ui/tabs/dashboard.js +515 -0
- package/ui/tabs/infra.js +537 -0
- package/ui/tabs/logs.js +783 -0
- package/ui/tabs/settings.js +1487 -0
- package/ui/tabs/tasks.js +1385 -0
- package/ui-server.mjs +4073 -0
- package/update-check.mjs +465 -0
- package/utils.mjs +172 -0
- package/ve-kanban.mjs +654 -0
- package/ve-kanban.ps1 +1365 -0
- package/ve-kanban.sh +18 -0
- package/ve-orchestrator.mjs +340 -0
- package/ve-orchestrator.ps1 +6546 -0
- package/ve-orchestrator.sh +18 -0
- package/vibe-kanban-wrapper.mjs +41 -0
- package/vk-error-resolver.mjs +470 -0
- package/vk-log-stream.mjs +914 -0
- package/whatsapp-channel.mjs +520 -0
- package/workspace-monitor.mjs +581 -0
- package/workspace-reaper.mjs +405 -0
- package/workspace-registry.mjs +238 -0
- package/worktree-manager.mjs +1266 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────────────────────
|
|
2
|
+
* Settings Schema — Shared definition of all configurable env vars
|
|
3
|
+
* Used by both the Settings UI and the server-side settings API.
|
|
4
|
+
* ────────────────────────────────────────────────────────────── */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} SettingDef
|
|
8
|
+
* @property {string} key - Environment variable name
|
|
9
|
+
* @property {string} label - Human-readable label
|
|
10
|
+
* @property {string} description - Tooltip help text explaining the setting
|
|
11
|
+
* @property {string} category - Category ID for grouping
|
|
12
|
+
* @property {string} type - 'string' | 'number' | 'boolean' | 'select' | 'secret' | 'text'
|
|
13
|
+
* @property {*} [defaultVal] - Default value
|
|
14
|
+
* @property {string[]} [options] - Valid choices for 'select' type
|
|
15
|
+
* @property {boolean} [sensitive] - If true, value is masked in UI and excluded from GET responses
|
|
16
|
+
* @property {string} [validate] - Regex pattern string for validation
|
|
17
|
+
* @property {number} [min] - Min value for 'number' type
|
|
18
|
+
* @property {number} [max] - Max value for 'number' type
|
|
19
|
+
* @property {string} [unit] - Display unit (e.g., 'ms', 'min', 'sec')
|
|
20
|
+
* @property {boolean} [restart] - If true, changing requires process restart
|
|
21
|
+
* @property {boolean} [advanced] - If true, hidden unless "Show advanced" is on
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export const CATEGORIES = [
|
|
25
|
+
{ id: "telegram", label: "Telegram Bot", icon: "📱", description: "Bot token, chat, polling, and notification settings" },
|
|
26
|
+
{ id: "miniapp", label: "Mini App / UI", icon: "🖥️", description: "Web UI server, port, auth, and tunnel settings" },
|
|
27
|
+
{ id: "executor", label: "Executor / AI", icon: "⚡", description: "Agent execution, SDK selection, parallelism, and timeouts" },
|
|
28
|
+
{ id: "kanban", label: "Kanban / Tasks", icon: "📋", description: "Task backend, sync, labels, and project mapping" },
|
|
29
|
+
{ id: "github", label: "GitHub / Git", icon: "🐙", description: "Repository, auth, PR, merge, and reconciliation settings" },
|
|
30
|
+
{ id: "network", label: "Network / Tunnel", icon: "🌐", description: "Cloudflare tunnel, presence, and multi-instance coordination" },
|
|
31
|
+
{ id: "security", label: "Security / Sandbox", icon: "🛡️", description: "Sandbox mode, container isolation, and permissions" },
|
|
32
|
+
{ id: "sentinel", label: "Sentinel / Reliability", icon: "🔗", description: "Auto-restart, crash recovery, and repair agent settings" },
|
|
33
|
+
{ id: "hooks", label: "Agent Hooks", icon: "🪝", description: "Pre-push, pre-commit, and lifecycle hook configuration" },
|
|
34
|
+
{ id: "logging", label: "Logging / Monitoring", icon: "📊", description: "Work logs, error thresholds, cost tracking, and retention" },
|
|
35
|
+
{ id: "advanced", label: "Advanced", icon: "🔧", description: "Daemon, dev mode, paths, and low-level tuning" },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
/** @type {SettingDef[]} */
|
|
39
|
+
export const SETTINGS_SCHEMA = [
|
|
40
|
+
// ── Telegram Bot ──────────────────────────────────────────────
|
|
41
|
+
{ key: "TELEGRAM_BOT_TOKEN", label: "Bot Token", category: "telegram", type: "secret", sensitive: true, description: "Token from @BotFather. Required for all Telegram features.", restart: true },
|
|
42
|
+
{ key: "TELEGRAM_CHAT_ID", label: "Chat ID", category: "telegram", type: "secret", sensitive: true, description: "Primary chat/group ID for status messages and commands." },
|
|
43
|
+
{ key: "TELEGRAM_ALLOWED_CHAT_IDS", label: "Allowed Chat IDs", category: "telegram", type: "string", description: "Comma-separated list of chat IDs allowed to send commands. Leave empty to allow all.", validate: "^[0-9,\\-\\s]*$" },
|
|
44
|
+
{ key: "TELEGRAM_INTERVAL_MIN", label: "Status Interval", category: "telegram", type: "number", defaultVal: 10, min: 1, max: 1440, unit: "min", description: "Minutes between automatic status summary messages." },
|
|
45
|
+
{ key: "TELEGRAM_COMMAND_POLL_TIMEOUT_SEC", label: "Poll Timeout", category: "telegram", type: "number", defaultVal: 20, min: 5, max: 120, unit: "sec", description: "Long-polling timeout for receiving commands." },
|
|
46
|
+
{ key: "TELEGRAM_AGENT_TIMEOUT_MIN", label: "Agent Timeout", category: "telegram", type: "number", defaultVal: 90, min: 5, max: 720, unit: "min", description: "Maximum time an SDK-triggered agent can run before timeout." },
|
|
47
|
+
{ key: "TELEGRAM_COMMAND_CONCURRENCY", label: "Command Concurrency", category: "telegram", type: "number", defaultVal: 2, min: 1, max: 10, description: "Max concurrent command handlers." },
|
|
48
|
+
{ key: "TELEGRAM_VERBOSITY", label: "Message Verbosity", category: "telegram", type: "select", defaultVal: "summary", options: ["minimal", "summary", "detailed"], description: "Level of detail in Telegram status messages." },
|
|
49
|
+
{ key: "TELEGRAM_BATCH_NOTIFICATIONS", label: "Batch Notifications", category: "telegram", type: "boolean", defaultVal: false, description: "Batch multiple notifications into periodic digests instead of sending individually." },
|
|
50
|
+
{ key: "TELEGRAM_BATCH_INTERVAL_SEC", label: "Batch Interval", category: "telegram", type: "number", defaultVal: 300, min: 30, max: 3600, unit: "sec", description: "Seconds between batch flushes when batching is enabled.", advanced: true },
|
|
51
|
+
{ key: "TELEGRAM_BATCH_MAX_SIZE", label: "Batch Max Size", category: "telegram", type: "number", defaultVal: 50, min: 5, max: 500, description: "Force flush batch when it reaches this many messages.", advanced: true },
|
|
52
|
+
{ key: "TELEGRAM_IMMEDIATE_PRIORITY", label: "Immediate Priority", category: "telegram", type: "select", defaultVal: "1", options: ["1", "2", "3"], description: "Messages at or above this priority send immediately even when batching. 1=critical only, 2=+errors, 3=+warnings.", advanced: true },
|
|
53
|
+
{ key: "TELEGRAM_API_BASE_URL", label: "API Base URL", category: "telegram", type: "string", defaultVal: "https://api.telegram.org", description: "Override for Telegram API proxy.", advanced: true, validate: "^https?://" },
|
|
54
|
+
{ key: "TELEGRAM_HTTP_TIMEOUT_MS", label: "HTTP Timeout", category: "telegram", type: "number", defaultVal: 15000, min: 5000, max: 60000, unit: "ms", description: "Per-request timeout for Telegram API calls.", advanced: true },
|
|
55
|
+
{ key: "TELEGRAM_RETRY_ATTEMPTS", label: "Retry Attempts", category: "telegram", type: "number", defaultVal: 4, min: 0, max: 10, description: "Number of retry attempts for transient Telegram API failures.", advanced: true },
|
|
56
|
+
{ key: "PROJECT_NAME", label: "Project Name", category: "telegram", type: "string", description: "Display name used in Telegram messages and logs. Auto-detected from package.json if not set." },
|
|
57
|
+
|
|
58
|
+
// ── Mini App / UI Server ──────────────────────────────────────
|
|
59
|
+
{ key: "TELEGRAM_MINIAPP_ENABLED", label: "Enable Mini App", category: "miniapp", type: "boolean", defaultVal: false, description: "Enable the Telegram Mini App web UI server.", restart: true },
|
|
60
|
+
{ key: "TELEGRAM_UI_PORT", label: "UI Port", category: "miniapp", type: "number", min: 1024, max: 65535, description: "HTTP/HTTPS port for the Mini App server. Required when enabled.", restart: true },
|
|
61
|
+
{ key: "TELEGRAM_UI_HOST", label: "Bind Host", category: "miniapp", type: "string", defaultVal: "0.0.0.0", description: "Network interface to bind. Use 127.0.0.1 for local-only access.", restart: true },
|
|
62
|
+
{ key: "TELEGRAM_UI_PUBLIC_HOST", label: "Public Host", category: "miniapp", type: "string", description: "Public hostname if behind a reverse proxy. Auto-detected if not set." },
|
|
63
|
+
{ key: "TELEGRAM_UI_BASE_URL", label: "Base URL Override", category: "miniapp", type: "string", description: "Full public URL (e.g., https://my-domain.com). Takes precedence over auto-detection.", validate: "^https?://" },
|
|
64
|
+
{ key: "TELEGRAM_UI_ALLOW_UNSAFE", label: "Allow Unsafe (No Auth)", category: "miniapp", type: "boolean", defaultVal: false, description: "⚠️ DANGER: Disables ALL authentication. Only for local development.", restart: true },
|
|
65
|
+
{ key: "TELEGRAM_UI_AUTH_MAX_AGE_SEC", label: "Auth Token Max Age", category: "miniapp", type: "number", defaultVal: 86400, min: 300, max: 604800, unit: "sec", description: "Maximum age for Telegram initData tokens before they expire." },
|
|
66
|
+
{ key: "TELEGRAM_UI_TUNNEL", label: "Tunnel Mode", category: "miniapp", type: "select", defaultVal: "auto", options: ["auto", "cloudflared", "disabled"], description: "Cloudflare tunnel mode. 'auto' starts tunnel if cloudflared is available.", restart: true },
|
|
67
|
+
|
|
68
|
+
// ── Executor / AI ──────────────────────────────────────────
|
|
69
|
+
{ key: "EXECUTOR_MODE", label: "Executor Mode", category: "executor", type: "select", defaultVal: "vk", options: ["vk", "internal", "hybrid"], description: "Task execution mode. 'internal' uses built-in agent pool, 'vk' delegates to Vibe-Kanban, 'hybrid' uses both.", restart: true },
|
|
70
|
+
{ key: "INTERNAL_EXECUTOR_PARALLEL", label: "Max Parallel Agents", category: "executor", type: "number", defaultVal: 3, min: 1, max: 20, description: "Maximum number of concurrent agent execution slots." },
|
|
71
|
+
{ key: "INTERNAL_EXECUTOR_SDK", label: "Default SDK", category: "executor", type: "select", defaultVal: "auto", options: ["auto", "codex", "copilot", "claude"], description: "Default AI SDK for task execution. 'auto' selects based on availability and task complexity." },
|
|
72
|
+
{ key: "INTERNAL_EXECUTOR_TIMEOUT_MS", label: "Task Timeout", category: "executor", type: "number", defaultVal: 5400000, min: 60000, max: 14400000, unit: "ms", description: "Maximum time a single task execution can run (default: 90 min)." },
|
|
73
|
+
{ key: "INTERNAL_EXECUTOR_MAX_RETRIES", label: "Max Retries", category: "executor", type: "number", defaultVal: 2, min: 0, max: 10, description: "Number of automatic retries per task before marking as failed." },
|
|
74
|
+
{ key: "INTERNAL_EXECUTOR_POLL_MS", label: "Poll Interval", category: "executor", type: "number", defaultVal: 30000, min: 5000, max: 300000, unit: "ms", description: "How often the executor polls the kanban board for new tasks.", advanced: true },
|
|
75
|
+
{ key: "INTERNAL_EXECUTOR_REVIEW_AGENT_ENABLED", label: "PR Review Agent", category: "executor", type: "boolean", defaultVal: true, description: "Enable automatic PR review handoff after task completion." },
|
|
76
|
+
{ key: "INTERNAL_EXECUTOR_REPLENISH_ENABLED", label: "Auto Replenish Backlog", category: "executor", type: "boolean", defaultVal: false, description: "Automatically generate new tasks when backlog is low." },
|
|
77
|
+
{ key: "PRIMARY_AGENT", label: "Primary Agent SDK", category: "executor", type: "select", defaultVal: "codex-sdk", options: ["codex-sdk", "copilot-sdk", "claude-sdk"], description: "Which AI SDK handles primary agent sessions and chat commands." },
|
|
78
|
+
{ key: "EXECUTORS", label: "Executor Distribution", category: "executor", type: "string", defaultVal: "CODEX:DEFAULT:100", description: "Weighted executor configuration. Format: TYPE:VARIANT:WEIGHT,... (e.g., CODEX:DEFAULT:70,COPILOT:DEFAULT:30)", validate: "^[A-Z_]+:[A-Z_]+:\\d+" },
|
|
79
|
+
{ key: "EXECUTOR_DISTRIBUTION", label: "Distribution Strategy", category: "executor", type: "select", defaultVal: "weighted", options: ["weighted", "round-robin", "primary-only"], description: "How tasks are distributed across configured executors.", advanced: true },
|
|
80
|
+
{ key: "FAILOVER_STRATEGY", label: "Failover Strategy", category: "executor", type: "select", defaultVal: "next-in-line", options: ["next-in-line", "weighted-random", "round-robin"], description: "Strategy for selecting next executor when the primary fails.", advanced: true },
|
|
81
|
+
{ key: "COMPLEXITY_ROUTING_ENABLED", label: "Complexity Routing", category: "executor", type: "boolean", defaultVal: true, description: "Automatically route tasks to different AI models based on estimated complexity.", advanced: true },
|
|
82
|
+
{ key: "PROJECT_REQUIREMENTS_PROFILE", label: "Requirements Profile", category: "executor", type: "select", defaultVal: "feature", options: ["simple-feature", "feature", "large-feature", "system", "multi-system"], description: "Project complexity profile for task generation and planning." },
|
|
83
|
+
|
|
84
|
+
// ── AI Provider Keys ────────────────────────────────────────
|
|
85
|
+
{ key: "OPENAI_API_KEY", label: "OpenAI API Key", category: "executor", type: "secret", sensitive: true, description: "OpenAI API key for Codex SDK. Required if using Codex executor." },
|
|
86
|
+
{ key: "AZURE_OPENAI_API_KEY", label: "Azure API Key", category: "executor", type: "secret", sensitive: true, description: "Azure OpenAI API key (used when provider/profile is azure)." },
|
|
87
|
+
{ key: "CODEX_MODEL", label: "Codex Model", category: "executor", type: "string", defaultVal: "gpt-4o", description: "Model for Codex SDK. E.g., gpt-4o, o3, o4-mini." },
|
|
88
|
+
{ key: "CODEX_MODEL_PROFILE", label: "Active Model Profile", category: "executor", type: "select", defaultVal: "xl", options: ["xl", "m"], description: "Select active Codex model profile for runtime sessions." },
|
|
89
|
+
{ key: "CODEX_MODEL_PROFILE_SUBAGENT", label: "Subagent Profile", category: "executor", type: "select", defaultVal: "m", options: ["xl", "m"], description: "Default profile to prefer for subagent-style delegated work." },
|
|
90
|
+
{ key: "CODEX_MODEL_PROFILE_XL_PROVIDER", label: "XL Provider", category: "executor", type: "select", defaultVal: "openai", options: ["openai", "azure", "compatible"], description: "Provider for XL profile." },
|
|
91
|
+
{ key: "CODEX_MODEL_PROFILE_XL_MODEL", label: "XL Model", category: "executor", type: "string", defaultVal: "gpt-5.3-codex", description: "Model/deployment name for XL profile." },
|
|
92
|
+
{ key: "CODEX_MODEL_PROFILE_XL_BASE_URL", label: "XL Base URL", category: "executor", type: "string", description: "Optional base URL override for XL profile.", validate: "^$|^https?://" },
|
|
93
|
+
{ key: "CODEX_MODEL_PROFILE_XL_API_KEY", label: "XL API Key", category: "executor", type: "secret", sensitive: true, description: "Optional profile-scoped API key for XL profile." },
|
|
94
|
+
{ key: "CODEX_MODEL_PROFILE_M_PROVIDER", label: "M Provider", category: "executor", type: "select", defaultVal: "openai", options: ["openai", "azure", "compatible"], description: "Provider for M profile." },
|
|
95
|
+
{ key: "CODEX_MODEL_PROFILE_M_MODEL", label: "M Model", category: "executor", type: "string", defaultVal: "gpt-5.1-codex-mini", description: "Model/deployment name for M profile." },
|
|
96
|
+
{ key: "CODEX_MODEL_PROFILE_M_BASE_URL", label: "M Base URL", category: "executor", type: "string", description: "Optional base URL override for M profile.", validate: "^$|^https?://" },
|
|
97
|
+
{ key: "CODEX_MODEL_PROFILE_M_API_KEY", label: "M API Key", category: "executor", type: "secret", sensitive: true, description: "Optional profile-scoped API key for M profile." },
|
|
98
|
+
{ key: "CODEX_SUBAGENT_MODEL", label: "Subagent Model", category: "executor", type: "string", defaultVal: "gpt-5.1-codex-mini", description: "Preferred lightweight model for delegated/subagent work." },
|
|
99
|
+
{ key: "ANTHROPIC_API_KEY", label: "Anthropic API Key", category: "executor", type: "secret", sensitive: true, description: "Anthropic API key for Claude SDK. Required if using Claude executor." },
|
|
100
|
+
{ key: "CLAUDE_MODEL", label: "Claude Model", category: "executor", type: "string", defaultVal: "claude-opus-4-6", description: "Model for Claude SDK. E.g., claude-opus-4-6, claude-sonnet-4-5." },
|
|
101
|
+
{ key: "COPILOT_MODEL", label: "Copilot Model", category: "executor", type: "string", defaultVal: "gpt-5", description: "Model for Copilot SDK sessions." },
|
|
102
|
+
{ key: "COPILOT_CLI_TOKEN", label: "Copilot CLI Token", category: "executor", type: "secret", sensitive: true, description: "Auth token for Copilot CLI remote mode." },
|
|
103
|
+
|
|
104
|
+
// ── Kanban / Tasks ─────────────────────────────────────────
|
|
105
|
+
{ key: "KANBAN_BACKEND", label: "Kanban Backend", category: "kanban", type: "select", defaultVal: "internal", options: ["internal", "vk", "github", "jira"], description: "Task management backend. 'internal' uses built-in store, 'github' syncs with GitHub Issues/Projects." },
|
|
106
|
+
{ key: "KANBAN_SYNC_POLICY", label: "Sync Policy", category: "kanban", type: "select", defaultVal: "internal-primary", options: ["internal-primary", "bidirectional"], description: "How tasks sync between internal store and external backend." },
|
|
107
|
+
{ key: "CODEX_MONITOR_TASK_LABEL", label: "Task Label", category: "kanban", type: "string", defaultVal: "openfleet", description: "GitHub label used to scope which issues are managed by Codex Monitor." },
|
|
108
|
+
{ key: "CODEX_MONITOR_ENFORCE_TASK_LABEL", label: "Enforce Task Label", category: "kanban", type: "boolean", defaultVal: true, description: "Only pick up issues that have the task label. Prevents processing unrelated issues." },
|
|
109
|
+
{ key: "STALE_TASK_AGE_HOURS", label: "Stale Task Age", category: "kanban", type: "number", defaultVal: 3, min: 1, max: 168, unit: "hours", description: "Hours before an in-progress task with no activity is considered stale and eligible for recovery." },
|
|
110
|
+
{ key: "TASK_PLANNER_MODE", label: "Task Planner Mode", category: "kanban", type: "select", defaultVal: "kanban", options: ["kanban", "codex-sdk", "disabled"], description: "How the autonomous task planner operates. 'disabled' turns off automatic task generation." },
|
|
111
|
+
{ key: "TASK_PLANNER_DEDUP_HOURS", label: "Planner Dedup Window", category: "kanban", type: "number", defaultVal: 6, min: 1, max: 72, unit: "hours", description: "Hours to look back for duplicate task detection.", advanced: true },
|
|
112
|
+
{ key: "CODEX_MONITOR_PROMPT_PLANNER", label: "Planner Prompt Path", category: "advanced", type: "string", description: "Override the task planner prompt file path.", advanced: true },
|
|
113
|
+
|
|
114
|
+
// ── GitHub / Git ─────────────────────────────────────────
|
|
115
|
+
{ key: "GITHUB_TOKEN", label: "GitHub Token", category: "github", type: "secret", sensitive: true, description: "Personal access token or fine-grained token for GitHub API. Required for GitHub kanban backend." },
|
|
116
|
+
{ key: "GITHUB_REPOSITORY", label: "Repository", category: "github", type: "string", description: "GitHub repository in owner/repo format. Auto-detected from git remote if not set.", validate: "^[\\w.-]+/[\\w.-]+$" },
|
|
117
|
+
{ key: "GITHUB_PROJECT_MODE", label: "Project Mode", category: "github", type: "select", defaultVal: "issues", options: ["issues", "kanban"], description: "Use GitHub Issues directly, or GitHub Projects v2 kanban board." },
|
|
118
|
+
{ key: "GITHUB_PROJECT_NUMBER", label: "Project Number", category: "github", type: "number", min: 1, description: "GitHub Projects v2 number. Required when project mode is 'kanban'." },
|
|
119
|
+
{ key: "GITHUB_PROJECT_WEBHOOK_PATH", label: "Project Webhook Path", category: "github", type: "string", description: "HTTP path exposed by the UI server for GitHub webhook deliveries.", validate: "^/.*", advanced: true },
|
|
120
|
+
{ key: "GITHUB_PROJECT_WEBHOOK_SECRET", label: "Project Webhook Secret", category: "github", type: "secret", sensitive: true, description: "Shared secret to validate GitHub webhook signatures.", advanced: true },
|
|
121
|
+
{ key: "GITHUB_PROJECT_WEBHOOK_REQUIRE_SIGNATURE", label: "Require Webhook Signature", category: "github", type: "boolean", defaultVal: false, description: "Reject webhook payloads unless signature validation succeeds.", advanced: true },
|
|
122
|
+
{ key: "GITHUB_PROJECT_SYNC_ALERT_FAILURE_THRESHOLD", label: "Sync Failure Alert Threshold", category: "github", type: "number", defaultVal: 3, min: 1, max: 20, description: "Consecutive project sync failures that trigger an alert.", advanced: true },
|
|
123
|
+
{ key: "GITHUB_PROJECT_SYNC_RATE_LIMIT_ALERT_THRESHOLD", label: "Rate Limit Alert Threshold", category: "github", type: "number", defaultVal: 3, min: 1, max: 20, description: "Rate-limit events before triggering an alert.", advanced: true },
|
|
124
|
+
{ key: "GITHUB_DEFAULT_ASSIGNEE", label: "Default Assignee", category: "github", type: "string", description: "GitHub username to assign new issues to. Uses authenticated user if not set." },
|
|
125
|
+
{ key: "GITHUB_AUTO_ASSIGN_CREATOR", label: "Auto-Assign Creator", category: "github", type: "boolean", defaultVal: true, description: "Automatically assign the authenticated user when creating issues." },
|
|
126
|
+
{ key: "VK_TARGET_BRANCH", label: "Target Branch", category: "github", type: "string", defaultVal: "origin/main", description: "Default base branch for PR comparisons and merge targets." },
|
|
127
|
+
{ key: "CODEX_ANALYZE_MERGE_STRATEGY", label: "Merge Analysis", category: "github", type: "boolean", defaultVal: true, description: "Enable intelligent merge strategy analysis for PRs." },
|
|
128
|
+
{ key: "DEPENDABOT_AUTO_MERGE", label: "Dependabot Auto-Merge", category: "github", type: "boolean", defaultVal: true, description: "Automatically merge passing Dependabot PRs." },
|
|
129
|
+
{ key: "GH_RECONCILE_ENABLED", label: "Issue Reconciler", category: "github", type: "boolean", defaultVal: true, description: "Auto-close issues when their associated PR is merged." },
|
|
130
|
+
|
|
131
|
+
// ── Network / Tunnel ──────────────────────────────────────
|
|
132
|
+
{ key: "CLOUDFLARE_TUNNEL_NAME", label: "Tunnel Name", category: "network", type: "string", description: "Named Cloudflare tunnel for persistent URL. Leave empty for random quick tunnel." },
|
|
133
|
+
{ key: "CLOUDFLARE_TUNNEL_CREDENTIALS", label: "Tunnel Credentials", category: "network", type: "secret", sensitive: true, description: "Path to Cloudflare tunnel credentials JSON file." },
|
|
134
|
+
{ key: "TELEGRAM_PRESENCE_INTERVAL_SEC", label: "Presence Interval", category: "network", type: "number", defaultVal: 60, min: 10, max: 600, unit: "sec", description: "How often this instance announces its presence to the coordinator." },
|
|
135
|
+
{ key: "TELEGRAM_PRESENCE_DISABLED", label: "Disable Presence", category: "network", type: "boolean", defaultVal: false, description: "Disable multi-instance presence entirely." },
|
|
136
|
+
{ key: "VE_INSTANCE_LABEL", label: "Instance Label", category: "network", type: "string", description: "Human-friendly name for this instance in multi-instance setups." },
|
|
137
|
+
{ key: "VE_COORDINATOR_ELIGIBLE", label: "Coordinator Eligible", category: "network", type: "boolean", defaultVal: true, description: "Whether this instance can be elected as coordinator in multi-instance mode." },
|
|
138
|
+
{ key: "VE_COORDINATOR_PRIORITY", label: "Coordinator Priority", category: "network", type: "number", defaultVal: 10, min: 1, max: 100, description: "Lower value = higher priority in coordinator election." },
|
|
139
|
+
{ key: "FLEET_ENABLED", label: "Fleet Enabled", category: "network", type: "boolean", defaultVal: true, description: "Enable multi-workstation fleet coordination.", advanced: true },
|
|
140
|
+
{ key: "FLEET_BUFFER_MULTIPLIER", label: "Fleet Buffer Multiplier", category: "network", type: "number", defaultVal: 3, min: 1, unit: "x", description: "Scale the planning buffer when coordinating across instances.", advanced: true },
|
|
141
|
+
{ key: "FLEET_SYNC_INTERVAL_MS", label: "Fleet Sync Interval", category: "network", type: "number", defaultVal: 120000, min: 10000, max: 3600000, unit: "ms", description: "How often fleet state is synced across instances.", advanced: true },
|
|
142
|
+
{ key: "FLEET_PRESENCE_TTL_MS", label: "Fleet Presence TTL", category: "network", type: "number", defaultVal: 300000, min: 60000, max: 3600000, unit: "ms", description: "Time before a fleet instance is considered offline.", advanced: true },
|
|
143
|
+
{ key: "FLEET_KNOWLEDGE_ENABLED", label: "Fleet Knowledge Enabled", category: "network", type: "boolean", defaultVal: true, description: "Share local knowledge files across the fleet.", advanced: true },
|
|
144
|
+
{ key: "FLEET_KNOWLEDGE_FILE", label: "Fleet Knowledge File", category: "network", type: "string", defaultVal: "AGENTS.md", description: "Knowledge file name to share across fleet members.", advanced: true },
|
|
145
|
+
|
|
146
|
+
// ── Security / Sandbox ────────────────────────────────────
|
|
147
|
+
{ key: "CODEX_SANDBOX", label: "Sandbox Mode", category: "security", type: "select", defaultVal: "workspace-write", options: ["workspace-write", "danger-full-access", "read-only"], description: "Agent filesystem access level. 'workspace-write' is permissive within workspace while avoiding full host access." },
|
|
148
|
+
{ key: "CODEX_FEATURES_BWRAP", label: "Bubblewrap Sandbox", category: "security", type: "boolean", defaultVal: true, description: "Enable Linux bubblewrap sandbox. Disable if user namespaces are blocked (bwrap uid map errors)." },
|
|
149
|
+
{ key: "CODEX_SANDBOX_PERMISSIONS", label: "Sandbox Permissions", category: "security", type: "string", defaultVal: "disk-full-write-access", description: "Comma-separated sandbox permission entries for Codex CLI config." },
|
|
150
|
+
{ key: "CODEX_SANDBOX_WRITABLE_ROOTS", label: "Writable Roots", category: "security", type: "string", description: "Comma-separated writable roots for workspace-write sandbox (include repo/.git as needed)." },
|
|
151
|
+
{ key: "CONTAINER_ENABLED", label: "Container Isolation", category: "security", type: "boolean", defaultVal: false, description: "Run agent tasks inside Docker/Podman containers for OS-level isolation.", restart: true },
|
|
152
|
+
{ key: "CONTAINER_RUNTIME", label: "Container Runtime", category: "security", type: "select", defaultVal: "docker", options: ["auto", "docker", "podman", "container"], description: "Container engine to use for isolated execution." },
|
|
153
|
+
{ key: "CONTAINER_IMAGE", label: "Container Image", category: "security", type: "string", defaultVal: "node:22-slim", description: "Docker image for agent execution containers." },
|
|
154
|
+
{ key: "CONTAINER_TIMEOUT_MS", label: "Container Timeout", category: "security", type: "number", defaultVal: 1800000, min: 60000, max: 7200000, unit: "ms", description: "Maximum time a container can run before being killed (default: 30 min)." },
|
|
155
|
+
{ key: "MAX_CONCURRENT_CONTAINERS", label: "Max Containers", category: "security", type: "number", defaultVal: 3, min: 1, max: 10, description: "Maximum number of concurrent agent containers." },
|
|
156
|
+
{ key: "CONTAINER_MEMORY_LIMIT", label: "Memory Limit", category: "security", type: "string", description: "Container memory limit (e.g., '4g', '2048m'). Leave empty for no limit.", validate: "^\\d+[kmg]?$" },
|
|
157
|
+
{ key: "CONTAINER_CPU_LIMIT", label: "CPU Limit", category: "security", type: "string", description: "Container CPU limit (e.g., '2', '1.5'). Leave empty for no limit.", validate: "^\\d+\\.?\\d*$" },
|
|
158
|
+
|
|
159
|
+
// ── Sentinel / Reliability ─────────────────────────────────
|
|
160
|
+
{ key: "CODEX_MONITOR_SENTINEL_AUTO_START", label: "Auto-Start Sentinel", category: "sentinel", type: "boolean", defaultVal: false, description: "Automatically start the sentinel watchdog on boot." },
|
|
161
|
+
{ key: "SENTINEL_AUTO_RESTART_MONITOR", label: "Auto-Restart on Crash", category: "sentinel", type: "boolean", defaultVal: true, description: "Automatically restart the monitor process if it crashes." },
|
|
162
|
+
{ key: "SENTINEL_CRASH_LOOP_THRESHOLD", label: "Crash Loop Threshold", category: "sentinel", type: "number", defaultVal: 3, min: 2, max: 20, description: "Number of crashes within the window before declaring a crash loop." },
|
|
163
|
+
{ key: "SENTINEL_CRASH_LOOP_WINDOW_MIN", label: "Crash Loop Window", category: "sentinel", type: "number", defaultVal: 10, min: 2, max: 60, unit: "min", description: "Rolling time window for crash loop detection." },
|
|
164
|
+
{ key: "SENTINEL_REPAIR_AGENT_ENABLED", label: "Repair Agent", category: "sentinel", type: "boolean", defaultVal: true, description: "Enable AI-powered repair agent when a crash loop is detected." },
|
|
165
|
+
{ key: "SENTINEL_REPAIR_TIMEOUT_MIN", label: "Repair Timeout", category: "sentinel", type: "number", defaultVal: 20, min: 5, max: 120, unit: "min", description: "Maximum time the repair agent can run." },
|
|
166
|
+
|
|
167
|
+
// ── Agent Hooks ────────────────────────────────────────────
|
|
168
|
+
{ key: "CODEX_MONITOR_HOOK_PROFILE", label: "Hook Profile", category: "hooks", type: "select", defaultVal: "strict", options: ["strict", "balanced", "lightweight", "none"], description: "Pre-configured hook intensity. 'strict' runs all checks, 'none' disables hooks." },
|
|
169
|
+
{ key: "CODEX_MONITOR_HOOK_TARGETS", label: "Hook Targets", category: "hooks", type: "string", defaultVal: "codex,claude,copilot", description: "Comma-separated list of agent SDKs to install hooks for.", validate: "^[a-z,]+$" },
|
|
170
|
+
{ key: "CODEX_MONITOR_HOOKS_ENABLED", label: "Enable Hooks", category: "hooks", type: "boolean", defaultVal: true, description: "Enable agent lifecycle hook scaffolding." },
|
|
171
|
+
{ key: "CODEX_MONITOR_HOOKS_OVERWRITE", label: "Overwrite Existing", category: "hooks", type: "boolean", defaultVal: false, description: "Overwrite existing hook files when installing. Use with caution." },
|
|
172
|
+
{ key: "CODEX_MONITOR_HOOKS_BUILTINS_MODE", label: "Built-ins Mode", category: "hooks", type: "select", defaultVal: "force", options: ["force", "auto", "off"], description: "How built-in hooks are managed. 'force' always installs, 'auto' only if missing." },
|
|
173
|
+
|
|
174
|
+
// ── Logging / Monitoring ────────────────────────────────────
|
|
175
|
+
{ key: "AGENT_WORK_LOGGING_ENABLED", label: "Work Logging", category: "logging", type: "boolean", defaultVal: true, description: "Enable structured agent work logging with transcripts." },
|
|
176
|
+
{ key: "AGENT_WORK_ANALYZER_ENABLED", label: "Live Analyzer", category: "logging", type: "boolean", defaultVal: true, description: "Enable real-time agent output stream analysis for anomaly detection." },
|
|
177
|
+
{ key: "AGENT_SESSION_LOG_RETENTION", label: "Session Retention", category: "logging", type: "number", defaultVal: 100, min: 10, max: 10000, description: "Number of agent session transcripts to keep before rotation." },
|
|
178
|
+
{ key: "AGENT_ERROR_LOOP_THRESHOLD", label: "Error Loop Threshold", category: "logging", type: "number", defaultVal: 4, min: 2, max: 20, description: "Errors in a 10-minute window that trigger a loop alert." },
|
|
179
|
+
{ key: "AGENT_STUCK_THRESHOLD_MS", label: "Stuck Detection", category: "logging", type: "number", defaultVal: 300000, min: 60000, max: 1800000, unit: "ms", description: "Idle time before an agent is considered stuck." },
|
|
180
|
+
{ key: "LOG_MAX_SIZE_MB", label: "Max Log Size", category: "logging", type: "number", defaultVal: 500, min: 0, max: 10000, unit: "MB", description: "Maximum total log size before rotation. 0 = unlimited." },
|
|
181
|
+
|
|
182
|
+
// ── Advanced ────────────────────────────────────────────────
|
|
183
|
+
{ key: "DEVMODE", label: "Dev Mode", category: "advanced", type: "boolean", defaultVal: false, description: "Enable development mode with extra logging, self-restart watcher, and debug endpoints." },
|
|
184
|
+
{ key: "SELF_RESTART_WATCH_ENABLED", label: "Self-Restart Watcher", category: "advanced", type: "boolean", description: "Auto-restart when source files change. Defaults to true in devmode." },
|
|
185
|
+
{ key: "MAX_PARALLEL", label: "Global Max Parallel", category: "advanced", type: "number", defaultVal: 6, min: 1, max: 50, description: "Global maximum parallel task slots across all executors." },
|
|
186
|
+
{ key: "RESTART_DELAY_MS", label: "Restart Delay", category: "advanced", type: "number", defaultVal: 10000, min: 1000, max: 60000, unit: "ms", description: "Delay before restarting after a crash." },
|
|
187
|
+
{ key: "SHARED_STATE_ENABLED", label: "Shared State", category: "advanced", type: "boolean", defaultVal: true, description: "Enable distributed task coordination for multi-instance setups." },
|
|
188
|
+
{ key: "SHARED_STATE_STALE_THRESHOLD_MS", label: "Stale Threshold", category: "advanced", type: "number", defaultVal: 300000, min: 60000, max: 1800000, unit: "ms", description: "Time before a heartbeat is considered stale.", advanced: true },
|
|
189
|
+
{ key: "VE_CI_SWEEP_EVERY", label: "CI Sweep Interval", category: "advanced", type: "number", defaultVal: 15, min: 1, max: 100, description: "Trigger CI sweep after every N completed tasks.", advanced: true },
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get settings grouped by category.
|
|
194
|
+
* @param {boolean} includeAdvanced - Include settings marked as advanced
|
|
195
|
+
* @returns {Map<string, SettingDef[]>}
|
|
196
|
+
*/
|
|
197
|
+
export function getGroupedSettings(includeAdvanced = false) {
|
|
198
|
+
const groups = new Map();
|
|
199
|
+
for (const cat of CATEGORIES) groups.set(cat.id, []);
|
|
200
|
+
for (const s of SETTINGS_SCHEMA) {
|
|
201
|
+
if (!includeAdvanced && s.advanced) continue;
|
|
202
|
+
const list = groups.get(s.category);
|
|
203
|
+
if (list) list.push(s);
|
|
204
|
+
}
|
|
205
|
+
return groups;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Validate a value against a setting definition.
|
|
210
|
+
* @param {SettingDef} def
|
|
211
|
+
* @param {string} value
|
|
212
|
+
* @returns {{ valid: boolean, error?: string }}
|
|
213
|
+
*/
|
|
214
|
+
export function validateSetting(def, value) {
|
|
215
|
+
if (value === "" || value == null) return { valid: true };
|
|
216
|
+
if (def.key === "CODEX_MONITOR_HOOK_TARGETS") {
|
|
217
|
+
const targets = String(value || "")
|
|
218
|
+
.split(",")
|
|
219
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
220
|
+
.filter(Boolean);
|
|
221
|
+
const allowed = new Set(["codex", "claude", "copilot", "all"]);
|
|
222
|
+
const invalid = targets.filter((entry) => !allowed.has(entry));
|
|
223
|
+
if (invalid.length > 0) {
|
|
224
|
+
return {
|
|
225
|
+
valid: false,
|
|
226
|
+
error: `Invalid targets: ${invalid.join(", ")}`,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return { valid: true };
|
|
230
|
+
}
|
|
231
|
+
switch (def.type) {
|
|
232
|
+
case "number": {
|
|
233
|
+
const n = Number(value);
|
|
234
|
+
if (isNaN(n)) return { valid: false, error: "Must be a number" };
|
|
235
|
+
if (def.min != null && n < def.min) return { valid: false, error: `Minimum: ${def.min}` };
|
|
236
|
+
if (def.max != null && n > def.max) return { valid: false, error: `Maximum: ${def.max}` };
|
|
237
|
+
return { valid: true };
|
|
238
|
+
}
|
|
239
|
+
case "boolean":
|
|
240
|
+
if (!["true", "false", "1", "0", ""].includes(String(value).toLowerCase()))
|
|
241
|
+
return { valid: false, error: "Must be true or false" };
|
|
242
|
+
return { valid: true };
|
|
243
|
+
case "select":
|
|
244
|
+
if (def.options && !def.options.includes(String(value)))
|
|
245
|
+
return { valid: false, error: `Must be one of: ${def.options.join(", ")}` };
|
|
246
|
+
return { valid: true };
|
|
247
|
+
default:
|
|
248
|
+
if (def.validate) {
|
|
249
|
+
try {
|
|
250
|
+
if (!new RegExp(def.validate).test(value))
|
|
251
|
+
return { valid: false, error: `Invalid format` };
|
|
252
|
+
} catch { /* ignore bad regex */ }
|
|
253
|
+
}
|
|
254
|
+
return { valid: true };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** List of env var keys that are sensitive and should never be returned in full via API. */
|
|
259
|
+
export const SENSITIVE_KEYS = new Set(
|
|
260
|
+
SETTINGS_SCHEMA.filter((s) => s.sensitive).map((s) => s.key),
|
|
261
|
+
);
|