@xelauvas/xela-cli 0.3.0 → 0.4.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.
Files changed (136) hide show
  1. package/local/README.md +112 -0
  2. package/local/start-qwen.sh +47 -0
  3. package/local/start-tunnel.sh +36 -0
  4. package/local/xela-local.sh +139 -0
  5. package/package.json +19 -5
  6. package/run.sh +33 -0
  7. package/src/Tool.ts +1 -1
  8. package/src/_shims/_generated_stubs/_universal_stub.mjs +168 -0
  9. package/src/_shims/_generated_stubs/stub_346f96741420f62caece15b196e233c6.mjs +19 -0
  10. package/src/_shims/_generated_stubs/stub_4b79af2a6ac1af5a53a55fd666b2bbb4.mjs +3 -0
  11. package/src/_shims/_generated_stubs/stub_94345ddeadacc184ff895597ec5abf71.mjs +6 -0
  12. package/src/_shims/_generated_stubs/stub_99fa0bc272643c549d8a2ec6d578436f.mjs +3 -0
  13. package/src/_shims/_generated_stubs/stub_e3451b131fcaf272a2a75270b9a427a3.mjs +9 -0
  14. package/src/_shims/_generated_stubs/text_stub.mjs +1 -0
  15. package/src/_shims/bun_bundle.js +79 -4
  16. package/src/_shims/cjs_stub.cjs +32 -10
  17. package/src/_shims/loader.js +104 -5
  18. package/src/_shims/openai_adapter.ts +446 -230
  19. package/src/_shims/register.js +16 -3
  20. package/src/assistant/gate.ts +15 -0
  21. package/src/assistant/index.ts +89 -0
  22. package/src/bootstrap/state.ts +6 -1
  23. package/src/bridge/peerSessions.ts +18 -0
  24. package/src/cli/print.ts +5 -0
  25. package/src/commands/assistant/assistant.ts +17 -0
  26. package/src/commands/assistant/index.ts +11 -0
  27. package/src/commands/brief.ts +3 -1
  28. package/src/commands/buddy/buddy.ts +88 -0
  29. package/src/commands/buddy/index.ts +12 -0
  30. package/src/commands/model/model.tsx +8 -23
  31. package/src/commands/peers/index.ts +11 -0
  32. package/src/commands/peers/peers.ts +24 -0
  33. package/src/commands/proactive/proactive.ts +64 -0
  34. package/src/commands/proactive.ts +12 -0
  35. package/src/commands/workflows/index.ts +12 -0
  36. package/src/commands/workflows/workflows.ts +36 -0
  37. package/src/commands.ts +4 -8
  38. package/src/components/Messages.tsx +1 -1
  39. package/src/components/ModelPicker.tsx +4 -34
  40. package/src/components/Spinner.tsx +54 -1
  41. package/src/components/StructuredDiff/colorDiff.ts +3 -1
  42. package/src/components/messages/SnipBoundaryMessage.tsx +15 -0
  43. package/src/components/messages/UserCrossSessionMessage.tsx +26 -0
  44. package/src/components/permissions/PermissionRequest.tsx +4 -2
  45. package/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.tsx +96 -0
  46. package/src/constants/prompts.ts +26 -0
  47. package/src/ink/terminal.ts +9 -1
  48. package/src/jobs/classifier.ts +103 -0
  49. package/src/memdir/paths.ts +13 -1
  50. package/src/proactive/index.ts +158 -0
  51. package/src/proactive/useProactive.ts +78 -0
  52. package/src/screens/REPL.tsx +28 -8
  53. package/src/services/api/claude.ts +6 -1
  54. package/src/services/compact/autoCompact.ts +18 -4
  55. package/src/services/compact/cachedMCConfig.ts +1 -0
  56. package/src/services/compact/cachedMicrocompact.ts +113 -0
  57. package/src/services/compact/compact.ts +22 -2
  58. package/src/services/compact/reactiveCompact.ts +251 -0
  59. package/src/services/compact/snipCompact.ts +282 -0
  60. package/src/services/compact/snipProjection.ts +50 -0
  61. package/src/services/contextCollapse/index.ts +322 -0
  62. package/src/services/contextCollapse/operations.ts +187 -0
  63. package/src/services/contextCollapse/persist.ts +40 -0
  64. package/src/services/extractMemories/extractMemories.ts +11 -2
  65. package/src/services/skillSearch/featureCheck.ts +12 -0
  66. package/src/services/skillSearch/localSearch.ts +98 -0
  67. package/src/services/skillSearch/prefetch.ts +125 -0
  68. package/src/services/skillSearch/remoteSkillLoader.ts +9 -0
  69. package/src/services/skillSearch/remoteSkillState.ts +21 -0
  70. package/src/services/skillSearch/signals.ts +7 -0
  71. package/src/services/skillSearch/telemetry.ts +9 -0
  72. package/src/setup.ts +10 -5
  73. package/src/skills/bundled/dream.ts +31 -0
  74. package/src/skills/bundled/hunter.ts +45 -0
  75. package/src/skills/bundled/index.ts +10 -23
  76. package/src/skills/bundled/runSkillGenerator.ts +61 -0
  77. package/src/skills/mcpSkills.ts +101 -0
  78. package/src/tasks/LocalWorkflowTask/LocalWorkflowTask.ts +301 -0
  79. package/src/tasks/MonitorMcpTask/MonitorMcpTask.ts +273 -0
  80. package/src/tasks.ts +22 -8
  81. package/src/tools/AgentTool/runAgent.ts +11 -0
  82. package/src/tools/BriefTool/BriefTool.ts +2 -0
  83. package/src/tools/CtxInspectTool/CtxInspectTool.ts +102 -0
  84. package/src/tools/DiscoverSkillsTool/DiscoverSkillsTool.ts +78 -0
  85. package/src/tools/DiscoverSkillsTool/prompt.ts +3 -0
  86. package/src/tools/ListPeersTool/ListPeersTool.ts +89 -0
  87. package/src/tools/MCPTool/MCPTool.ts +6 -0
  88. package/src/tools/MonitorTool/MonitorTool.ts +273 -0
  89. package/src/tools/MonitorTool/UI.tsx +25 -0
  90. package/src/tools/MonitorTool/events.ts +84 -0
  91. package/src/tools/MonitorTool/prompt.ts +45 -0
  92. package/src/tools/OverflowTestTool/OverflowTestTool.ts +73 -0
  93. package/src/tools/PushNotificationTool/PushNotificationTool.ts +119 -0
  94. package/src/tools/ReviewArtifactTool/ReviewArtifactTool.ts +93 -0
  95. package/src/tools/ReviewArtifactTool/prompt.ts +5 -0
  96. package/src/tools/SendUserFileTool/SendUserFileTool.ts +87 -0
  97. package/src/tools/SendUserFileTool/prompt.ts +7 -0
  98. package/src/tools/SleepTool/SleepTool.ts +126 -0
  99. package/src/tools/SnipTool/SnipTool.ts +90 -0
  100. package/src/tools/SnipTool/prompt.ts +5 -0
  101. package/src/tools/SubscribePRTool/SubscribePRTool.ts +115 -0
  102. package/src/tools/TerminalCaptureTool/TerminalCaptureTool.ts +129 -0
  103. package/src/tools/TerminalCaptureTool/prompt.ts +8 -0
  104. package/src/tools/ToolSearchTool/prompt.ts +1 -1
  105. package/src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.ts +99 -0
  106. package/src/tools/WebBrowserTool/WebBrowserPanel.tsx +10 -0
  107. package/src/tools/WebBrowserTool/WebBrowserTool.ts +190 -0
  108. package/src/tools/WebBrowserTool/prompt.ts +16 -0
  109. package/src/tools/WorkflowTool/UI.tsx +27 -0
  110. package/src/tools/WorkflowTool/WorkflowTool.ts +401 -0
  111. package/src/tools/WorkflowTool/bundled/index.ts +88 -0
  112. package/src/tools/WorkflowTool/constants.ts +7 -0
  113. package/src/tools/WorkflowTool/createWorkflowCommand.ts +84 -0
  114. package/src/tools/WorkflowTool/prompt.ts +38 -0
  115. package/src/tools/WorkflowTool/runtime.ts +331 -0
  116. package/src/tools.ts +36 -31
  117. package/src/utils/betas.ts +5 -0
  118. package/src/utils/context.ts +9 -0
  119. package/src/utils/conversationRecovery.ts +1 -1
  120. package/src/utils/forkedAgent.ts +4 -0
  121. package/src/utils/logoV2Utils.ts +7 -3
  122. package/src/utils/messageQueueManager.ts +23 -9
  123. package/src/utils/model/model.ts +10 -9
  124. package/src/utils/model/modelOptions.ts +0 -21
  125. package/src/utils/model/validateModel.ts +0 -19
  126. package/src/utils/permissions/permissionSetup.ts +5 -0
  127. package/src/utils/permissions/permissions.ts +25 -0
  128. package/src/utils/permissions/yolo-classifier-prompts/auto_mode_system_prompt.txt +38 -0
  129. package/src/utils/permissions/yolo-classifier-prompts/permissions_external.txt +25 -0
  130. package/src/utils/permissions/yoloClassifier.ts +28 -6
  131. package/src/utils/plugins/officialMarketplaceStartupCheck.ts +9 -0
  132. package/src/utils/systemThemeWatcher.ts +62 -0
  133. package/src/utils/udsClient.ts +115 -0
  134. package/src/utils/udsMessaging.ts +157 -0
  135. package/src/utils/yaml.ts +251 -5
  136. package/src/utils/model/providerModels.ts +0 -168
@@ -0,0 +1,112 @@
1
+ # Xela with a local model (llama.cpp)
2
+
3
+ Everything needed to run Xela on your own GPU, without any cloud API. Tested on
4
+ an RTX 5090 Laptop (24 GB) with Qwen3.6-27B at 31-47 tok/s.
5
+
6
+ ## 1. Install Xela
7
+
8
+ ```bash
9
+ npm install -g @xelauvas/xela-cli
10
+ ```
11
+
12
+ This gives you two commands: `xela` (cloud providers, interactive setup) and
13
+ `xela-local` (local model, this guide).
14
+
15
+ ## 2. Build llama.cpp with CUDA
16
+
17
+ ```bash
18
+ sudo apt install -y git cmake build-essential python3 curl
19
+ git clone https://github.com/ggml-org/llama.cpp ~/llama.cpp
20
+ cd ~/llama.cpp
21
+ cmake -B build -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=120 # 120 = RTX 50xx; 89 = RTX 40xx; 86 = RTX 30xx
22
+ cmake --build build --config Release -j --target llama-server
23
+ ```
24
+
25
+ Needs the NVIDIA driver and the CUDA toolkit (12.8 or newer for RTX 50xx).
26
+
27
+ ## 3. Download the model
28
+
29
+ ```bash
30
+ mkdir -p ~/models && cd ~/models
31
+ # main model, ~17.6 GB
32
+ curl -L -o Qwen3.6-27B-UD-Q4_K_XL.gguf \
33
+ https://huggingface.co/unsloth/Qwen3.6-27B-GGUF/resolve/main/Qwen3.6-27B-UD-Q4_K_XL.gguf
34
+ # MTP draft head for speculative decoding, ~3.2 GB (optional, +50% speed at 64k context)
35
+ curl -L -o mtp-Qwen3.6-27B-Q8_0.gguf \
36
+ https://huggingface.co/unsloth/Qwen3.6-27B-GGUF/resolve/main/mtp-Qwen3.6-27B-Q8_0.gguf
37
+ ```
38
+
39
+ Keep the models on the Linux disk (not `/mnt/c`) when using WSL.
40
+
41
+ ## 4. Run
42
+
43
+ ```bash
44
+ xela-local # starts the server if needed, then Xela in the current directory
45
+ CTX=65536 xela-local # faster mode: 64k context + speculative decoding
46
+ OPENAI_THINKING=off xela-local # no reasoning, quicker answers
47
+ ```
48
+
49
+ Environment variables (all optional):
50
+
51
+ | Variable | Default | Meaning |
52
+ |---|---|---|
53
+ | `XELA_MODELS_DIR` | `~/models` | folder with the GGUF files |
54
+ | `LLAMA_SERVER` | `~/llama.cpp/build/bin/llama-server` | server binary |
55
+ | `CTX` | `131072` | context length; MTP turns on automatically at 65536 or less |
56
+ | `XELA_CONFIG_DIR` | `~/.xela-local` | Xela config, separate from `~/.claude` |
57
+ | `XELA_SERVER_URL` | `http://localhost:8080` | use an existing server (another machine works too) |
58
+
59
+ The server can be started by hand with `start-qwen.sh` (same directory as
60
+ `xela-local`); its log is in `$XELA_MODELS_DIR/server.log`.
61
+
62
+ ## What is different from the cloud setup
63
+
64
+ - Auto mode permission classifier runs on the local model; read-only tools skip
65
+ it. Expect 5-7 s per write/shell action.
66
+ - Background memory extraction, compaction, workflows and subagents all use the
67
+ same local server (4 parallel slots).
68
+ - `/peers`, proactive mode (`/proactive on`), assistant mode (`xela-local --assistant`)
69
+ and the other Claude Code features are enabled by default; see
70
+ `src/_shims/bun_bundle.js` for the feature list (`XELA_FEATURES_DISABLE=NAME` to turn one off).
71
+
72
+ ## Using Xela from any computer (like Claude Code or Codex)
73
+
74
+ The model server stays on the GPU machine; Xela on any other computer or
75
+ network talks to it over the internet. Install once, enter the server address
76
+ once, then just run `xela-local`.
77
+
78
+ **On the GPU machine**, start the server with a key and expose it through a
79
+ tunnel (no router or firewall changes needed; the key is the only protection,
80
+ so keep it secret):
81
+
82
+ ```bash
83
+ LLAMA_API_KEY=choose-a-secret CTX=65536 start-qwen.sh # or let xela-local start it
84
+ start-tunnel.sh # ngrok (needs `ngrok config add-authtoken ...` once)
85
+ ```
86
+
87
+ `start-tunnel.sh` prints the public https URL and checks that requests without
88
+ the key are refused. The free ngrok URL changes on every restart; claim the
89
+ free static domain in the ngrok dashboard (Domains) and run
90
+ `NGROK_DOMAIN=yourname.ngrok-free.app start-tunnel.sh` to keep it fixed.
91
+
92
+ Same network only? Skip the tunnel and use `http://<gpu-machine-ip>:8080`. If
93
+ the server runs inside WSL, enable mirrored networking (Windows 11: add
94
+ `networkingMode=mirrored` under `[wsl2]` in `%UserProfile%\.wslconfig`, then
95
+ `wsl --shutdown`) and allow port 8080 in the Windows firewall:
96
+
97
+ ```powershell
98
+ New-NetFirewallHyperVRule -Name llama-8080 -DisplayName "llama-server 8080 (WSL)" -Direction Inbound -VMCreatorId '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' -Protocol TCP -LocalPorts 8080
99
+ New-NetFirewallRule -DisplayName "llama-server 8080" -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow
100
+ ```
101
+
102
+ **On any other computer** (Node 20+ and bash/curl; no GPU, no model):
103
+
104
+ ```bash
105
+ npm install -g @xelauvas/xela-cli
106
+ xela-local # first run asks: Server URL, API key → saved in ~/.xela-local/server.env
107
+ ```
108
+
109
+ Afterwards `xela-local` works in any directory. `xela-local --setup` changes
110
+ the server; `xela-local --server URL --key KEY` sets it non-interactively.
111
+ `XELA_SERVER_URL` / `LLAMA_API_KEY` in the environment override the saved
112
+ values. The launcher never starts a server when the address is not localhost.
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+ # Start a local Qwen3.6-27B as an OpenAI-compatible server on http://localhost:8080/v1
3
+ # using llama.cpp. Tuned for a 24 GB GPU.
4
+ #
5
+ # XELA_MODELS_DIR where the GGUF files live (default ~/models)
6
+ # LLAMA_SERVER llama-server binary (default ~/llama.cpp/build/bin/llama-server)
7
+ # MODEL main model file (default Qwen3.6-27B-UD-Q4_K_XL.gguf)
8
+ # MTP_MODEL MTP draft head for speculative decoding (default mtp-Qwen3.6-27B-Q8_0.gguf)
9
+ # CTX context length (default 131072); MTP is enabled automatically at <= 65536
10
+ # MTP=0|1 force speculative decoding on/off (both do not fit in 24 GB at 128k)
11
+ # PORT default 8080
12
+ # LLAMA_API_KEY if set, clients must send it as a Bearer token (use it when exposing the port)
13
+ #
14
+ # Modes on a 24 GB card:
15
+ # CTX=131072 (default) no MTP ~31 tok/s, large context, rare compactions
16
+ # CTX=65536 + MTP ~47 tok/s, auto-compact kicks in more often
17
+ set -u
18
+ MODELS="${XELA_MODELS_DIR:-$HOME/models}"
19
+ BIN="${LLAMA_SERVER:-$HOME/llama.cpp/build/bin/llama-server}"
20
+ MODEL_FILE="$MODELS/${MODEL:-Qwen3.6-27B-UD-Q4_K_XL.gguf}"
21
+ MTP_FILE="$MODELS/${MTP_MODEL:-mtp-Qwen3.6-27B-Q8_0.gguf}"
22
+ CTX="${CTX:-131072}"
23
+ PORT="${PORT:-8080}"
24
+ if [ -z "${MTP:-}" ]; then
25
+ [ "$CTX" -le 65536 ] && MTP=1 || MTP=0
26
+ fi
27
+ [ -x "$BIN" ] || { echo "llama-server not found at $BIN (set LLAMA_SERVER). See local/README.md." >&2; exit 1; }
28
+ [ -f "$MODEL_FILE" ] || { echo "model not found: $MODEL_FILE (set XELA_MODELS_DIR / MODEL). See local/README.md." >&2; exit 1; }
29
+ KEY=()
30
+ [ -n "${LLAMA_API_KEY:-}" ] && KEY=(--api-key "$LLAMA_API_KEY")
31
+ SPEC=()
32
+ if [ "$MTP" = "1" ] && [ -f "$MTP_FILE" ]; then
33
+ SPEC=(-md "$MTP_FILE" --spec-type draft-mtp)
34
+ fi
35
+ exec "$BIN" \
36
+ -m "$MODEL_FILE" \
37
+ "${SPEC[@]}" "${KEY[@]}" \
38
+ --alias qwen3.6-27b \
39
+ -ngl 99 \
40
+ -c "$CTX" \
41
+ -fa on \
42
+ --cache-type-k q8_0 --cache-type-v q8_0 \
43
+ --cache-reuse 256 \
44
+ --cache-ram 0 --no-cache-idle-slots \
45
+ --jinja \
46
+ --temp 0.6 --top-p 0.95 --top-k 20 --min-p 0 \
47
+ --host 0.0.0.0 --port "$PORT"
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env bash
2
+ # Expose the model server (localhost:8080) on the internet through ngrok and print the public URL.
3
+ # The server must run with LLAMA_API_KEY: the key is the only protection of the public URL.
4
+ # NGROK_DOMAIN=yourname.ngrok-free.app start-tunnel.sh fixed URL (free static domain from the ngrok dashboard)
5
+ # PORT=8080 XELA_MODELS_DIR=~/models defaults
6
+ set -u
7
+ PORT="${PORT:-8080}"
8
+ MODELS="${XELA_MODELS_DIR:-$HOME/models}"
9
+ command -v ngrok >/dev/null || { echo "ngrok is not installed: https://ngrok.com/download, then: ngrok config add-authtoken <token>" >&2; exit 1; }
10
+ pgrep -x llama-server >/dev/null || { echo "llama-server is not running; start it with start-qwen.sh" >&2; exit 1; }
11
+ KEY="${LLAMA_API_KEY:-$(cat "$MODELS/llama-api-key" 2>/dev/null)}"
12
+ [ -z "$KEY" ] && echo "WARNING: no API key (LLAMA_API_KEY or $MODELS/llama-api-key): the public URL will be open to everyone" >&2
13
+ pkill -x ngrok 2>/dev/null || true
14
+ DOM=(); [ -n "${NGROK_DOMAIN:-}" ] && DOM=(--url "https://$NGROK_DOMAIN")
15
+ nohup ngrok http "$PORT" "${DOM[@]}" --log "$MODELS/ngrok.log" --log-format json >/dev/null 2>&1 &
16
+ disown
17
+ URL=""
18
+ for _ in $(seq 1 15); do
19
+ URL=$(curl -s http://127.0.0.1:4040/api/tunnels 2>/dev/null | grep -o '"public_url":"https://[^"]*"' | head -1 | cut -d'"' -f4)
20
+ [ -n "$URL" ] && break
21
+ sleep 1
22
+ done
23
+ [ -z "$URL" ] && { echo "ngrok did not start:" >&2; grep -o '"err":"[^"]*"' "$MODELS/ngrok.log" | tail -3 >&2; exit 1; }
24
+ # ngrok answers 404 "tunnel not found" for a few seconds after start
25
+ for _ in $(seq 1 20); do
26
+ code=$(curl -s -o /dev/null -w '%{http_code}' "$URL/v1/models")
27
+ [ "$code" != "404" ] && [ "$code" != "000" ] && break
28
+ sleep 1
29
+ done
30
+ AUTH=(); [ -n "$KEY" ] && AUTH=(-H "Authorization: Bearer $KEY")
31
+ echo "Public URL: $URL"
32
+ echo "without key: HTTP $(curl -s -o /dev/null -w '%{http_code}' "$URL/v1/models") (expected 401)"
33
+ echo "with key: HTTP $(curl -s -o /dev/null -w '%{http_code}' "${AUTH[@]}" "$URL/v1/models") (expected 200)"
34
+ echo
35
+ echo "On another computer: npm install -g @xelauvas/xela-cli && xela-local --server $URL --key <key>"
36
+ echo "Stop the tunnel: pkill -x ngrok"
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env bash
2
+ # Run Xela against your own model server (llama-server). Works from any directory.
3
+ #
4
+ # xela-local interactive (first run on a machine without a GPU asks for
5
+ # the server URL + API key once and saves them, like a login)
6
+ # xela-local -p "question" one answer
7
+ # xela-local --setup enter the server URL / API key again
8
+ # xela-local --server URL --key KEY one-off override (also saved for next time)
9
+ #
10
+ # Env overrides (take precedence over the saved config):
11
+ # XELA_SERVER_URL=... default http://localhost:8080; a remote host never starts a server
12
+ # LLAMA_API_KEY=... key the server was started with (start-qwen.sh LLAMA_API_KEY)
13
+ # XELA_CONFIG_DIR=... config dir (default ~/.xela-local, separate from ~/.claude)
14
+ # OPENAI_THINKING=off no reasoning (faster, weaker on hard tasks)
15
+ set -u
16
+ HERE="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
17
+ ROOT="$(cd "$HERE/.." && pwd)"
18
+ export CLAUDE_CONFIG_DIR="${XELA_CONFIG_DIR:-$HOME/.xela-local}"
19
+ SERVER_CONF="$CLAUDE_CONFIG_DIR/server.env"
20
+ MODEL_FILE="${XELA_MODEL_FILE:-${XELA_MODELS_DIR:-$HOME/models}/Qwen3.6-27B-UD-Q4_K_XL.gguf}"
21
+ LOG="${XELA_SERVER_LOG:-${XELA_MODELS_DIR:-$HOME/models}/server.log}"
22
+
23
+ # --- arguments handled here: --setup, --server, --key -------------------------------------
24
+ SETUP=0; ARGS=()
25
+ while [ $# -gt 0 ]; do
26
+ case "$1" in
27
+ --setup) SETUP=1; shift ;;
28
+ --server) XELA_SERVER_URL="$2"; SETUP=2; shift 2 ;;
29
+ --key) LLAMA_API_KEY="$2"; SETUP=2; shift 2 ;;
30
+ *) ARGS+=("$1"); shift ;;
31
+ esac
32
+ done
33
+ set -- "${ARGS[@]+"${ARGS[@]}"}"
34
+
35
+ # --- saved config (env wins) -------------------------------------------------------------
36
+ if [ -f "$SERVER_CONF" ]; then
37
+ SAVED_URL=$(sed -n 's/^XELA_SERVER_URL=//p' "$SERVER_CONF" | tail -1)
38
+ SAVED_KEY=$(sed -n 's/^LLAMA_API_KEY=//p' "$SERVER_CONF" | tail -1)
39
+ : "${XELA_SERVER_URL:=$SAVED_URL}"
40
+ : "${LLAMA_API_KEY:=$SAVED_KEY}"
41
+ fi
42
+ [ -z "${LLAMA_API_KEY:-}" ] && [ -f "${XELA_MODELS_DIR:-$HOME/models}/llama-api-key" ] && \
43
+ LLAMA_API_KEY=$(cat "${XELA_MODELS_DIR:-$HOME/models}/llama-api-key")
44
+
45
+ health() { # $1 url, $2 key
46
+ local a=(); [ -n "$2" ] && a=(-H "Authorization: Bearer $2")
47
+ # /v1/models requires the API key (unlike /health), so a wrong key fails here, not later
48
+ curl -sf --connect-timeout 5 "${a[@]}" "$1/v1/models" >/dev/null 2>&1
49
+ }
50
+ save_conf() {
51
+ mkdir -p "$CLAUDE_CONFIG_DIR"
52
+ printf 'XELA_SERVER_URL=%s\nLLAMA_API_KEY=%s\n' "$XELA_SERVER_URL" "${LLAMA_API_KEY:-}" > "$SERVER_CONF"
53
+ chmod 600 "$SERVER_CONF"
54
+ }
55
+ setup() {
56
+ echo "" >&2
57
+ echo " Xela needs a model server (llama-server started with local/start-qwen.sh)." >&2
58
+ echo " Enter its address, e.g. https://xxxx.ngrok-free.app or http://192.168.1.20:8080" >&2
59
+ echo "" >&2
60
+ while :; do
61
+ read -r -p " Server URL [${XELA_SERVER_URL:-http://localhost:8080}]: " u </dev/tty
62
+ XELA_SERVER_URL="${u:-${XELA_SERVER_URL:-http://localhost:8080}}"
63
+ XELA_SERVER_URL="${XELA_SERVER_URL%/}"; XELA_SERVER_URL="${XELA_SERVER_URL%/v1}"
64
+ read -r -s -p " API key (empty if the server has none): " k </dev/tty; echo "" >&2
65
+ [ -n "$k" ] && LLAMA_API_KEY="$k"
66
+ if health "$XELA_SERVER_URL" "${LLAMA_API_KEY:-}"; then
67
+ save_conf
68
+ echo " Connected. Saved to $SERVER_CONF (xela-local --setup to change)." >&2
69
+ echo "" >&2
70
+ return 0
71
+ fi
72
+ echo " Cannot reach $XELA_SERVER_URL with that key. Try again (Ctrl+C to quit)." >&2
73
+ done
74
+ }
75
+
76
+ if [ "$SETUP" = "1" ]; then
77
+ setup
78
+ elif [ "$SETUP" = "2" ]; then
79
+ XELA_SERVER_URL="${XELA_SERVER_URL:-http://localhost:8080}"
80
+ health "$XELA_SERVER_URL" "${LLAMA_API_KEY:-}" || { echo "Model server not reachable at $XELA_SERVER_URL" >&2; exit 1; }
81
+ save_conf
82
+ fi
83
+
84
+ SERVER="${XELA_SERVER_URL:-http://localhost:8080}"
85
+ case "$SERVER" in
86
+ http://localhost*|http://127.0.0.1*|http://0.0.0.0*) REMOTE=0 ;;
87
+ *) REMOTE=1 ;;
88
+ esac
89
+
90
+ if ! health "$SERVER" "${LLAMA_API_KEY:-}"; then
91
+ if [ "$REMOTE" = "1" ]; then
92
+ echo "Model server not reachable at $SERVER. Is it (and the tunnel) running? Run xela-local --setup to change it." >&2
93
+ exit 1
94
+ elif [ ! -f "$MODEL_FILE" ]; then
95
+ # No local model on this machine: first run → ask where the server is.
96
+ setup
97
+ SERVER="$XELA_SERVER_URL"
98
+ else
99
+ echo "Starting the local model server (log: $LOG)..." >&2
100
+ mkdir -p "$(dirname "$LOG")"
101
+ nohup "$HERE/start-qwen.sh" > "$LOG" 2>&1 &
102
+ for _ in $(seq 1 180); do
103
+ health "$SERVER" "${LLAMA_API_KEY:-}" && break
104
+ sleep 1
105
+ done
106
+ if ! health "$SERVER" "${LLAMA_API_KEY:-}"; then
107
+ echo "Server did not come up in 3 minutes. See $LOG" >&2
108
+ exit 1
109
+ fi
110
+ fi
111
+ fi
112
+ AUTH=(); [ -n "${LLAMA_API_KEY:-}" ] && AUTH=(-H "Authorization: Bearer $LLAMA_API_KEY")
113
+
114
+ # Variables inherited from a real Claude Code session would mix the two apps.
115
+ unset CLAUDE_CODE_MESSAGING_SOCKET CLAUDE_CODE_SESSION_KIND CLAUDE_CODE_SESSION_NAME CLAUDE_CODE_SESSION_LOG \
116
+ CLAUDE_CODE_ENTRYPOINT CLAUDECODE CLAUDE_CODE_SSE_PORT CLAUDE_CODE_AGENT CLAUDE_PLAN_FILE 2>/dev/null
117
+
118
+ if [ ! -f "$CLAUDE_CONFIG_DIR/.claude.json" ]; then
119
+ mkdir -p "$CLAUDE_CONFIG_DIR"
120
+ echo '{"hasCompletedOnboarding": true, "numStartups": 1}' > "$CLAUDE_CONFIG_DIR/.claude.json"
121
+ fi
122
+ if [ ! -f "$CLAUDE_CONFIG_DIR/settings.json" ]; then
123
+ echo '{"theme": "dark", "skipAutoPermissionPrompt": true, "permissions": {"defaultMode": "auto"}}' > "$CLAUDE_CONFIG_DIR/settings.json"
124
+ fi
125
+
126
+ export DISABLE_INSTALLATION_CHECKS=1 DISABLE_AUTOUPDATER=1 CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL=1
127
+ export DISABLE_LOGIN_COMMAND=1 DISABLE_LOGOUT_COMMAND=1 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
128
+ export OPENAI_API_KEY="${OPENAI_API_KEY:-${LLAMA_API_KEY:-local}}"
129
+ export OPENAI_BASE_URL="${OPENAI_BASE_URL:-$SERVER/v1}"
130
+ export OPENAI_MODEL="${OPENAI_MODEL:-qwen3.6-27b}"
131
+
132
+ # Real context size of the server (drives the context indicator and auto-compact); no python needed
133
+ CTX=$(curl -s --connect-timeout 5 "${AUTH[@]}" "$SERVER/props" | grep -o '"n_ctx":[0-9]*' | head -1 | cut -d: -f2)
134
+ CTX="${CTX:-65536}"
135
+ export OPENAI_CONTEXT_WINDOW="$CTX"
136
+ MAX_OUT=$(( CTX / 4 )); [ "$MAX_OUT" -lt 16384 ] && MAX_OUT=16384
137
+ export OPENAI_MAX_TOKENS="${OPENAI_MAX_TOKENS:-$MAX_OUT}"
138
+
139
+ exec "$ROOT/run.sh" "$@"
package/package.json CHANGED
@@ -1,22 +1,36 @@
1
1
  {
2
2
  "name": "@xelauvas/xela-cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Xela — AI coding assistant powered by any model (OpenRouter, Groq, Ollama, DeepSeek, OpenAI)",
5
5
  "author": "xelauvas",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "https://github.com/xelauvas/codeclau.git"
10
+ "url": "git+https://github.com/xelauvas/codeclau.git"
11
11
  },
12
- "keywords": ["ai", "coding", "assistant", "cli", "openrouter", "groq", "ollama", "deepseek", "xela"],
12
+ "keywords": [
13
+ "ai",
14
+ "coding",
15
+ "assistant",
16
+ "cli",
17
+ "openrouter",
18
+ "groq",
19
+ "ollama",
20
+ "deepseek",
21
+ "xela"
22
+ ],
13
23
  "bin": {
14
- "xela": "./bin/xela.js"
24
+ "xela": "bin/xela.js",
25
+ "xela-local": "local/xela-local.sh",
26
+ "xela-tunnel": "local/start-tunnel.sh"
15
27
  },
16
28
  "files": [
17
29
  "bin/",
18
30
  "src/",
19
- "start.js"
31
+ "start.js",
32
+ "local/",
33
+ "run.sh"
20
34
  ],
21
35
  "scripts": {
22
36
  "start": "node --import ./src/_shims/register.js ./src/entrypoints/cli.tsx",
package/run.sh ADDED
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+ # Run Claude Code with any OpenAI-compatible backend
3
+ #
4
+ # Providers (auto-detected from key prefix or OPENAI_BASE_URL):
5
+ #
6
+ # OpenAI: OPENAI_API_KEY=sk-proj-...
7
+ # Groq (free): OPENAI_API_KEY=gsk_...
8
+ # OpenRouter: OPENAI_API_KEY=sk-or-...
9
+ # DeepSeek: OPENAI_API_KEY=sk-... OPENAI_BASE_URL=https://api.deepseek.com
10
+ # Moonshot: OPENAI_API_KEY=sk-... OPENAI_BASE_URL=https://api.moonshot.cn/v1
11
+ # Ollama: OPENAI_API_KEY=ollama OPENAI_BASE_URL=http://localhost:11434/v1
12
+ # Mistral: OPENAI_API_KEY=... OPENAI_BASE_URL=https://api.mistral.ai/v1
13
+ # Together: OPENAI_API_KEY=... OPENAI_BASE_URL=https://api.together.xyz/v1
14
+ #
15
+ # Optional: OPENAI_MODEL=model-name (auto-detected per provider)
16
+
17
+ if [ -z "$OPENAI_API_KEY" ]; then
18
+ echo "Error: OPENAI_API_KEY is not set"
19
+ echo ""
20
+ echo "Usage examples:"
21
+ echo " OPENAI_API_KEY=sk-... ./run.sh # OpenAI (gpt-4o)"
22
+ echo " OPENAI_API_KEY=gsk_... ./run.sh # Groq free (llama-3.3-70b)"
23
+ echo " OPENAI_API_KEY=sk-or-... ./run.sh # OpenRouter"
24
+ echo " OPENAI_API_KEY=sk-... OPENAI_BASE_URL=https://api.deepseek.com ./run.sh # DeepSeek"
25
+ exit 1
26
+ fi
27
+
28
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
29
+
30
+ exec node \
31
+ --import "$SCRIPT_DIR/src/_shims/register.js" \
32
+ "$SCRIPT_DIR/start.js" \
33
+ "$@"
package/src/Tool.ts CHANGED
@@ -152,7 +152,7 @@ export type CompactProgressEvent =
152
152
  type: 'hooks_start'
153
153
  hookType: 'pre_compact' | 'post_compact' | 'session_start'
154
154
  }
155
- | { type: 'compact_start' }
155
+ | { type: 'compact_start'; preCompactTokenCount?: number }
156
156
  | { type: 'compact_end' }
157
157
 
158
158
  export type ToolUseContext = {
@@ -0,0 +1,168 @@
1
+ // Universal stub — exports all known names for unresolved modules
2
+ export default {};
3
+
4
+ // --- Arrays (names ending in S, LIST, TOOLS, etc.) ---
5
+ export const BROWSER_TOOLS = [];
6
+ export const DEFAULT_SESSION_TIMEOUT_MS = [];
7
+ export const RARITY_COLORS = [];
8
+ export const EYES = [];
9
+ export const HATS = [];
10
+ export const RARITIES = [];
11
+ export const RARITY_WEIGHTS = [];
12
+ export const SPECIES = [];
13
+ export const STAT_NAMES = [];
14
+ export const AGENT_PATHS = [];
15
+ export const DEFAULT_GRANT_FLAGS = [];
16
+ export const MEMORY_TYPE_VALUES = [];
17
+ export const SYNC_KEYS = [];
18
+ export const CUSTOMIZATION_SURFACES = [];
19
+ export const FIND_KEYS = [];
20
+ export const OPERATORS = [];
21
+ export const SIMPLE_MOTIONS = [];
22
+ export const TEXT_OBJ_SCOPES = [];
23
+ export const TEXT_OBJ_TYPES = [];
24
+ export const SOURCES = [];
25
+ export const FRAME_INTERVAL_MS = [];
26
+ export const ONE_SHOT_BUILTIN_AGENT_TYPES = [];
27
+ export const REPL_ONLY_TOOLS = [];
28
+ export const SETTING_SOURCES = [];
29
+ export const MDM_SUBPROCESS_TIMEOUT_MS = [];
30
+
31
+ // --- Functions (is/has/get/set/create/handle...) ---
32
+ export const isBackgroundTask = () => undefined;
33
+ export const isInProcessTeammateTask = () => undefined;
34
+ export const isMcpServerCommandEntry = () => undefined;
35
+ export const isMcpServerNameEntry = () => undefined;
36
+ export const isMcpServerUrlEntry = () => undefined;
37
+ export const isPaneBackend = () => undefined;
38
+ export const isOperatorKey = () => undefined;
39
+ export const isTextObjScopeKey = () => undefined;
40
+ export const isReplModeEnabled = () => undefined;
41
+ export const isSettingSourceEnabled = () => undefined;
42
+ export const getSourceDisplayName = () => undefined;
43
+ export const getSettingSourceName = () => undefined;
44
+ export const getSwarmSocketName = () => undefined;
45
+ export const getSettingSourceDisplayNameLowercase = () => undefined;
46
+ export const getSettingSourceDisplayNameCapitalized = () => undefined;
47
+ export const getEnabledSettingSources = () => undefined;
48
+ export const getMacOSPlistPaths = () => undefined;
49
+ export const getSyntaxTheme = () => undefined;
50
+ export const createClaudeForChromeMcpServer = () => undefined;
51
+ export const createInitialPersistentState = () => undefined;
52
+ export const createInitialVimState = () => undefined;
53
+ export const parseSettingSourcesFlag = () => undefined;
54
+ export const reduceAnsiCodes = () => undefined;
55
+
56
+ // --- Constants/schemas/values ---
57
+ export const BRIDGE_LOGIN_INSTRUCTION = undefined;
58
+ export const BRIDGE_LOGIN_ERROR = undefined;
59
+ export const axolotl = undefined;
60
+ export const blob = undefined;
61
+ export const cactus = undefined;
62
+ export const capybara = undefined;
63
+ export const cat = undefined;
64
+ export const chonk = undefined;
65
+ export const dragon = undefined;
66
+ export const duck = undefined;
67
+ export const ghost = undefined;
68
+ export const goose = undefined;
69
+ export const mushroom = undefined;
70
+ export const octopus = undefined;
71
+ export const owl = undefined;
72
+ export const penguin = undefined;
73
+ export const rabbit = undefined;
74
+ export const robot = undefined;
75
+ export const snail = undefined;
76
+ export const turtle = undefined;
77
+ export const ElicitRequestSchema = undefined;
78
+ export const ElicitationCompleteNotificationSchema = undefined;
79
+ export const REMOTE_CONTROL_DISCONNECTED_MSG = undefined;
80
+ export const CallToolRequestSchema = undefined;
81
+ export const ListToolsRequestSchema = undefined;
82
+ export const defaultStyle = undefined;
83
+ export const connectResponseSchema = undefined;
84
+ export const CallToolResultSchema = undefined;
85
+ export const ErrorCode = undefined;
86
+ export const ListPromptsResultSchema = undefined;
87
+ export const ListResourcesResultSchema = undefined;
88
+ export const ListRootsRequestSchema = undefined;
89
+ export const ListToolsResultSchema = undefined;
90
+ export const McpError = undefined;
91
+ export const McpJsonConfigSchema = undefined;
92
+ export const McpServerConfigSchema = undefined;
93
+ export const PromptListChangedNotificationSchema = undefined;
94
+ export const ResourceListChangedNotificationSchema = undefined;
95
+ export const ToolListChangedNotificationSchema = undefined;
96
+ export const ConfigScopeSchema = undefined;
97
+ export const PolicyLimitsResponseSchema = undefined;
98
+ export const SettingsSchema = undefined;
99
+ export const RemoteManagedSettingsResponseSchema = undefined;
100
+ export const UserSyncDataSchema = undefined;
101
+ export const TeamMemoryDataSchema = undefined;
102
+ export const TeamMemoryTooManyEntriesSchema = undefined;
103
+ export const HooksSchema = undefined;
104
+ export const appendCappedMessage = undefined;
105
+ export const inputSchema = undefined;
106
+ export const outputSchema = undefined;
107
+ export const gitDiffSchema = undefined;
108
+ export const hunkSchema = undefined;
109
+ export const ReadResourceResultSchema = undefined;
110
+ export const TodoListSchema = undefined;
111
+ export const McpStdioServerConfigSchema = undefined;
112
+ export const DEFAULT_UPLOAD_CONCURRENCY = undefined;
113
+ export const FILE_COUNT_LIMIT = undefined;
114
+ export const OUTPUTS_SUBDIR = undefined;
115
+ export const JSONRPCMessageSchema = undefined;
116
+ export const MAX_VIM_COUNT = undefined;
117
+ export const AGENT_TOOL_NAME = undefined;
118
+ export const LEGACY_AGENT_TOOL_NAME = undefined;
119
+ export const EXIT_PLAN_MODE_V2_TOOL_NAME = undefined;
120
+ export const TEAM_CREATE_TOOL_NAME = undefined;
121
+ export const CLAUDE_FOLDER_PERMISSION_PATTERN = undefined;
122
+ export const FILE_EDIT_TOOL_NAME = undefined;
123
+ export const GLOBAL_CLAUDE_FOLDER_PERMISSION_PATTERN = undefined;
124
+ export const SKILL_TOOL_NAME = undefined;
125
+ export const TEAM_LEAD_NAME = undefined;
126
+ export const TMUX_COMMAND = undefined;
127
+ export const VERIFICATION_AGENT_TYPE = undefined;
128
+ export const TODO_WRITE_TOOL_NAME = undefined;
129
+ export const TASK_CREATE_TOOL_NAME = undefined;
130
+ export const TASK_OUTPUT_TOOL_NAME = undefined;
131
+ export const ENTER_PLAN_MODE_TOOL_NAME = undefined;
132
+ export const NOTEBOOK_EDIT_TOOL_NAME = undefined;
133
+ export const SEND_MESSAGE_TOOL_NAME = undefined;
134
+ export const TASK_GET_TOOL_NAME = undefined;
135
+ export const TASK_LIST_TOOL_NAME = undefined;
136
+ export const TASK_UPDATE_TOOL_NAME = undefined;
137
+ export const ENTER_WORKTREE_TOOL_NAME = undefined;
138
+ export const EXIT_WORKTREE_TOOL_NAME = undefined;
139
+ export const WORKFLOW_TOOL_NAME = undefined;
140
+ export const TEAM_DELETE_TOOL_NAME = undefined;
141
+ export const ContinuousEventPriority = undefined;
142
+ export const DefaultEventPriority = undefined;
143
+ export const DiscreteEventPriority = undefined;
144
+ export const NoEventPriority = undefined;
145
+ export const ConcurrentRoot = undefined;
146
+ export const LegacyRoot = undefined;
147
+ export const REPL_TOOL_NAME = undefined;
148
+ export const EXIT_PLAN_MODE_TOOL_NAME = undefined;
149
+ export const CONFIG_TOOL_NAME = undefined;
150
+ export const FILE_UNEXPECTEDLY_MODIFIED_ERROR = undefined;
151
+ export const TOOL_SEARCH_TOOL_NAME = undefined;
152
+ export const SWARM_SESSION_NAME = undefined;
153
+ export const TEAMMATE_COMMAND_ENV_VAR = undefined;
154
+ export const PLUTIL_ARGS_PREFIX = undefined;
155
+ export const PLUTIL_PATH = undefined;
156
+ export const WINDOWS_REGISTRY_KEY_PATH_HKCU = undefined;
157
+ export const WINDOWS_REGISTRY_KEY_PATH_HKLM = undefined;
158
+ export const WINDOWS_REGISTRY_VALUE_NAME = undefined;
159
+ export const CLAUDE_CODE_SETTINGS_SCHEMA_URL = undefined;
160
+ export const HIDDEN_SESSION_NAME = undefined;
161
+ export const SWARM_VIEW_WINDOW_NAME = undefined;
162
+ export const ColorDiff = undefined;
163
+ export const ColorFile = undefined;
164
+ export const ansiCodesToString = undefined;
165
+ export const diffAnsiCodes = undefined;
166
+ export const styledCharsFromTokens = undefined;
167
+ export const tokenize = undefined;
168
+ export const undoAnsiCodes = undefined;
@@ -0,0 +1,19 @@
1
+ // Generated stub for missing module ./sdk/runtimeTypes.js (imported by entrypoints/agentSdkTypes.ts)
2
+ export const AnyZodRawShape = undefined;
3
+ export const ForkSessionOptions = undefined;
4
+ export const ForkSessionResult = undefined;
5
+ export const GetSessionInfoOptions = undefined;
6
+ export const GetSessionMessagesOptions = undefined;
7
+ export const InferShape = undefined;
8
+ export const InternalOptions = undefined;
9
+ export const InternalQuery = undefined;
10
+ export const ListSessionsOptions = undefined;
11
+ export const McpSdkServerConfigWithInstance = undefined;
12
+ export const Options = undefined;
13
+ export const Query = undefined;
14
+ export const SDKSession = undefined;
15
+ export const SDKSessionOptions = undefined;
16
+ export const SdkMcpToolDefinition = undefined;
17
+ export const SessionMessage = undefined;
18
+ export const SessionMutationOptions = undefined;
19
+ export default {};
@@ -0,0 +1,3 @@
1
+ // Generated stub for missing module @ant/claude-for-chrome-mcp (imported by utils/claudeInChrome/setup.ts)
2
+ export const BROWSER_TOOLS = [];
3
+ export default {};
@@ -0,0 +1,6 @@
1
+ // Generated stub for missing module color-diff-napi (imported by components/StructuredDiff/colorDiff.ts)
2
+ export const ColorDiff = undefined;
3
+ export const ColorFile = undefined;
4
+ export const getSyntaxTheme = () => undefined;
5
+ export const SyntaxTheme = undefined;
6
+ export default {};
@@ -0,0 +1,3 @@
1
+ // Generated stub for missing module ../tools/TungstenTool/TungstenLiveMonitor.js (imported by screens/REPL.tsx)
2
+ export const TungstenLiveMonitor = undefined;
3
+ export default {};
@@ -0,0 +1,9 @@
1
+ // Generated stub for missing module ./types.js (imported by utils/filePersistence/filePersistence.ts)
2
+ export const DEFAULT_UPLOAD_CONCURRENCY = '';
3
+ export const FailedPersistence = undefined;
4
+ export const FILE_COUNT_LIMIT = '';
5
+ export const FilesPersistedEventData = undefined;
6
+ export const OUTPUTS_SUBDIR = '';
7
+ export const PersistedFile = undefined;
8
+ export const TurnStartTime = undefined;
9
+ export default {};
@@ -0,0 +1 @@
1
+ export default '';