@kaitranntt/ccs 7.54.0-dev.1 → 7.54.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -4
- package/dist/ccs.js +2 -112
- package/dist/ccs.js.map +1 -1
- package/dist/commands/api-command/copy-command.d.ts +2 -0
- package/dist/commands/api-command/copy-command.d.ts.map +1 -0
- package/dist/commands/api-command/copy-command.js +41 -0
- package/dist/commands/api-command/copy-command.js.map +1 -0
- package/dist/commands/api-command/create-command.d.ts +2 -0
- package/dist/commands/api-command/create-command.d.ts.map +1 -0
- package/dist/commands/api-command/create-command.js +239 -0
- package/dist/commands/api-command/create-command.js.map +1 -0
- package/dist/commands/api-command/discover-command.d.ts +2 -0
- package/dist/commands/api-command/discover-command.d.ts.map +1 -0
- package/dist/commands/api-command/discover-command.js +69 -0
- package/dist/commands/api-command/discover-command.js.map +1 -0
- package/dist/commands/api-command/export-command.d.ts +2 -0
- package/dist/commands/api-command/export-command.d.ts.map +1 -0
- package/dist/commands/api-command/export-command.js +73 -0
- package/dist/commands/api-command/export-command.js.map +1 -0
- package/dist/commands/api-command/help.d.ts +3 -0
- package/dist/commands/api-command/help.d.ts.map +1 -0
- package/dist/commands/api-command/help.js +100 -0
- package/dist/commands/api-command/help.js.map +1 -0
- package/dist/commands/api-command/import-command.d.ts +2 -0
- package/dist/commands/api-command/import-command.d.ts.map +1 -0
- package/dist/commands/api-command/import-command.js +111 -0
- package/dist/commands/api-command/import-command.js.map +1 -0
- package/dist/commands/api-command/index.d.ts +3 -0
- package/dist/commands/api-command/index.d.ts.map +1 -0
- package/dist/commands/api-command/index.js +34 -0
- package/dist/commands/api-command/index.js.map +1 -0
- package/dist/commands/api-command/list-command.d.ts +2 -0
- package/dist/commands/api-command/list-command.d.ts.map +1 -0
- package/dist/commands/api-command/list-command.js +53 -0
- package/dist/commands/api-command/list-command.js.map +1 -0
- package/dist/commands/api-command/remove-command.d.ts +2 -0
- package/dist/commands/api-command/remove-command.d.ts.map +1 -0
- package/dist/commands/api-command/remove-command.js +63 -0
- package/dist/commands/api-command/remove-command.js.map +1 -0
- package/dist/commands/api-command/shared.d.ts +36 -0
- package/dist/commands/api-command/shared.d.ts.map +1 -0
- package/dist/commands/api-command/shared.js +164 -0
- package/dist/commands/api-command/shared.js.map +1 -0
- package/dist/commands/api-command.d.ts +1 -26
- package/dist/commands/api-command.d.ts.map +1 -1
- package/dist/commands/api-command.js +3 -807
- package/dist/commands/api-command.js.map +1 -1
- package/dist/commands/arg-extractor.d.ts +15 -0
- package/dist/commands/arg-extractor.d.ts.map +1 -1
- package/dist/commands/arg-extractor.js +48 -2
- package/dist/commands/arg-extractor.js.map +1 -1
- package/dist/commands/config-auth/index.d.ts.map +1 -1
- package/dist/commands/config-auth/index.js +35 -19
- package/dist/commands/config-auth/index.js.map +1 -1
- package/dist/commands/config-command-options.d.ts +14 -0
- package/dist/commands/config-command-options.d.ts.map +1 -0
- package/dist/commands/config-command-options.js +108 -0
- package/dist/commands/config-command-options.js.map +1 -0
- package/dist/commands/config-command.d.ts +1 -1
- package/dist/commands/config-command.d.ts.map +1 -1
- package/dist/commands/config-command.js +91 -104
- package/dist/commands/config-command.js.map +1 -1
- package/dist/commands/config-dashboard-host.d.ts +17 -0
- package/dist/commands/config-dashboard-host.d.ts.map +1 -0
- package/dist/commands/config-dashboard-host.js +99 -0
- package/dist/commands/config-dashboard-host.js.map +1 -0
- package/dist/commands/help-command.d.ts.map +1 -1
- package/dist/commands/help-command.js +1 -0
- package/dist/commands/help-command.js.map +1 -1
- package/dist/commands/named-command-router.d.ts +17 -0
- package/dist/commands/named-command-router.d.ts.map +1 -0
- package/dist/commands/named-command-router.js +39 -0
- package/dist/commands/named-command-router.js.map +1 -0
- package/dist/commands/root-command-router.d.ts +2 -0
- package/dist/commands/root-command-router.d.ts.map +1 -0
- package/dist/commands/root-command-router.js +209 -0
- package/dist/commands/root-command-router.js.map +1 -0
- package/dist/cursor/cursor-anthropic-response.d.ts +6 -0
- package/dist/cursor/cursor-anthropic-response.d.ts.map +1 -0
- package/dist/cursor/cursor-anthropic-response.js +190 -0
- package/dist/cursor/cursor-anthropic-response.js.map +1 -0
- package/dist/cursor/cursor-anthropic-translator.d.ts +11 -0
- package/dist/cursor/cursor-anthropic-translator.d.ts.map +1 -0
- package/dist/cursor/cursor-anthropic-translator.js +167 -0
- package/dist/cursor/cursor-anthropic-translator.js.map +1 -0
- package/dist/cursor/cursor-anthropic-types.d.ts +46 -0
- package/dist/cursor/cursor-anthropic-types.d.ts.map +1 -0
- package/dist/cursor/cursor-anthropic-types.js +3 -0
- package/dist/cursor/cursor-anthropic-types.js.map +1 -0
- package/dist/cursor/cursor-daemon-entry.d.ts.map +1 -1
- package/dist/cursor/cursor-daemon-entry.js +53 -24
- package/dist/cursor/cursor-daemon-entry.js.map +1 -1
- package/dist/cursor/cursor-models.d.ts.map +1 -1
- package/dist/cursor/cursor-models.js +36 -2
- package/dist/cursor/cursor-models.js.map +1 -1
- package/dist/glmt/sse-parser.d.ts +2 -0
- package/dist/glmt/sse-parser.d.ts.map +1 -1
- package/dist/glmt/sse-parser.js +4 -0
- package/dist/glmt/sse-parser.js.map +1 -1
- package/dist/management/instance-manager.d.ts.map +1 -1
- package/dist/management/instance-manager.js +1 -0
- package/dist/management/instance-manager.js.map +1 -1
- package/dist/management/shared-manager.d.ts +18 -1
- package/dist/management/shared-manager.d.ts.map +1 -1
- package/dist/management/shared-manager.js +82 -14
- package/dist/management/shared-manager.js.map +1 -1
- package/dist/shared/claude-extension-setup.d.ts.map +1 -1
- package/dist/shared/claude-extension-setup.js +3 -0
- package/dist/shared/claude-extension-setup.js.map +1 -1
- package/dist/shared/provider-preset-catalog.d.ts +1 -1
- package/dist/shared/provider-preset-catalog.d.ts.map +1 -1
- package/dist/shared/provider-preset-catalog.js +32 -15
- package/dist/shared/provider-preset-catalog.js.map +1 -1
- package/dist/ui/assets/{accounts-CZEg1_PX.js → accounts-v8ElDmpv.js} +1 -1
- package/dist/ui/assets/{alert-dialog-DhwS38kc.js → alert-dialog-L5Ct0Tm9.js} +1 -1
- package/dist/ui/assets/{api-sWNND4wP.js → api-C5CuNrT6.js} +1 -1
- package/dist/ui/assets/{auth-section-nJIpOcnm.js → auth-section-P8GsBk1u.js} +1 -1
- package/dist/ui/assets/{backups-section-D3A6hmrU.js → backups-section-gBIJ2rQw.js} +1 -1
- package/dist/ui/assets/checkbox-DQ1oAx_4.js +1 -0
- package/dist/ui/assets/{claude-extension-BjInaILv.js → claude-extension-CjEyjaGL.js} +1 -1
- package/dist/ui/assets/cliproxy-C0dWlSJs.js +3 -0
- package/dist/ui/assets/{cliproxy-control-panel-CKO2Sn9B.js → cliproxy-control-panel-CdCrzgLe.js} +1 -1
- package/dist/ui/assets/{confirm-dialog-DTKxwrat.js → confirm-dialog-DaydoeD7.js} +1 -1
- package/dist/ui/assets/copilot-SA3U22Y9.js +3 -0
- package/dist/ui/assets/cursor-BfkF3VwC.js +1 -0
- package/dist/ui/assets/{droid-Cl8QsJJL.js → droid-BfSJyZXD.js} +2 -2
- package/dist/ui/assets/{globalenv-section-C3dxxoD9.js → globalenv-section-rg8Ctc2R.js} +1 -1
- package/dist/ui/assets/{health-BUifaDU7.js → health-Cii2iTlp.js} +1 -1
- package/dist/ui/assets/icons-DtwH984l.js +1 -0
- package/dist/ui/assets/{index-CPdceT1C.js → index-B4Qc134R.js} +1 -1
- package/dist/ui/assets/{index-CYo-E5rU.js → index-CBleAyoZ.js} +1 -1
- package/dist/ui/assets/index-ClEn7Y7g.css +1 -0
- package/dist/ui/assets/{index-BOsbrhaa.js → index-D1CmdSLO.js} +1 -1
- package/dist/ui/assets/{index-xayyyR26.js → index-Gpb2Emvl.js} +1 -1
- package/dist/ui/assets/index-og5NMtJP.js +47 -0
- package/dist/ui/assets/providers/llama-cpp.svg +5 -0
- package/dist/ui/assets/{proxy-status-widget-D94htBPb.js → proxy-status-widget-CZnGc4zY.js} +1 -1
- package/dist/ui/assets/{radix-ui-BR1vy4kf.js → radix-ui-Dt3edmE5.js} +8 -8
- package/dist/ui/assets/searchable-select-BHhY-dTx.js +1 -0
- package/dist/ui/assets/{separator-3fBbTn-V.js → separator-7ggevEK6.js} +1 -1
- package/dist/ui/assets/{shared-q_FNNbjD.js → shared-CoiUG_Qa.js} +1 -1
- package/dist/ui/assets/{switch-5N8qBdBr.js → switch-3-7lTxFj.js} +1 -1
- package/dist/ui/assets/{tanstack-e99Cjjy2.js → tanstack-B8i0evp-.js} +1 -1
- package/dist/ui/assets/{updates-CubQ54J0.js → updates-rQ3GVJIq.js} +1 -1
- package/dist/ui/icons/novita.svg +9 -0
- package/dist/ui/index.html +5 -5
- package/dist/utils/fetch-proxy-setup.d.ts.map +1 -1
- package/dist/utils/fetch-proxy-setup.js.map +1 -1
- package/dist/utils/shell-executor.d.ts.map +1 -1
- package/dist/utils/shell-executor.js +12 -0
- package/dist/utils/shell-executor.js.map +1 -1
- package/dist/web-server/index.d.ts +1 -0
- package/dist/web-server/index.d.ts.map +1 -1
- package/dist/web-server/index.js +39 -3
- package/dist/web-server/index.js.map +1 -1
- package/dist/web-server/routes/profile-routes.d.ts +1 -0
- package/dist/web-server/routes/profile-routes.d.ts.map +1 -1
- package/dist/web-server/routes/profile-routes.js +3 -0
- package/dist/web-server/routes/profile-routes.js.map +1 -1
- package/dist/web-server/routes/variant-routes.d.ts +1 -0
- package/dist/web-server/routes/variant-routes.d.ts.map +1 -1
- package/dist/web-server/routes/variant-routes.js +3 -0
- package/dist/web-server/routes/variant-routes.js.map +1 -1
- package/package.json +2 -1
- package/dist/ui/assets/checkbox-CZrxD1iS.js +0 -1
- package/dist/ui/assets/cliproxy-BGiSCGkl.js +0 -3
- package/dist/ui/assets/copilot-CuRngdBg.js +0 -3
- package/dist/ui/assets/cursor-Dxo0uIiU.js +0 -1
- package/dist/ui/assets/icons-DrEfTmfX.js +0 -1
- package/dist/ui/assets/index-Btf_ow2V.css +0 -1
- package/dist/ui/assets/index-Cw9Urr0S.js +0 -47
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* API Command Handler
|
|
4
|
-
*
|
|
5
|
-
* Manages CCS API profiles for custom API providers.
|
|
6
|
-
* Commands: create, list, remove
|
|
7
|
-
*
|
|
8
|
-
* CLI parsing and output formatting only.
|
|
9
|
-
* Business logic delegated to src/api/services/.
|
|
10
|
-
*/
|
|
11
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
3
|
if (k2 === undefined) k2 = k;
|
|
13
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -19,804 +10,9 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
19
10
|
if (k2 === undefined) k2 = k;
|
|
20
11
|
o[k2] = m[k];
|
|
21
12
|
}));
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
}) : function(o, v) {
|
|
25
|
-
o["default"] = v;
|
|
26
|
-
});
|
|
27
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
33
15
|
};
|
|
34
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
|
|
36
|
-
const fs = __importStar(require("fs"));
|
|
37
|
-
const path = __importStar(require("path"));
|
|
38
|
-
const ui_1 = require("../utils/ui");
|
|
39
|
-
const prompt_1 = require("../utils/prompt");
|
|
40
|
-
const services_1 = require("../api/services");
|
|
41
|
-
const local_config_sync_1 = require("../cliproxy/sync/local-config-sync");
|
|
42
|
-
const arg_extractor_1 = require("./arg-extractor");
|
|
43
|
-
const API_BOOLEAN_FLAGS = ['--force', '--yes', '-y'];
|
|
44
|
-
const API_VALUE_FLAGS = ['--base-url', '--api-key', '--model', '--preset', '--target'];
|
|
45
|
-
const API_KNOWN_FLAGS = [...API_BOOLEAN_FLAGS, ...API_VALUE_FLAGS];
|
|
46
|
-
const API_VALUE_FLAG_SET = new Set(API_VALUE_FLAGS);
|
|
47
|
-
function sanitizeHelpText(value) {
|
|
48
|
-
return value
|
|
49
|
-
.replace(/[\r\n\t]+/g, ' ')
|
|
50
|
-
.replace(/[\x00-\x1f\x7f]/g, ' ')
|
|
51
|
-
.replace(/\s+/g, ' ')
|
|
52
|
-
.trim();
|
|
53
|
-
}
|
|
54
|
-
function renderPresetHelpLine(preset, idWidth) {
|
|
55
|
-
const presetId = sanitizeHelpText(preset.id) || 'unknown';
|
|
56
|
-
const paddedId = presetId.padEnd(idWidth);
|
|
57
|
-
const presetName = sanitizeHelpText(preset.name) || 'Unknown preset';
|
|
58
|
-
const presetDescription = sanitizeHelpText(preset.description) || 'No description';
|
|
59
|
-
return ` ${(0, ui_1.color)(paddedId, 'command')} ${presetName} - ${presetDescription}`;
|
|
60
|
-
}
|
|
61
|
-
function applyRepeatedOption(args, flags, onValue, onMissing) {
|
|
62
|
-
let remaining = [...args];
|
|
63
|
-
while (true) {
|
|
64
|
-
const extracted = (0, arg_extractor_1.extractOption)(remaining, flags, {
|
|
65
|
-
allowDashValue: true,
|
|
66
|
-
knownFlags: API_KNOWN_FLAGS,
|
|
67
|
-
});
|
|
68
|
-
if (!extracted.found) {
|
|
69
|
-
return remaining;
|
|
70
|
-
}
|
|
71
|
-
if (extracted.missingValue || !extracted.value) {
|
|
72
|
-
onMissing();
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
onValue(extracted.value);
|
|
76
|
-
}
|
|
77
|
-
remaining = extracted.remainingArgs;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function extractPositionalArgs(args) {
|
|
81
|
-
const positionals = [];
|
|
82
|
-
for (let i = 0; i < args.length; i++) {
|
|
83
|
-
const token = args[i];
|
|
84
|
-
if (token === '--') {
|
|
85
|
-
positionals.push(...args.slice(i + 1));
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
if (token.startsWith('-')) {
|
|
89
|
-
if (!token.includes('=') && API_VALUE_FLAG_SET.has(token)) {
|
|
90
|
-
const next = args[i + 1];
|
|
91
|
-
if (next && !next.startsWith('-')) {
|
|
92
|
-
i++;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
positionals.push(token);
|
|
98
|
-
}
|
|
99
|
-
return positionals;
|
|
100
|
-
}
|
|
101
|
-
function parseTargetValue(value) {
|
|
102
|
-
const normalized = value.trim().toLowerCase();
|
|
103
|
-
if (normalized === 'claude' || normalized === 'droid') {
|
|
104
|
-
return normalized;
|
|
105
|
-
}
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
function parseOptionalTargetFlag(args, knownFlags) {
|
|
109
|
-
const extracted = (0, arg_extractor_1.extractOption)(args, ['--target'], {
|
|
110
|
-
allowDashValue: true,
|
|
111
|
-
knownFlags,
|
|
112
|
-
});
|
|
113
|
-
if (!extracted.found) {
|
|
114
|
-
return { remainingArgs: args, errors: [] };
|
|
115
|
-
}
|
|
116
|
-
if (extracted.missingValue || !extracted.value) {
|
|
117
|
-
return { remainingArgs: extracted.remainingArgs, errors: ['Missing value for --target'] };
|
|
118
|
-
}
|
|
119
|
-
const target = parseTargetValue(extracted.value);
|
|
120
|
-
if (!target) {
|
|
121
|
-
return {
|
|
122
|
-
remainingArgs: extracted.remainingArgs,
|
|
123
|
-
errors: [`Invalid --target value "${extracted.value}". Use: claude or droid`],
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
return { target, remainingArgs: extracted.remainingArgs, errors: [] };
|
|
127
|
-
}
|
|
128
|
-
/** Parse command line arguments for api commands */
|
|
129
|
-
function parseApiCommandArgs(args) {
|
|
130
|
-
const result = {
|
|
131
|
-
force: (0, arg_extractor_1.hasAnyFlag)(args, ['--force']),
|
|
132
|
-
yes: (0, arg_extractor_1.hasAnyFlag)(args, ['--yes', '-y']),
|
|
133
|
-
errors: [],
|
|
134
|
-
};
|
|
135
|
-
let remaining = [...args];
|
|
136
|
-
remaining = applyRepeatedOption(remaining, ['--base-url'], (value) => {
|
|
137
|
-
result.baseUrl = value;
|
|
138
|
-
}, () => {
|
|
139
|
-
result.errors.push('Missing value for --base-url');
|
|
140
|
-
});
|
|
141
|
-
remaining = applyRepeatedOption(remaining, ['--api-key'], (value) => {
|
|
142
|
-
result.apiKey = value;
|
|
143
|
-
}, () => {
|
|
144
|
-
result.errors.push('Missing value for --api-key');
|
|
145
|
-
});
|
|
146
|
-
remaining = applyRepeatedOption(remaining, ['--model'], (value) => {
|
|
147
|
-
result.model = value;
|
|
148
|
-
}, () => {
|
|
149
|
-
result.errors.push('Missing value for --model');
|
|
150
|
-
});
|
|
151
|
-
remaining = applyRepeatedOption(remaining, ['--preset'], (value) => {
|
|
152
|
-
result.preset = value;
|
|
153
|
-
}, () => {
|
|
154
|
-
result.errors.push('Missing value for --preset');
|
|
155
|
-
});
|
|
156
|
-
remaining = applyRepeatedOption(remaining, ['--target'], (value) => {
|
|
157
|
-
const target = parseTargetValue(value);
|
|
158
|
-
if (!target) {
|
|
159
|
-
result.errors.push(`Invalid --target value "${value}". Use: claude or droid`);
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
result.target = target;
|
|
163
|
-
}, () => {
|
|
164
|
-
result.errors.push('Missing value for --target');
|
|
165
|
-
});
|
|
166
|
-
const positionalArgs = extractPositionalArgs(remaining);
|
|
167
|
-
result.name = positionalArgs[0];
|
|
168
|
-
return result;
|
|
169
|
-
}
|
|
170
|
-
exports.parseApiCommandArgs = parseApiCommandArgs;
|
|
171
|
-
/** Handle 'ccs api create' command */
|
|
172
|
-
async function handleCreate(args) {
|
|
173
|
-
await (0, ui_1.initUI)();
|
|
174
|
-
const parsedArgs = parseApiCommandArgs(args);
|
|
175
|
-
if (parsedArgs.errors.length > 0) {
|
|
176
|
-
parsedArgs.errors.forEach((errorMessage) => {
|
|
177
|
-
console.log((0, ui_1.fail)(errorMessage));
|
|
178
|
-
});
|
|
179
|
-
process.exit(1);
|
|
180
|
-
}
|
|
181
|
-
console.log((0, ui_1.header)('Create API Profile'));
|
|
182
|
-
console.log('');
|
|
183
|
-
// Handle --preset option for quick provider setup
|
|
184
|
-
const preset = parsedArgs.preset ? (0, services_1.getPresetById)(parsedArgs.preset) : null;
|
|
185
|
-
if (parsedArgs.preset && !preset) {
|
|
186
|
-
console.log((0, ui_1.fail)(`Unknown preset: ${parsedArgs.preset}`));
|
|
187
|
-
console.log('');
|
|
188
|
-
console.log('Available presets:');
|
|
189
|
-
(0, services_1.getPresetIds)().forEach((id) => console.log(` - ${sanitizeHelpText(id)}`));
|
|
190
|
-
process.exit(1);
|
|
191
|
-
}
|
|
192
|
-
// Step 1: API name (use preset default if --preset provided)
|
|
193
|
-
let name = parsedArgs.name || preset?.defaultProfileName;
|
|
194
|
-
if (!name) {
|
|
195
|
-
name = await prompt_1.InteractivePrompt.input('API name', {
|
|
196
|
-
validate: services_1.validateApiName,
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
const error = (0, services_1.validateApiName)(name);
|
|
201
|
-
if (error) {
|
|
202
|
-
console.log((0, ui_1.fail)(error));
|
|
203
|
-
process.exit(1);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
// Check if exists
|
|
207
|
-
if ((0, services_1.apiProfileExists)(name) && !parsedArgs.force) {
|
|
208
|
-
console.log((0, ui_1.fail)(`API '${name}' already exists`));
|
|
209
|
-
console.log(` Use ${(0, ui_1.color)('--force', 'command')} to overwrite`);
|
|
210
|
-
process.exit(1);
|
|
211
|
-
}
|
|
212
|
-
// Step 2: Base URL (use preset if provided; skip prompt for presets with empty baseUrl like anthropic)
|
|
213
|
-
let baseUrl = parsedArgs.baseUrl ?? preset?.baseUrl ?? '';
|
|
214
|
-
if (!baseUrl && !preset) {
|
|
215
|
-
baseUrl = await prompt_1.InteractivePrompt.input('API Base URL (e.g., https://api.example.com/v1 - without /chat/completions)', { validate: services_1.validateUrl });
|
|
216
|
-
}
|
|
217
|
-
else if (!preset) {
|
|
218
|
-
// Only validate custom URLs, not preset URLs
|
|
219
|
-
const error = (0, services_1.validateUrl)(baseUrl);
|
|
220
|
-
if (error) {
|
|
221
|
-
console.log((0, ui_1.fail)(error));
|
|
222
|
-
process.exit(1);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
// Check for common URL mistakes and warn (skip for presets)
|
|
226
|
-
if (!preset) {
|
|
227
|
-
const urlWarning = (0, services_1.getUrlWarning)(baseUrl);
|
|
228
|
-
if (urlWarning) {
|
|
229
|
-
console.log('');
|
|
230
|
-
console.log((0, ui_1.warn)(urlWarning));
|
|
231
|
-
const continueAnyway = await prompt_1.InteractivePrompt.confirm('Continue with this URL anyway?', {
|
|
232
|
-
default: false,
|
|
233
|
-
});
|
|
234
|
-
if (!continueAnyway) {
|
|
235
|
-
baseUrl = await prompt_1.InteractivePrompt.input('API Base URL', {
|
|
236
|
-
validate: services_1.validateUrl,
|
|
237
|
-
default: (0, services_1.sanitizeBaseUrl)(baseUrl),
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
// Show preset info
|
|
244
|
-
console.log((0, ui_1.info)(`Using preset: ${preset.name}`));
|
|
245
|
-
console.log((0, ui_1.dim)(` ${preset.description}`));
|
|
246
|
-
if (preset.baseUrl) {
|
|
247
|
-
console.log((0, ui_1.dim)(` Base URL: ${preset.baseUrl}`));
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
console.log((0, ui_1.dim)(` Auth: Native Anthropic API (x-api-key header)`));
|
|
251
|
-
}
|
|
252
|
-
console.log('');
|
|
253
|
-
}
|
|
254
|
-
// Auto-detect Anthropic direct API when user enters api.anthropic.com URL without preset
|
|
255
|
-
if (baseUrl && baseUrl.includes('api.anthropic.com') && !preset) {
|
|
256
|
-
console.log('');
|
|
257
|
-
console.log((0, ui_1.info)('Anthropic Direct API detected. Base URL will be omitted for native auth.'));
|
|
258
|
-
baseUrl = '';
|
|
259
|
-
}
|
|
260
|
-
// OpenRouter detection: offer interactive model picker
|
|
261
|
-
let openRouterModel;
|
|
262
|
-
let openRouterTierMapping;
|
|
263
|
-
if ((0, services_1.isOpenRouterUrl)(baseUrl) && !parsedArgs.model) {
|
|
264
|
-
console.log('');
|
|
265
|
-
console.log((0, ui_1.info)('OpenRouter detected!'));
|
|
266
|
-
const useInteractive = await prompt_1.InteractivePrompt.confirm('Browse models interactively?', {
|
|
267
|
-
default: true,
|
|
268
|
-
});
|
|
269
|
-
if (useInteractive) {
|
|
270
|
-
const selection = await (0, services_1.pickOpenRouterModel)();
|
|
271
|
-
if (selection) {
|
|
272
|
-
openRouterModel = selection.model;
|
|
273
|
-
openRouterTierMapping = selection.tierMapping;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
console.log('');
|
|
277
|
-
console.log((0, ui_1.dim)('Note: For OpenRouter, ANTHROPIC_API_KEY should be empty.'));
|
|
278
|
-
}
|
|
279
|
-
// Step 3: API Key (skip if preset has requiresApiKey: false)
|
|
280
|
-
let apiKey = parsedArgs.apiKey;
|
|
281
|
-
if (preset?.requiresApiKey === false) {
|
|
282
|
-
const presetLabel = preset.name;
|
|
283
|
-
const optionalApiKey = preset.apiKeyPlaceholder || preset.id;
|
|
284
|
-
if (parsedArgs.apiKey) {
|
|
285
|
-
console.log((0, ui_1.dim)(`Note: Using provided API key for ${presetLabel} (optional)`));
|
|
286
|
-
apiKey = parsedArgs.apiKey;
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
console.log((0, ui_1.info)(`No API key required for ${presetLabel}`));
|
|
290
|
-
// Local providers still need a truthy auth token persisted in settings.json.
|
|
291
|
-
apiKey = optionalApiKey;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
else if (!apiKey) {
|
|
295
|
-
const keyPrompt = preset?.apiKeyHint ? `API Key (${preset.apiKeyHint})` : 'API Key';
|
|
296
|
-
apiKey = await prompt_1.InteractivePrompt.password(keyPrompt);
|
|
297
|
-
if (!apiKey) {
|
|
298
|
-
console.log((0, ui_1.fail)('API key is required'));
|
|
299
|
-
process.exit(1);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
// Step 4: Model configuration (use preset default if available)
|
|
303
|
-
const defaultModel = preset?.defaultModel || 'claude-sonnet-4-6';
|
|
304
|
-
let model = parsedArgs.model || openRouterModel || preset?.defaultModel;
|
|
305
|
-
if (!model && !parsedArgs.yes && !preset) {
|
|
306
|
-
model = await prompt_1.InteractivePrompt.input('Default model (ANTHROPIC_MODEL)', {
|
|
307
|
-
default: defaultModel,
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
model = model || defaultModel;
|
|
311
|
-
// Step 5: Model mapping for Opus/Sonnet/Haiku (skip prompt for presets with --yes)
|
|
312
|
-
let opusModel = openRouterTierMapping?.opus || model;
|
|
313
|
-
let sonnetModel = openRouterTierMapping?.sonnet || model;
|
|
314
|
-
let haikuModel = openRouterTierMapping?.haiku || model;
|
|
315
|
-
const isCustomModel = model !== defaultModel;
|
|
316
|
-
const hasOpenRouterTierMapping = openRouterTierMapping !== undefined;
|
|
317
|
-
const hasPreset = preset !== null;
|
|
318
|
-
if (!parsedArgs.yes && !hasOpenRouterTierMapping && !hasPreset) {
|
|
319
|
-
let wantCustomMapping = isCustomModel;
|
|
320
|
-
if (!isCustomModel) {
|
|
321
|
-
console.log('');
|
|
322
|
-
console.log((0, ui_1.dim)('Some API proxies route different model types to different backends.'));
|
|
323
|
-
wantCustomMapping = await prompt_1.InteractivePrompt.confirm('Configure different models for Opus/Sonnet/Haiku?', { default: false });
|
|
324
|
-
}
|
|
325
|
-
if (wantCustomMapping) {
|
|
326
|
-
console.log('');
|
|
327
|
-
console.log((0, ui_1.dim)(isCustomModel
|
|
328
|
-
? 'Configure model IDs for each tier (defaults to your model):'
|
|
329
|
-
: 'Leave blank to use the default model for each.'));
|
|
330
|
-
opusModel =
|
|
331
|
-
(await prompt_1.InteractivePrompt.input('Opus model (ANTHROPIC_DEFAULT_OPUS_MODEL)', {
|
|
332
|
-
default: model,
|
|
333
|
-
})) || model;
|
|
334
|
-
sonnetModel =
|
|
335
|
-
(await prompt_1.InteractivePrompt.input('Sonnet model (ANTHROPIC_DEFAULT_SONNET_MODEL)', {
|
|
336
|
-
default: model,
|
|
337
|
-
})) || model;
|
|
338
|
-
haikuModel =
|
|
339
|
-
(await prompt_1.InteractivePrompt.input('Haiku model (ANTHROPIC_DEFAULT_HAIKU_MODEL)', {
|
|
340
|
-
default: model,
|
|
341
|
-
})) || model;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
const models = {
|
|
345
|
-
default: model,
|
|
346
|
-
opus: opusModel,
|
|
347
|
-
sonnet: sonnetModel,
|
|
348
|
-
haiku: haikuModel,
|
|
349
|
-
};
|
|
350
|
-
let resolvedTarget = parsedArgs.target || 'claude';
|
|
351
|
-
if (!parsedArgs.target && !parsedArgs.yes) {
|
|
352
|
-
const useDroidByDefault = await prompt_1.InteractivePrompt.confirm('Set default target to Factory Droid for this profile?', { default: false });
|
|
353
|
-
if (useDroidByDefault) {
|
|
354
|
-
resolvedTarget = 'droid';
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
// Create profile
|
|
358
|
-
console.log('');
|
|
359
|
-
console.log((0, ui_1.info)('Creating API profile...'));
|
|
360
|
-
const result = (0, services_1.createApiProfile)(name, baseUrl || '', apiKey, models, resolvedTarget);
|
|
361
|
-
if (!result.success) {
|
|
362
|
-
console.log((0, ui_1.fail)(`Failed to create API profile: ${result.error}`));
|
|
363
|
-
process.exit(1);
|
|
364
|
-
}
|
|
365
|
-
// Trigger sync to local CLIProxy config (best-effort)
|
|
366
|
-
try {
|
|
367
|
-
(0, local_config_sync_1.syncToLocalConfig)();
|
|
368
|
-
}
|
|
369
|
-
catch (err) {
|
|
370
|
-
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
371
|
-
console.log(`[i] Auto-sync to CLIProxy config skipped: ${message}`);
|
|
372
|
-
}
|
|
373
|
-
// Display success
|
|
374
|
-
console.log('');
|
|
375
|
-
const hasCustomMapping = opusModel !== model || sonnetModel !== model || haikuModel !== model;
|
|
376
|
-
let infoMsg = `API: ${name}\n` +
|
|
377
|
-
`Config: ${(0, services_1.isUsingUnifiedConfig)() ? '~/.ccs/config.yaml' : '~/.ccs/config.json'}\n` +
|
|
378
|
-
`Settings: ${result.settingsFile}\n` +
|
|
379
|
-
`Base URL: ${baseUrl}\n` +
|
|
380
|
-
`Model: ${model}\n` +
|
|
381
|
-
`Target: ${resolvedTarget}`;
|
|
382
|
-
if (hasCustomMapping) {
|
|
383
|
-
infoMsg +=
|
|
384
|
-
`\n\nModel Mapping:\n` +
|
|
385
|
-
` Opus: ${opusModel}\n` +
|
|
386
|
-
` Sonnet: ${sonnetModel}\n` +
|
|
387
|
-
` Haiku: ${haikuModel}`;
|
|
388
|
-
}
|
|
389
|
-
console.log((0, ui_1.infoBox)(infoMsg, 'API Profile Created'));
|
|
390
|
-
console.log('');
|
|
391
|
-
console.log((0, ui_1.header)('Usage'));
|
|
392
|
-
if (resolvedTarget === 'droid') {
|
|
393
|
-
console.log(` ${(0, ui_1.color)(`ccs ${name} "your prompt"`, 'command')} ${(0, ui_1.dim)('# uses droid by default')}`);
|
|
394
|
-
console.log(` ${(0, ui_1.color)(`ccsd ${name} "your prompt"`, 'command')} ${(0, ui_1.dim)('# explicit droid alias')}`);
|
|
395
|
-
console.log(` ${(0, ui_1.color)(`ccs ${name} --target claude "your prompt"`, 'command')} ${(0, ui_1.dim)('# override to Claude')}`);
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
console.log(` ${(0, ui_1.color)(`ccs ${name} "your prompt"`, 'command')} ${(0, ui_1.dim)('# uses claude by default')}`);
|
|
399
|
-
console.log(` ${(0, ui_1.color)(`ccs ${name} --target droid "your prompt"`, 'command')} ${(0, ui_1.dim)('# run on droid for this call')}`);
|
|
400
|
-
}
|
|
401
|
-
console.log('');
|
|
402
|
-
console.log((0, ui_1.header)('Edit Settings'));
|
|
403
|
-
console.log(` ${(0, ui_1.dim)('To modify env vars later:')}`);
|
|
404
|
-
console.log(` ${(0, ui_1.color)(`nano ${result.settingsFile.replace('~', '$HOME')}`, 'command')}`);
|
|
405
|
-
console.log('');
|
|
406
|
-
}
|
|
407
|
-
/** Handle 'ccs api list' command */
|
|
408
|
-
async function handleList() {
|
|
409
|
-
await (0, ui_1.initUI)();
|
|
410
|
-
console.log((0, ui_1.header)('CCS API Profiles'));
|
|
411
|
-
console.log('');
|
|
412
|
-
const { profiles, variants } = (0, services_1.listApiProfiles)();
|
|
413
|
-
if (profiles.length === 0) {
|
|
414
|
-
console.log((0, ui_1.warn)('No API profiles configured'));
|
|
415
|
-
console.log('');
|
|
416
|
-
console.log('To create an API profile:');
|
|
417
|
-
console.log(` ${(0, ui_1.color)('ccs api create', 'command')}`);
|
|
418
|
-
console.log('');
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
// Build table data
|
|
422
|
-
const rows = profiles.map((p) => {
|
|
423
|
-
const status = p.isConfigured ? (0, ui_1.color)('[OK]', 'success') : (0, ui_1.color)('[!]', 'warning');
|
|
424
|
-
return [p.name, p.target, p.settingsPath, status];
|
|
425
|
-
});
|
|
426
|
-
const colWidths = (0, services_1.isUsingUnifiedConfig)() ? [15, 10, 20, 10] : [15, 10, 35, 10];
|
|
427
|
-
console.log((0, ui_1.table)(rows, {
|
|
428
|
-
head: ['API', 'Target', (0, services_1.isUsingUnifiedConfig)() ? 'Config' : 'Settings File', 'Status'],
|
|
429
|
-
colWidths,
|
|
430
|
-
}));
|
|
431
|
-
console.log('');
|
|
432
|
-
// Show CLIProxy variants if any
|
|
433
|
-
if (variants.length > 0) {
|
|
434
|
-
console.log((0, ui_1.subheader)('CLIProxy Variants'));
|
|
435
|
-
const cliproxyRows = variants.map((v) => [v.name, v.provider, v.target, v.settings]);
|
|
436
|
-
console.log((0, ui_1.table)(cliproxyRows, {
|
|
437
|
-
head: ['Variant', 'Provider', 'Target', 'Settings'],
|
|
438
|
-
colWidths: [15, 12, 10, 28],
|
|
439
|
-
}));
|
|
440
|
-
console.log('');
|
|
441
|
-
}
|
|
442
|
-
console.log((0, ui_1.dim)(`Total: ${profiles.length} API profile(s)`));
|
|
443
|
-
console.log('');
|
|
444
|
-
}
|
|
445
|
-
/** Handle 'ccs api remove' command */
|
|
446
|
-
async function handleRemove(args) {
|
|
447
|
-
await (0, ui_1.initUI)();
|
|
448
|
-
const parsedArgs = parseApiCommandArgs(args);
|
|
449
|
-
if (parsedArgs.errors.length > 0) {
|
|
450
|
-
parsedArgs.errors.forEach((errorMessage) => {
|
|
451
|
-
console.log((0, ui_1.fail)(errorMessage));
|
|
452
|
-
});
|
|
453
|
-
process.exit(1);
|
|
454
|
-
}
|
|
455
|
-
const apis = (0, services_1.getApiProfileNames)();
|
|
456
|
-
if (apis.length === 0) {
|
|
457
|
-
console.log((0, ui_1.warn)('No API profiles to remove'));
|
|
458
|
-
process.exit(0);
|
|
459
|
-
}
|
|
460
|
-
// Interactive API selection if not provided
|
|
461
|
-
let name = parsedArgs.name;
|
|
462
|
-
if (!name) {
|
|
463
|
-
console.log((0, ui_1.header)('Remove API Profile'));
|
|
464
|
-
console.log('');
|
|
465
|
-
console.log('Available APIs:');
|
|
466
|
-
apis.forEach((p, i) => console.log(` ${i + 1}. ${p}`));
|
|
467
|
-
console.log('');
|
|
468
|
-
name = await prompt_1.InteractivePrompt.input('API name to remove', {
|
|
469
|
-
validate: (val) => {
|
|
470
|
-
if (!val)
|
|
471
|
-
return 'API name is required';
|
|
472
|
-
if (!apis.includes(val))
|
|
473
|
-
return `API '${val}' not found`;
|
|
474
|
-
return null;
|
|
475
|
-
},
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
if (!apis.includes(name)) {
|
|
479
|
-
console.log((0, ui_1.fail)(`API '${name}' not found`));
|
|
480
|
-
console.log('');
|
|
481
|
-
console.log('Available APIs:');
|
|
482
|
-
apis.forEach((p) => console.log(` - ${p}`));
|
|
483
|
-
process.exit(1);
|
|
484
|
-
}
|
|
485
|
-
// Confirm deletion
|
|
486
|
-
console.log('');
|
|
487
|
-
console.log(`API '${(0, ui_1.color)(name, 'command')}' will be removed.`);
|
|
488
|
-
console.log(` Settings: ~/.ccs/${name}.settings.json`);
|
|
489
|
-
if ((0, services_1.isUsingUnifiedConfig)()) {
|
|
490
|
-
console.log(' Config: ~/.ccs/config.yaml');
|
|
491
|
-
}
|
|
492
|
-
console.log('');
|
|
493
|
-
const confirmed = parsedArgs.yes ||
|
|
494
|
-
(await prompt_1.InteractivePrompt.confirm('Delete this API profile?', { default: false }));
|
|
495
|
-
if (!confirmed) {
|
|
496
|
-
console.log((0, ui_1.info)('Cancelled'));
|
|
497
|
-
process.exit(0);
|
|
498
|
-
}
|
|
499
|
-
const result = (0, services_1.removeApiProfile)(name);
|
|
500
|
-
if (!result.success) {
|
|
501
|
-
console.log((0, ui_1.fail)(`Failed to remove API profile: ${result.error}`));
|
|
502
|
-
process.exit(1);
|
|
503
|
-
}
|
|
504
|
-
console.log((0, ui_1.ok)(`API profile removed: ${name}`));
|
|
505
|
-
console.log('');
|
|
506
|
-
}
|
|
507
|
-
/** Handle 'ccs api discover' command */
|
|
508
|
-
async function handleDiscover(args) {
|
|
509
|
-
await (0, ui_1.initUI)();
|
|
510
|
-
const register = (0, arg_extractor_1.hasAnyFlag)(args, ['--register']);
|
|
511
|
-
const jsonOutput = (0, arg_extractor_1.hasAnyFlag)(args, ['--json']);
|
|
512
|
-
const force = (0, arg_extractor_1.hasAnyFlag)(args, ['--force']);
|
|
513
|
-
const targetParsed = parseOptionalTargetFlag(args, [...API_KNOWN_FLAGS, '--register', '--json']);
|
|
514
|
-
if (targetParsed.errors.length > 0) {
|
|
515
|
-
targetParsed.errors.forEach((errorMessage) => console.log((0, ui_1.fail)(errorMessage)));
|
|
516
|
-
process.exit(1);
|
|
517
|
-
}
|
|
518
|
-
const result = (0, services_1.discoverApiProfileOrphans)();
|
|
519
|
-
if (jsonOutput) {
|
|
520
|
-
console.log(JSON.stringify(result, null, 2));
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
console.log((0, ui_1.header)('Discover Orphan API Profiles'));
|
|
524
|
-
console.log('');
|
|
525
|
-
if (result.orphans.length === 0) {
|
|
526
|
-
console.log((0, ui_1.ok)('No orphan settings files found.'));
|
|
527
|
-
console.log('');
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
const rows = result.orphans.map((orphan) => {
|
|
531
|
-
const status = orphan.validation.valid ? (0, ui_1.color)('[OK]', 'success') : (0, ui_1.color)('[X]', 'error');
|
|
532
|
-
const issueSummary = orphan.validation.issues.length > 0
|
|
533
|
-
? orphan.validation.issues[0].message
|
|
534
|
-
: 'Ready to register';
|
|
535
|
-
return [orphan.name, status, issueSummary];
|
|
536
|
-
});
|
|
537
|
-
console.log((0, ui_1.table)(rows, {
|
|
538
|
-
head: ['Profile', 'Status', 'Validation'],
|
|
539
|
-
colWidths: [20, 10, 64],
|
|
540
|
-
}));
|
|
541
|
-
console.log('');
|
|
542
|
-
if (!register) {
|
|
543
|
-
console.log((0, ui_1.info)('To register discovered profiles:'));
|
|
544
|
-
console.log(` ${(0, ui_1.color)('ccs api discover --register', 'command')}`);
|
|
545
|
-
console.log('');
|
|
546
|
-
return;
|
|
547
|
-
}
|
|
548
|
-
const registration = (0, services_1.registerApiProfileOrphans)({
|
|
549
|
-
target: targetParsed.target || 'claude',
|
|
550
|
-
force,
|
|
551
|
-
});
|
|
552
|
-
console.log((0, ui_1.ok)(`Registered: ${registration.registered.length}`));
|
|
553
|
-
if (registration.skipped.length > 0) {
|
|
554
|
-
console.log((0, ui_1.warn)(`Skipped: ${registration.skipped.length}`));
|
|
555
|
-
registration.skipped.forEach((item) => {
|
|
556
|
-
console.log(` - ${item.name}: ${item.reason}`);
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
console.log('');
|
|
560
|
-
}
|
|
561
|
-
/** Handle 'ccs api copy' command */
|
|
562
|
-
async function handleCopy(args) {
|
|
563
|
-
await (0, ui_1.initUI)();
|
|
564
|
-
const parsedArgs = parseApiCommandArgs(args);
|
|
565
|
-
if (parsedArgs.errors.length > 0) {
|
|
566
|
-
parsedArgs.errors.forEach((errorMessage) => console.log((0, ui_1.fail)(errorMessage)));
|
|
567
|
-
process.exit(1);
|
|
568
|
-
}
|
|
569
|
-
const positionals = extractPositionalArgs(args);
|
|
570
|
-
const source = positionals[0];
|
|
571
|
-
let destination = positionals[1];
|
|
572
|
-
if (!source) {
|
|
573
|
-
console.log((0, ui_1.fail)('Source profile is required. Usage: ccs api copy <source> <destination>'));
|
|
574
|
-
process.exit(1);
|
|
575
|
-
}
|
|
576
|
-
if (!destination) {
|
|
577
|
-
destination = await prompt_1.InteractivePrompt.input('Destination profile name');
|
|
578
|
-
}
|
|
579
|
-
if (!parsedArgs.yes) {
|
|
580
|
-
const confirmed = await prompt_1.InteractivePrompt.confirm(`Copy profile "${source}" to "${destination}"?`, { default: true });
|
|
581
|
-
if (!confirmed) {
|
|
582
|
-
console.log((0, ui_1.info)('Cancelled'));
|
|
583
|
-
process.exit(0);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
const result = (0, services_1.copyApiProfile)(source, destination, {
|
|
587
|
-
target: parsedArgs.target,
|
|
588
|
-
force: parsedArgs.force,
|
|
589
|
-
});
|
|
590
|
-
if (!result.success) {
|
|
591
|
-
console.log((0, ui_1.fail)(result.error || 'Failed to copy profile'));
|
|
592
|
-
process.exit(1);
|
|
593
|
-
}
|
|
594
|
-
console.log((0, ui_1.ok)(`Profile copied: ${source} -> ${destination}`));
|
|
595
|
-
if (result.warnings && result.warnings.length > 0) {
|
|
596
|
-
result.warnings.forEach((warningMessage) => console.log((0, ui_1.warn)(warningMessage)));
|
|
597
|
-
}
|
|
598
|
-
console.log('');
|
|
599
|
-
}
|
|
600
|
-
/** Handle 'ccs api export' command */
|
|
601
|
-
async function handleExport(args) {
|
|
602
|
-
await (0, ui_1.initUI)();
|
|
603
|
-
const includeSecrets = (0, arg_extractor_1.hasAnyFlag)(args, ['--include-secrets']);
|
|
604
|
-
const outExtracted = (0, arg_extractor_1.extractOption)(args, ['--out'], {
|
|
605
|
-
allowDashValue: true,
|
|
606
|
-
knownFlags: [...API_KNOWN_FLAGS, '--out', '--include-secrets'],
|
|
607
|
-
});
|
|
608
|
-
if (outExtracted.found && (outExtracted.missingValue || !outExtracted.value)) {
|
|
609
|
-
console.log((0, ui_1.fail)('Missing value for --out'));
|
|
610
|
-
process.exit(1);
|
|
611
|
-
}
|
|
612
|
-
const outPath = outExtracted.value;
|
|
613
|
-
const positionals = extractPositionalArgs(outExtracted.remainingArgs);
|
|
614
|
-
const name = positionals[0];
|
|
615
|
-
if (!name) {
|
|
616
|
-
console.log((0, ui_1.fail)('Profile name is required. Usage: ccs api export <name> [--out <file>]'));
|
|
617
|
-
process.exit(1);
|
|
618
|
-
}
|
|
619
|
-
const result = (0, services_1.exportApiProfile)(name, includeSecrets);
|
|
620
|
-
if (!result.success || !result.bundle) {
|
|
621
|
-
console.log((0, ui_1.fail)(result.error || 'Failed to export profile'));
|
|
622
|
-
process.exit(1);
|
|
623
|
-
}
|
|
624
|
-
const resolvedOutputPath = path.resolve(outPath || `${name}.ccs-profile.json`);
|
|
625
|
-
fs.mkdirSync(path.dirname(resolvedOutputPath), { recursive: true });
|
|
626
|
-
fs.writeFileSync(resolvedOutputPath, JSON.stringify(result.bundle, null, 2) + '\n', 'utf8');
|
|
627
|
-
console.log((0, ui_1.ok)(`Profile exported to: ${resolvedOutputPath}`));
|
|
628
|
-
if (result.redacted) {
|
|
629
|
-
console.log((0, ui_1.warn)('Token was redacted in export. Use --include-secrets to include it.'));
|
|
630
|
-
}
|
|
631
|
-
console.log('');
|
|
632
|
-
}
|
|
633
|
-
/** Handle 'ccs api import' command */
|
|
634
|
-
async function handleImport(args) {
|
|
635
|
-
await (0, ui_1.initUI)();
|
|
636
|
-
const force = (0, arg_extractor_1.hasAnyFlag)(args, ['--force']);
|
|
637
|
-
const yes = (0, arg_extractor_1.hasAnyFlag)(args, ['--yes', '-y']);
|
|
638
|
-
const nameExtracted = (0, arg_extractor_1.extractOption)(args, ['--name'], {
|
|
639
|
-
allowDashValue: true,
|
|
640
|
-
knownFlags: [...API_KNOWN_FLAGS, '--name'],
|
|
641
|
-
});
|
|
642
|
-
if (nameExtracted.found && (nameExtracted.missingValue || !nameExtracted.value)) {
|
|
643
|
-
console.log((0, ui_1.fail)('Missing value for --name'));
|
|
644
|
-
process.exit(1);
|
|
645
|
-
}
|
|
646
|
-
const targetParsed = parseOptionalTargetFlag(nameExtracted.remainingArgs, [
|
|
647
|
-
...API_KNOWN_FLAGS,
|
|
648
|
-
'--name',
|
|
649
|
-
]);
|
|
650
|
-
if (targetParsed.errors.length > 0) {
|
|
651
|
-
targetParsed.errors.forEach((errorMessage) => console.log((0, ui_1.fail)(errorMessage)));
|
|
652
|
-
process.exit(1);
|
|
653
|
-
}
|
|
654
|
-
const positionals = extractPositionalArgs(targetParsed.remainingArgs);
|
|
655
|
-
const importPath = positionals[0];
|
|
656
|
-
if (!importPath) {
|
|
657
|
-
console.log((0, ui_1.fail)('Import file path is required. Usage: ccs api import <file> [--name <new-name>]'));
|
|
658
|
-
process.exit(1);
|
|
659
|
-
}
|
|
660
|
-
if (!fs.existsSync(importPath)) {
|
|
661
|
-
console.log((0, ui_1.fail)(`File not found: ${importPath}`));
|
|
662
|
-
process.exit(1);
|
|
663
|
-
}
|
|
664
|
-
const raw = fs.readFileSync(importPath, 'utf8');
|
|
665
|
-
let bundle;
|
|
666
|
-
try {
|
|
667
|
-
bundle = JSON.parse(raw);
|
|
668
|
-
}
|
|
669
|
-
catch (error) {
|
|
670
|
-
console.log((0, ui_1.fail)(`Invalid JSON file: ${error.message}`));
|
|
671
|
-
process.exit(1);
|
|
672
|
-
}
|
|
673
|
-
if (!yes) {
|
|
674
|
-
const confirmed = await prompt_1.InteractivePrompt.confirm(`Import profile bundle from "${importPath}"?`, {
|
|
675
|
-
default: true,
|
|
676
|
-
});
|
|
677
|
-
if (!confirmed) {
|
|
678
|
-
console.log((0, ui_1.info)('Cancelled'));
|
|
679
|
-
process.exit(0);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
const result = (0, services_1.importApiProfileBundle)(bundle, {
|
|
683
|
-
name: nameExtracted.value,
|
|
684
|
-
target: targetParsed.target,
|
|
685
|
-
force,
|
|
686
|
-
});
|
|
687
|
-
if (!result.success) {
|
|
688
|
-
console.log((0, ui_1.fail)(result.error || 'Failed to import profile'));
|
|
689
|
-
if (result.validation?.issues?.length) {
|
|
690
|
-
console.log('');
|
|
691
|
-
result.validation.issues.forEach((issue) => {
|
|
692
|
-
const indicator = issue.level === 'error' ? (0, ui_1.color)('[X]', 'error') : (0, ui_1.color)('[!]', 'warning');
|
|
693
|
-
console.log(`${indicator} ${issue.message}`);
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
process.exit(1);
|
|
697
|
-
}
|
|
698
|
-
console.log((0, ui_1.ok)(`Profile imported: ${result.name}`));
|
|
699
|
-
if (result.warnings && result.warnings.length > 0) {
|
|
700
|
-
result.warnings.forEach((warningMessage) => console.log((0, ui_1.warn)(warningMessage)));
|
|
701
|
-
}
|
|
702
|
-
console.log('');
|
|
703
|
-
}
|
|
704
|
-
/** Show help for api commands */
|
|
705
|
-
async function showHelp() {
|
|
706
|
-
await (0, ui_1.initUI)();
|
|
707
|
-
const presetIds = (0, services_1.getPresetIds)()
|
|
708
|
-
.map((id) => sanitizeHelpText(id))
|
|
709
|
-
.filter(Boolean);
|
|
710
|
-
const presetAliases = (0, services_1.getPresetAliases)();
|
|
711
|
-
const presetIdWidth = Math.max(0, ...presetIds.map((id) => id.length)) + 2;
|
|
712
|
-
console.log((0, ui_1.header)('CCS API Management'));
|
|
713
|
-
console.log('');
|
|
714
|
-
console.log((0, ui_1.subheader)('Usage'));
|
|
715
|
-
console.log(` ${(0, ui_1.color)('ccs api', 'command')} <command> [options]`);
|
|
716
|
-
console.log('');
|
|
717
|
-
console.log((0, ui_1.subheader)('Commands'));
|
|
718
|
-
console.log(` ${(0, ui_1.color)('create [name]', 'command')} Create new API profile (interactive)`);
|
|
719
|
-
console.log(` ${(0, ui_1.color)('list', 'command')} List all API profiles`);
|
|
720
|
-
console.log(` ${(0, ui_1.color)('discover', 'command')} Discover orphan *.settings.json and register`);
|
|
721
|
-
console.log(` ${(0, ui_1.color)('copy <src> <dest>', 'command')} Duplicate API profile settings + config`);
|
|
722
|
-
console.log(` ${(0, ui_1.color)('export <name>', 'command')} Export profile bundle for cross-device transfer`);
|
|
723
|
-
console.log(` ${(0, ui_1.color)('import <file>', 'command')} Import profile bundle and register profile`);
|
|
724
|
-
console.log(` ${(0, ui_1.color)('remove <name>', 'command')} Remove an API profile`);
|
|
725
|
-
console.log('');
|
|
726
|
-
console.log((0, ui_1.subheader)('Options'));
|
|
727
|
-
console.log(` ${(0, ui_1.color)('--preset <id>', 'command')} Use provider preset (${presetIds.join(', ')})`);
|
|
728
|
-
console.log(` ${(0, ui_1.color)('--base-url <url>', 'command')} API base URL (create)`);
|
|
729
|
-
console.log(` ${(0, ui_1.color)('--api-key <key>', 'command')} API key (create)`);
|
|
730
|
-
console.log(` ${(0, ui_1.color)('--model <model>', 'command')} Default model (create)`);
|
|
731
|
-
console.log(` ${(0, ui_1.color)('--target <cli>', 'command')} Default target: claude or droid (create)`);
|
|
732
|
-
console.log(` ${(0, ui_1.color)('--register', 'command')} Register discovered orphan settings`);
|
|
733
|
-
console.log(` ${(0, ui_1.color)('--json', 'command')} JSON output for discover command`);
|
|
734
|
-
console.log(` ${(0, ui_1.color)('--out <file>', 'command')} Export bundle output path`);
|
|
735
|
-
console.log(` ${(0, ui_1.color)('--include-secrets', 'command')} Include token in export bundle`);
|
|
736
|
-
console.log(` ${(0, ui_1.color)('--name <name>', 'command')} Override profile name during import`);
|
|
737
|
-
console.log(` ${(0, ui_1.color)('--force', 'command')} Overwrite existing or bypass validation (create/discover/copy/import)`);
|
|
738
|
-
console.log(` ${(0, ui_1.color)('--yes, -y', 'command')} Skip confirmation prompts`);
|
|
739
|
-
console.log('');
|
|
740
|
-
console.log((0, ui_1.subheader)('Provider Presets'));
|
|
741
|
-
services_1.PROVIDER_PRESETS.forEach((preset) => console.log(renderPresetHelpLine(preset, presetIdWidth)));
|
|
742
|
-
Object.entries(presetAliases).forEach(([alias, canonical]) => {
|
|
743
|
-
const safeAlias = sanitizeHelpText(alias);
|
|
744
|
-
const safeCanonical = sanitizeHelpText(canonical);
|
|
745
|
-
console.log(` ${(0, ui_1.dim)(`Legacy alias: --preset ${safeAlias} (auto-mapped to ${safeCanonical})`)}`);
|
|
746
|
-
});
|
|
747
|
-
console.log('');
|
|
748
|
-
console.log((0, ui_1.subheader)('Examples'));
|
|
749
|
-
console.log(` ${(0, ui_1.dim)('# Interactive wizard')}`);
|
|
750
|
-
console.log(` ${(0, ui_1.color)('ccs api create', 'command')}`);
|
|
751
|
-
console.log('');
|
|
752
|
-
console.log(` ${(0, ui_1.dim)('# Quick setup with preset')}`);
|
|
753
|
-
console.log(` ${(0, ui_1.color)('ccs api create --preset anthropic', 'command')}`);
|
|
754
|
-
console.log(` ${(0, ui_1.color)('ccs api create --preset openrouter', 'command')}`);
|
|
755
|
-
console.log(` ${(0, ui_1.color)('ccs api create --preset alibaba-coding-plan', 'command')}`);
|
|
756
|
-
console.log(` ${(0, ui_1.color)('ccs api create --preset alibaba', 'command')} ${(0, ui_1.dim)('# alias')}`);
|
|
757
|
-
console.log(` ${(0, ui_1.color)('ccs api create --preset glm', 'command')}`);
|
|
758
|
-
console.log('');
|
|
759
|
-
console.log(` ${(0, ui_1.dim)('# Create with name')}`);
|
|
760
|
-
console.log(` ${(0, ui_1.color)('ccs api create myapi', 'command')}`);
|
|
761
|
-
console.log(` ${(0, ui_1.color)('ccs api create mydroid --preset glm --target droid', 'command')}`);
|
|
762
|
-
console.log('');
|
|
763
|
-
console.log(` ${(0, ui_1.dim)('# Remove API profile')}`);
|
|
764
|
-
console.log(` ${(0, ui_1.color)('ccs api remove myapi', 'command')}`);
|
|
765
|
-
console.log('');
|
|
766
|
-
console.log(` ${(0, ui_1.dim)('# Discover and register orphan settings files')}`);
|
|
767
|
-
console.log(` ${(0, ui_1.color)('ccs api discover', 'command')}`);
|
|
768
|
-
console.log(` ${(0, ui_1.color)('ccs api discover --register', 'command')}`);
|
|
769
|
-
console.log('');
|
|
770
|
-
console.log(` ${(0, ui_1.dim)('# Duplicate an existing API profile')}`);
|
|
771
|
-
console.log(` ${(0, ui_1.color)('ccs api copy glm glm-backup', 'command')}`);
|
|
772
|
-
console.log('');
|
|
773
|
-
console.log(` ${(0, ui_1.dim)('# Export and import across devices')}`);
|
|
774
|
-
console.log(` ${(0, ui_1.color)('ccs api export glm --out ./glm.ccs-profile.json', 'command')}`);
|
|
775
|
-
console.log(` ${(0, ui_1.color)('ccs api import ./glm.ccs-profile.json', 'command')}`);
|
|
776
|
-
console.log('');
|
|
777
|
-
console.log(` ${(0, ui_1.dim)('# Show all API profiles')}`);
|
|
778
|
-
console.log(` ${(0, ui_1.color)('ccs api list', 'command')}`);
|
|
779
|
-
console.log('');
|
|
780
|
-
}
|
|
781
|
-
/** Main api command router */
|
|
782
|
-
async function handleApiCommand(args) {
|
|
783
|
-
const command = args[0];
|
|
784
|
-
if (!command || command === '--help' || command === '-h' || command === 'help') {
|
|
785
|
-
await showHelp();
|
|
786
|
-
return;
|
|
787
|
-
}
|
|
788
|
-
switch (command) {
|
|
789
|
-
case 'create':
|
|
790
|
-
await handleCreate(args.slice(1));
|
|
791
|
-
break;
|
|
792
|
-
case 'list':
|
|
793
|
-
await handleList();
|
|
794
|
-
break;
|
|
795
|
-
case 'discover':
|
|
796
|
-
await handleDiscover(args.slice(1));
|
|
797
|
-
break;
|
|
798
|
-
case 'copy':
|
|
799
|
-
await handleCopy(args.slice(1));
|
|
800
|
-
break;
|
|
801
|
-
case 'export':
|
|
802
|
-
await handleExport(args.slice(1));
|
|
803
|
-
break;
|
|
804
|
-
case 'import':
|
|
805
|
-
await handleImport(args.slice(1));
|
|
806
|
-
break;
|
|
807
|
-
case 'remove':
|
|
808
|
-
case 'delete':
|
|
809
|
-
case 'rm':
|
|
810
|
-
await handleRemove(args.slice(1));
|
|
811
|
-
break;
|
|
812
|
-
default:
|
|
813
|
-
await (0, ui_1.initUI)();
|
|
814
|
-
console.log((0, ui_1.fail)(`Unknown command: ${command}`));
|
|
815
|
-
console.log('');
|
|
816
|
-
console.log('Run for help:');
|
|
817
|
-
console.log(` ${(0, ui_1.color)('ccs api --help', 'command')}`);
|
|
818
|
-
process.exit(1);
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
exports.handleApiCommand = handleApiCommand;
|
|
17
|
+
__exportStar(require("./api-command/index"), exports);
|
|
822
18
|
//# sourceMappingURL=api-command.js.map
|