@inetafrica/open-claudia 2.15.0 → 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/.env.example +30 -4
- package/CHANGELOG.md +22 -0
- package/README.md +87 -66
- package/bin/agent.js +44 -18
- package/bin/cli.js +30 -28
- package/bin/dream.js +5 -11
- package/bin/loopback-client.js +29 -5
- package/bin/schedule.js +19 -5
- package/bin/tool.js +23 -5
- package/bot-agent.js +5 -2350
- package/bot.js +81 -3
- package/channels/telegram/adapter.js +65 -5
- package/channels/voice/adapter.js +1 -0
- package/channels/voice/manage.js +43 -5
- package/config-dir.js +3 -11
- package/core/actions.js +155 -40
- package/core/approvals.js +136 -29
- package/core/auth-flow.js +103 -19
- package/core/config-dir.js +19 -0
- package/core/config.js +115 -69
- package/core/doctor.js +111 -57
- package/core/dream.js +219 -62
- package/core/enforcer.js +0 -0
- package/core/entities.js +2 -1
- package/core/fsutil.js +21 -4
- package/core/handlers.js +542 -224
- package/core/ideas.js +2 -1
- package/core/jobs.js +589 -72
- package/core/lessons.js +3 -2
- package/core/loopback.js +42 -6
- package/core/memory-mutation-queue.js +241 -0
- package/core/migration-backup.js +1060 -0
- package/core/pack-review.js +295 -88
- package/core/packs.js +4 -3
- package/core/persona.js +2 -1
- package/core/process-tree.js +19 -2
- package/core/provider-migration.js +39 -0
- package/core/provider-status.js +80 -0
- package/core/providers/claude-events.js +121 -0
- package/core/providers/claude-hook.js +114 -0
- package/core/providers/claude.js +296 -0
- package/core/providers/codex-events.js +125 -0
- package/core/providers/codex-hook.js +280 -0
- package/core/providers/codex.js +286 -0
- package/core/providers/contract.js +153 -0
- package/core/providers/env.js +148 -0
- package/core/providers/events.js +171 -0
- package/core/providers/hook-command.js +22 -0
- package/core/providers/index.js +240 -0
- package/core/providers/utility-policy.js +269 -0
- package/core/recall/classic.js +2 -2
- package/core/recall/discoverer.js +71 -22
- package/core/recall/metrics.js +27 -1
- package/core/recall/tuning.js +4 -1
- package/core/recall/warm-walker.js +151 -108
- package/core/recall-filter.js +86 -61
- package/core/router.js +79 -7
- package/core/run-context.js +185 -0
- package/core/runner.js +1562 -1286
- package/core/scheduler.js +515 -210
- package/core/side-chat.js +346 -0
- package/core/single-instance.js +46 -0
- package/core/state.js +1084 -97
- package/core/subagent.js +72 -98
- package/core/system-prompt.js +462 -279
- package/core/tool-guard.js +73 -39
- package/core/tools.js +22 -5
- package/core/transcripts.js +30 -1
- package/core/usage-log.js +19 -4
- package/core/utility-agent.js +654 -0
- package/core/web-auth.js +29 -13
- package/docs/CHANNEL_DESIGN.md +181 -0
- package/docs/MULTI_CHANNEL_PLAN.md +254 -0
- package/docs/PROVIDER_MIGRATION.md +67 -0
- package/health.js +50 -39
- package/package.json +48 -4
- package/setup.js +198 -38
- package/soul.md +39 -0
- package/test-ability-extraction.js +5 -0
- package/test-approval-async.js +63 -4
- package/test-cursor-removal.js +337 -0
- package/test-enforcer.js +70 -27
- package/test-fixtures/current-provider-parity.json +132 -0
- package/test-fixtures/fake-agent-cli.js +509 -0
- package/test-fixtures/migrations/claude-only/jobs.json +3 -0
- package/test-fixtures/migrations/claude-only/sessions.json +5 -0
- package/test-fixtures/migrations/claude-only/state.json +5 -0
- package/test-fixtures/migrations/cursor-selected/crons.json +3 -0
- package/test-fixtures/migrations/cursor-selected/jobs.json +3 -0
- package/test-fixtures/migrations/cursor-selected/sessions.json +5 -0
- package/test-fixtures/migrations/cursor-selected/state.json +6 -0
- package/test-fixtures/migrations/dual-provider/jobs.json +3 -0
- package/test-fixtures/migrations/dual-provider/sessions.json +7 -0
- package/test-fixtures/migrations/dual-provider/state.json +10 -0
- package/test-fixtures/migrations/malformed-partial/jobs.json +1 -0
- package/test-fixtures/migrations/malformed-partial/sessions.json +1 -0
- package/test-fixtures/migrations/malformed-partial/sessions.json.bak +3 -0
- package/test-fixtures/migrations/malformed-partial/state.json +1 -0
- package/test-fixtures/migrations/malformed-partial/state.json.bak +5 -0
- package/test-fixtures/migrations/missing-project/jobs.json +3 -0
- package/test-fixtures/migrations/missing-project/sessions.json +3 -0
- package/test-fixtures/migrations/missing-project/state.json +4 -0
- package/test-fixtures/migrations/multi-user/jobs.json +4 -0
- package/test-fixtures/migrations/multi-user/sessions.json +4 -0
- package/test-fixtures/migrations/multi-user/state.json +6 -0
- package/test-fixtures/provider-event-samples.json +17 -0
- package/test-learning-e2e.js +5 -0
- package/test-memory-mutation-queue.js +191 -0
- package/test-provider-boot-matrix.js +399 -0
- package/test-provider-bootstrap.js +158 -0
- package/test-provider-capabilities.js +232 -0
- package/test-provider-claude.js +206 -0
- package/test-provider-codex.js +228 -0
- package/test-provider-compaction.js +371 -0
- package/test-provider-core-prompt.js +264 -0
- package/test-provider-coupling-audit.js +90 -0
- package/test-provider-dream.js +312 -0
- package/test-provider-enforcer.js +252 -0
- package/test-provider-env-isolation.js +150 -0
- package/test-provider-events.js +171 -0
- package/test-provider-fixture.js +332 -0
- package/test-provider-gateway.js +508 -0
- package/test-provider-language.js +89 -0
- package/test-provider-migration-backup.js +424 -0
- package/test-provider-pack-review.js +436 -0
- package/test-provider-parity-e2e.js +537 -0
- package/test-provider-prompt-parity.js +89 -0
- package/test-provider-recall.js +271 -0
- package/test-provider-registry.js +251 -0
- package/test-provider-resume-parity.js +41 -0
- package/test-provider-run-lifecycle.js +349 -0
- package/test-provider-runner.js +271 -0
- package/test-provider-scheduler.js +689 -0
- package/test-provider-session-commands.js +185 -0
- package/test-provider-session-history.js +205 -0
- package/test-provider-side-chat.js +337 -0
- package/test-provider-state-migration.js +316 -0
- package/test-provider-stream-decoder.js +69 -0
- package/test-provider-subagent.js +228 -0
- package/test-provider-tool-hooks.js +360 -0
- package/test-recall-discoverer.js +1 -0
- package/test-recall-engine.js +3 -3
- package/test-recall-evolution.js +18 -0
- package/test-runner-watchdog-static.js +16 -8
- package/test-single-runtime.js +35 -0
- package/test-telegram-poll-recovery.js +93 -0
- package/test-tool-guard.js +56 -0
- package/test-tools.js +19 -0
- package/test-unified-identity.js +3 -1
- package/test-usage-accounting.js +92 -20
- package/test-utility-provider-policy.js +486 -0
- package/web.js +130 -35
package/.env.example
CHANGED
|
@@ -15,11 +15,35 @@ KAZEE_OWNER_USER_ID=
|
|
|
15
15
|
KAZEE_DEBUG_EVENTS=
|
|
16
16
|
|
|
17
17
|
WORKSPACE=/path/to/your/workspace
|
|
18
|
-
|
|
18
|
+
# Both provider paths are optional. Leave blank to discover the CLI on PATH.
|
|
19
|
+
CLAUDE_PATH=
|
|
20
|
+
CODEX_PATH=
|
|
21
|
+
# Optional explicit foreground/global default. When blank, Open Claudia picks
|
|
22
|
+
# the first available compatible provider deterministically (Claude, then Codex).
|
|
23
|
+
DEFAULT_PROVIDER=
|
|
19
24
|
# Default Claude Code model when users haven't selected one with /model.
|
|
20
25
|
CLAUDE_MODEL=claude-fable-5
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
CODEX_MODEL=
|
|
27
|
+
# Background intelligence uses the active provider by default. Per-purpose
|
|
28
|
+
# overrides and fallbacks are opt-in; fallbacks never retarget foreground turns.
|
|
29
|
+
UTILITY_PROVIDER=active
|
|
30
|
+
PROVIDER_FALLBACKS=
|
|
31
|
+
DREAM_PROVIDER=
|
|
32
|
+
MEMORY_PROVIDER=
|
|
33
|
+
RECALL_PROVIDER=
|
|
34
|
+
ENFORCER_PROVIDER=
|
|
35
|
+
SUBAGENT_PROVIDER=
|
|
36
|
+
# Exact per-provider model overrides for utility work (optional).
|
|
37
|
+
DREAM_MODEL_CLAUDE=
|
|
38
|
+
DREAM_MODEL_CODEX=
|
|
39
|
+
PACK_REVIEW_MODEL_CLAUDE=
|
|
40
|
+
PACK_REVIEW_MODEL_CODEX=
|
|
41
|
+
RECALL_MODEL_CLAUDE=
|
|
42
|
+
RECALL_MODEL_CODEX=
|
|
43
|
+
ENFORCER_MODEL_CLAUDE=
|
|
44
|
+
ENFORCER_MODEL_CODEX=
|
|
45
|
+
SUBAGENT_MODEL_CLAUDE=
|
|
46
|
+
SUBAGENT_MODEL_CODEX=
|
|
23
47
|
AUTO_COMPACT_TOKENS=280000
|
|
24
48
|
# Inactivity watchdog: kill a heavy turn's child if it emits no output for
|
|
25
49
|
# this many ms, so a hung tool call can't wedge the bot. Default 600000 (10min).
|
|
@@ -32,8 +56,10 @@ USAGE_ALERT_COOLDOWN_MS=1800000
|
|
|
32
56
|
MEMORY_RECALL_MAX_CHARS=9000
|
|
33
57
|
# Default recall engine when a chat hasn't picked one with /engine: classic | discoverer
|
|
34
58
|
RECALL_ENGINE=classic
|
|
35
|
-
# Dream
|
|
59
|
+
# Dream utility tier is mapped by the selected provider: low | medium | high (default).
|
|
36
60
|
DREAM_TIER=high
|
|
61
|
+
# Independent external-person guardrail fails closed. Every total provider
|
|
62
|
+
# failure holds the action for owner approval.
|
|
37
63
|
PROJECT_TRANSCRIPTS=true
|
|
38
64
|
TRANSCRIPT_MAX_ENTRY_CHARS=12000
|
|
39
65
|
TRANSCRIPTS_DIR=
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.0.1 — streaming restored, /stop queue survival, boot resilience
|
|
4
|
+
|
|
5
|
+
- **Live streaming is back, and the final message stays clean.** The v3.0.0 provider rewrite dropped the in-chat streaming feel: no live progress while a run worked, and the settled reply concatenated every text block into one blob. Now an active run edits a throttled preview message in place with the agent's narration (and its thinking, when `/verbose` is on — new command + button toggle), and when the run settles only the **last** text segment is delivered as the final answer; earlier pre-tool text is preserved as narration instead of being glued onto the reply. Providers emit a normalized `thinking` event (Claude thinking blocks, Codex reasoning items) that feeds the preview but can never leak into settled output. On success the preview becomes the narration record (or is deleted when there was none); on failure or cancel the partial preview is kept so you can see how far the run got. Preview edits are channel-guarded, so a bubble minted on one channel is never edited from another.
|
|
6
|
+
- **`/stop` no longer throws away your queued messages.** Cancelling killed the current turn *and* silently emptied the message queue — every turn you'd typed behind the running one vanished. `/stop` now cancels only the current turn (including a pre-spawn abort checkpoint for runs still building their prompt), keeps the queue intact, and tells you how many queued messages will run next. Cancelled runs unwind quietly instead of delivering an error-shaped reply.
|
|
7
|
+
- **The Codex model menu now offers the GPT-5.6 generation.** The retired `gpt-5.1-codex` trio is replaced by `gpt-5.6-sol` / `gpt-5.6-terra` / `gpt-5.6-luna`; effort tiers map low→luna and medium→terra so utility work stays cheap, with sol as the default.
|
|
8
|
+
- **One 409 doesn't kill the bot anymore.** A single Telegram 409 Conflict (another poller on the same token — usually a ghost poll from a restarting predecessor) used to `exit(1)` immediately, which is how one stray poll became a restart storm. The poller now rides out a conflict streak: pause 15s and retry, clear the streak after 45s of quiet, and only exit if the conflict persists beyond 2 minutes (a real second instance). The watchdog defers restarts during a streak.
|
|
9
|
+
- **A single-instance lock refuses double-boots.** Boot now claims `bot.lock` in the config dir (pid, start time, entrypoint); a second bot pointed at the same config refuses to start while the holder is alive, claims a stale or corrupt lock safely, and release never deletes a successor's lock. Combined with the 409 grace this makes accidental duplicate launches self-identifying and harmless.
|
|
10
|
+
- **Startup polling stalls recover on their own.** A Telegram long-poll that went silent right after boot (dead socket, no error) is now detected and restarted instead of leaving a deaf bot.
|
|
11
|
+
- **Agent-space / OpenClaw:** no new deps, no new env, no schema change; Docker image builds identically. New hermetic tests (`test-streaming-split.js`, `test-telegram-409-grace.js`, `test-single-instance.js`, `test-telegram-poll-recovery.js`) wired into `npm test`; CI test commands now carry the fake-agent env explicitly so the suite is hermetic on runners with no provider CLIs.
|
|
12
|
+
|
|
13
|
+
## v3.0.0 — provider parity and Cursor removal
|
|
14
|
+
|
|
15
|
+
- **The runtime is now a provider-agnostic coding-agent harness.** Claude Code and OpenAI Codex implement one registry contract for prompts, immutable run admission, normalized events, native sessions, capability reporting, utility work, and pre-tool safety policy. Setup, web configuration, status, and doctor work with either, both, or neither provider installed; only model turns require a compatible authenticated provider.
|
|
16
|
+
- **Active Cursor Agent runtime support has been removed.** Open Claudia now runs model turns through the registered Claude Code and OpenAI Codex providers only. The command, model/backend buttons, executable discovery, auth/doctor branches, configuration key, active session pointer, and runtime parser/invocation path are gone. Buttons from an older message return a removal notice and direct the user to `/backend`; they never switch to another provider silently.
|
|
17
|
+
- **Cursor data is archived, not rewritten.** The verified provider-migration snapshot retains the byte-for-byte original state, session, job, and legacy cron files. Cursor selections, settings, session pointers/history, and pinned jobs move only into non-selectable/disabled archive records; no native session ID or model is reassigned to Claude or Codex.
|
|
18
|
+
- **Migration activation is proven, not asserted.** Startup snapshots the allowlisted originals, migrates state, sessions, and jobs before the scheduler/router/adapters load, and records each live output's schema, size, path, and SHA-256. A partial, stale, or legacy output cannot satisfy provider-removal readiness; rerunning startup safely completes an interrupted component.
|
|
19
|
+
- **Rollback requires the matching older runtime.** Stop every bot/scheduler process, validate and restore the snapshot described in `docs/PROVIDER_MIGRATION.md`, then restart a pre-removal Open Claudia release that still understands the restored schema. Do not run old and new schedulers against the same restored files.
|
|
20
|
+
- **Authenticated release validation passed locally on 2026-07-10.** Claude Code 2.1.158 and Codex CLI 0.144.0 each passed a fresh turn, resumed turn, read-only plan, harmless tool command, utility JSON output, and prompt-context sentinel through the Open Claudia adapters. Claude-only and Codex-only startup/status probes also passed with the opposite executable absent. These were isolated existing-auth checks only: no login, credential change, publish, deploy, or production action was performed.
|
|
21
|
+
- **Real-CLI validation tightened three compatibility edges.** Claude `structured_output` is now the authoritative terminal value for schema-constrained utility work even when the CLI also streams presentation text. Codex hook trust uses a strict inline `projects` table accepted by the current CLI while user configuration remains ignored, and the supported model tiers no longer select deprecated `o4-mini` for utility work.
|
|
22
|
+
- **Breaking-release recommendation accepted — released as `v3.0.0` (2026-07-10).** Removing an active provider and changing configuration/session schemas are breaking changes; package metadata and the git tag are v3.0.0.
|
|
23
|
+
- **Post-review hardening (2026-07-10).** stdin EPIPE from a fast-exiting provider child no longer crashes the bot — it surfaces as a stderr diagnostic and the exit code decides the run. Crons/wakeups archived by the provider migration are announced once at boot and listed in `open-claudia cron-list` and `/cron`. Healthy provider status is cached for 30 seconds so per-message admission stops respawning CLI probes; disappearance detection stays instant and unhealthy states always re-probe. `/doctor` now runs the real-binary Codex tool-hook enforcement probe behind an explicit opt-in, so boot/health/setup never spawn a model turn. Merged main's Telegram polling recovery fix.
|
|
24
|
+
|
|
3
25
|
## v2.15.0
|
|
4
26
|
- **Production-hardening pass (P0). Two root causes, closed at the source.** A deep-dive audit traced the reliability and safety gaps to two patterns: (1) **overloaded return contracts** where a falsy value meant both "no id" and "failed", so callers guessed — the exact shape behind v2.14.8's Kazee double-send; and (2) **unsafe shared state under concurrency**, amplified because the owner's Telegram + Kazee turns now share ONE in-memory state object *and* load-modify-write the same JSON files under unified identity. This release fixes both, plus the credential-exposure and crash-durability gaps found alongside them. No new deps, no new required env, no schema change.
|
|
5
27
|
- **One explicit delivery contract, so no caller guesses.** Adapters historically overloaded `send()`'s return: a message id on success, a bare `true` for an idless success (server fast-ack), or a falsy value on failure. `core/io.send()` now collapses every adapter's raw return through `normalizeSendResult` into `{ ok, messageId, editable }` — `messageId` is always a string or null, so `typeof`/edit-target checks are uniform across transports. The runner's final-delivery guard is now `if (!sent.ok)` (an idless success no longer reads as failure → no phantom re-send), and the streaming-preview path keeps the real string id when editable or a truthy sentinel otherwise, so `canEditStatus()` still declines to edit an unaddressable bubble. The loopback approval-prompt send routes through the same normalizer. New `test-delivery-contract.js`.
|
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Open Claudia
|
|
2
2
|
|
|
3
|
-
Your always-on
|
|
3
|
+
Your always-on, provider-agnostic coding-agent harness — Claude Code and OpenAI Codex via Telegram or Kazee Chat.
|
|
4
4
|
|
|
5
|
-
Send text, voice notes, screenshots, and files from your phone.
|
|
5
|
+
Send text, voice notes, screenshots, and files from your phone. Open Claudia runs the selected coding-agent provider on your projects, remembers what it learned, and reports back.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
### Channels &
|
|
9
|
+
### Channels & providers
|
|
10
10
|
- **Multi-channel** — run the same bot on Telegram, Kazee Chat, or both at once (`CHANNELS=telegram,kazee`). Each channel renders keyboards, files, voice notes, and edits natively
|
|
11
|
-
- **Multi-
|
|
12
|
-
- **Multi-user / team mode** — one bot serves multiple authorized users in parallel, each with their own conversations, settings, model,
|
|
11
|
+
- **Multi-provider** — switch between Claude Code and OpenAI Codex on the fly (`/claude`, `/codex`); each keeps its own project-scoped session state
|
|
12
|
+
- **Multi-user / team mode** — one bot serves multiple authorized users in parallel, each with their own conversations, settings, model, provider, and usage counters
|
|
13
13
|
- **Multi-project sessions** — switch between workspace projects; per-project conversation history auto-resumes
|
|
14
14
|
|
|
15
15
|
### Memory & long-term context
|
|
@@ -44,7 +44,7 @@ Send text, voice notes, screenshots, and files from your phone. Your chosen AI a
|
|
|
44
44
|
### Operations
|
|
45
45
|
- **Encrypted vault** — store API keys and credentials securely
|
|
46
46
|
- **Customizable soul** — define your assistant's personality and knowledge
|
|
47
|
-
- **
|
|
47
|
+
- **Capability-driven settings** — model, effort, read-only mode, budget, and worktree controls appear only when the selected provider supports them
|
|
48
48
|
- **Token economy** — byte-stable system prompt for maximum Anthropic prompt-cache hits; dynamic state rides each message instead
|
|
49
49
|
- **Web UI** — optional browser UI for setup and config (`open-claudia start --web`)
|
|
50
50
|
- **Auto-updates** — checks npm every 5 minutes, upgrade with `/upgrade`
|
|
@@ -56,16 +56,16 @@ Send text, voice notes, screenshots, and files from your phone. Your chosen AI a
|
|
|
56
56
|
|
|
57
57
|
- [Node.js](https://nodejs.org/) 18+ (22.5+ recommended — its built-in SQLite powers transcript/pack/entity search; on older Node those features quietly disable themselves)
|
|
58
58
|
- A Telegram bot token (from [@BotFather](https://t.me/BotFather)) and/or a Kazee Chat bot
|
|
59
|
-
- At least one authenticated
|
|
59
|
+
- At least one authenticated coding-agent provider on the host machine for model turns (setup, doctor, status, and web configuration also work with none installed)
|
|
60
60
|
- (Optional) [whisper.cpp](https://github.com/ggerganov/whisper.cpp) + ffmpeg for voice notes
|
|
61
61
|
|
|
62
62
|
## Quick Start
|
|
63
63
|
|
|
64
|
-
### 1. Install and authenticate
|
|
64
|
+
### 1. Install and authenticate coding-agent providers
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
For model-bearing turns, authenticate **at least one** of these on the machine where Open Claudia will run.
|
|
67
67
|
|
|
68
|
-
**Claude Code** (required):
|
|
68
|
+
**Claude Code** (optional — at least one provider is required for model turns):
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
71
|
npm install -g @anthropic-ai/claude-code
|
|
@@ -73,16 +73,7 @@ claude # Opens browser to log in
|
|
|
73
73
|
claude --version # Verify it works
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
**
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
# Install from Cursor IDE: Settings > General > Agent CLI
|
|
80
|
-
# Or download from https://docs.cursor.com/agent
|
|
81
|
-
agent login # Opens browser to authenticate
|
|
82
|
-
agent status # Verify: should show your email and plan
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
**OpenAI Codex** (optional — enables `/codex` backend):
|
|
76
|
+
**OpenAI Codex** (optional — at least one provider is required for model turns):
|
|
86
77
|
|
|
87
78
|
```bash
|
|
88
79
|
npm install -g @openai/codex
|
|
@@ -92,7 +83,7 @@ codex login # Opens browser to authenticate
|
|
|
92
83
|
codex --version # Verify it works
|
|
93
84
|
```
|
|
94
85
|
|
|
95
|
-
Docker images include the Codex CLI. Direct npm installs still need optional
|
|
86
|
+
Docker images include the Codex CLI. Direct npm installs still need optional provider CLIs installed on the host.
|
|
96
87
|
|
|
97
88
|
> **Important**: Claude Code can use macOS Keychain when you log in interactively, but a launchd/background bot may not be able to read that Keychain session. Open Claudia supports `CLAUDE_CODE_OAUTH_TOKEN` for non-interactive Claude runs. Prefer `/setup_token` then `/use_oauth_token` if chat shows Claude auth/keychain errors.
|
|
98
89
|
|
|
@@ -110,8 +101,8 @@ open-claudia setup
|
|
|
110
101
|
|
|
111
102
|
The setup wizard will:
|
|
112
103
|
|
|
113
|
-
1. Detect Claude
|
|
114
|
-
2.
|
|
104
|
+
1. Detect the Claude and Codex CLIs, plus ffmpeg and whisper, on your system
|
|
105
|
+
2. Report provider authentication status
|
|
115
106
|
3. Ask for your Telegram bot token and verify it
|
|
116
107
|
4. Generate a verification code — send it to your bot to prove your identity
|
|
117
108
|
5. Set your workspace path (default: `~/.open-claudia/Workspace`)
|
|
@@ -142,16 +133,15 @@ If installed as a background service, the bot starts automatically on login and
|
|
|
142
133
|
|
|
143
134
|
## Chat Commands
|
|
144
135
|
|
|
145
|
-
###
|
|
136
|
+
### Provider switching
|
|
146
137
|
|
|
147
138
|
| Command | Description |
|
|
148
139
|
|---------|-------------|
|
|
149
|
-
| `/claude` | Switch to Claude Code
|
|
150
|
-
| `/
|
|
151
|
-
| `/
|
|
152
|
-
| `/backend` | Show current backend with picker |
|
|
140
|
+
| `/claude` | Switch to the Claude Code provider |
|
|
141
|
+
| `/codex` | Switch to the OpenAI Codex provider |
|
|
142
|
+
| `/backend` | Show the current provider with picker |
|
|
153
143
|
|
|
154
|
-
Each
|
|
144
|
+
Each provider keeps its own persistent project session. Switching doesn't lose your place — you can go back and forth freely.
|
|
155
145
|
|
|
156
146
|
### Session management
|
|
157
147
|
|
|
@@ -171,14 +161,14 @@ When you select a project, the last conversation is automatically resumed. Tap "
|
|
|
171
161
|
|
|
172
162
|
| Command | Description |
|
|
173
163
|
|---------|-------------|
|
|
174
|
-
| `/model [<model>]` | Switch model
|
|
175
|
-
| `/effort [
|
|
176
|
-
| `/budget [$N]` | Set max spend for next task
|
|
177
|
-
| `/plan` | Toggle
|
|
178
|
-
| `/ask` | Toggle
|
|
179
|
-
| `/worktree` | Toggle isolated git branch |
|
|
164
|
+
| `/model [<model>]` | Switch model for the selected provider |
|
|
165
|
+
| `/effort [<value>]` | Set a provider-supported effort level |
|
|
166
|
+
| `/budget [$N]` | Set max spend for the next task when supported (Claude Code) |
|
|
167
|
+
| `/plan` | Toggle read-only planning — Claude permission mode / Codex read-only sandbox |
|
|
168
|
+
| `/ask` | Toggle read-only Q&A through the selected provider's read-only mode |
|
|
169
|
+
| `/worktree` | Toggle a provider-managed isolated git branch when supported (Claude Code) |
|
|
180
170
|
| `/mode` | Switch between direct and agent bot modes |
|
|
181
|
-
| `/status` | Show current session,
|
|
171
|
+
| `/status` | Show current session, provider, capabilities, recall engine, and settings |
|
|
182
172
|
| `/usage` | Token usage and cost for this session |
|
|
183
173
|
| `/doctor` / `/requirements` | Check Node, CLI binaries/versions/auth, voice stack, and writable paths |
|
|
184
174
|
|
|
@@ -259,7 +249,7 @@ Available only when the bot runs as an AgentSpace-provisioned pod (the broker cr
|
|
|
259
249
|
|
|
260
250
|
## Memory & Long-Term Context
|
|
261
251
|
|
|
262
|
-
Open Claudia layers three memory systems on top of
|
|
252
|
+
Open Claudia layers three memory systems on top of provider-native sessions:
|
|
263
253
|
|
|
264
254
|
**Context packs** (`~/.open-claudia/packs/<dir>/PACK.md`) are living per-topic documents with four sections: *Stance* (how to think about the topic — your preferences and hard rules), *Procedure* (verified how-to steps), *State* (where work stands now), and *Journal* (a dated one-line log of past sessions). Incoming messages are matched against packs (FTS5, field-weighted so a stray word can't drag a pack in) and hits are injected into the agent's context — mention a project anywhere and the assistant picks up its train of thought, decisions, and history without you re-explaining. After every substantial turn, a background reviewer on a cheap model updates the relevant pack (or creates one for a genuinely new topic). Every change is announced in chat.
|
|
265
255
|
|
|
@@ -267,7 +257,7 @@ Open Claudia layers three memory systems on top of the backend's native sessions
|
|
|
267
257
|
|
|
268
258
|
**Recall engines** — how packs and entities get matched and surfaced is pluggable per chat via `/engine` (or the `RECALL_ENGINE` env default). **classic** (the default) is keyword FTS plus a relevance judge with headline injection — stable and unchanged. **discoverer** (opt-in) adds a typed-edge graph over the same corpus (`parent`/`governed-by`/`related` edges with weights in `recall-graph.db`) and runs: a pre-gate that skips recall on trivial turns → FTS seeding → spreading activation across the graph (1–2 hops — auto-pulls cross-cutting concerns the query never named) → a walker that reads each candidate and returns the genuinely-relevant set with one-line why-bullets (fail-open to keyword seeds, so it never recalls worse than classic). Edges form structurally from pack `parent` frontmatter and `[[links]]`, and strengthen via Hebbian co-use when the agent opens packs together (📖); weights decay over time. Inspect with `open-claudia recall-stats` and `open-claudia recall graph [--sync]`, or flip on `/recall` to watch — per turn — which packs/entities surfaced and why, right in the chat. Switch back any time with `/engine classic`.
|
|
269
259
|
|
|
270
|
-
**Dream consolidation** — while the per-turn reviewer takes quick notes, *dream* is the slow overnight pass (default 4am,
|
|
260
|
+
**Dream consolidation** — while the per-turn reviewer takes quick notes, *dream* is the slow overnight pass (default 4am, through the configured provider's high model tier): it merges packs that drifted into the same topic, builds parent/sub pack trees with umbrella summaries, tightens descriptions and tags so the router matches with less noise, dedupes entities, cross-links notes, and tends the recall graph (structural sync, weight decay, orphan prune). The pass is *evidence-grounded*: per-turn recall telemetry (what surfaced, what got kept, what the agent actually opened) feeds the prompt, so archive/merge calls rest on usage numbers rather than vibes. Most nights run as cheap *deltas* — full pack bodies only for what changed since the last dream plus graph neighbours and pre-computed merge candidates; a full-corpus sweep runs every `DREAM_FULL_SWEEP_DAYS` (30). Deterministic phases run even if the model call fails: journal backfill dedupe, weakening of graph nodes that keep arriving but never get kept, co-rescue edge reinforcement, episodic index tending, and a memory-health report (rescue rate, noise, latency, spend) in the morning chat summary. Dream may also tune one bounded recall knob per night (`recall-tuning.json`) — every change is checked against the next window's health and auto-rolled-back if rescue drops or noise rises; env pins always win. Anything merged away is backed up under `~/.open-claudia/backup/dream-<stamp>/` first, and each report and morning summary records the provider/model used. Configure with `DREAM_CRON`, `DREAM_TIER`, `DREAM_PROVIDER`, or a provider-specific `DREAM_MODEL_CLAUDE` / `DREAM_MODEL_CODEX`; disable with `DREAM=off`.
|
|
271
261
|
|
|
272
262
|
**Personality** — your `soul.md` holds identity and hard rules; `~/.open-claudia/persona.md` holds the voice on top — tone, quirks, emoji habits. It feeds into the system prompt and the dream pass may evolve it gently (bounded, backed up, announced). Edit it directly any time.
|
|
273
263
|
|
|
@@ -332,22 +322,41 @@ open-claudia send-to --person "<name>" "<message>"
|
|
|
332
322
|
open-claudia recent --person "<name>" [--limit 20] # read recent activity from another chat
|
|
333
323
|
```
|
|
334
324
|
|
|
335
|
-
|
|
325
|
+
Replies and write/destructive actions for external people pass through an independent, read-only relationship guard. The guard can use Claude or Codex (`ENFORCER_PROVIDER`) and fails closed: malformed output, timeout, or total provider failure holds the action for owner approval. A fallback is used only when explicitly listed in `PROVIDER_FALLBACKS`; audit records identify the provider/model that judged the action without storing the mandate or proposed content.
|
|
326
|
+
|
|
327
|
+
## Provider Comparison
|
|
328
|
+
|
|
329
|
+
| | Claude Code | OpenAI Codex |
|
|
330
|
+
|---|---|---|
|
|
331
|
+
| Binary | `claude` | `codex` |
|
|
332
|
+
| Session flag | `--resume <id>` | `exec resume <id>` |
|
|
333
|
+
| Auth | `claude auth` | `codex login` |
|
|
334
|
+
| Plan mode | Yes (`--permission-mode plan`) | Yes (read-only sandbox) |
|
|
335
|
+
| Budget control | Yes (`--max-budget-usd`) | No |
|
|
336
|
+
| Effort levels | Native (`low` through `max`) | Native (`minimal` through `xhigh`) |
|
|
337
|
+
| Worktree | Yes (`--worktree`) | No |
|
|
338
|
+
| Model switching | Yes | Yes (`--model`) |
|
|
339
|
+
| Partial text streaming | Yes | No; normalized progress and final events only |
|
|
340
|
+
|
|
341
|
+
Both providers output structured events which Open Claudia normalizes for progress, usage, tools, sessions, and terminal results.
|
|
342
|
+
|
|
343
|
+
Unsupported optional controls return a provider-specific explanation and do not change saved settings. Mandatory safety controls are different: Open Claudia configures each provider's native pre-tool hook, and refuses unrestricted execution if that policy cannot initialize.
|
|
344
|
+
|
|
345
|
+
## Utility provider policy
|
|
336
346
|
|
|
337
|
-
|
|
338
|
-
|---|---|---|---|
|
|
339
|
-
| Binary | `claude` | `agent` | `codex` |
|
|
340
|
-
| Session flag | `--resume <id>` | `--resume <id>` | `exec resume <id>` |
|
|
341
|
-
| Auth | `claude auth` | `agent login` | `codex login` |
|
|
342
|
-
| Plan mode | Yes (`--permission-mode plan`) | Yes (`--mode plan`) | Yes (`--sandbox read-only`) |
|
|
343
|
-
| Ask mode | No | Yes (`--mode ask`) | No |
|
|
344
|
-
| Budget control | Yes (`--max-budget-usd`) | No | No |
|
|
345
|
-
| Effort levels | Yes | No | Via config.toml |
|
|
346
|
-
| Worktree | Yes (`--worktree`) | Yes (`--worktree`) | No |
|
|
347
|
-
| Model switching | Yes | Yes | Yes (`--model`) |
|
|
348
|
-
| Dangerously skip permissions | Yes | Yes (`--trust`) | Yes (`--dangerously-bypass-approvals-and-sandbox`) |
|
|
347
|
+
Background intelligence—sub-agents, recall, memory review, dream/introspection, and the external-person enforcer—uses one provider-selection policy. A per-purpose override is checked first, then `UTILITY_PROVIDER` (default `active`), the active foreground provider when a chat exists, and `DEFAULT_PROVIDER` for global jobs. Providers translate the neutral `low`, `medium`, and `high` tiers to their own models; exact per-provider model overrides remain available.
|
|
349
348
|
|
|
350
|
-
|
|
349
|
+
Foreground turns never silently fall back to a different provider. Utility work uses `PROVIDER_FALLBACKS` only when the operator explicitly supplies an ordered list, starts a fresh provider session, and records the provider/model used. The relationship enforcer may try that configured list, but total failure always fails closed and asks the owner to decide.
|
|
350
|
+
|
|
351
|
+
## Provider session semantics
|
|
352
|
+
|
|
353
|
+
Conversation identity is the tuple of canonical user, project, provider, and native session ID. Claude Code and Codex histories and active pointers stay separate: switching providers restores only that provider's project session and never passes one provider's native session ID to another. Session-history entries are provider-tagged; ambiguous legacy records remain visible but non-selectable.
|
|
354
|
+
|
|
355
|
+
Model, effort, budget, permission mode, and worktree settings are stored per provider. `/new` clears only the selected project/provider pointer, while `/end` closes the project selection without deleting history. Compaction and scheduled jobs capture an immutable provider/session tuple; an explicitly configured scheduled fallback starts fresh from a provider-neutral archived brief.
|
|
356
|
+
|
|
357
|
+
## Provider migration and rollback
|
|
358
|
+
|
|
359
|
+
Upgrades from a release with the removed third provider snapshot `state.json`, `sessions.json`, `jobs.json`, legacy cron sources, and their relevant backups before activating provider-aware schemas. Removed-provider selections, histories, and jobs become non-selectable or disabled archives; they are never reassigned to Claude Code or Codex. See [Provider migration snapshots and rollback](docs/PROVIDER_MIGRATION.md) before upgrading or restoring an older runtime.
|
|
351
360
|
|
|
352
361
|
## Sending Files
|
|
353
362
|
|
|
@@ -379,16 +388,19 @@ Voice notes are transcribed locally — nothing sent to external services. On ma
|
|
|
379
388
|
|
|
380
389
|
```
|
|
381
390
|
Phone (Telegram / Kazee) --> Bot (Node.js) --> Claude Code CLI --> Your codebase
|
|
382
|
-
--> Cursor Agent CLI -->
|
|
383
391
|
--> OpenAI Codex CLI -->
|
|
384
392
|
<-- <-- <--
|
|
385
393
|
```
|
|
386
394
|
|
|
387
|
-
The bot spawns the
|
|
395
|
+
The bot spawns the selected provider CLI in headless mode for each message, normalizing its JSONL output back to the chat. It maintains provider-native context through the provider adapter and passes the same Open Claudia prompt/context contract to either CLI.
|
|
388
396
|
|
|
389
397
|
The appended system prompt is byte-stable within a session to maximize Anthropic prompt-cache hits; per-turn state (vault status, pending tasks, matched packs/entities) rides the user message instead, where it is always uncached anyway.
|
|
390
398
|
|
|
391
|
-
Open Claudia does not summarize one
|
|
399
|
+
Open Claudia does not summarize one provider's native session into another during switches; instead it records a redacted project transcript outside the repo and injects a small pointer telling fresh/switched sessions to search it only if needed.
|
|
400
|
+
|
|
401
|
+
### Provider credential boundary
|
|
402
|
+
|
|
403
|
+
Native Claude and Codex child processes receive allowlisted process variables plus explicitly configured `AGENT_ENV_PASSTHROUGH` entries. Open Claudia removes control-plane, keyring, and all provider credential keys before adding back only the selected provider's credentials and auth/config root. This is environment isolation, not OS containment: a native same-UID process retains whatever filesystem access that operating-system user has, including access to readable CLI auth stores and configuration files.
|
|
392
404
|
|
|
393
405
|
## Configuration Files
|
|
394
406
|
|
|
@@ -408,7 +420,7 @@ All stored in `~/.open-claudia/`:
|
|
|
408
420
|
| `packs/` | Context packs (living topic documents) + FTS index |
|
|
409
421
|
| `entities/` | Entity notes (people/places/projects) + FTS index |
|
|
410
422
|
| `sessions.json` | Per-project conversation history |
|
|
411
|
-
| `state.json` | Current
|
|
423
|
+
| `state.json` | Current provider/project state and provider-scoped settings (survives restarts) |
|
|
412
424
|
| `transcripts/` | Redacted project-scoped JSONL transcripts + FTS index |
|
|
413
425
|
| `briefs/` | Archived full compaction briefs |
|
|
414
426
|
| `audit.log` | Relay/intro/auth audit trail |
|
|
@@ -426,10 +438,13 @@ All stored in `~/.open-claudia/`:
|
|
|
426
438
|
| `CHANNELS` | No | Channels to start: `telegram`, `kazee`, or `telegram,kazee` (default `telegram`) |
|
|
427
439
|
| `KAZEE_URL` / `KAZEE_BOT_TOKEN` / `KAZEE_BOT_USER_ID` / `KAZEE_OWNER_USER_ID` | Kazee only | Kazee Chat connection |
|
|
428
440
|
| `WORKSPACE` | Yes | Path to your projects directory |
|
|
429
|
-
| `CLAUDE_PATH` |
|
|
430
|
-
| `
|
|
441
|
+
| `CLAUDE_PATH` / `CODEX_PATH` | No | Optional paths to provider CLIs (auto-detected if in PATH) |
|
|
442
|
+
| `DEFAULT_PROVIDER` | No | Foreground default (`claude` or `codex`); blank deterministically chooses the first compatible provider |
|
|
443
|
+
| `UTILITY_PROVIDER` | No | Utility default (`active`, `claude`, or `codex`); defaults to the active foreground provider |
|
|
444
|
+
| `MEMORY_PROVIDER` / `RECALL_PROVIDER` / `SUBAGENT_PROVIDER` | No | Optional per-purpose utility-provider overrides |
|
|
431
445
|
| `CLAUDE_CODE_OAUTH_TOKEN` | No | OAuth token for non-interactive Claude runs (set via `/use_oauth_token`) |
|
|
432
|
-
| `
|
|
446
|
+
| `AGENT_ENV_PASSTHROUGH` | No | Comma-separated project environment keys to pass to provider children; reserved provider/control/keyring keys are always filtered and re-added only by the selected provider |
|
|
447
|
+
| `CLAUDE_MODEL` / `CODEX_MODEL` | No | Optional default model for the matching provider |
|
|
433
448
|
| `AUTO_COMPACT_TOKENS` | No | Auto-compact threshold in tokens (also settable via `/compactwindow`) |
|
|
434
449
|
| `USAGE_ALERT_CONTEXT_TOKENS` | No | Alert when one completed turn's context tokens exceed this ceiling (default `120000`, `off` disables) |
|
|
435
450
|
| `USAGE_ALERT_RATE_MULTIPLIER` | No | Alert when the latest context-token rate exceeds the recent baseline by this multiple (default `1.75`, `off` disables) |
|
|
@@ -450,9 +465,13 @@ All stored in `~/.open-claudia/`:
|
|
|
450
465
|
| `PACK_MATCH_THRESHOLD` / `ENTITY_MATCH_THRESHOLD` | No | Router match score thresholds (default `2`) |
|
|
451
466
|
| `DREAM` | No | `off` disables the nightly memory consolidation pass (default on) |
|
|
452
467
|
| `DREAM_CRON` | No | Schedule for the dream pass (default `0 4 * * *`) |
|
|
453
|
-
| `
|
|
454
|
-
| `
|
|
468
|
+
| `DREAM_PROVIDER` | No | Provider for dream and introspection (`claude` or `codex`); otherwise scheduled work resolves through `DEFAULT_PROVIDER` |
|
|
469
|
+
| `DREAM_MODEL_CLAUDE` / `DREAM_MODEL_CODEX` | No | Exact per-provider dream model override; legacy `DREAM_MODEL` remains a Claude-only compatibility alias |
|
|
470
|
+
| `DREAM_TIER` | No | Provider-owned model tier for the dream pass: `low`, `medium`, or `high` (default) |
|
|
455
471
|
| `DREAM_FULL_SWEEP_DAYS` | No | Days between full-corpus dream sweeps; other nights are cheap deltas over recently-touched packs (default `30`) |
|
|
472
|
+
| `ENFORCER_PROVIDER` | No | Provider for the independent external-person guard (`claude` or `codex`) |
|
|
473
|
+
| `ENFORCER_MODEL_CLAUDE` / `ENFORCER_MODEL_CODEX` | No | Exact per-provider guard model override; legacy `ENFORCER_MODEL` remains a Claude-only compatibility alias |
|
|
474
|
+
| `PROVIDER_FALLBACKS` | No | Explicit ordered utility fallback list (for example `codex`); the enforcer never invents an unconfigured fallback |
|
|
456
475
|
| `PERSONA_FILE` | No | Override the persona file location |
|
|
457
476
|
| `WEB_UI` / `WEB_PORT` / `WEB_PASSWORD` | No | Web UI toggle, port, and password |
|
|
458
477
|
| `WHISPER_CLI` / `WHISPER_MODEL` | No | whisper.cpp binary and model for voice notes |
|
|
@@ -467,13 +486,13 @@ All stored in `~/.open-claudia/`:
|
|
|
467
486
|
Set up during `open-claudia setup`, or manually:
|
|
468
487
|
|
|
469
488
|
```bash
|
|
470
|
-
# The setup wizard
|
|
489
|
+
# The setup wizard retains the legacy-compatible service id com.claude-telegram-bot
|
|
471
490
|
# To manage:
|
|
472
|
-
launchctl load ~/Library/LaunchAgents/com.
|
|
473
|
-
launchctl unload ~/Library/LaunchAgents/com.
|
|
491
|
+
launchctl load ~/Library/LaunchAgents/com.claude-telegram-bot.plist
|
|
492
|
+
launchctl unload ~/Library/LaunchAgents/com.claude-telegram-bot.plist
|
|
474
493
|
```
|
|
475
494
|
|
|
476
|
-
**Important**: If
|
|
495
|
+
**Important**: If a provider CLI is installed in a non-standard location, make sure that path is included in the launchd plist's `PATH` environment variable or configure its explicit path.
|
|
477
496
|
|
|
478
497
|
### Linux (systemd)
|
|
479
498
|
|
|
@@ -485,11 +504,13 @@ sudo systemctl start claude-telegram-bot
|
|
|
485
504
|
sudo systemctl status claude-telegram-bot
|
|
486
505
|
```
|
|
487
506
|
|
|
507
|
+
The systemd unit name is retained as a legacy service identifier so upgrades manage the existing unit instead of installing a duplicate; it does not select the coding-agent provider.
|
|
508
|
+
|
|
488
509
|
## Auto-Updates
|
|
489
510
|
|
|
490
511
|
The bot checks npm for new versions every 5 minutes. When an update is available, you get a chat notification. Send `/upgrade` to update — the bot installs the new version, restarts, runs a doctor check, and notifies you it's back.
|
|
491
512
|
|
|
492
|
-
For direct npm installs, `/upgrade` updates Open Claudia itself and does not install optional
|
|
513
|
+
For direct npm installs, `/upgrade` updates Open Claudia itself and does not install optional provider CLIs such as Codex. Container deployments should roll out a new Docker image when bundled CLI tools change.
|
|
493
514
|
|
|
494
515
|
## Cron Jobs
|
|
495
516
|
|
package/bin/agent.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
// open-claudia agent "<prompt>" [--role "<role>"] [--json] [--cwd <dir>]
|
|
2
|
-
// Spawn a fresh
|
|
1
|
+
// open-claudia agent "<prompt>" [--role "<role>"] [--provider active|claude|codex] [--json] [--cwd <dir>]
|
|
2
|
+
// Spawn a fresh provider-isolated sub-agent for focused research.
|
|
3
3
|
// No session resume; the parent agent captures stdout and decides what
|
|
4
4
|
// to do with the result.
|
|
5
5
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
|
|
8
8
|
const HELP = `
|
|
9
|
-
Spawn a fresh
|
|
9
|
+
Spawn a fresh Open Claudia sub-agent. Output goes to stdout.
|
|
10
10
|
|
|
11
|
-
open-claudia agent "<prompt>" [--role "<role>"] [--cwd <dir>] [--json] [--timeout <s>]
|
|
11
|
+
open-claudia agent "<prompt>" [--role "<role>"] [--provider active|claude|codex] [--cwd <dir>] [--json] [--timeout <s>]
|
|
12
12
|
|
|
13
13
|
The sub-agent has read-only research tools (Read, Glob, Grep, Bash for read-only
|
|
14
14
|
commands) but no access to your chat session or the send-* CLIs.
|
|
@@ -18,6 +18,7 @@ function takeFlag(args, name) {
|
|
|
18
18
|
const idx = args.indexOf(`--${name}`);
|
|
19
19
|
if (idx < 0) return null;
|
|
20
20
|
const v = args[idx + 1];
|
|
21
|
+
if (v == null || String(v).startsWith("--")) throw new Error(`--${name} requires a value`);
|
|
21
22
|
args.splice(idx, 2);
|
|
22
23
|
return v;
|
|
23
24
|
}
|
|
@@ -29,32 +30,57 @@ function hasFlag(args, name) {
|
|
|
29
30
|
return true;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
console.log(HELP); process.exit(args[0] === "--help" || args[0] === "help" ? 0 : 2);
|
|
35
|
-
}
|
|
36
|
-
const rest = args.slice();
|
|
33
|
+
function parseAgentArgs(input) {
|
|
34
|
+
const rest = input.slice();
|
|
37
35
|
const role = takeFlag(rest, "role");
|
|
36
|
+
const provider = takeFlag(rest, "provider");
|
|
37
|
+
if (provider !== null && !new Set(["active", "claude", "codex"]).has(provider)) {
|
|
38
|
+
throw new Error("--provider must be active, claude, or codex");
|
|
39
|
+
}
|
|
38
40
|
const cwd = takeFlag(rest, "cwd") || process.cwd();
|
|
39
41
|
const timeoutS = takeFlag(rest, "timeout");
|
|
40
42
|
const json = hasFlag(rest, "json");
|
|
43
|
+
if (rest.some((value) => value.startsWith("--"))) {
|
|
44
|
+
throw new Error(`Unknown agent option: ${rest.find((value) => value.startsWith("--"))}`);
|
|
45
|
+
}
|
|
41
46
|
const prompt = rest.join(" ").trim();
|
|
42
|
-
if (!prompt)
|
|
47
|
+
if (!prompt) throw new Error("Missing prompt.");
|
|
48
|
+
let timeoutMs;
|
|
49
|
+
if (timeoutS != null) {
|
|
50
|
+
const seconds = Number(timeoutS);
|
|
51
|
+
if (!Number.isFinite(seconds) || seconds <= 0) throw new Error("--timeout must be a positive number of seconds");
|
|
52
|
+
timeoutMs = seconds * 1000;
|
|
53
|
+
}
|
|
54
|
+
return { prompt, role, provider, cwd, timeoutMs, json };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function run(args) {
|
|
58
|
+
if (args.length === 0 || args[0] === "--help" || args[0] === "help") {
|
|
59
|
+
console.log(HELP); process.exit(args[0] === "--help" || args[0] === "help" ? 0 : 2);
|
|
60
|
+
}
|
|
61
|
+
let parsed;
|
|
62
|
+
try { parsed = parseAgentArgs(args); }
|
|
63
|
+
catch (error) { console.error(error.message); process.exit(2); return; }
|
|
43
64
|
|
|
44
|
-
const {
|
|
65
|
+
const { spawnUtilityAgent } = require(path.join(__dirname, "..", "core", "utility-agent"));
|
|
66
|
+
const { buildSubagentSystemPrompt } = require(path.join(__dirname, "..", "core", "subagent"));
|
|
45
67
|
const channelId = process.env.OC_CHANNEL_ID || null;
|
|
46
68
|
try {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
const request = {
|
|
70
|
+
purpose: "subagent",
|
|
71
|
+
tier: "medium",
|
|
72
|
+
cwd: parsed.cwd,
|
|
73
|
+
systemPrompt: buildSubagentSystemPrompt(parsed.role),
|
|
74
|
+
readOnly: true,
|
|
50
75
|
channelId,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
76
|
+
timeoutMs: parsed.timeoutMs,
|
|
77
|
+
};
|
|
78
|
+
if (parsed.provider !== null) request.provider = parsed.provider;
|
|
79
|
+
const res = await spawnUtilityAgent(parsed.prompt, request);
|
|
54
80
|
if (res.text) process.stdout.write(res.text + (res.text.endsWith("\n") ? "" : "\n"));
|
|
55
81
|
if (res.truncated) process.stderr.write("(output truncated to 64KB)\n");
|
|
56
82
|
process.exit(0);
|
|
57
83
|
} catch (e) { console.error(`agent failed: ${e.message}`); process.exit(1); }
|
|
58
84
|
}
|
|
59
85
|
|
|
60
|
-
module.exports = { run, HELP };
|
|
86
|
+
module.exports = { run, HELP, parseAgentArgs };
|