@inetafrica/open-claudia 1.16.0 → 1.16.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/CHANGELOG.md +5 -0
- package/bot.js +55 -23
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.16.1
|
|
4
|
+
- `/model` is now a single unified picker — all Claude, Cursor, and Codex models in one keyboard, with section dividers per backend
|
|
5
|
+
- Tapping any model auto-switches the active backend if needed (e.g. picking gpt-5 from Claude flips you to Codex). No more `/codex` + `/model` two-step
|
|
6
|
+
- Only backends with a detected CLI binary appear in the picker (Cursor/Codex rows hidden if not installed)
|
|
7
|
+
|
|
3
8
|
## v1.16.0
|
|
4
9
|
- OpenAI Codex backend support: `/codex` to switch, `/backend` picker now has 3 options
|
|
5
10
|
- Auto-detects `codex` binary via `which codex` at startup; opt-in via `CODEX_PATH` in .env
|
package/bot.js
CHANGED
|
@@ -1750,30 +1750,43 @@ bot.onText(/\/sessions$/, (msg) => {
|
|
|
1750
1750
|
|
|
1751
1751
|
bot.onText(/\/model$/, (msg) => {
|
|
1752
1752
|
if (!isAuthorized(msg)) return;
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1753
|
+
// Unified picker: every model from every available backend in one keyboard.
|
|
1754
|
+
// Tapping a button switches backend (if needed) and sets the model.
|
|
1755
|
+
// Callback format: `mb:<backend>:<model>` (model may itself contain `-`).
|
|
1756
|
+
const rows = [];
|
|
1757
|
+
rows.push([{ text: "── Claude ──", callback_data: "noop" }]);
|
|
1758
|
+
rows.push([
|
|
1759
|
+
{ text: "Opus 4.7", callback_data: "mb:claude:claude-opus-4-7" },
|
|
1760
|
+
{ text: "Opus 4.6", callback_data: "mb:claude:claude-opus-4-6" },
|
|
1761
|
+
{ text: "Sonnet 4.6", callback_data: "mb:claude:claude-sonnet-4-6" },
|
|
1762
|
+
{ text: "Haiku", callback_data: "mb:claude:claude-haiku-4-5-20251001" },
|
|
1763
|
+
]);
|
|
1764
|
+
if (resolvedCursorPath) {
|
|
1765
|
+
rows.push([{ text: "── Cursor ──", callback_data: "noop" }]);
|
|
1766
|
+
rows.push([
|
|
1767
|
+
{ text: "Composer 2", callback_data: "mb:cursor:composer-2" },
|
|
1768
|
+
{ text: "Composer 2 Fast", callback_data: "mb:cursor:composer-2-fast" },
|
|
1769
|
+
{ text: "Auto", callback_data: "mb:cursor:auto" },
|
|
1770
|
+
]);
|
|
1771
|
+
rows.push([
|
|
1772
|
+
{ text: "Opus 4.6 Thinking", callback_data: "mb:cursor:claude-4.6-opus-high-thinking" },
|
|
1773
|
+
{ text: "GPT-5.4", callback_data: "mb:cursor:gpt-5.4-medium" },
|
|
1774
|
+
]);
|
|
1775
|
+
}
|
|
1776
|
+
if (resolvedCodexPath) {
|
|
1777
|
+
rows.push([{ text: "── Codex ──", callback_data: "noop" }]);
|
|
1778
|
+
rows.push([
|
|
1779
|
+
{ text: "gpt-5", callback_data: "mb:codex:gpt-5" },
|
|
1780
|
+
{ text: "gpt-5-codex", callback_data: "mb:codex:gpt-5-codex" },
|
|
1781
|
+
]);
|
|
1782
|
+
rows.push([
|
|
1783
|
+
{ text: "o3", callback_data: "mb:codex:o3" },
|
|
1784
|
+
{ text: "o4-mini", callback_data: "mb:codex:o4-mini" },
|
|
1785
|
+
]);
|
|
1775
1786
|
}
|
|
1776
|
-
|
|
1787
|
+
rows.push([{ text: "Default (current backend)", callback_data: "m:default" }]);
|
|
1788
|
+
const beLabel = settings.backend === "cursor" ? "Cursor" : settings.backend === "codex" ? "Codex" : "Claude";
|
|
1789
|
+
send(`Current: ${beLabel} · ${settings.model || "default"}\n\nPick a model — backend switches automatically.\nOr type /model <name>.`, { keyboard: { inline_keyboard: rows } });
|
|
1777
1790
|
});
|
|
1778
1791
|
bot.onText(/\/model (.+)/, (msg, match) => { if (!isAuthorized(msg)) return; settings.model = match[1].trim().toLowerCase(); if (settings.model === "default") settings.model = null; send(`Model: ${settings.model || "default"}`); });
|
|
1779
1792
|
|
|
@@ -2143,6 +2156,25 @@ bot.on("callback_query", async (q) => {
|
|
|
2143
2156
|
}
|
|
2144
2157
|
if (d === "a:continue") { if (currentSession) await runClaude("continue", currentSession.dir); else send("No session."); return; }
|
|
2145
2158
|
if (d === "a:end") { if (currentSession) { const n = currentSession.name; currentSession = null; lastSessionId = null; messageQueue = []; resetSettings(); resetSessionUsage(); saveState(); await send(`Ended: ${n}`, { keyboard: { inline_keyboard: [[{ text: "New", callback_data: "show:projects" }]] } }); } return; }
|
|
2159
|
+
if (d === "noop") { return; }
|
|
2160
|
+
if (d.startsWith("mb:")) {
|
|
2161
|
+
// Unified picker: switch backend + set model in one tap.
|
|
2162
|
+
// Format: mb:<backend>:<model>. Model may contain `:` itself (unlikely), so split on first two.
|
|
2163
|
+
const rest = d.slice(3);
|
|
2164
|
+
const colon = rest.indexOf(":");
|
|
2165
|
+
if (colon < 0) return;
|
|
2166
|
+
const be = rest.slice(0, colon);
|
|
2167
|
+
const model = rest.slice(colon + 1);
|
|
2168
|
+
if (be === "cursor" && !resolvedCursorPath) { await send("Cursor Agent CLI not found."); return; }
|
|
2169
|
+
if (be === "codex" && !resolvedCodexPath) { await send("Codex CLI not found. Install: npm install -g @openai/codex"); return; }
|
|
2170
|
+
const switched = settings.backend !== be;
|
|
2171
|
+
settings.backend = be;
|
|
2172
|
+
settings.model = model;
|
|
2173
|
+
saveState();
|
|
2174
|
+
const beLabel = be === "cursor" ? "Cursor Agent" : be === "codex" ? "Codex" : "Claude Code";
|
|
2175
|
+
await send(switched ? `Switched to ${beLabel}.\nModel: ${model}` : `Model: ${model}`);
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2146
2178
|
if (d.startsWith("m:")) { settings.model = d.slice(2) === "default" ? null : d.slice(2); await send(`Model: ${settings.model || "default"}`); return; }
|
|
2147
2179
|
if (d.startsWith("e:")) { const e = d.slice(2); settings.effort = e === "default" ? null : e; await send(`Effort: ${settings.effort || "default"}`); return; }
|
|
2148
2180
|
if (d.startsWith("b:")) { const b = d.slice(2); settings.budget = b === "none" ? null : parseFloat(b); await send(`Budget: ${settings.budget ? "$"+settings.budget : "none"}`); return; }
|