@annabest/ticket-ai 0.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/README.md +59 -0
- package/bin/codex-config.js +160 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# @annabest/ticket-ai
|
|
2
|
+
|
|
3
|
+
CLI for bootstrapping Codex on a Linux server against a Ticket AI OpenAI-compatible endpoint.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Running `codex-config` creates:
|
|
8
|
+
|
|
9
|
+
- `~/.codex/config.toml`
|
|
10
|
+
- `~/.codex/auth.json`
|
|
11
|
+
|
|
12
|
+
The generated `config.toml` uses:
|
|
13
|
+
|
|
14
|
+
- provider: `OpenAI`
|
|
15
|
+
- model: `gpt-5.4`
|
|
16
|
+
- base URL: `http://151.242.85.111:8080`
|
|
17
|
+
- wire API: `responses`
|
|
18
|
+
|
|
19
|
+
The command prompts the user for an API key, then writes:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"OPENAI_API_KEY": "sk-xxxx"
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Remote server usage
|
|
28
|
+
|
|
29
|
+
After this package is published to npm, users only need:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
sudo npm install -g @annabest/ticket-ai
|
|
33
|
+
codex-config
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then they paste their key once.
|
|
37
|
+
|
|
38
|
+
## Local test before publish
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm pack
|
|
42
|
+
npm install -g ./annabest-ticket-ai-0.1.0.tgz
|
|
43
|
+
codex-config
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Non-interactive usage
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
codex-config --api-key sk-xxxx
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Publish
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm login
|
|
56
|
+
npm publish --access=public
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If the scoped package name is unavailable, change the scope or package name in `package.json` and publish again.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const readline = require("readline/promises");
|
|
7
|
+
const { stdin, stdout } = require("process");
|
|
8
|
+
|
|
9
|
+
const DEFAULTS = {
|
|
10
|
+
providerName: "OpenAI",
|
|
11
|
+
baseUrl: "http://151.242.85.111:8080",
|
|
12
|
+
model: "gpt-5.4",
|
|
13
|
+
reviewModel: "gpt-5.4",
|
|
14
|
+
reasoningEffort: "xhigh",
|
|
15
|
+
contextWindow: 1000000,
|
|
16
|
+
compactTokenLimit: 900000
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function usage() {
|
|
20
|
+
stdout.write(
|
|
21
|
+
[
|
|
22
|
+
"Usage: codex-config [--api-key <key>] [--force]",
|
|
23
|
+
"",
|
|
24
|
+
"Creates ~/.codex/config.toml and ~/.codex/auth.json for the Sub2API endpoint."
|
|
25
|
+
].join("\n") + "\n"
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseArgs(argv) {
|
|
30
|
+
const args = {
|
|
31
|
+
apiKey: process.env.OPENAI_API_KEY || "",
|
|
32
|
+
force: false
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
36
|
+
const arg = argv[i];
|
|
37
|
+
if (arg === "--help" || arg === "-h") {
|
|
38
|
+
usage();
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
if (arg === "--force" || arg === "-f") {
|
|
42
|
+
args.force = true;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (arg === "--api-key") {
|
|
46
|
+
const next = argv[i + 1];
|
|
47
|
+
if (!next) {
|
|
48
|
+
throw new Error("--api-key requires a value");
|
|
49
|
+
}
|
|
50
|
+
args.apiKey = next.trim();
|
|
51
|
+
i += 1;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return args;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function ensureDir(dirPath) {
|
|
61
|
+
fs.mkdirSync(dirPath, { recursive: true, mode: 0o700 });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function timestampForBackup() {
|
|
65
|
+
return new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function backupIfExists(filePath) {
|
|
69
|
+
if (!fs.existsSync(filePath)) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const backupPath = `${filePath}.bak.${timestampForBackup()}`;
|
|
73
|
+
fs.copyFileSync(filePath, backupPath);
|
|
74
|
+
return backupPath;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function buildConfigToml() {
|
|
78
|
+
return [
|
|
79
|
+
`model_provider = "${DEFAULTS.providerName}"`,
|
|
80
|
+
`model = "${DEFAULTS.model}"`,
|
|
81
|
+
`review_model = "${DEFAULTS.reviewModel}"`,
|
|
82
|
+
`model_reasoning_effort = "${DEFAULTS.reasoningEffort}"`,
|
|
83
|
+
"disable_response_storage = true",
|
|
84
|
+
'network_access = "enabled"',
|
|
85
|
+
"windows_wsl_setup_acknowledged = true",
|
|
86
|
+
`model_context_window = ${DEFAULTS.contextWindow}`,
|
|
87
|
+
`model_auto_compact_token_limit = ${DEFAULTS.compactTokenLimit}`,
|
|
88
|
+
"",
|
|
89
|
+
`[model_providers.${DEFAULTS.providerName}]`,
|
|
90
|
+
`name = "${DEFAULTS.providerName}"`,
|
|
91
|
+
`base_url = "${DEFAULTS.baseUrl}"`,
|
|
92
|
+
'wire_api = "responses"',
|
|
93
|
+
"requires_openai_auth = true",
|
|
94
|
+
""
|
|
95
|
+
].join("\n");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function buildAuthJson(apiKey) {
|
|
99
|
+
return `${JSON.stringify({ OPENAI_API_KEY: apiKey }, null, 2)}\n`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function promptForApiKey() {
|
|
103
|
+
const rl = readline.createInterface({
|
|
104
|
+
input: stdin,
|
|
105
|
+
output: stdout
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
stdout.write("Paste your OpenAI API key for Codex access: ");
|
|
110
|
+
const value = (await rl.question("")).trim();
|
|
111
|
+
if (!value) {
|
|
112
|
+
throw new Error("API key cannot be empty");
|
|
113
|
+
}
|
|
114
|
+
return value;
|
|
115
|
+
} finally {
|
|
116
|
+
rl.close();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function writeFile(filePath, content, mode) {
|
|
121
|
+
fs.writeFileSync(filePath, content, { encoding: "utf8", mode });
|
|
122
|
+
fs.chmodSync(filePath, mode);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function main() {
|
|
126
|
+
const args = parseArgs(process.argv.slice(2));
|
|
127
|
+
const codexDir = path.join(os.homedir(), ".codex");
|
|
128
|
+
const configPath = path.join(codexDir, "config.toml");
|
|
129
|
+
const authPath = path.join(codexDir, "auth.json");
|
|
130
|
+
|
|
131
|
+
const apiKey = args.apiKey || (await promptForApiKey());
|
|
132
|
+
ensureDir(codexDir);
|
|
133
|
+
|
|
134
|
+
const backups = [];
|
|
135
|
+
if (!args.force) {
|
|
136
|
+
const configBackup = backupIfExists(configPath);
|
|
137
|
+
const authBackup = backupIfExists(authPath);
|
|
138
|
+
if (configBackup) {
|
|
139
|
+
backups.push(configBackup);
|
|
140
|
+
}
|
|
141
|
+
if (authBackup) {
|
|
142
|
+
backups.push(authBackup);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
writeFile(configPath, buildConfigToml(), 0o600);
|
|
147
|
+
writeFile(authPath, buildAuthJson(apiKey), 0o600);
|
|
148
|
+
|
|
149
|
+
stdout.write(`Created ${configPath}\n`);
|
|
150
|
+
stdout.write(`Created ${authPath}\n`);
|
|
151
|
+
if (backups.length > 0) {
|
|
152
|
+
stdout.write(`Backups:\n${backups.map((item) => `- ${item}`).join("\n")}\n`);
|
|
153
|
+
}
|
|
154
|
+
stdout.write("Codex configuration completed.\n");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
main().catch((error) => {
|
|
158
|
+
console.error(`codex-config failed: ${error.message}`);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@annabest/ticket-ai",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Bootstrap Codex config for a Sub2API OpenAI-compatible endpoint.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"files": [
|
|
7
|
+
"bin",
|
|
8
|
+
"README.md"
|
|
9
|
+
],
|
|
10
|
+
"bin": {
|
|
11
|
+
"codex-config": "bin/codex-config.js"
|
|
12
|
+
},
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"codex",
|
|
18
|
+
"openai",
|
|
19
|
+
"sub2api",
|
|
20
|
+
"config",
|
|
21
|
+
"cli"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
}
|
|
26
|
+
}
|