@t2000/cli 9.0.0 → 9.2.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.
package/dist/index.js
CHANGED
|
@@ -33689,6 +33689,542 @@ function registerModels(program3) {
|
|
|
33689
33689
|
});
|
|
33690
33690
|
}
|
|
33691
33691
|
|
|
33692
|
+
// src/commands/connect/index.ts
|
|
33693
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync3, appendFileSync } from "fs";
|
|
33694
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
33695
|
+
import { homedir as homedir4 } from "os";
|
|
33696
|
+
|
|
33697
|
+
// src/commands/connect/clients.ts
|
|
33698
|
+
import { join as join4 } from "path";
|
|
33699
|
+
import { homedir as homedir3 } from "os";
|
|
33700
|
+
var API_BASE = "https://api.t2000.ai/v1";
|
|
33701
|
+
var CHAT_COMPLETIONS_URL = `${API_BASE}/chat/completions`;
|
|
33702
|
+
var DEFAULT_MODEL = "t2000/auto";
|
|
33703
|
+
var OPEN_MODEL = "t2000/auto-open";
|
|
33704
|
+
var CONSOLE_KEYS_URL = "https://agents.t2000.ai/manage";
|
|
33705
|
+
var CONNECT_CLIENTS = [
|
|
33706
|
+
{
|
|
33707
|
+
slug: "t2code",
|
|
33708
|
+
name: "t2 code",
|
|
33709
|
+
aliases: ["code"],
|
|
33710
|
+
blurb: "the t2000 coding agent (npm i -g @t2000/code) \u2014 saves your key"
|
|
33711
|
+
},
|
|
33712
|
+
{
|
|
33713
|
+
slug: "claude-code",
|
|
33714
|
+
name: "Claude Code (via claude-code-router)",
|
|
33715
|
+
aliases: ["ccr", "claude"],
|
|
33716
|
+
blurb: "adds a t2000 provider to ~/.claude-code-router"
|
|
33717
|
+
},
|
|
33718
|
+
{
|
|
33719
|
+
slug: "continue",
|
|
33720
|
+
name: "Continue",
|
|
33721
|
+
aliases: [],
|
|
33722
|
+
blurb: "model entry for ~/.continue/config.yaml"
|
|
33723
|
+
},
|
|
33724
|
+
{
|
|
33725
|
+
slug: "aider",
|
|
33726
|
+
name: "Aider",
|
|
33727
|
+
aliases: [],
|
|
33728
|
+
blurb: "OpenAI-compatible base + model for ~/.aider.conf.yml"
|
|
33729
|
+
},
|
|
33730
|
+
{
|
|
33731
|
+
slug: "codex",
|
|
33732
|
+
name: "OpenAI Codex CLI",
|
|
33733
|
+
aliases: [],
|
|
33734
|
+
blurb: "t2000 provider profile in ~/.codex/config.toml"
|
|
33735
|
+
},
|
|
33736
|
+
{
|
|
33737
|
+
slug: "grok",
|
|
33738
|
+
name: "Grok Build",
|
|
33739
|
+
aliases: ["grok-build"],
|
|
33740
|
+
blurb: "custom-model block in ~/.grok/config.toml (the BYOK pattern)"
|
|
33741
|
+
},
|
|
33742
|
+
{
|
|
33743
|
+
slug: "cline",
|
|
33744
|
+
name: "Cline",
|
|
33745
|
+
aliases: [],
|
|
33746
|
+
blurb: "settings walkthrough (GUI-managed config)"
|
|
33747
|
+
},
|
|
33748
|
+
{
|
|
33749
|
+
slug: "cursor",
|
|
33750
|
+
name: "Cursor",
|
|
33751
|
+
aliases: [],
|
|
33752
|
+
blurb: "settings walkthrough (GUI-managed config)"
|
|
33753
|
+
}
|
|
33754
|
+
];
|
|
33755
|
+
function resolveClientSlug(input) {
|
|
33756
|
+
const needle = input.toLowerCase();
|
|
33757
|
+
for (const c of CONNECT_CLIENTS) {
|
|
33758
|
+
if (c.slug === needle || c.aliases.includes(needle)) return c.slug;
|
|
33759
|
+
}
|
|
33760
|
+
return void 0;
|
|
33761
|
+
}
|
|
33762
|
+
function t2codeCredentialsPath(home = homedir3()) {
|
|
33763
|
+
return join4(home, ".config", "t2code", "credentials.json");
|
|
33764
|
+
}
|
|
33765
|
+
function withT2codeKey(existing, key) {
|
|
33766
|
+
return {
|
|
33767
|
+
...existing,
|
|
33768
|
+
default: {
|
|
33769
|
+
name: "t2000",
|
|
33770
|
+
email: "",
|
|
33771
|
+
...typeof existing.default === "object" && existing.default !== null ? existing.default : {},
|
|
33772
|
+
authToken: key
|
|
33773
|
+
}
|
|
33774
|
+
};
|
|
33775
|
+
}
|
|
33776
|
+
function t2codeHasKey(existing, key) {
|
|
33777
|
+
return existing.default?.authToken === key;
|
|
33778
|
+
}
|
|
33779
|
+
function ccrDir(home = homedir3()) {
|
|
33780
|
+
return join4(home, ".claude-code-router");
|
|
33781
|
+
}
|
|
33782
|
+
function ccrSqlitePath(home = homedir3()) {
|
|
33783
|
+
return join4(ccrDir(home), "config.sqlite");
|
|
33784
|
+
}
|
|
33785
|
+
function ccrConfigJsonPath(home = homedir3()) {
|
|
33786
|
+
return join4(ccrDir(home), "config.json");
|
|
33787
|
+
}
|
|
33788
|
+
function withCcrProvider(existing, key) {
|
|
33789
|
+
const provider = {
|
|
33790
|
+
name: "t2000",
|
|
33791
|
+
api_base_url: CHAT_COMPLETIONS_URL,
|
|
33792
|
+
api_key: key,
|
|
33793
|
+
models: [DEFAULT_MODEL, OPEN_MODEL]
|
|
33794
|
+
};
|
|
33795
|
+
const providers = Array.isArray(existing.Providers) ? [...existing.Providers] : [];
|
|
33796
|
+
const idx = providers.findIndex((p) => p?.name === "t2000");
|
|
33797
|
+
if (idx >= 0) providers[idx] = { ...providers[idx], ...provider };
|
|
33798
|
+
else providers.push(provider);
|
|
33799
|
+
const router = { ...existing.Router ?? {} };
|
|
33800
|
+
if (!router.default) router.default = `t2000,${DEFAULT_MODEL}`;
|
|
33801
|
+
return { ...existing, Providers: providers, Router: router };
|
|
33802
|
+
}
|
|
33803
|
+
function ccrHasProvider(existing) {
|
|
33804
|
+
return Array.isArray(existing.Providers) && existing.Providers.some((p) => p?.name === "t2000");
|
|
33805
|
+
}
|
|
33806
|
+
function continueConfigPath(home = homedir3()) {
|
|
33807
|
+
return join4(home, ".continue", "config.yaml");
|
|
33808
|
+
}
|
|
33809
|
+
function continueModelYaml(key) {
|
|
33810
|
+
return [
|
|
33811
|
+
` - name: t2000 auto`,
|
|
33812
|
+
` provider: openai`,
|
|
33813
|
+
` model: ${DEFAULT_MODEL}`,
|
|
33814
|
+
` apiBase: ${API_BASE}`,
|
|
33815
|
+
` apiKey: ${key}`,
|
|
33816
|
+
` roles:`,
|
|
33817
|
+
` - chat`,
|
|
33818
|
+
` - edit`,
|
|
33819
|
+
` - apply`
|
|
33820
|
+
].join("\n");
|
|
33821
|
+
}
|
|
33822
|
+
function continueFreshConfigYaml(key) {
|
|
33823
|
+
return [
|
|
33824
|
+
`name: t2000 Private Inference`,
|
|
33825
|
+
`version: 0.0.1`,
|
|
33826
|
+
`schema: v1`,
|
|
33827
|
+
``,
|
|
33828
|
+
`models:`,
|
|
33829
|
+
continueModelYaml(key),
|
|
33830
|
+
``
|
|
33831
|
+
].join("\n");
|
|
33832
|
+
}
|
|
33833
|
+
function aiderConfPath(home = homedir3()) {
|
|
33834
|
+
return join4(home, ".aider.conf.yml");
|
|
33835
|
+
}
|
|
33836
|
+
function aiderConfYaml(key) {
|
|
33837
|
+
return [
|
|
33838
|
+
`# t2000 Private Inference (written by \`t2 connect aider\`)`,
|
|
33839
|
+
`openai-api-base: ${API_BASE}`,
|
|
33840
|
+
`openai-api-key: ${key}`,
|
|
33841
|
+
`model: openai/${DEFAULT_MODEL}`,
|
|
33842
|
+
``
|
|
33843
|
+
].join("\n");
|
|
33844
|
+
}
|
|
33845
|
+
function codexConfigPath(home = homedir3()) {
|
|
33846
|
+
return join4(home, ".codex", "config.toml");
|
|
33847
|
+
}
|
|
33848
|
+
function codexTomlBlock() {
|
|
33849
|
+
return [
|
|
33850
|
+
``,
|
|
33851
|
+
`# t2000 Private Inference (written by \`t2 connect codex\`)`,
|
|
33852
|
+
`[model_providers.t2000]`,
|
|
33853
|
+
`name = "t2000"`,
|
|
33854
|
+
`base_url = "${API_BASE}"`,
|
|
33855
|
+
`env_key = "T2000_API_KEY"`,
|
|
33856
|
+
``,
|
|
33857
|
+
`[profiles.t2000]`,
|
|
33858
|
+
`model = "${DEFAULT_MODEL}"`,
|
|
33859
|
+
`model_provider = "t2000"`,
|
|
33860
|
+
``
|
|
33861
|
+
].join("\n");
|
|
33862
|
+
}
|
|
33863
|
+
function codexHasProvider(existingToml) {
|
|
33864
|
+
return existingToml.includes("[model_providers.t2000]");
|
|
33865
|
+
}
|
|
33866
|
+
function grokConfigPath(home = homedir3()) {
|
|
33867
|
+
return join4(home, ".grok", "config.toml");
|
|
33868
|
+
}
|
|
33869
|
+
function grokModelBlock() {
|
|
33870
|
+
return [
|
|
33871
|
+
``,
|
|
33872
|
+
`# t2000 Private Inference (written by \`t2 connect grok\`)`,
|
|
33873
|
+
`[model.t2000]`,
|
|
33874
|
+
`model = "${DEFAULT_MODEL}"`,
|
|
33875
|
+
`base_url = "${API_BASE}"`,
|
|
33876
|
+
`name = "t2000 auto (Private Inference)"`,
|
|
33877
|
+
`env_key = "T2000_API_KEY"`,
|
|
33878
|
+
`api_backend = "chat_completions"`,
|
|
33879
|
+
``
|
|
33880
|
+
].join("\n");
|
|
33881
|
+
}
|
|
33882
|
+
function grokFreshConfigToml() {
|
|
33883
|
+
return grokModelBlock().trimStart() + [`[models]`, `default = "t2000"`, ``].join("\n");
|
|
33884
|
+
}
|
|
33885
|
+
function grokHasModel(existingToml) {
|
|
33886
|
+
return existingToml.includes("[model.t2000]");
|
|
33887
|
+
}
|
|
33888
|
+
|
|
33889
|
+
// src/commands/connect/index.ts
|
|
33890
|
+
function t2000ConfigPath() {
|
|
33891
|
+
return join5(homedir4(), ".t2000", "config.json");
|
|
33892
|
+
}
|
|
33893
|
+
function loadSavedKey() {
|
|
33894
|
+
try {
|
|
33895
|
+
const raw = JSON.parse(readFileSync3(t2000ConfigPath(), "utf-8"));
|
|
33896
|
+
const inference = raw.inference;
|
|
33897
|
+
if (typeof inference === "object" && inference !== null) {
|
|
33898
|
+
const key = inference.apiKey;
|
|
33899
|
+
if (typeof key === "string" && key.length > 0) return key;
|
|
33900
|
+
}
|
|
33901
|
+
} catch {
|
|
33902
|
+
}
|
|
33903
|
+
return void 0;
|
|
33904
|
+
}
|
|
33905
|
+
function saveKey2(key) {
|
|
33906
|
+
const path2 = t2000ConfigPath();
|
|
33907
|
+
let existing = {};
|
|
33908
|
+
try {
|
|
33909
|
+
existing = JSON.parse(readFileSync3(path2, "utf-8"));
|
|
33910
|
+
} catch {
|
|
33911
|
+
existing = {};
|
|
33912
|
+
}
|
|
33913
|
+
const merged = { ...existing, inference: { apiKey: key } };
|
|
33914
|
+
if (!existsSync3(dirname3(path2))) mkdirSync2(dirname3(path2), { recursive: true });
|
|
33915
|
+
writeFileSync3(path2, JSON.stringify(merged, null, 2) + "\n", { mode: 384 });
|
|
33916
|
+
}
|
|
33917
|
+
function resolveKey(flagKey) {
|
|
33918
|
+
if (flagKey && flagKey.trim().length > 0) return { key: flagKey.trim(), source: "--key" };
|
|
33919
|
+
const envKey = process.env.T2000_API_KEY;
|
|
33920
|
+
if (envKey && envKey.trim().length > 0) return { key: envKey.trim(), source: "T2000_API_KEY" };
|
|
33921
|
+
const saved = loadSavedKey();
|
|
33922
|
+
if (saved) return { key: saved, source: "~/.t2000/config.json" };
|
|
33923
|
+
return { source: "none" };
|
|
33924
|
+
}
|
|
33925
|
+
function readJson(path2) {
|
|
33926
|
+
try {
|
|
33927
|
+
return JSON.parse(readFileSync3(path2, "utf-8"));
|
|
33928
|
+
} catch {
|
|
33929
|
+
return {};
|
|
33930
|
+
}
|
|
33931
|
+
}
|
|
33932
|
+
function writeFileEnsuringDir(path2, contents, mode) {
|
|
33933
|
+
const dir = dirname3(path2);
|
|
33934
|
+
if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
|
|
33935
|
+
writeFileSync3(path2, contents, mode !== void 0 ? { mode } : void 0);
|
|
33936
|
+
}
|
|
33937
|
+
function connectT2code(key, print2) {
|
|
33938
|
+
const path2 = t2codeCredentialsPath();
|
|
33939
|
+
const existing = readJson(path2);
|
|
33940
|
+
if (t2codeHasKey(existing, key)) {
|
|
33941
|
+
return { client: "t2code", action: "exists", path: path2, detail: "already connected with this key" };
|
|
33942
|
+
}
|
|
33943
|
+
if (print2) {
|
|
33944
|
+
return {
|
|
33945
|
+
client: "t2code",
|
|
33946
|
+
action: "snippet",
|
|
33947
|
+
path: path2,
|
|
33948
|
+
detail: "would write the key into t2 code credentials",
|
|
33949
|
+
text: `Would set default.authToken in ${path2}`
|
|
33950
|
+
};
|
|
33951
|
+
}
|
|
33952
|
+
writeFileEnsuringDir(path2, JSON.stringify(withT2codeKey(existing, key), null, 2), 384);
|
|
33953
|
+
return {
|
|
33954
|
+
client: "t2code",
|
|
33955
|
+
action: "written",
|
|
33956
|
+
path: path2,
|
|
33957
|
+
detail: "key saved \u2014 run `t2code` (or `npm i -g @t2000/code` first)"
|
|
33958
|
+
};
|
|
33959
|
+
}
|
|
33960
|
+
function connectClaudeCode(key, print2) {
|
|
33961
|
+
const sqlite = ccrSqlitePath();
|
|
33962
|
+
if (existsSync3(sqlite)) {
|
|
33963
|
+
return {
|
|
33964
|
+
client: "claude-code",
|
|
33965
|
+
action: "instructions",
|
|
33966
|
+
detail: "claude-code-router already manages config in SQLite \u2014 add the provider in its UI",
|
|
33967
|
+
text: [
|
|
33968
|
+
`claude-code-router found (SQLite config). Add the provider in the ccr UI:`,
|
|
33969
|
+
` Providers \u2192 Add Provider \u2192 Other / custom API endpoint`,
|
|
33970
|
+
` name: t2000`,
|
|
33971
|
+
` base URL: ${API_BASE}/chat/completions`,
|
|
33972
|
+
` protocol: OpenAI`,
|
|
33973
|
+
` API key: ${key}`,
|
|
33974
|
+
` models: ${DEFAULT_MODEL}`,
|
|
33975
|
+
` Then set the default route to t2000,${DEFAULT_MODEL}.`
|
|
33976
|
+
].join("\n")
|
|
33977
|
+
};
|
|
33978
|
+
}
|
|
33979
|
+
const path2 = ccrConfigJsonPath();
|
|
33980
|
+
const existing = readJson(path2);
|
|
33981
|
+
const already = ccrHasProvider(existing);
|
|
33982
|
+
if (print2) {
|
|
33983
|
+
return {
|
|
33984
|
+
client: "claude-code",
|
|
33985
|
+
action: "snippet",
|
|
33986
|
+
path: path2,
|
|
33987
|
+
detail: already ? "t2000 provider already present" : "would add the t2000 provider",
|
|
33988
|
+
text: JSON.stringify(withCcrProvider(existing, key), null, 2)
|
|
33989
|
+
};
|
|
33990
|
+
}
|
|
33991
|
+
writeFileEnsuringDir(path2, JSON.stringify(withCcrProvider(existing, key), null, 2) + "\n", 384);
|
|
33992
|
+
return {
|
|
33993
|
+
client: "claude-code",
|
|
33994
|
+
action: "written",
|
|
33995
|
+
path: path2,
|
|
33996
|
+
detail: already ? "t2000 provider refreshed \u2014 install ccr (npm i -g @musistudio/claude-code-router), then `ccr code`" : "t2000 provider added \u2014 install ccr (npm i -g @musistudio/claude-code-router), then `ccr code`"
|
|
33997
|
+
};
|
|
33998
|
+
}
|
|
33999
|
+
function connectContinue(key, print2) {
|
|
34000
|
+
const path2 = continueConfigPath();
|
|
34001
|
+
if (!existsSync3(path2) && !print2) {
|
|
34002
|
+
writeFileEnsuringDir(path2, continueFreshConfigYaml(key), 384);
|
|
34003
|
+
return { client: "continue", action: "written", path: path2, detail: "config.yaml created" };
|
|
34004
|
+
}
|
|
34005
|
+
return {
|
|
34006
|
+
client: "continue",
|
|
34007
|
+
action: "snippet",
|
|
34008
|
+
path: path2,
|
|
34009
|
+
detail: existsSync3(path2) ? "config.yaml exists \u2014 paste this model block under `models:`" : "would create config.yaml with this model block",
|
|
34010
|
+
text: continueModelYaml(key)
|
|
34011
|
+
};
|
|
34012
|
+
}
|
|
34013
|
+
function connectAider(key, print2) {
|
|
34014
|
+
const path2 = aiderConfPath();
|
|
34015
|
+
if (!existsSync3(path2) && !print2) {
|
|
34016
|
+
writeFileEnsuringDir(path2, aiderConfYaml(key), 384);
|
|
34017
|
+
return { client: "aider", action: "written", path: path2, detail: ".aider.conf.yml created" };
|
|
34018
|
+
}
|
|
34019
|
+
return {
|
|
34020
|
+
client: "aider",
|
|
34021
|
+
action: "snippet",
|
|
34022
|
+
path: path2,
|
|
34023
|
+
detail: existsSync3(path2) ? ".aider.conf.yml exists \u2014 add these lines (or use the flags below)" : "would create .aider.conf.yml",
|
|
34024
|
+
text: aiderConfYaml(key) + `
|
|
34025
|
+
# or without touching the file:
|
|
34026
|
+
# aider --openai-api-base ${API_BASE} --openai-api-key ${key} --model openai/${DEFAULT_MODEL}`
|
|
34027
|
+
};
|
|
34028
|
+
}
|
|
34029
|
+
function connectCodex(key, print2) {
|
|
34030
|
+
const path2 = codexConfigPath();
|
|
34031
|
+
const existing = existsSync3(path2) ? readFileSync3(path2, "utf-8") : "";
|
|
34032
|
+
if (codexHasProvider(existing)) {
|
|
34033
|
+
return {
|
|
34034
|
+
client: "codex",
|
|
34035
|
+
action: "exists",
|
|
34036
|
+
path: path2,
|
|
34037
|
+
detail: "t2000 provider already in config.toml \u2014 run `codex --profile t2000`"
|
|
34038
|
+
};
|
|
34039
|
+
}
|
|
34040
|
+
if (print2) {
|
|
34041
|
+
return {
|
|
34042
|
+
client: "codex",
|
|
34043
|
+
action: "snippet",
|
|
34044
|
+
path: path2,
|
|
34045
|
+
detail: "would append the t2000 provider + profile",
|
|
34046
|
+
text: codexTomlBlock()
|
|
34047
|
+
};
|
|
34048
|
+
}
|
|
34049
|
+
if (existsSync3(path2)) appendFileSync(path2, codexTomlBlock());
|
|
34050
|
+
else writeFileEnsuringDir(path2, codexTomlBlock().trimStart(), 384);
|
|
34051
|
+
return {
|
|
34052
|
+
client: "codex",
|
|
34053
|
+
action: "written",
|
|
34054
|
+
path: path2,
|
|
34055
|
+
detail: `provider + profile added \u2014 export T2000_API_KEY=${maskKey(key)} then \`codex --profile t2000\``
|
|
34056
|
+
};
|
|
34057
|
+
}
|
|
34058
|
+
function connectGrok(key, print2) {
|
|
34059
|
+
const path2 = grokConfigPath();
|
|
34060
|
+
const existing = existsSync3(path2) ? readFileSync3(path2, "utf-8") : "";
|
|
34061
|
+
if (grokHasModel(existing)) {
|
|
34062
|
+
return {
|
|
34063
|
+
client: "grok",
|
|
34064
|
+
action: "exists",
|
|
34065
|
+
path: path2,
|
|
34066
|
+
detail: "t2000 model already in config.toml \u2014 run `grok -m t2000` (or /model t2000)"
|
|
34067
|
+
};
|
|
34068
|
+
}
|
|
34069
|
+
if (print2) {
|
|
34070
|
+
return {
|
|
34071
|
+
client: "grok",
|
|
34072
|
+
action: "snippet",
|
|
34073
|
+
path: path2,
|
|
34074
|
+
detail: existsSync3(path2) ? "would append the t2000 model block" : "would create config.toml with the t2000 model (+ default)",
|
|
34075
|
+
text: existsSync3(path2) ? grokModelBlock() : grokFreshConfigToml()
|
|
34076
|
+
};
|
|
34077
|
+
}
|
|
34078
|
+
if (existsSync3(path2)) {
|
|
34079
|
+
appendFileSync(path2, grokModelBlock());
|
|
34080
|
+
return {
|
|
34081
|
+
client: "grok",
|
|
34082
|
+
action: "written",
|
|
34083
|
+
path: path2,
|
|
34084
|
+
detail: `t2000 model added \u2014 export T2000_API_KEY=${maskKey(key)} then \`grok -m t2000\` (set \`default = "t2000"\` under your existing [models] to make it stick)`
|
|
34085
|
+
};
|
|
34086
|
+
}
|
|
34087
|
+
writeFileEnsuringDir(path2, grokFreshConfigToml(), 384);
|
|
34088
|
+
return {
|
|
34089
|
+
client: "grok",
|
|
34090
|
+
action: "written",
|
|
34091
|
+
path: path2,
|
|
34092
|
+
detail: `config.toml created with t2000 as default \u2014 export T2000_API_KEY=${maskKey(key)} then \`grok\``
|
|
34093
|
+
};
|
|
34094
|
+
}
|
|
34095
|
+
function connectCline(key) {
|
|
34096
|
+
return {
|
|
34097
|
+
client: "cline",
|
|
34098
|
+
action: "instructions",
|
|
34099
|
+
detail: "Cline stores provider config in VS Code \u2014 set it in the extension settings",
|
|
34100
|
+
text: [
|
|
34101
|
+
`In Cline settings, choose the "OpenAI Compatible" API provider:`,
|
|
34102
|
+
` Base URL: ${API_BASE}`,
|
|
34103
|
+
` API key: ${key}`,
|
|
34104
|
+
` Model ID: ${DEFAULT_MODEL}`
|
|
34105
|
+
].join("\n")
|
|
34106
|
+
};
|
|
34107
|
+
}
|
|
34108
|
+
function connectCursor(key) {
|
|
34109
|
+
return {
|
|
34110
|
+
client: "cursor",
|
|
34111
|
+
action: "instructions",
|
|
34112
|
+
detail: "Cursor is configured in Settings \u2014 no file to write",
|
|
34113
|
+
text: [
|
|
34114
|
+
`Cursor \u2192 Settings \u2192 Models \u2192 API Keys:`,
|
|
34115
|
+
` 1. Paste the key into "OpenAI API Key": ${maskKey(key)}`,
|
|
34116
|
+
` 2. Expand "Override OpenAI Base URL" and set: ${API_BASE}`,
|
|
34117
|
+
` 3. Under Models, add \`${DEFAULT_MODEL}\`, then Verify.`,
|
|
34118
|
+
`Note: Cursor's agent features are tuned for its own models \u2014 use this`,
|
|
34119
|
+
`for private chat models; delegation runs through t2 code.`
|
|
34120
|
+
].join("\n")
|
|
34121
|
+
};
|
|
34122
|
+
}
|
|
34123
|
+
function maskKey(key) {
|
|
34124
|
+
return key.length > 8 ? `${key.slice(0, 5)}\u2026${key.slice(-3)}` : "sk-\u2026";
|
|
34125
|
+
}
|
|
34126
|
+
function runConnect(slug, key, print2) {
|
|
34127
|
+
switch (slug) {
|
|
34128
|
+
case "t2code":
|
|
34129
|
+
return connectT2code(key, print2);
|
|
34130
|
+
case "claude-code":
|
|
34131
|
+
return connectClaudeCode(key, print2);
|
|
34132
|
+
case "continue":
|
|
34133
|
+
return connectContinue(key, print2);
|
|
34134
|
+
case "aider":
|
|
34135
|
+
return connectAider(key, print2);
|
|
34136
|
+
case "codex":
|
|
34137
|
+
return connectCodex(key, print2);
|
|
34138
|
+
case "grok":
|
|
34139
|
+
return connectGrok(key, print2);
|
|
34140
|
+
case "cline":
|
|
34141
|
+
return connectCline(key);
|
|
34142
|
+
case "cursor":
|
|
34143
|
+
return connectCursor(key);
|
|
34144
|
+
}
|
|
34145
|
+
}
|
|
34146
|
+
function registerConnect(program3) {
|
|
34147
|
+
program3.command("connect").description("Point a coding tool at Private Inference (api.t2000.ai/v1) with your key").argument("[client]", "client to connect: t2code | claude-code | continue | aider | codex | grok | cline | cursor").option("--key <sk-key>", `Private Inference key (create one at ${CONSOLE_KEYS_URL})`).option("--print", "Show what would be written / the paste snippet, without writing").addHelpText(
|
|
34148
|
+
"after",
|
|
34149
|
+
`
|
|
34150
|
+
Examples:
|
|
34151
|
+
$ t2 connect List supported clients
|
|
34152
|
+
$ t2 connect t2code --key sk-... Save your key into t2 code
|
|
34153
|
+
$ t2 connect claude-code Add the t2000 provider to claude-code-router
|
|
34154
|
+
$ t2 connect aider --print Show the aider config without writing it
|
|
34155
|
+
|
|
34156
|
+
The key comes from the console: sign in at ${CONSOLE_KEYS_URL}
|
|
34157
|
+
(Google), create an API key, paste it once \u2014 it is saved to ~/.t2000/config.json
|
|
34158
|
+
and reused by later connects. All clients get model ${DEFAULT_MODEL} (the router;
|
|
34159
|
+
you pay the price of the model that actually served each request).`
|
|
34160
|
+
).action(async (clientArg, opts) => {
|
|
34161
|
+
try {
|
|
34162
|
+
if (!clientArg) {
|
|
34163
|
+
const { key: key2 } = resolveKey(opts.key);
|
|
34164
|
+
if (isJsonMode()) {
|
|
34165
|
+
printJson({
|
|
34166
|
+
clients: CONNECT_CLIENTS.map((c) => ({ slug: c.slug, name: c.name, blurb: c.blurb })),
|
|
34167
|
+
keySaved: !!key2
|
|
34168
|
+
});
|
|
34169
|
+
return;
|
|
34170
|
+
}
|
|
34171
|
+
printBlank();
|
|
34172
|
+
printLine(" Connect a coding tool to Private Inference:");
|
|
34173
|
+
printBlank();
|
|
34174
|
+
for (const c of CONNECT_CLIENTS) {
|
|
34175
|
+
printKeyValue(c.slug.padEnd(12), c.blurb);
|
|
34176
|
+
}
|
|
34177
|
+
printBlank();
|
|
34178
|
+
printInfo(`Usage: t2 connect <client> [--key sk-...]`);
|
|
34179
|
+
printInfo(
|
|
34180
|
+
key2 ? "A key is saved \u2014 connects will reuse it." : `No key yet \u2014 create one at ${CONSOLE_KEYS_URL}`
|
|
34181
|
+
);
|
|
34182
|
+
printBlank();
|
|
34183
|
+
return;
|
|
34184
|
+
}
|
|
34185
|
+
const slug = resolveClientSlug(clientArg);
|
|
34186
|
+
if (!slug) {
|
|
34187
|
+
printWarning(`Unknown client '${clientArg}'.`);
|
|
34188
|
+
printInfo(`Supported: ${CONNECT_CLIENTS.map((c) => c.slug).join(" \xB7 ")}`);
|
|
34189
|
+
process.exitCode = 1;
|
|
34190
|
+
return;
|
|
34191
|
+
}
|
|
34192
|
+
const { key, source } = resolveKey(opts.key);
|
|
34193
|
+
if (!key) {
|
|
34194
|
+
printBlank();
|
|
34195
|
+
printWarning("No API key found.");
|
|
34196
|
+
printInfo(`1. Sign in at ${CONSOLE_KEYS_URL} (Google) and create an API key`);
|
|
34197
|
+
printInfo(`2. Re-run: t2 connect ${slug} --key sk-...`);
|
|
34198
|
+
printBlank();
|
|
34199
|
+
process.exitCode = 1;
|
|
34200
|
+
return;
|
|
34201
|
+
}
|
|
34202
|
+
const result = runConnect(slug, key, !!opts.print);
|
|
34203
|
+
if (!opts.print && source !== "~/.t2000/config.json") saveKey2(key);
|
|
34204
|
+
if (isJsonMode()) {
|
|
34205
|
+
printJson({ ...result, keySource: source });
|
|
34206
|
+
return;
|
|
34207
|
+
}
|
|
34208
|
+
printBlank();
|
|
34209
|
+
if (result.action === "written") {
|
|
34210
|
+
printSuccess(`${slug}: ${result.detail}`);
|
|
34211
|
+
if (result.path) printKeyValue("wrote", result.path);
|
|
34212
|
+
} else if (result.action === "exists") {
|
|
34213
|
+
printInfo(`${slug}: ${result.detail}`);
|
|
34214
|
+
} else {
|
|
34215
|
+
printInfo(`${slug}: ${result.detail}`);
|
|
34216
|
+
}
|
|
34217
|
+
if (result.text) {
|
|
34218
|
+
printBlank();
|
|
34219
|
+
for (const line of result.text.split("\n")) printLine(` ${line}`);
|
|
34220
|
+
}
|
|
34221
|
+
printBlank();
|
|
34222
|
+
} catch (error) {
|
|
34223
|
+
handleError(error);
|
|
34224
|
+
}
|
|
34225
|
+
});
|
|
34226
|
+
}
|
|
34227
|
+
|
|
33692
34228
|
// src/commands/verify.ts
|
|
33693
34229
|
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
33694
34230
|
function mark(check2) {
|
|
@@ -34121,7 +34657,7 @@ function registerMcpStart(parent) {
|
|
|
34121
34657
|
parent.command("start", { isDefault: true }).description("Start MCP server (stdio transport \u2014 for AI client integration)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(async (opts) => {
|
|
34122
34658
|
let mod3;
|
|
34123
34659
|
try {
|
|
34124
|
-
mod3 = await import("./dist-
|
|
34660
|
+
mod3 = await import("./dist-STP3HAL6.js");
|
|
34125
34661
|
} catch {
|
|
34126
34662
|
console.error("MCP server not installed. Run:\n npm install -g @t2000/mcp");
|
|
34127
34663
|
process.exit(1);
|
|
@@ -34172,12 +34708,12 @@ function registerMcpInstall(parent) {
|
|
|
34172
34708
|
}
|
|
34173
34709
|
|
|
34174
34710
|
// src/commands/mcp/uninstall.ts
|
|
34175
|
-
import { existsSync as
|
|
34711
|
+
import { existsSync as existsSync4 } from "fs";
|
|
34176
34712
|
async function runUninstall() {
|
|
34177
34713
|
const platforms = getPlatformConfigs();
|
|
34178
34714
|
const results = [];
|
|
34179
34715
|
for (const platform of platforms) {
|
|
34180
|
-
if (!
|
|
34716
|
+
if (!existsSync4(platform.path)) {
|
|
34181
34717
|
results.push({ name: platform.name, slug: platform.slug, removed: false });
|
|
34182
34718
|
continue;
|
|
34183
34719
|
}
|
|
@@ -34233,12 +34769,12 @@ Subcommands:
|
|
|
34233
34769
|
|
|
34234
34770
|
// src/commands/skills/check.ts
|
|
34235
34771
|
import { readdir, readFile as readFile3 } from "fs/promises";
|
|
34236
|
-
import { join as
|
|
34772
|
+
import { join as join7 } from "path";
|
|
34237
34773
|
|
|
34238
34774
|
// src/commands/skills/lib.ts
|
|
34239
34775
|
import { stat } from "fs/promises";
|
|
34240
|
-
import { join as
|
|
34241
|
-
import { homedir as
|
|
34776
|
+
import { join as join6 } from "path";
|
|
34777
|
+
import { homedir as homedir5 } from "os";
|
|
34242
34778
|
var MANIFEST_URL = "https://t2000.ai/.well-known/agent-skills/index.json";
|
|
34243
34779
|
var SKILL_PREFIXES = ["t2000-", "mpp-"];
|
|
34244
34780
|
function isManagedSkillName(name) {
|
|
@@ -34246,21 +34782,21 @@ function isManagedSkillName(name) {
|
|
|
34246
34782
|
}
|
|
34247
34783
|
var SKILL_TARGETS = ["agents", "cursor", "claude-code"];
|
|
34248
34784
|
function resolveTargetDir(target, useGlobal, cwd = process.cwd()) {
|
|
34249
|
-
const root = useGlobal ?
|
|
34785
|
+
const root = useGlobal ? homedir5() : cwd;
|
|
34250
34786
|
switch (target) {
|
|
34251
34787
|
case "agents":
|
|
34252
|
-
return
|
|
34788
|
+
return join6(root, ".agents", "skills");
|
|
34253
34789
|
case "cursor":
|
|
34254
|
-
return
|
|
34790
|
+
return join6(root, ".cursor", "rules");
|
|
34255
34791
|
case "claude-code":
|
|
34256
|
-
return
|
|
34792
|
+
return join6(root, ".claude", "skills");
|
|
34257
34793
|
}
|
|
34258
34794
|
}
|
|
34259
34795
|
function filenameForTarget(slug, target) {
|
|
34260
34796
|
switch (target) {
|
|
34261
34797
|
case "agents":
|
|
34262
34798
|
case "claude-code":
|
|
34263
|
-
return
|
|
34799
|
+
return join6(slug, "SKILL.md");
|
|
34264
34800
|
case "cursor":
|
|
34265
34801
|
return `${slug}.mdc`;
|
|
34266
34802
|
}
|
|
@@ -34334,7 +34870,7 @@ async function checkTargetScope(manifest, servedCache, target, scope) {
|
|
|
34334
34870
|
const slugs = await installedSlugs(dir, target);
|
|
34335
34871
|
const rows = [];
|
|
34336
34872
|
for (const slug of slugs) {
|
|
34337
|
-
const path2 =
|
|
34873
|
+
const path2 = join7(dir, filenameForTarget(slug, target));
|
|
34338
34874
|
let installed;
|
|
34339
34875
|
try {
|
|
34340
34876
|
installed = await readFile3(path2, "utf-8");
|
|
@@ -34462,7 +34998,7 @@ function registerSkillsList(parent) {
|
|
|
34462
34998
|
|
|
34463
34999
|
// src/commands/skills/install.ts
|
|
34464
35000
|
import { writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
34465
|
-
import { join as
|
|
35001
|
+
import { join as join8 } from "path";
|
|
34466
35002
|
function registerSkillsInstall(parent) {
|
|
34467
35003
|
parent.command("install [slug]").description("Install all skills (or one named slug) into a local directory").option("--target <name>", "Target client layout: agents (default), cursor, claude-code", "agents").option("--global", "Install to ~/.<target>/ instead of <cwd>/.<target>/").action(async (slug, opts) => {
|
|
34468
35004
|
try {
|
|
@@ -34483,8 +35019,8 @@ function registerSkillsInstall(parent) {
|
|
|
34483
35019
|
const raw = await fetchSkill(s.url);
|
|
34484
35020
|
const transformed = transformForTarget(raw, target, s.description);
|
|
34485
35021
|
const relPath = filenameForTarget(s.name, target);
|
|
34486
|
-
const fullPath =
|
|
34487
|
-
await mkdir3(
|
|
35022
|
+
const fullPath = join8(targetDir, relPath);
|
|
35023
|
+
await mkdir3(join8(fullPath, ".."), { recursive: true });
|
|
34488
35024
|
await writeFile3(fullPath, transformed, "utf-8");
|
|
34489
35025
|
installed.push({ name: s.name, path: fullPath });
|
|
34490
35026
|
}
|
|
@@ -34513,7 +35049,7 @@ function registerSkillsInstall(parent) {
|
|
|
34513
35049
|
|
|
34514
35050
|
// src/commands/skills/uninstall.ts
|
|
34515
35051
|
import { readdir as readdir2, unlink, rmdir } from "fs/promises";
|
|
34516
|
-
import { join as
|
|
35052
|
+
import { join as join9 } from "path";
|
|
34517
35053
|
function registerSkillsUninstall(parent) {
|
|
34518
35054
|
parent.command("uninstall").description("Remove installed t2000 + MPP skills from the target directory").option("--target <name>", "Target client layout: agents (default), cursor, claude-code", "agents").option("--global", "Uninstall from ~/.<target>/ instead of <cwd>/.<target>/").action(async (opts) => {
|
|
34519
35055
|
try {
|
|
@@ -34531,7 +35067,7 @@ function registerSkillsUninstall(parent) {
|
|
|
34531
35067
|
const entries = await readdir2(targetDir);
|
|
34532
35068
|
const removed = [];
|
|
34533
35069
|
for (const entry of entries) {
|
|
34534
|
-
const full =
|
|
35070
|
+
const full = join9(targetDir, entry);
|
|
34535
35071
|
if (target === "cursor") {
|
|
34536
35072
|
const slug = entry.endsWith(".mdc") ? entry.slice(0, -".mdc".length) : entry;
|
|
34537
35073
|
if (entry.endsWith(".mdc") && isManagedSkillName(slug)) {
|
|
@@ -34540,7 +35076,7 @@ function registerSkillsUninstall(parent) {
|
|
|
34540
35076
|
}
|
|
34541
35077
|
} else {
|
|
34542
35078
|
if (isManagedSkillName(entry)) {
|
|
34543
|
-
const skillFile =
|
|
35079
|
+
const skillFile = join9(full, "SKILL.md");
|
|
34544
35080
|
try {
|
|
34545
35081
|
await unlink(skillFile);
|
|
34546
35082
|
} catch {
|
|
@@ -35156,6 +35692,7 @@ Examples:
|
|
|
35156
35692
|
$ t2 send 5 USDC alice.sui Send 5 USDC (gasless; asset required)
|
|
35157
35693
|
$ t2 swap 100 USDC SUI Swap 100 USDC for SUI via Cetus
|
|
35158
35694
|
$ t2 models List the Private Inference model catalog (chat lives in \`t2 code\`)
|
|
35695
|
+
$ t2 connect t2code --key sk-... Point a coding tool at Private Inference
|
|
35159
35696
|
$ t2 pay <url> --estimate Preview an x402 service's price + input schema (no payment)
|
|
35160
35697
|
$ t2 services search "image" Discover x402 services in the gateway catalog
|
|
35161
35698
|
$ t2 agents Look up the agent directory (agents.t2000.ai)
|
|
@@ -35172,6 +35709,7 @@ Examples:
|
|
|
35172
35709
|
registerSwap(program3);
|
|
35173
35710
|
registerPay(program3);
|
|
35174
35711
|
registerModels(program3);
|
|
35712
|
+
registerConnect(program3);
|
|
35175
35713
|
registerVerify(program3);
|
|
35176
35714
|
registerServices(program3);
|
|
35177
35715
|
registerLimit(program3);
|