@rikcodes/teamclaude 1.1.20-rik.1 → 1.1.20-rik.2
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/README.md +1 -1
- package/package.json +1 -1
- package/src/dashboard.js +13 -4
- package/src/index.js +6 -3
- package/src/tui.js +7 -2
package/README.md
CHANGED
|
@@ -150,7 +150,7 @@ At launch, `teamclaude run` — and the `claude` alias, which passes through `ru
|
|
|
150
150
|
| Row field | Where it ends up |
|
|
151
151
|
| --- | --- |
|
|
152
152
|
| `model`, `label`, `description` | A `/model` picker row under the **real** model id (`--settings`), so `/model gpt-5.6-sol` works picked or typed |
|
|
153
|
-
| `model` | A dispatchable subagent named after the model (`--agents`), so "dispatch a `gpt-5.6-terra` subagent" works from a Claude parent |
|
|
153
|
+
| `model` | A dispatchable subagent named after the model (`--agents`), so "dispatch a `gpt-5.6-terra` subagent" works from a Claude parent. Set `"customModelAgents": false` to skip these if you define your own agents in `~/.claude/agents/` |
|
|
154
154
|
| `contextTokens` | `CLAUDE_CODE_MAX_CONTEXT_TOKENS`, set to the largest value across rows, so Claude Code compacts at the real window instead of assuming 200k |
|
|
155
155
|
|
|
156
156
|
For tools that spawn `claude` themselves, `teamclaude env` can set only environment variables. It carries the window and `ANTHROPIC_CUSTOM_MODEL_OPTION` for the **first** row. For GPT subagents under `env`, create `~/.claude/agents/<name>.md` with `model: gpt-5.6-terra` in its frontmatter.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rikcodes/teamclaude",
|
|
3
|
-
"version": "1.1.20-rik.
|
|
3
|
+
"version": "1.1.20-rik.2",
|
|
4
4
|
"description": "Multi-account proxy for Claude Code and Codex: pools Claude Max, ChatGPT/Codex, API-key and third-party backend accounts, and rotates on quota",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/dashboard.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
// /teamclaude/status (same origin) with the proxy key and re-renders every few
|
|
6
6
|
// seconds. That split is what lets the asset be served without the key (a
|
|
7
7
|
// browser address bar cannot send x-api-key) while every byte of actual status
|
|
8
|
-
// stays behind the existing gate. The key is asked for
|
|
9
|
-
//
|
|
8
|
+
// stays behind the existing gate. The key is asked for only when the server
|
|
9
|
+
// refuses the page without one (401/403; loopback browsers are exempt), and is
|
|
10
|
+
// kept in localStorage; a later refusal (wrong or rotated key) asks again.
|
|
10
11
|
//
|
|
11
12
|
// Self-contained on purpose: no external scripts, styles, or fonts, so the
|
|
12
13
|
// page works on air-gapped deployments and adds no third-party surface. All
|
|
@@ -894,7 +895,10 @@ ${SHARED_HELPERS}
|
|
|
894
895
|
function poll() {
|
|
895
896
|
fetch('/teamclaude/status', { headers: { 'x-api-key': localStorage.getItem(KEY) || '' } })
|
|
896
897
|
.then(function (res) {
|
|
897
|
-
|
|
898
|
+
// 403 is the loopback exemption refusing a key-less request (a Host
|
|
899
|
+
// that does not name this machine, e.g. behind a local reverse proxy
|
|
900
|
+
// that adds no forwarding headers). A valid key clears that gate too.
|
|
901
|
+
if (res.status === 401 || res.status === 403) { localStorage.removeItem(KEY); showKeybox(); return null; }
|
|
898
902
|
if (!res.ok) throw new Error('status ' + res.status);
|
|
899
903
|
return res.json();
|
|
900
904
|
})
|
|
@@ -909,6 +913,9 @@ ${SHARED_HELPERS}
|
|
|
909
913
|
var err = document.getElementById('err');
|
|
910
914
|
err.style.display = 'block';
|
|
911
915
|
err.textContent = 'Cannot reach the proxy: ' + e.message;
|
|
916
|
+
// The banner lives inside #app, which stays hidden until a first
|
|
917
|
+
// status lands; without this a first poll that fails is a blank page.
|
|
918
|
+
if (document.getElementById('keybox').style.display !== 'block') document.getElementById('app').style.display = '';
|
|
912
919
|
});
|
|
913
920
|
}
|
|
914
921
|
|
|
@@ -936,7 +943,9 @@ ${SHARED_HELPERS}
|
|
|
936
943
|
});
|
|
937
944
|
});
|
|
938
945
|
|
|
939
|
-
|
|
946
|
+
// Poll before asking: a loopback browser is key-exempt, so the prompt is
|
|
947
|
+
// shown only once the server refuses the request without a valid key.
|
|
948
|
+
start();
|
|
940
949
|
})();
|
|
941
950
|
</script>
|
|
942
951
|
</body>
|
package/src/index.js
CHANGED
|
@@ -472,7 +472,7 @@ async function serverCommand() {
|
|
|
472
472
|
|
|
473
473
|
if (useTUI) {
|
|
474
474
|
tui = new TUI({
|
|
475
|
-
accountManager, config, sx, activityLogPath, sessionTitles,
|
|
475
|
+
accountManager, config, sx, activityLogPath, sessionTitles, version: serverVersion,
|
|
476
476
|
saveConfig: () => atomicConfigUpdate(async diskConfig => {
|
|
477
477
|
diskConfig.accounts = mergeAccountsForSave(
|
|
478
478
|
config.accounts, accountManager.accounts, diskConfig.accounts, removedAccountIds(config),
|
|
@@ -1092,8 +1092,11 @@ async function runCommand() {
|
|
|
1092
1092
|
if (settings && !claudeArgs.includes('--settings')) claudeArgs.push('--settings', settings);
|
|
1093
1093
|
// Dispatchable subagents per custom model — the Agent tool's `model`
|
|
1094
1094
|
// parameter is an alias enum, so only a named agent definition can carry a
|
|
1095
|
-
// custom model id into a subagent.
|
|
1096
|
-
|
|
1095
|
+
// custom model id into a subagent. `customModelAgents: false` skips them for
|
|
1096
|
+
// operators with their own ~/.claude/agents definitions: the plain agents
|
|
1097
|
+
// invite an effort-less dispatch, and a file-based agent's `model:` reaches
|
|
1098
|
+
// the proxy without them.
|
|
1099
|
+
const agents = config.customModelAgents === false ? null : buildCustomModelAgents(config.customModels);
|
|
1097
1100
|
if (agents && !claudeArgs.includes('--agents')) claudeArgs.push('--agents', agents);
|
|
1098
1101
|
}
|
|
1099
1102
|
|
package/src/tui.js
CHANGED
|
@@ -414,7 +414,11 @@ export class TUI {
|
|
|
414
414
|
readCredentials = importCredentials, readProfile = fetchProfile,
|
|
415
415
|
// Names the activity column against the session id the client sent. Absent
|
|
416
416
|
// or disabled leaves every row showing the short id.
|
|
417
|
-
sessionTitles = null
|
|
417
|
+
sessionTitles = null,
|
|
418
|
+
// Shown faint beside the title. Null in attach mode, where the dashboard is
|
|
419
|
+
// built before the first poll and the server's version is not yet known,
|
|
420
|
+
// and in tests — both render the title alone rather than a stray `null`.
|
|
421
|
+
version = null }) {
|
|
418
422
|
this.am = accountManager;
|
|
419
423
|
this.remote = remote;
|
|
420
424
|
this.applySwitch = applySwitch;
|
|
@@ -430,6 +434,7 @@ export class TUI {
|
|
|
430
434
|
this._readProfile = readProfile;
|
|
431
435
|
this._activityStream = null;
|
|
432
436
|
this.sessionTitles = sessionTitles;
|
|
437
|
+
/** @type {string|null} */ this.version = version;
|
|
433
438
|
|
|
434
439
|
this.log = []; // completed activity entries
|
|
435
440
|
this.active = new Map(); // in-flight requests
|
|
@@ -1372,7 +1377,7 @@ export class TUI {
|
|
|
1372
1377
|
const lines = [];
|
|
1373
1378
|
|
|
1374
1379
|
// ── Header
|
|
1375
|
-
const left = bold('
|
|
1380
|
+
const left = bold(' RikClaude Harness') + (this.version ? dim(` ${this.version}`) : '');
|
|
1376
1381
|
const port = this.config.proxy?.port || 3456;
|
|
1377
1382
|
const sess = this.am.sessionStats();
|
|
1378
1383
|
const sessStr = (sess.active || sess.known)
|