@spinabot/brigade 1.23.0 → 1.24.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 (76) hide show
  1. package/dist/agents/agent-loop.d.ts.map +1 -1
  2. package/dist/agents/agent-loop.js +73 -3
  3. package/dist/agents/agent-loop.js.map +1 -1
  4. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  5. package/dist/agents/channels/inbound-pipeline.js +6 -0
  6. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  7. package/dist/agents/claude-cli/availability.d.ts +12 -0
  8. package/dist/agents/claude-cli/availability.d.ts.map +1 -0
  9. package/dist/agents/claude-cli/availability.js +79 -0
  10. package/dist/agents/claude-cli/availability.js.map +1 -0
  11. package/dist/agents/claude-cli/catalog.d.ts +91 -0
  12. package/dist/agents/claude-cli/catalog.d.ts.map +1 -0
  13. package/dist/agents/claude-cli/catalog.js +260 -0
  14. package/dist/agents/claude-cli/catalog.js.map +1 -0
  15. package/dist/agents/claude-cli/claude-config.d.ts +38 -0
  16. package/dist/agents/claude-cli/claude-config.d.ts.map +1 -0
  17. package/dist/agents/claude-cli/claude-config.js +111 -0
  18. package/dist/agents/claude-cli/claude-config.js.map +1 -0
  19. package/dist/agents/claude-cli/register.d.ts +32 -0
  20. package/dist/agents/claude-cli/register.d.ts.map +1 -0
  21. package/dist/agents/claude-cli/register.js +68 -0
  22. package/dist/agents/claude-cli/register.js.map +1 -0
  23. package/dist/agents/claude-cli/spawn.d.ts +42 -0
  24. package/dist/agents/claude-cli/spawn.d.ts.map +1 -0
  25. package/dist/agents/claude-cli/spawn.js +179 -0
  26. package/dist/agents/claude-cli/spawn.js.map +1 -0
  27. package/dist/agents/claude-cli/stream-json.d.ts +129 -0
  28. package/dist/agents/claude-cli/stream-json.d.ts.map +1 -0
  29. package/dist/agents/claude-cli/stream-json.js +84 -0
  30. package/dist/agents/claude-cli/stream-json.js.map +1 -0
  31. package/dist/agents/claude-cli/stream.d.ts +27 -0
  32. package/dist/agents/claude-cli/stream.d.ts.map +1 -0
  33. package/dist/agents/claude-cli/stream.js +380 -0
  34. package/dist/agents/claude-cli/stream.js.map +1 -0
  35. package/dist/agents/error-classifier.d.ts +2 -2
  36. package/dist/agents/error-classifier.d.ts.map +1 -1
  37. package/dist/agents/error-classifier.js +43 -0
  38. package/dist/agents/error-classifier.js.map +1 -1
  39. package/dist/agents/model-resolution.d.ts +36 -0
  40. package/dist/agents/model-resolution.d.ts.map +1 -1
  41. package/dist/agents/model-resolution.js +59 -0
  42. package/dist/agents/model-resolution.js.map +1 -1
  43. package/dist/agents/retry-policy.d.ts.map +1 -1
  44. package/dist/agents/retry-policy.js +25 -1
  45. package/dist/agents/retry-policy.js.map +1 -1
  46. package/dist/auth/auth-health.d.ts +89 -0
  47. package/dist/auth/auth-health.d.ts.map +1 -1
  48. package/dist/auth/auth-health.js +207 -1
  49. package/dist/auth/auth-health.js.map +1 -1
  50. package/dist/buildstamp.json +1 -1
  51. package/dist/cli/commands/auth.js +18 -0
  52. package/dist/cli/commands/auth.js.map +1 -1
  53. package/dist/cli/commands/doctor.d.ts.map +1 -1
  54. package/dist/cli/commands/doctor.js +46 -0
  55. package/dist/cli/commands/doctor.js.map +1 -1
  56. package/dist/cli/commands/gateway.d.ts +4 -0
  57. package/dist/cli/commands/gateway.d.ts.map +1 -1
  58. package/dist/cli/commands/gateway.js +44 -2
  59. package/dist/cli/commands/gateway.js.map +1 -1
  60. package/dist/cli/commands/login.d.ts.map +1 -1
  61. package/dist/cli/commands/login.js +107 -19
  62. package/dist/cli/commands/login.js.map +1 -1
  63. package/dist/core/auth-bridge.d.ts.map +1 -1
  64. package/dist/core/auth-bridge.js +16 -0
  65. package/dist/core/auth-bridge.js.map +1 -1
  66. package/dist/core/server.d.ts.map +1 -1
  67. package/dist/core/server.js +13 -0
  68. package/dist/core/server.js.map +1 -1
  69. package/dist/providers/catalog.d.ts.map +1 -1
  70. package/dist/providers/catalog.js +18 -0
  71. package/dist/providers/catalog.js.map +1 -1
  72. package/dist/ui/onboarding.d.ts +11 -0
  73. package/dist/ui/onboarding.d.ts.map +1 -1
  74. package/dist/ui/onboarding.js +343 -4
  75. package/dist/ui/onboarding.js.map +1 -1
  76. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/providers/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,YAAY;IAC5B,iGAAiG;IACjG,EAAE,EAAE,MAAM,CAAC;IACX;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oGAAoG;IACpG,YAAY,CAAC,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD;;;;;OAKG;IACH,GAAG,CAAC,EAAE,oBAAoB,GAAG,oBAAoB,CAAC;IAClD,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,SAAS,EAAE,YAAY,EAwLnC,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEjE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,YAAY,GAAG,SAAS,GAAG,CAAC,IAAI,YAAY,GAAG;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,CAExG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAE7E;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,QAAQ,EAAE,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAW7C"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/providers/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,YAAY;IAC5B,iGAAiG;IACjG,EAAE,EAAE,MAAM,CAAC;IACX;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oGAAoG;IACpG,YAAY,CAAC,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD;;;;;OAKG;IACH,GAAG,CAAC,EAAE,oBAAoB,GAAG,oBAAoB,CAAC;IAClD,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,SAAS,EAAE,YAAY,EA0MnC,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEjE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,YAAY,GAAG,SAAS,GAAG,CAAC,IAAI,YAAY,GAAG;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,CAExG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAE7E;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,QAAQ,EAAE,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAW7C"}
@@ -37,6 +37,24 @@ export const PROVIDERS = [
37
37
  subscription: { oauthProviderId: "anthropic", label: "Log in with Claude Pro / Max" },
38
38
  cliLogin: { read: "claude", label: "Use your existing Claude Code login" },
39
39
  },
40
+ {
41
+ // The claude-cli backend: Brigade drives the installed `claude` binary as
42
+ // the inference transport, so a turn bills against the Claude subscription
43
+ // EXACTLY like the Claude Code CLI / IDE extension (the binary uses its own
44
+ // login; Anthropic never routes it into the metered "extra usage" tier the
45
+ // raw-HTTP OAuth path can hit). No key + no browser flow here — the binary
46
+ // authenticates itself; if it isn't logged in, the operator runs
47
+ // `claude` once (or `claude /login`). `local:true` makes onboarding skip
48
+ // key entry and validate the binary instead; models are synthesized (see
49
+ // src/agents/claude-cli), so there's no catalog/models.json entry to seed.
50
+ id: "claude-cli",
51
+ name: "Claude (via Claude Code CLI)",
52
+ description: "Run on your Claude subscription through the installed claude binary — no key, no extra-usage",
53
+ keyUrl: "https://claude.ai/download",
54
+ envVar: "",
55
+ noAuth: true,
56
+ local: true,
57
+ },
40
58
  {
41
59
  id: "openai",
42
60
  name: "OpenAI",
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/providers/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAiFH,MAAM,CAAC,MAAM,SAAS,GAAmB;IACxC;QACC,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,wCAAwC;QACrD,MAAM,EAAE,6CAA6C;QACrD,MAAM,EAAE,mBAAmB;QAC3B,yEAAyE;QACzE,2EAA2E;QAC3E,4EAA4E;QAC5E,iDAAiD;QACjD,eAAe,EAAE,CAAC,uBAAuB,CAAC;KAC1C;IACD;QACC,2EAA2E;QAC3E,yEAAyE;QACzE,0EAA0E;QAC1E,EAAE,EAAE,aAAa;QACjB,UAAU,EAAE,WAAW;QACvB,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,qDAAqD;QAClE,MAAM,EAAE,mBAAmB;QAC3B,MAAM,EAAE,EAAE;QACV,YAAY,EAAE,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,EAAE,8BAA8B,EAAE;QACrF,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,qCAAqC,EAAE;KAC1E;IACD;QACC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,eAAe;QAC5B,MAAM,EAAE,sCAAsC;QAC9C,MAAM,EAAE,gBAAgB;KACxB;IACD;QACC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,iCAAiC;QAC9C,MAAM,EAAE,oCAAoC;QAC5C,MAAM,EAAE,gBAAgB;KACxB;IACD;QACC,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,0BAA0B;QACvC,MAAM,EAAE,qCAAqC;QAC7C,MAAM,EAAE,oBAAoB;KAC5B;IACD;QACC,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,yCAAyC;QACtD,MAAM,EAAE,+BAA+B;QACvC,MAAM,EAAE,cAAc;KACtB;IACD;QACC,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,0BAA0B;QACvC,MAAM,EAAE,2BAA2B;QACnC,MAAM,EAAE,kBAAkB;KAC1B;IACD;QACC,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,aAAa;QAC1B,MAAM,EAAE,sBAAsB;QAC9B,MAAM,EAAE,aAAa;KACrB;IACD;QACC,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,wBAAwB;QACrC,MAAM,EAAE,wCAAwC;QAChD,MAAM,EAAE,kBAAkB;KAC1B;IACD;QACC,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,oCAAoC;QACjD,MAAM,EAAE,qCAAqC;QAC7C,MAAM,EAAE,iBAAiB;KACzB;IACD;QACC,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,wCAAwC;QACrD,MAAM,EAAE,qBAAqB;QAC7B,MAAM,EAAE,EAAE;QACV,YAAY,EAAE,EAAE,eAAe,EAAE,cAAc,EAAE,KAAK,EAAE,gCAAgC,EAAE;QAC1F,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,+BAA+B,EAAE;KACnE;IACD;QACC,EAAE,EAAE,gBAAgB;QACpB,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,qDAAqD;QAClE,MAAM,EAAE,qCAAqC;QAC7C,MAAM,EAAE,EAAE;QACV,YAAY,EAAE,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,EAAE,4BAA4B,EAAE;KACxF;IACD;QACC,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,mCAAmC;QAChD,MAAM,EAAE,wCAAwC;QAChD,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,gCAAgC;QACzC,MAAM,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,CAAC;KAC7C;IACD;QACC,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,8BAA8B;QAC3C,MAAM,EAAE,+CAA+C;QACvD,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,mCAAmC;QAC5C,MAAM,EAAE,CAAC,gBAAgB,EAAE,WAAW,CAAC;KACvC;IACD;QACC,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,gCAAgC;QAC7C,MAAM,EAAE,0CAA0C;QAClD,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,oDAAoD;QAC7D,MAAM,EAAE,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;KAChD;IACD;QACC,EAAE,EAAE,aAAa;QACjB,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,sBAAsB;QACnC,MAAM,EAAE,6BAA6B;QACrC,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,kCAAkC;QAC3C,MAAM,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;KACtC;IACD;QACC,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,wBAAwB;QAC9B,WAAW,EAAE,uBAAuB;QACpC,MAAM,EAAE,wCAAwC;QAChD,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,oCAAoC;QAC7C,MAAM,EAAE,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;KAChD;IACD;QACC,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,6EAA6E;QAC1F,MAAM,EAAE,0BAA0B;QAClC,MAAM,EAAE,gBAAgB;QACxB,eAAe,EAAE,CAAC,oBAAoB,EAAE,aAAa,CAAC;QACtD,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,IAAI,EAAE,oDAAoD;QACtE,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,qCAAqC;KAC9C;IACD;QACC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,gDAAgD;QAC7D,MAAM,EAAE,6BAA6B;QACrC,MAAM,EAAE,EAAE,EAAE,aAAa;QACzB,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,wBAAwB;KACjC;IACD;QACC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,4BAA4B;QAClC,WAAW,EAAE,uEAAuE;QACpF,MAAM,EAAE,GAAG;QACX,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;KACZ;CACD,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,EAAU;IACtC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,CAA2B;IACjE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;AACpB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAsB;IACxD,OAAO,2BAA2B,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;AACrD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CAC1C,QAAsB;IAEtB,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC;IAChC,IAAI,OAAO,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACtF,CAAC;IACD,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;QACvD,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/providers/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAiFH,MAAM,CAAC,MAAM,SAAS,GAAmB;IACxC;QACC,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,wCAAwC;QACrD,MAAM,EAAE,6CAA6C;QACrD,MAAM,EAAE,mBAAmB;QAC3B,yEAAyE;QACzE,2EAA2E;QAC3E,4EAA4E;QAC5E,iDAAiD;QACjD,eAAe,EAAE,CAAC,uBAAuB,CAAC;KAC1C;IACD;QACC,2EAA2E;QAC3E,yEAAyE;QACzE,0EAA0E;QAC1E,EAAE,EAAE,aAAa;QACjB,UAAU,EAAE,WAAW;QACvB,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,qDAAqD;QAClE,MAAM,EAAE,mBAAmB;QAC3B,MAAM,EAAE,EAAE;QACV,YAAY,EAAE,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,EAAE,8BAA8B,EAAE;QACrF,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,qCAAqC,EAAE;KAC1E;IACD;QACC,0EAA0E;QAC1E,2EAA2E;QAC3E,4EAA4E;QAC5E,2EAA2E;QAC3E,2EAA2E;QAC3E,iEAAiE;QACjE,yEAAyE;QACzE,yEAAyE;QACzE,2EAA2E;QAC3E,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,8BAA8B;QACpC,WAAW,EAAE,8FAA8F;QAC3G,MAAM,EAAE,4BAA4B;QACpC,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,IAAI;KACX;IACD;QACC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,eAAe;QAC5B,MAAM,EAAE,sCAAsC;QAC9C,MAAM,EAAE,gBAAgB;KACxB;IACD;QACC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,iCAAiC;QAC9C,MAAM,EAAE,oCAAoC;QAC5C,MAAM,EAAE,gBAAgB;KACxB;IACD;QACC,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,0BAA0B;QACvC,MAAM,EAAE,qCAAqC;QAC7C,MAAM,EAAE,oBAAoB;KAC5B;IACD;QACC,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,yCAAyC;QACtD,MAAM,EAAE,+BAA+B;QACvC,MAAM,EAAE,cAAc;KACtB;IACD;QACC,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,0BAA0B;QACvC,MAAM,EAAE,2BAA2B;QACnC,MAAM,EAAE,kBAAkB;KAC1B;IACD;QACC,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,aAAa;QAC1B,MAAM,EAAE,sBAAsB;QAC9B,MAAM,EAAE,aAAa;KACrB;IACD;QACC,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,wBAAwB;QACrC,MAAM,EAAE,wCAAwC;QAChD,MAAM,EAAE,kBAAkB;KAC1B;IACD;QACC,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,oCAAoC;QACjD,MAAM,EAAE,qCAAqC;QAC7C,MAAM,EAAE,iBAAiB;KACzB;IACD;QACC,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,wCAAwC;QACrD,MAAM,EAAE,qBAAqB;QAC7B,MAAM,EAAE,EAAE;QACV,YAAY,EAAE,EAAE,eAAe,EAAE,cAAc,EAAE,KAAK,EAAE,gCAAgC,EAAE;QAC1F,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,+BAA+B,EAAE;KACnE;IACD;QACC,EAAE,EAAE,gBAAgB;QACpB,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,qDAAqD;QAClE,MAAM,EAAE,qCAAqC;QAC7C,MAAM,EAAE,EAAE;QACV,YAAY,EAAE,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,EAAE,4BAA4B,EAAE;KACxF;IACD;QACC,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,mCAAmC;QAChD,MAAM,EAAE,wCAAwC;QAChD,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,gCAAgC;QACzC,MAAM,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,CAAC;KAC7C;IACD;QACC,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,8BAA8B;QAC3C,MAAM,EAAE,+CAA+C;QACvD,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,mCAAmC;QAC5C,MAAM,EAAE,CAAC,gBAAgB,EAAE,WAAW,CAAC;KACvC;IACD;QACC,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,gCAAgC;QAC7C,MAAM,EAAE,0CAA0C;QAClD,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,oDAAoD;QAC7D,MAAM,EAAE,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;KAChD;IACD;QACC,EAAE,EAAE,aAAa;QACjB,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,sBAAsB;QACnC,MAAM,EAAE,6BAA6B;QACrC,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,kCAAkC;QAC3C,MAAM,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;KACtC;IACD;QACC,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,wBAAwB;QAC9B,WAAW,EAAE,uBAAuB;QACpC,MAAM,EAAE,wCAAwC;QAChD,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,oCAAoC;QAC7C,MAAM,EAAE,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;KAChD;IACD;QACC,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,6EAA6E;QAC1F,MAAM,EAAE,0BAA0B;QAClC,MAAM,EAAE,gBAAgB;QACxB,eAAe,EAAE,CAAC,oBAAoB,EAAE,aAAa,CAAC;QACtD,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,IAAI,EAAE,oDAAoD;QACtE,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,qCAAqC;KAC9C;IACD;QACC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,gDAAgD;QAC7D,MAAM,EAAE,6BAA6B;QACrC,MAAM,EAAE,EAAE,EAAE,aAAa;QACzB,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,wBAAwB;KACjC;IACD;QACC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,4BAA4B;QAClC,WAAW,EAAE,uEAAuE;QACpF,MAAM,EAAE,GAAG;QACX,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;KACZ;CACD,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,EAAU;IACtC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,CAA2B;IACjE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;AACpB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAsB;IACxD,OAAO,2BAA2B,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;AACrD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CAC1C,QAAsB;IAEtB,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC;IAChC,IAAI,OAAO,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACtF,CAAC;IACD,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;QACvD,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC"}
@@ -98,6 +98,17 @@ export declare function ensureApiKey(tui: TUI, authStorage: AuthStorage, provide
98
98
  * provider.
99
99
  */
100
100
  export declare function ensureSubscriptionLogin(tui: TUI, authStorage: AuthStorage, provider: ProviderInfo): Promise<"ok" | "back">;
101
+ /**
102
+ * Connect the claude-cli backend end to end — no terminal, no token paste:
103
+ * 1. Ensure the `claude` binary is installed (offer to `npm i -g` it).
104
+ * 2. Ensure a login exists — if not, drive the SAME browser OAuth Brigade uses
105
+ * for Claude Pro/Max and write the result into Brigade's OWN Claude config
106
+ * dir (a dedicated grant, isolated from the operator's personal ~/.claude).
107
+ * Turns then run on the Claude subscription via the binary (no extra-usage).
108
+ *
109
+ * Returns "ok" to proceed to model selection, or "back" to re-pick the provider.
110
+ */
111
+ export declare function ensureClaudeCli(tui: TUI, authStorage: AuthStorage): Promise<"ok" | "back">;
101
112
  /**
102
113
  * Render an API key in a form safe to splat to the terminal/log: shows the
103
114
  * first 4 and last 4 characters separated by an ellipsis, e.g. `sk-o…2b5x`.
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/ui/onboarding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,EAA+D,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAa1G,OAAO,EAMN,KAAK,YAAY,EACjB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAWpF,MAAM,WAAW,gBAAgB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;+DAC2D;IAC3D,OAAO,EAAE,iBAAiB,CAAC;CAC3B;AAiGD,MAAM,WAAW,iBAAiB;IACjC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,eAAe,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IACtC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,wBAAsB,aAAa,CAClC,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAC5B,IAAI,GAAE,iBAAsB,GAC1B,OAAO,CAAC,gBAAgB,CAAC,CAmO3B;AA4GD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CACjC,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,WAAW,GAAG,KAAK,CAAA;CAAO,GACzE,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAoLxB;AAkND;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,uBAAuB,CAC5C,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CA+MxB;AA0ZD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CASpG"}
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/ui/onboarding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,EAA+D,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAgB1G,OAAO,EAMN,KAAK,YAAY,EACjB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAWpF,MAAM,WAAW,gBAAgB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;+DAC2D;IAC3D,OAAO,EAAE,iBAAiB,CAAC;CAC3B;AAiGD,MAAM,WAAW,iBAAiB;IACjC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,eAAe,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IACtC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,wBAAsB,aAAa,CAClC,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAC5B,IAAI,GAAE,iBAAsB,GAC1B,OAAO,CAAC,gBAAgB,CAAC,CA4P3B;AAuHD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CACjC,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,WAAW,GAAG,KAAK,CAAA;CAAO,GACzE,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAoLxB;AAkND;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,uBAAuB,CAC5C,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CA+MxB;AAQD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CA4GhG;AA+lBD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CASpG"}
@@ -25,6 +25,9 @@ import { upsertApiKeyProfile, upsertApiKeyRefProfile, upsertOAuthProfile, upsert
25
25
  import { DEFAULT_AGENT_ID, resolveAuthProfilesPath, resolveModelsPath } from "../config/paths.js";
26
26
  import { saveConfig } from "../core/config.js";
27
27
  import { readClaudeCliLogin, readCodexCliLogin } from "../integrations/cli-login.js";
28
+ import { isClaudeCliAvailable } from "../agents/claude-cli/availability.js";
29
+ import { CLAUDE_CLI_DEFAULT_MODEL, CLAUDE_CLI_MODELS } from "../agents/claude-cli/catalog.js";
30
+ import { hasBrigadeClaudeLogin, writeBrigadeClaudeCredential } from "../agents/claude-cli/claude-config.js";
28
31
  import { writeCustomProviderToModelsJson } from "../integrations/custom-provider.js";
29
32
  import { discoverOllamaModels, writeOllamaToModelsJson } from "../integrations/ollama.js";
30
33
  import { findProvider, PROVIDERS, readProviderEnvKey, resolveProviderEnvVarSource, routesToCustomProvider, } from "../providers/catalog.js";
@@ -194,6 +197,19 @@ export async function runOnboarding(tui, authStorage, modelRegistry, opts = {})
194
197
  step = "model";
195
198
  continue;
196
199
  }
200
+ // claude-cli backend — no key + no browser flow: the `claude` binary
201
+ // authenticates with its OWN login. Validate the binary is installed
202
+ // and logged in; if not, guide the operator to run `claude` once. Models
203
+ // are synthesized, so nothing is written to models.json.
204
+ if (providerInfo?.id === "claude-cli") {
205
+ const result = await ensureClaudeCli(tui, authStorage);
206
+ if (result === "back") {
207
+ step = "provider";
208
+ continue;
209
+ }
210
+ step = "model";
211
+ continue;
212
+ }
197
213
  // CLI-login reuse — if the provider can adopt an already-logged-in
198
214
  // vendor CLI's token on this machine (Claude Code, Codex), offer the
199
215
  // one-keystroke "reuse this login" path FIRST. "other" means no CLI
@@ -261,6 +277,17 @@ export async function runOnboarding(tui, authStorage, modelRegistry, opts = {})
261
277
  }
262
278
  // step === "model"
263
279
  renderScreen(tui, "Step 4 of 5 · Default model");
280
+ // claude-cli models are synthesized (not in the registry), so pick from the
281
+ // backend's own catalog instead of the registry-backed picker.
282
+ if (provider === "claude-cli") {
283
+ const result = await pickClaudeCliModel(tui);
284
+ if (result === "back") {
285
+ step = "provider";
286
+ continue;
287
+ }
288
+ modelId = result.modelId;
289
+ break; // model chosen — exit the wizard loop to persist + finish
290
+ }
264
291
  const result = await pickModel(tui, modelRegistry, findProvider(provider)?.providerId ?? provider);
265
292
  if (result === "back") {
266
293
  step = "provider"; // go all the way back so they can change provider too
@@ -383,10 +410,22 @@ async function pickProvider(tui) {
383
410
  const isBYO = p.custom === true && !p.baseUrl;
384
411
  let rank;
385
412
  let badge;
386
- // A subscription provider stays "log in" (browser-first, multi-account) even
387
- // when a CLI login is on disk reuse is offered as a secondary option inside
388
- // the flow. Only a pure CLI-login provider gets the rank-0 "reuse" treatment.
389
- if (cliReady && !isSubscription) {
413
+ // The claude-cli backend: it's `local+noAuth` in the catalog, but it's a
414
+ // SUBSCRIPTION path, not a local server. Rank it with the subscription tier
415
+ // and surface it at the very top when the binary is installed + logged in
416
+ // (the cleanest "no extra-usage" route). Checked BEFORE the generic
417
+ // cliReady / local branches so it doesn't get the wrong badge.
418
+ if (p.id === "claude-cli") {
419
+ const ready = isClaudeCliAvailable() && (readClaudeCliLogin() !== null || hasBrigadeClaudeLogin());
420
+ rank = ready ? 0 : 2;
421
+ badge = ready
422
+ ? "installed + signed in — subscription, no key, no extra-usage"
423
+ : "your Claude subscription — browser sign-in, no key, no extra-usage";
424
+ }
425
+ else if (cliReady && !isSubscription) {
426
+ // A subscription provider stays "log in" (browser-first, multi-account)
427
+ // even when a CLI login is on disk — reuse is offered as a secondary
428
+ // option inside the flow. Only a pure CLI-login provider gets rank-0.
390
429
  rank = 0;
391
430
  badge = "logged in — reuse, no key";
392
431
  }
@@ -975,6 +1014,269 @@ export async function ensureSubscriptionLogin(tui, authStorage, provider) {
975
1014
  return "ok";
976
1015
  }
977
1016
  }
1017
+ /** True when EITHER the operator's own `claude` login OR Brigade's managed
1018
+ * dedicated login is present — the backend can run with either. */
1019
+ function claudeCliLoggedIn() {
1020
+ return readClaudeCliLogin() !== null || hasBrigadeClaudeLogin();
1021
+ }
1022
+ /**
1023
+ * Connect the claude-cli backend end to end — no terminal, no token paste:
1024
+ * 1. Ensure the `claude` binary is installed (offer to `npm i -g` it).
1025
+ * 2. Ensure a login exists — if not, drive the SAME browser OAuth Brigade uses
1026
+ * for Claude Pro/Max and write the result into Brigade's OWN Claude config
1027
+ * dir (a dedicated grant, isolated from the operator's personal ~/.claude).
1028
+ * Turns then run on the Claude subscription via the binary (no extra-usage).
1029
+ *
1030
+ * Returns "ok" to proceed to model selection, or "back" to re-pick the provider.
1031
+ */
1032
+ export async function ensureClaudeCli(tui, authStorage) {
1033
+ while (true) {
1034
+ renderScreen(tui, "Step 3 of 5 · Connect Claude");
1035
+ // ── 1. binary present? ──
1036
+ if (!isClaudeCliAvailable({ force: true })) {
1037
+ tui.addChild(new Text(` ${brand.white("Brigade runs on your Claude subscription via the Claude Code engine.")}`, 0, 0));
1038
+ tui.addChild(new Text(brand.dim(" The `claude` command isn't installed yet. Brigade can install it for you."), 0, 0));
1039
+ tui.addChild(new Text("", 0, 0));
1040
+ const choice = new SelectList([
1041
+ { value: "install", label: "Install it now", description: "runs: npm i -g @anthropic-ai/claude-code" },
1042
+ { value: "recheck", label: "I'll install it myself — re-check", description: "" },
1043
+ ], 2, selectListTheme, { minPrimaryColumnWidth: 18, maxPrimaryColumnWidth: 24 });
1044
+ tui.addChild(choice);
1045
+ tui.setFocus(choice);
1046
+ tui.requestRender();
1047
+ let pick;
1048
+ try {
1049
+ const chosen = await new Promise((resolve, reject) => {
1050
+ choice.onSelect = (item) => resolve(item);
1051
+ choice.onCancel = () => reject(new Error("back"));
1052
+ });
1053
+ pick = chosen.value === "install" ? "install" : "recheck";
1054
+ }
1055
+ catch {
1056
+ return "back";
1057
+ }
1058
+ if (pick === "install") {
1059
+ renderScreen(tui, "Step 3 of 5 · Connect Claude");
1060
+ const loader = new CancellableLoader(tui, (s) => brand.amber(s), (s) => brand.dim(s), "Installing Claude Code (npm i -g @anthropic-ai/claude-code)…");
1061
+ tui.addChild(loader);
1062
+ tui.requestRender();
1063
+ const ok = await installClaudeCode();
1064
+ loader.stop?.();
1065
+ if (!ok) {
1066
+ renderScreen(tui, "Step 3 of 5 · Connect Claude");
1067
+ tui.addChild(new Text(` ${brand.error("✗")} ${brand.error("Install failed. Run `npm i -g @anthropic-ai/claude-code` manually, then Enter.")}`, 0, 0));
1068
+ const c = new Input();
1069
+ tui.addChild(c);
1070
+ tui.setFocus(c);
1071
+ tui.requestRender();
1072
+ try {
1073
+ await new Promise((res, rej) => {
1074
+ c.onSubmit = () => res();
1075
+ c.onEscape = () => rej(new Error("back"));
1076
+ });
1077
+ }
1078
+ catch {
1079
+ return "back";
1080
+ }
1081
+ }
1082
+ }
1083
+ continue; // re-loop: re-check install state
1084
+ }
1085
+ // ── 2. login present? ──
1086
+ if (claudeCliLoggedIn()) {
1087
+ tui.addChild(new Text(` ${brand.amber("✓")} ${brand.dim("Claude is installed and signed in.")}`, 0, 0));
1088
+ tui.addChild(new Text(brand.dim(" Turns run on your Claude subscription — no key, no extra-usage billing."), 0, 0));
1089
+ tui.addChild(new Text("", 0, 0));
1090
+ tui.addChild(new Text(brand.dim(" Enter to continue · Esc to go back"), 0, 0));
1091
+ const confirm = new Input();
1092
+ tui.addChild(confirm);
1093
+ tui.setFocus(confirm);
1094
+ tui.requestRender();
1095
+ try {
1096
+ await new Promise((resolve, reject) => {
1097
+ confirm.onSubmit = () => resolve();
1098
+ confirm.onEscape = () => reject(new Error("back"));
1099
+ });
1100
+ }
1101
+ catch {
1102
+ return "back";
1103
+ }
1104
+ return "ok";
1105
+ }
1106
+ // ── 3. no login → drive the browser OAuth ourselves, write Brigade's grant ──
1107
+ tui.addChild(new Text(` ${brand.white("Sign in to your Claude account")}`, 0, 0));
1108
+ tui.addChild(new Text(brand.dim(" We'll open your browser. Approve it there — no key, no terminal."), 0, 0));
1109
+ tui.addChild(new Text(brand.dim(" Enter to start · Esc to go back"), 0, 0));
1110
+ const start = new Input();
1111
+ tui.addChild(start);
1112
+ tui.setFocus(start);
1113
+ tui.requestRender();
1114
+ try {
1115
+ await new Promise((resolve, reject) => {
1116
+ start.onSubmit = () => resolve();
1117
+ start.onEscape = () => reject(new Error("back"));
1118
+ });
1119
+ }
1120
+ catch {
1121
+ return "back";
1122
+ }
1123
+ tui.removeChild(start);
1124
+ const result = await runClaudeBrowserLogin(tui, authStorage);
1125
+ if (result === "ok") {
1126
+ tui.addChild(new Text("", 0, 0));
1127
+ tui.addChild(new Text(` ${brand.amber("✓")} Signed in — your Claude subscription is connected.`, 0, 0));
1128
+ tui.requestRender();
1129
+ await delay(600);
1130
+ return "ok";
1131
+ }
1132
+ if (result === "back")
1133
+ return "back";
1134
+ // "retry" → loop shows the sign-in prompt again.
1135
+ }
1136
+ }
1137
+ /**
1138
+ * Install Claude Code globally via npm. Returns true on success. Best-effort +
1139
+ * bounded; surfaces nothing itself (the caller renders status).
1140
+ */
1141
+ async function installClaudeCode() {
1142
+ return await new Promise((resolve) => {
1143
+ try {
1144
+ const npm = process.platform === "win32" ? "npm.cmd" : "npm";
1145
+ const child = spawn(npm, ["install", "-g", "@anthropic-ai/claude-code"], {
1146
+ stdio: "ignore",
1147
+ shell: process.platform === "win32",
1148
+ });
1149
+ const timer = setTimeout(() => {
1150
+ try {
1151
+ child.kill();
1152
+ }
1153
+ catch {
1154
+ /* already gone */
1155
+ }
1156
+ resolve(false);
1157
+ }, 180_000);
1158
+ timer.unref?.();
1159
+ child.on("close", (code) => {
1160
+ clearTimeout(timer);
1161
+ resolve(code === 0 && isClaudeCliAvailable({ force: true }));
1162
+ });
1163
+ child.on("error", () => {
1164
+ clearTimeout(timer);
1165
+ resolve(false);
1166
+ });
1167
+ }
1168
+ catch {
1169
+ resolve(false);
1170
+ }
1171
+ });
1172
+ }
1173
+ /**
1174
+ * Drive Brigade's browser OAuth for Anthropic (the same flow Claude Pro/Max
1175
+ * onboarding uses — pi-ai requests the full Claude Code scopes) and write the
1176
+ * result into Brigade's OWN managed Claude config dir, so the `claude` binary
1177
+ * authenticates + refreshes from Brigade's dedicated grant. Also mirrors the
1178
+ * credential into Brigade's anthropic profile so the HTTP path is available too.
1179
+ *
1180
+ * Returns "ok" on success, "back" on user abort, "retry" on a recoverable error.
1181
+ */
1182
+ async function runClaudeBrowserLogin(tui, authStorage) {
1183
+ const oauthProvider = getOAuthProvider("anthropic");
1184
+ if (!oauthProvider) {
1185
+ tui.addChild(new Text(` ${brand.error("✗")} ${brand.error("Browser sign-in isn't available in this build.")}`, 0, 0));
1186
+ tui.requestRender();
1187
+ await delay(1200);
1188
+ return "back";
1189
+ }
1190
+ const controller = new AbortController();
1191
+ let creds;
1192
+ try {
1193
+ creds = (await oauthProvider.login({
1194
+ onAuth: (info) => {
1195
+ tui.addChild(new Text(` ${brand.amber("→")} Opening your browser to sign in…`, 0, 0));
1196
+ openSubscriptionBrowser(info.url);
1197
+ tui.addChild(new Text("", 0, 0));
1198
+ tui.addChild(new Text(" " + brand.amber(info.url), 0, 0));
1199
+ tui.addChild(new Text(brand.dim(" If your browser didn't open, copy the link above. Paste the code here if asked."), 0, 0));
1200
+ const waiter = new CancellableLoader(tui, (s) => brand.amber(s), (s) => brand.dim(s), "Waiting for you to authorize…");
1201
+ waiter.onAbort = () => controller.abort();
1202
+ tui.addChild(waiter);
1203
+ tui.setFocus(waiter);
1204
+ tui.requestRender();
1205
+ },
1206
+ onManualCodeInput: () => new Promise((resolve, reject) => {
1207
+ tui.addChild(new Text("", 0, 0));
1208
+ tui.addChild(new Text(brand.dim(" Paste the code or redirect URL, then press Enter · Esc to cancel"), 0, 0));
1209
+ const input = new Input();
1210
+ tui.addChild(input);
1211
+ tui.setFocus(input);
1212
+ tui.requestRender();
1213
+ input.onSubmit = (value) => resolve(sanitizePastedValue(value));
1214
+ input.onEscape = () => reject(new Error("cancelled"));
1215
+ }),
1216
+ onProgress: (msg) => {
1217
+ tui.addChild(new Text(brand.dim(" " + msg), 0, 0));
1218
+ tui.requestRender();
1219
+ },
1220
+ // Anthropic's loopback flow never uses these, but the callback contract
1221
+ // requires them — provide minimal implementations so the type + runtime
1222
+ // are both satisfied.
1223
+ onDeviceCode: () => {
1224
+ /* not used by the anthropic loopback flow */
1225
+ },
1226
+ onPrompt: (p) => new Promise((resolve, reject) => {
1227
+ tui.addChild(new Text("", 0, 0));
1228
+ tui.addChild(new Text(` ${p.message}`, 0, 0));
1229
+ const input = new Input();
1230
+ tui.addChild(input);
1231
+ tui.setFocus(input);
1232
+ tui.requestRender();
1233
+ input.onSubmit = (value) => {
1234
+ const v = value.trim();
1235
+ if (!v && !p.allowEmpty)
1236
+ return;
1237
+ resolve(v);
1238
+ };
1239
+ input.onEscape = () => reject(new Error("cancelled"));
1240
+ }),
1241
+ onSelect: (p) => new Promise((resolve) => {
1242
+ const list = new SelectList(p.options.map((o) => ({ value: o.id, label: o.label })), Math.min(p.options.length, 6), selectListTheme, { minPrimaryColumnWidth: 12, maxPrimaryColumnWidth: 28 });
1243
+ tui.addChild(list);
1244
+ tui.setFocus(list);
1245
+ tui.requestRender();
1246
+ list.onSelect = (item) => resolve(item.value);
1247
+ list.onCancel = () => resolve(undefined);
1248
+ }),
1249
+ signal: controller.signal,
1250
+ }));
1251
+ }
1252
+ catch (err) {
1253
+ controller.abort();
1254
+ const reason = err instanceof Error ? err.message : String(err);
1255
+ const softCancel = /^login cancelled$/i.test(reason) || reason === "cancelled" || reason === "back";
1256
+ tui.addChild(new Text(` ${brand.error("✗")} ${brand.error(softCancel ? "Sign-in cancelled." : "Couldn't finish signing in — check your connection and try again.")}`, 0, 0));
1257
+ tui.requestRender();
1258
+ await delay(1000);
1259
+ return softCancel ? "back" : "retry";
1260
+ }
1261
+ // Write Brigade's dedicated Claude login ONLY into the managed config dir.
1262
+ // The `claude` binary owns this grant from here on: it authenticates AND
1263
+ // refreshes (rotating the refresh token) in-place. We deliberately DON'T
1264
+ // also mirror it into Brigade's anthropic auth-profile — that would create a
1265
+ // SECOND independent refresher (Brigade's HTTP-path backend) for the same
1266
+ // grant, and the two would rotate each other's refresh token to death
1267
+ // (the split-brain failure). Single grant, single owner (the binary).
1268
+ void authStorage; // intentionally unused now — kept for signature stability
1269
+ try {
1270
+ writeBrigadeClaudeCredential({ access: creds.access, refresh: creds.refresh, expires: creds.expires });
1271
+ }
1272
+ catch (err) {
1273
+ tui.addChild(new Text(` ${brand.error("✗")} ${brand.error(`Couldn't save the login: ${err.message}`)}`, 0, 0));
1274
+ tui.requestRender();
1275
+ await delay(1200);
1276
+ return "retry";
1277
+ }
1278
+ return "ok";
1279
+ }
978
1280
  /**
979
1281
  * Connect a subscription provider that ALSO has a vendor CLI login on disk
980
1282
  * (Claude Code / Codex). When such a login exists we present a choice that LEADS
@@ -1027,6 +1329,12 @@ async function ensureCliLogin(tui, authStorage, provider) {
1027
1329
  access: cred.access,
1028
1330
  refresh: cred.refresh,
1029
1331
  expires: cred.expires,
1332
+ // Borrowed from the vendor CLI's on-disk login — mark the family so
1333
+ // `adoptNewerClaudeCliLogin` keeps adopting the CLI's rotations
1334
+ // instead of refreshing (and rotating) a stale shared grant.
1335
+ ...(provider.cliLogin.read === "claude"
1336
+ ? { metadata: { importedFrom: "claude-cli" } }
1337
+ : {}),
1030
1338
  });
1031
1339
  authStorage.set(cred.provider, {
1032
1340
  type: "oauth",
@@ -1330,6 +1638,37 @@ async function pickModel(tui, modelRegistry, providerId) {
1330
1638
  return "back";
1331
1639
  }
1332
1640
  }
1641
+ /** Model picker for the claude-cli backend — its models are synthesized (not in
1642
+ * the registry), so we present the backend's own catalog. */
1643
+ async function pickClaudeCliModel(tui) {
1644
+ const items = CLAUDE_CLI_MODELS.map((m) => ({
1645
+ value: m.id,
1646
+ label: m.id,
1647
+ description: m.name,
1648
+ }));
1649
+ // Default first = the catalog default (Sonnet), then the rest as listed.
1650
+ items.sort((a, b) => a.value === CLAUDE_CLI_DEFAULT_MODEL ? -1 : b.value === CLAUDE_CLI_DEFAULT_MODEL ? 1 : 0);
1651
+ const list = new SearchableSelectList(items, 8, selectListTheme, {
1652
+ minPrimaryColumnWidth: 26,
1653
+ maxPrimaryColumnWidth: 38,
1654
+ formatHeader: (q, matchCount, total) => brand.dim(q.length > 0
1655
+ ? ` search: ${q}▌ (${matchCount}/${total})`
1656
+ : ` ${total} models · ↑↓ move · Enter select · Esc back`),
1657
+ });
1658
+ tui.addChild(list);
1659
+ tui.setFocus(list);
1660
+ tui.requestRender();
1661
+ try {
1662
+ const chosen = await new Promise((resolve, reject) => {
1663
+ list.onSelect = (item) => resolve(item);
1664
+ list.onCancel = () => reject(new Error("back"));
1665
+ });
1666
+ return { modelId: chosen.value };
1667
+ }
1668
+ catch {
1669
+ return "back";
1670
+ }
1671
+ }
1333
1672
  function renderDone(tui, provider, modelId) {
1334
1673
  const p = findProvider(provider)?.name ?? provider;
1335
1674
  tui.addChild(new Text("", 0, 0));