@t2000/cli 8.2.0 → 9.1.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
@@ -33657,72 +33657,9 @@ function describeSchemaFields(schema) {
33657
33657
  });
33658
33658
  }
33659
33659
 
33660
- // src/commands/chat.ts
33660
+ // src/commands/models.ts
33661
33661
  var import_picocolors9 = __toESM(require_picocolors(), 1);
33662
- function receiptLine(receiptId) {
33663
- if (receiptId) {
33664
- printLine(import_picocolors9.default.dim(`\u{1F512} confidential \xB7 attested \xB7 receipt ${receiptId}`));
33665
- }
33666
- }
33667
- var DEFAULT_MODEL = "openai/gpt-oss-120b";
33668
- function numOrUndef(v) {
33669
- if (v === void 0) {
33670
- return;
33671
- }
33672
- const n = Number(v);
33673
- return Number.isFinite(n) ? n : void 0;
33674
- }
33675
- function registerChat(program3) {
33676
- program3.command("chat").argument("<message...>", "Your prompt").description(
33677
- "Chat with a model on t2000 Private Inference (OpenAI-compatible, ZDR; a phala/* tier is GPU-TEE confidential). Needs an API key \u2014 generate one at agents.t2000.ai/manage, then pass --api-key or set T2000_API_KEY."
33678
- ).option("--model <id>", `Model id (default ${DEFAULT_MODEL}; see \`t2 models\`)`, DEFAULT_MODEL).option("--system <text>", "System prompt").option("--max-tokens <n>", "Max output tokens").option("--temperature <t>", "Sampling temperature (0\u20132)").option("--no-stream", "Wait for the full response instead of streaming").option("--api-key <key>", "Private Inference key (or set T2000_API_KEY)").option("--api <url>", "API base URL (default https://api.t2000.ai/v1)").action(
33679
- async (messageParts, opts) => {
33680
- try {
33681
- const messages = [];
33682
- if (opts.system) {
33683
- messages.push({ role: "system", content: opts.system });
33684
- }
33685
- messages.push({ role: "user", content: messageParts.join(" ") });
33686
- const params = {
33687
- model: opts.model,
33688
- messages,
33689
- apiKey: opts.apiKey,
33690
- apiBase: opts.api,
33691
- maxTokens: numOrUndef(opts.maxTokens),
33692
- temperature: numOrUndef(opts.temperature)
33693
- };
33694
- if (isJsonMode() || opts.stream === false) {
33695
- const res = await chatCompletion(params);
33696
- if (isJsonMode()) {
33697
- printJson({
33698
- model: res.model,
33699
- content: res.content,
33700
- usage: res.usage,
33701
- receiptId: res.receiptId
33702
- });
33703
- return;
33704
- }
33705
- printBlank();
33706
- printLine(res.content);
33707
- receiptLine(res.receiptId);
33708
- printBlank();
33709
- return;
33710
- }
33711
- const gen = chatCompletionStream(params);
33712
- let any = false;
33713
- let next = await gen.next();
33714
- while (!next.done) {
33715
- process.stdout.write(next.value);
33716
- any = true;
33717
- next = await gen.next();
33718
- }
33719
- process.stdout.write(any ? "\n" : "");
33720
- receiptLine(next.value?.receiptId);
33721
- } catch (error) {
33722
- handleError(error);
33723
- }
33724
- }
33725
- );
33662
+ function registerModels(program3) {
33726
33663
  program3.command("models").description("List the t2000 Private Inference model catalog (id \xB7 privacy tier \xB7 per-1M pricing).").option("--api-key <key>", "Private Inference key (or set T2000_API_KEY)").option("--api <url>", "API base URL (default https://api.t2000.ai/v1)").action(async (opts) => {
33727
33664
  try {
33728
33665
  const models = await listModels({ apiKey: opts.apiKey, apiBase: opts.api });
@@ -33743,6 +33680,482 @@ function registerChat(program3) {
33743
33680
  handleError(error);
33744
33681
  }
33745
33682
  });
33683
+ program3.command("chat", { hidden: true }).allowUnknownOption(true).argument("[message...]").action(() => {
33684
+ printLine("`t2 chat` moved into t2 code \u2014 the coding agent on the same rail.");
33685
+ printLine(" npm install -g @t2000/code");
33686
+ printLine(' t2code "your prompt" # interactive');
33687
+ printLine(' t2code exec "your task" # one-shot, headless');
33688
+ process.exitCode = 1;
33689
+ });
33690
+ }
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: "cline",
33738
+ name: "Cline",
33739
+ aliases: [],
33740
+ blurb: "settings walkthrough (GUI-managed config)"
33741
+ },
33742
+ {
33743
+ slug: "cursor",
33744
+ name: "Cursor",
33745
+ aliases: [],
33746
+ blurb: "settings walkthrough (GUI-managed config)"
33747
+ }
33748
+ ];
33749
+ function resolveClientSlug(input) {
33750
+ const needle = input.toLowerCase();
33751
+ for (const c of CONNECT_CLIENTS) {
33752
+ if (c.slug === needle || c.aliases.includes(needle)) return c.slug;
33753
+ }
33754
+ return void 0;
33755
+ }
33756
+ function t2codeCredentialsPath(home = homedir3()) {
33757
+ return join4(home, ".config", "t2code", "credentials.json");
33758
+ }
33759
+ function withT2codeKey(existing, key) {
33760
+ return {
33761
+ ...existing,
33762
+ default: {
33763
+ name: "t2000",
33764
+ email: "",
33765
+ ...typeof existing.default === "object" && existing.default !== null ? existing.default : {},
33766
+ authToken: key
33767
+ }
33768
+ };
33769
+ }
33770
+ function t2codeHasKey(existing, key) {
33771
+ return existing.default?.authToken === key;
33772
+ }
33773
+ function ccrDir(home = homedir3()) {
33774
+ return join4(home, ".claude-code-router");
33775
+ }
33776
+ function ccrSqlitePath(home = homedir3()) {
33777
+ return join4(ccrDir(home), "config.sqlite");
33778
+ }
33779
+ function ccrConfigJsonPath(home = homedir3()) {
33780
+ return join4(ccrDir(home), "config.json");
33781
+ }
33782
+ function withCcrProvider(existing, key) {
33783
+ const provider = {
33784
+ name: "t2000",
33785
+ api_base_url: CHAT_COMPLETIONS_URL,
33786
+ api_key: key,
33787
+ models: [DEFAULT_MODEL, OPEN_MODEL]
33788
+ };
33789
+ const providers = Array.isArray(existing.Providers) ? [...existing.Providers] : [];
33790
+ const idx = providers.findIndex((p) => p?.name === "t2000");
33791
+ if (idx >= 0) providers[idx] = { ...providers[idx], ...provider };
33792
+ else providers.push(provider);
33793
+ const router = { ...existing.Router ?? {} };
33794
+ if (!router.default) router.default = `t2000,${DEFAULT_MODEL}`;
33795
+ return { ...existing, Providers: providers, Router: router };
33796
+ }
33797
+ function ccrHasProvider(existing) {
33798
+ return Array.isArray(existing.Providers) && existing.Providers.some((p) => p?.name === "t2000");
33799
+ }
33800
+ function continueConfigPath(home = homedir3()) {
33801
+ return join4(home, ".continue", "config.yaml");
33802
+ }
33803
+ function continueModelYaml(key) {
33804
+ return [
33805
+ ` - name: t2000 auto`,
33806
+ ` provider: openai`,
33807
+ ` model: ${DEFAULT_MODEL}`,
33808
+ ` apiBase: ${API_BASE}`,
33809
+ ` apiKey: ${key}`,
33810
+ ` roles:`,
33811
+ ` - chat`,
33812
+ ` - edit`,
33813
+ ` - apply`
33814
+ ].join("\n");
33815
+ }
33816
+ function continueFreshConfigYaml(key) {
33817
+ return [
33818
+ `name: t2000 Private Inference`,
33819
+ `version: 0.0.1`,
33820
+ `schema: v1`,
33821
+ ``,
33822
+ `models:`,
33823
+ continueModelYaml(key),
33824
+ ``
33825
+ ].join("\n");
33826
+ }
33827
+ function aiderConfPath(home = homedir3()) {
33828
+ return join4(home, ".aider.conf.yml");
33829
+ }
33830
+ function aiderConfYaml(key) {
33831
+ return [
33832
+ `# t2000 Private Inference (written by \`t2 connect aider\`)`,
33833
+ `openai-api-base: ${API_BASE}`,
33834
+ `openai-api-key: ${key}`,
33835
+ `model: openai/${DEFAULT_MODEL}`,
33836
+ ``
33837
+ ].join("\n");
33838
+ }
33839
+ function codexConfigPath(home = homedir3()) {
33840
+ return join4(home, ".codex", "config.toml");
33841
+ }
33842
+ function codexTomlBlock() {
33843
+ return [
33844
+ ``,
33845
+ `# t2000 Private Inference (written by \`t2 connect codex\`)`,
33846
+ `[model_providers.t2000]`,
33847
+ `name = "t2000"`,
33848
+ `base_url = "${API_BASE}"`,
33849
+ `env_key = "T2000_API_KEY"`,
33850
+ ``,
33851
+ `[profiles.t2000]`,
33852
+ `model = "${DEFAULT_MODEL}"`,
33853
+ `model_provider = "t2000"`,
33854
+ ``
33855
+ ].join("\n");
33856
+ }
33857
+ function codexHasProvider(existingToml) {
33858
+ return existingToml.includes("[model_providers.t2000]");
33859
+ }
33860
+
33861
+ // src/commands/connect/index.ts
33862
+ function t2000ConfigPath() {
33863
+ return join5(homedir4(), ".t2000", "config.json");
33864
+ }
33865
+ function loadSavedKey() {
33866
+ try {
33867
+ const raw = JSON.parse(readFileSync3(t2000ConfigPath(), "utf-8"));
33868
+ const inference = raw.inference;
33869
+ if (typeof inference === "object" && inference !== null) {
33870
+ const key = inference.apiKey;
33871
+ if (typeof key === "string" && key.length > 0) return key;
33872
+ }
33873
+ } catch {
33874
+ }
33875
+ return void 0;
33876
+ }
33877
+ function saveKey2(key) {
33878
+ const path2 = t2000ConfigPath();
33879
+ let existing = {};
33880
+ try {
33881
+ existing = JSON.parse(readFileSync3(path2, "utf-8"));
33882
+ } catch {
33883
+ existing = {};
33884
+ }
33885
+ const merged = { ...existing, inference: { apiKey: key } };
33886
+ if (!existsSync3(dirname3(path2))) mkdirSync2(dirname3(path2), { recursive: true });
33887
+ writeFileSync3(path2, JSON.stringify(merged, null, 2) + "\n", { mode: 384 });
33888
+ }
33889
+ function resolveKey(flagKey) {
33890
+ if (flagKey && flagKey.trim().length > 0) return { key: flagKey.trim(), source: "--key" };
33891
+ const envKey = process.env.T2000_API_KEY;
33892
+ if (envKey && envKey.trim().length > 0) return { key: envKey.trim(), source: "T2000_API_KEY" };
33893
+ const saved = loadSavedKey();
33894
+ if (saved) return { key: saved, source: "~/.t2000/config.json" };
33895
+ return { source: "none" };
33896
+ }
33897
+ function readJson(path2) {
33898
+ try {
33899
+ return JSON.parse(readFileSync3(path2, "utf-8"));
33900
+ } catch {
33901
+ return {};
33902
+ }
33903
+ }
33904
+ function writeFileEnsuringDir(path2, contents, mode) {
33905
+ const dir = dirname3(path2);
33906
+ if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
33907
+ writeFileSync3(path2, contents, mode !== void 0 ? { mode } : void 0);
33908
+ }
33909
+ function connectT2code(key, print2) {
33910
+ const path2 = t2codeCredentialsPath();
33911
+ const existing = readJson(path2);
33912
+ if (t2codeHasKey(existing, key)) {
33913
+ return { client: "t2code", action: "exists", path: path2, detail: "already connected with this key" };
33914
+ }
33915
+ if (print2) {
33916
+ return {
33917
+ client: "t2code",
33918
+ action: "snippet",
33919
+ path: path2,
33920
+ detail: "would write the key into t2 code credentials",
33921
+ text: `Would set default.authToken in ${path2}`
33922
+ };
33923
+ }
33924
+ writeFileEnsuringDir(path2, JSON.stringify(withT2codeKey(existing, key), null, 2), 384);
33925
+ return {
33926
+ client: "t2code",
33927
+ action: "written",
33928
+ path: path2,
33929
+ detail: "key saved \u2014 run `t2code` (or `npm i -g @t2000/code` first)"
33930
+ };
33931
+ }
33932
+ function connectClaudeCode(key, print2) {
33933
+ const sqlite = ccrSqlitePath();
33934
+ if (existsSync3(sqlite)) {
33935
+ return {
33936
+ client: "claude-code",
33937
+ action: "instructions",
33938
+ detail: "claude-code-router already manages config in SQLite \u2014 add the provider in its UI",
33939
+ text: [
33940
+ `claude-code-router found (SQLite config). Add the provider in the ccr UI:`,
33941
+ ` Providers \u2192 Add Provider \u2192 Other / custom API endpoint`,
33942
+ ` name: t2000`,
33943
+ ` base URL: ${API_BASE}/chat/completions`,
33944
+ ` protocol: OpenAI`,
33945
+ ` API key: ${key}`,
33946
+ ` models: ${DEFAULT_MODEL}`,
33947
+ ` Then set the default route to t2000,${DEFAULT_MODEL}.`
33948
+ ].join("\n")
33949
+ };
33950
+ }
33951
+ const path2 = ccrConfigJsonPath();
33952
+ const existing = readJson(path2);
33953
+ const already = ccrHasProvider(existing);
33954
+ if (print2) {
33955
+ return {
33956
+ client: "claude-code",
33957
+ action: "snippet",
33958
+ path: path2,
33959
+ detail: already ? "t2000 provider already present" : "would add the t2000 provider",
33960
+ text: JSON.stringify(withCcrProvider(existing, key), null, 2)
33961
+ };
33962
+ }
33963
+ writeFileEnsuringDir(path2, JSON.stringify(withCcrProvider(existing, key), null, 2) + "\n", 384);
33964
+ return {
33965
+ client: "claude-code",
33966
+ action: "written",
33967
+ path: path2,
33968
+ 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`"
33969
+ };
33970
+ }
33971
+ function connectContinue(key, print2) {
33972
+ const path2 = continueConfigPath();
33973
+ if (!existsSync3(path2) && !print2) {
33974
+ writeFileEnsuringDir(path2, continueFreshConfigYaml(key), 384);
33975
+ return { client: "continue", action: "written", path: path2, detail: "config.yaml created" };
33976
+ }
33977
+ return {
33978
+ client: "continue",
33979
+ action: "snippet",
33980
+ path: path2,
33981
+ detail: existsSync3(path2) ? "config.yaml exists \u2014 paste this model block under `models:`" : "would create config.yaml with this model block",
33982
+ text: continueModelYaml(key)
33983
+ };
33984
+ }
33985
+ function connectAider(key, print2) {
33986
+ const path2 = aiderConfPath();
33987
+ if (!existsSync3(path2) && !print2) {
33988
+ writeFileEnsuringDir(path2, aiderConfYaml(key), 384);
33989
+ return { client: "aider", action: "written", path: path2, detail: ".aider.conf.yml created" };
33990
+ }
33991
+ return {
33992
+ client: "aider",
33993
+ action: "snippet",
33994
+ path: path2,
33995
+ detail: existsSync3(path2) ? ".aider.conf.yml exists \u2014 add these lines (or use the flags below)" : "would create .aider.conf.yml",
33996
+ text: aiderConfYaml(key) + `
33997
+ # or without touching the file:
33998
+ # aider --openai-api-base ${API_BASE} --openai-api-key ${key} --model openai/${DEFAULT_MODEL}`
33999
+ };
34000
+ }
34001
+ function connectCodex(key, print2) {
34002
+ const path2 = codexConfigPath();
34003
+ const existing = existsSync3(path2) ? readFileSync3(path2, "utf-8") : "";
34004
+ if (codexHasProvider(existing)) {
34005
+ return {
34006
+ client: "codex",
34007
+ action: "exists",
34008
+ path: path2,
34009
+ detail: "t2000 provider already in config.toml \u2014 run `codex --profile t2000`"
34010
+ };
34011
+ }
34012
+ if (print2) {
34013
+ return {
34014
+ client: "codex",
34015
+ action: "snippet",
34016
+ path: path2,
34017
+ detail: "would append the t2000 provider + profile",
34018
+ text: codexTomlBlock()
34019
+ };
34020
+ }
34021
+ if (existsSync3(path2)) appendFileSync(path2, codexTomlBlock());
34022
+ else writeFileEnsuringDir(path2, codexTomlBlock().trimStart(), 384);
34023
+ return {
34024
+ client: "codex",
34025
+ action: "written",
34026
+ path: path2,
34027
+ detail: `provider + profile added \u2014 export T2000_API_KEY=${maskKey(key)} then \`codex --profile t2000\``
34028
+ };
34029
+ }
34030
+ function connectCline(key) {
34031
+ return {
34032
+ client: "cline",
34033
+ action: "instructions",
34034
+ detail: "Cline stores provider config in VS Code \u2014 set it in the extension settings",
34035
+ text: [
34036
+ `In Cline settings, choose the "OpenAI Compatible" API provider:`,
34037
+ ` Base URL: ${API_BASE}`,
34038
+ ` API key: ${key}`,
34039
+ ` Model ID: ${DEFAULT_MODEL}`
34040
+ ].join("\n")
34041
+ };
34042
+ }
34043
+ function connectCursor(key) {
34044
+ return {
34045
+ client: "cursor",
34046
+ action: "instructions",
34047
+ detail: "Cursor is configured in Settings \u2014 no file to write",
34048
+ text: [
34049
+ `Cursor \u2192 Settings \u2192 Models \u2192 API Keys:`,
34050
+ ` 1. Paste the key into "OpenAI API Key": ${maskKey(key)}`,
34051
+ ` 2. Expand "Override OpenAI Base URL" and set: ${API_BASE}`,
34052
+ ` 3. Under Models, add \`${DEFAULT_MODEL}\`, then Verify.`,
34053
+ `Note: Cursor's agent features are tuned for its own models \u2014 use this`,
34054
+ `for private chat models; delegation runs through t2 code.`
34055
+ ].join("\n")
34056
+ };
34057
+ }
34058
+ function maskKey(key) {
34059
+ return key.length > 8 ? `${key.slice(0, 5)}\u2026${key.slice(-3)}` : "sk-\u2026";
34060
+ }
34061
+ function runConnect(slug, key, print2) {
34062
+ switch (slug) {
34063
+ case "t2code":
34064
+ return connectT2code(key, print2);
34065
+ case "claude-code":
34066
+ return connectClaudeCode(key, print2);
34067
+ case "continue":
34068
+ return connectContinue(key, print2);
34069
+ case "aider":
34070
+ return connectAider(key, print2);
34071
+ case "codex":
34072
+ return connectCodex(key, print2);
34073
+ case "cline":
34074
+ return connectCline(key);
34075
+ case "cursor":
34076
+ return connectCursor(key);
34077
+ }
34078
+ }
34079
+ function registerConnect(program3) {
34080
+ 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 | 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(
34081
+ "after",
34082
+ `
34083
+ Examples:
34084
+ $ t2 connect List supported clients
34085
+ $ t2 connect t2code --key sk-... Save your key into t2 code
34086
+ $ t2 connect claude-code Add the t2000 provider to claude-code-router
34087
+ $ t2 connect aider --print Show the aider config without writing it
34088
+
34089
+ The key comes from the console: sign in at ${CONSOLE_KEYS_URL}
34090
+ (Google), create an API key, paste it once \u2014 it is saved to ~/.t2000/config.json
34091
+ and reused by later connects. All clients get model ${DEFAULT_MODEL} (the router;
34092
+ you pay the price of the model that actually served each request).`
34093
+ ).action(async (clientArg, opts) => {
34094
+ try {
34095
+ if (!clientArg) {
34096
+ const { key: key2 } = resolveKey(opts.key);
34097
+ if (isJsonMode()) {
34098
+ printJson({
34099
+ clients: CONNECT_CLIENTS.map((c) => ({ slug: c.slug, name: c.name, blurb: c.blurb })),
34100
+ keySaved: !!key2
34101
+ });
34102
+ return;
34103
+ }
34104
+ printBlank();
34105
+ printLine(" Connect a coding tool to Private Inference:");
34106
+ printBlank();
34107
+ for (const c of CONNECT_CLIENTS) {
34108
+ printKeyValue(c.slug.padEnd(12), c.blurb);
34109
+ }
34110
+ printBlank();
34111
+ printInfo(`Usage: t2 connect <client> [--key sk-...]`);
34112
+ printInfo(
34113
+ key2 ? "A key is saved \u2014 connects will reuse it." : `No key yet \u2014 create one at ${CONSOLE_KEYS_URL}`
34114
+ );
34115
+ printBlank();
34116
+ return;
34117
+ }
34118
+ const slug = resolveClientSlug(clientArg);
34119
+ if (!slug) {
34120
+ printWarning(`Unknown client '${clientArg}'.`);
34121
+ printInfo(`Supported: ${CONNECT_CLIENTS.map((c) => c.slug).join(" \xB7 ")}`);
34122
+ process.exitCode = 1;
34123
+ return;
34124
+ }
34125
+ const { key, source } = resolveKey(opts.key);
34126
+ if (!key) {
34127
+ printBlank();
34128
+ printWarning("No API key found.");
34129
+ printInfo(`1. Sign in at ${CONSOLE_KEYS_URL} (Google) and create an API key`);
34130
+ printInfo(`2. Re-run: t2 connect ${slug} --key sk-...`);
34131
+ printBlank();
34132
+ process.exitCode = 1;
34133
+ return;
34134
+ }
34135
+ const result = runConnect(slug, key, !!opts.print);
34136
+ if (!opts.print && source !== "~/.t2000/config.json") saveKey2(key);
34137
+ if (isJsonMode()) {
34138
+ printJson({ ...result, keySource: source });
34139
+ return;
34140
+ }
34141
+ printBlank();
34142
+ if (result.action === "written") {
34143
+ printSuccess(`${slug}: ${result.detail}`);
34144
+ if (result.path) printKeyValue("wrote", result.path);
34145
+ } else if (result.action === "exists") {
34146
+ printInfo(`${slug}: ${result.detail}`);
34147
+ } else {
34148
+ printInfo(`${slug}: ${result.detail}`);
34149
+ }
34150
+ if (result.text) {
34151
+ printBlank();
34152
+ for (const line of result.text.split("\n")) printLine(` ${line}`);
34153
+ }
34154
+ printBlank();
34155
+ } catch (error) {
34156
+ handleError(error);
34157
+ }
34158
+ });
33746
34159
  }
33747
34160
 
33748
34161
  // src/commands/verify.ts
@@ -34177,7 +34590,7 @@ function registerMcpStart(parent) {
34177
34590
  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) => {
34178
34591
  let mod3;
34179
34592
  try {
34180
- mod3 = await import("./dist-7ZQFQB45.js");
34593
+ mod3 = await import("./dist-RTG3A7CI.js");
34181
34594
  } catch {
34182
34595
  console.error("MCP server not installed. Run:\n npm install -g @t2000/mcp");
34183
34596
  process.exit(1);
@@ -34228,12 +34641,12 @@ function registerMcpInstall(parent) {
34228
34641
  }
34229
34642
 
34230
34643
  // src/commands/mcp/uninstall.ts
34231
- import { existsSync as existsSync3 } from "fs";
34644
+ import { existsSync as existsSync4 } from "fs";
34232
34645
  async function runUninstall() {
34233
34646
  const platforms = getPlatformConfigs();
34234
34647
  const results = [];
34235
34648
  for (const platform of platforms) {
34236
- if (!existsSync3(platform.path)) {
34649
+ if (!existsSync4(platform.path)) {
34237
34650
  results.push({ name: platform.name, slug: platform.slug, removed: false });
34238
34651
  continue;
34239
34652
  }
@@ -34289,12 +34702,12 @@ Subcommands:
34289
34702
 
34290
34703
  // src/commands/skills/check.ts
34291
34704
  import { readdir, readFile as readFile3 } from "fs/promises";
34292
- import { join as join5 } from "path";
34705
+ import { join as join7 } from "path";
34293
34706
 
34294
34707
  // src/commands/skills/lib.ts
34295
34708
  import { stat } from "fs/promises";
34296
- import { join as join4 } from "path";
34297
- import { homedir as homedir3 } from "os";
34709
+ import { join as join6 } from "path";
34710
+ import { homedir as homedir5 } from "os";
34298
34711
  var MANIFEST_URL = "https://t2000.ai/.well-known/agent-skills/index.json";
34299
34712
  var SKILL_PREFIXES = ["t2000-", "mpp-"];
34300
34713
  function isManagedSkillName(name) {
@@ -34302,21 +34715,21 @@ function isManagedSkillName(name) {
34302
34715
  }
34303
34716
  var SKILL_TARGETS = ["agents", "cursor", "claude-code"];
34304
34717
  function resolveTargetDir(target, useGlobal, cwd = process.cwd()) {
34305
- const root = useGlobal ? homedir3() : cwd;
34718
+ const root = useGlobal ? homedir5() : cwd;
34306
34719
  switch (target) {
34307
34720
  case "agents":
34308
- return join4(root, ".agents", "skills");
34721
+ return join6(root, ".agents", "skills");
34309
34722
  case "cursor":
34310
- return join4(root, ".cursor", "rules");
34723
+ return join6(root, ".cursor", "rules");
34311
34724
  case "claude-code":
34312
- return join4(root, ".claude", "skills");
34725
+ return join6(root, ".claude", "skills");
34313
34726
  }
34314
34727
  }
34315
34728
  function filenameForTarget(slug, target) {
34316
34729
  switch (target) {
34317
34730
  case "agents":
34318
34731
  case "claude-code":
34319
- return join4(slug, "SKILL.md");
34732
+ return join6(slug, "SKILL.md");
34320
34733
  case "cursor":
34321
34734
  return `${slug}.mdc`;
34322
34735
  }
@@ -34390,7 +34803,7 @@ async function checkTargetScope(manifest, servedCache, target, scope) {
34390
34803
  const slugs = await installedSlugs(dir, target);
34391
34804
  const rows = [];
34392
34805
  for (const slug of slugs) {
34393
- const path2 = join5(dir, filenameForTarget(slug, target));
34806
+ const path2 = join7(dir, filenameForTarget(slug, target));
34394
34807
  let installed;
34395
34808
  try {
34396
34809
  installed = await readFile3(path2, "utf-8");
@@ -34518,7 +34931,7 @@ function registerSkillsList(parent) {
34518
34931
 
34519
34932
  // src/commands/skills/install.ts
34520
34933
  import { writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
34521
- import { join as join6 } from "path";
34934
+ import { join as join8 } from "path";
34522
34935
  function registerSkillsInstall(parent) {
34523
34936
  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) => {
34524
34937
  try {
@@ -34539,8 +34952,8 @@ function registerSkillsInstall(parent) {
34539
34952
  const raw = await fetchSkill(s.url);
34540
34953
  const transformed = transformForTarget(raw, target, s.description);
34541
34954
  const relPath = filenameForTarget(s.name, target);
34542
- const fullPath = join6(targetDir, relPath);
34543
- await mkdir3(join6(fullPath, ".."), { recursive: true });
34955
+ const fullPath = join8(targetDir, relPath);
34956
+ await mkdir3(join8(fullPath, ".."), { recursive: true });
34544
34957
  await writeFile3(fullPath, transformed, "utf-8");
34545
34958
  installed.push({ name: s.name, path: fullPath });
34546
34959
  }
@@ -34569,7 +34982,7 @@ function registerSkillsInstall(parent) {
34569
34982
 
34570
34983
  // src/commands/skills/uninstall.ts
34571
34984
  import { readdir as readdir2, unlink, rmdir } from "fs/promises";
34572
- import { join as join7 } from "path";
34985
+ import { join as join9 } from "path";
34573
34986
  function registerSkillsUninstall(parent) {
34574
34987
  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) => {
34575
34988
  try {
@@ -34587,7 +35000,7 @@ function registerSkillsUninstall(parent) {
34587
35000
  const entries = await readdir2(targetDir);
34588
35001
  const removed = [];
34589
35002
  for (const entry of entries) {
34590
- const full = join7(targetDir, entry);
35003
+ const full = join9(targetDir, entry);
34591
35004
  if (target === "cursor") {
34592
35005
  const slug = entry.endsWith(".mdc") ? entry.slice(0, -".mdc".length) : entry;
34593
35006
  if (entry.endsWith(".mdc") && isManagedSkillName(slug)) {
@@ -34596,7 +35009,7 @@ function registerSkillsUninstall(parent) {
34596
35009
  }
34597
35010
  } else {
34598
35011
  if (isManagedSkillName(entry)) {
34599
- const skillFile = join7(full, "SKILL.md");
35012
+ const skillFile = join9(full, "SKILL.md");
34600
35013
  try {
34601
35014
  await unlink(skillFile);
34602
35015
  } catch {
@@ -35211,8 +35624,8 @@ Examples:
35211
35624
  $ t2 balance Show USDC / USDsui / SUI holdings
35212
35625
  $ t2 send 5 USDC alice.sui Send 5 USDC (gasless; asset required)
35213
35626
  $ t2 swap 100 USDC SUI Swap 100 USDC for SUI via Cetus
35214
- $ t2 chat "Summarize Sui in 3 lines" Private Inference (OpenAI-compatible; needs T2000_API_KEY)
35215
- $ t2 models List the Private Inference model catalog
35627
+ $ t2 models List the Private Inference model catalog (chat lives in \`t2 code\`)
35628
+ $ t2 connect t2code --key sk-... Point a coding tool at Private Inference
35216
35629
  $ t2 pay <url> --estimate Preview an x402 service's price + input schema (no payment)
35217
35630
  $ t2 services search "image" Discover x402 services in the gateway catalog
35218
35631
  $ t2 agents Look up the agent directory (agents.t2000.ai)
@@ -35228,7 +35641,8 @@ Examples:
35228
35641
  registerSend(program3);
35229
35642
  registerSwap(program3);
35230
35643
  registerPay(program3);
35231
- registerChat(program3);
35644
+ registerModels(program3);
35645
+ registerConnect(program3);
35232
35646
  registerVerify(program3);
35233
35647
  registerServices(program3);
35234
35648
  registerLimit(program3);