@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 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.1",
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 once and kept in
9
- // localStorage; a 401 (wrong or rotated key) brings the prompt back.
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
- if (res.status === 401) { localStorage.removeItem(KEY); showKeybox(); return null; }
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
- if (localStorage.getItem(KEY)) start(); else showKeybox();
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
- const agents = buildCustomModelAgents(config.customModels);
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(' TeamClaude');
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)