sanook-cli 0.5.8 → 0.5.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/CHANGELOG.md +12 -0
- package/dist/commands.js +14 -6
- package/dist/config.js +6 -0
- package/dist/i18n/en.js +1 -0
- package/dist/i18n/th.js +1 -0
- package/dist/loop.js +10 -1
- package/dist/model-picker.js +4 -1
- package/dist/providers/codex.js +75 -2
- package/dist/providers/models.js +17 -2
- package/dist/providers/registry.js +6 -13
- package/dist/ui/setup.js +3 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.10
|
|
4
|
+
|
|
5
|
+
- Patch release (npm republish guard — use this version after 0.5.9 is already on the registry).
|
|
6
|
+
|
|
7
|
+
## 0.5.9
|
|
8
|
+
|
|
9
|
+
### Codex (ChatGPT plan) + install
|
|
10
|
+
|
|
11
|
+
- **Codex models** — setup, `/model` picker, and config migration now only offer ChatGPT-plan-safe models (`gpt-5.5`, `gpt-5.4`, `gpt-5.4-mini`); legacy `gpt-5-codex` / `*-codex` ids auto-migrate instead of failing at runtime.
|
|
12
|
+
- **Codex errors** — surface JSONL API errors from `codex exec` (not just opaque exit codes).
|
|
13
|
+
- **Install** — README install section, GitHub Pages deploy script, npm publish guard (`scripts/publish-npm.sh`).
|
|
14
|
+
|
|
3
15
|
## 0.5.8
|
|
4
16
|
|
|
5
17
|
### Self-maintaining memory + reliability & security hardening
|
package/dist/commands.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { readdir, readFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { canonicalSpec, consoleUrl, hasUsableEnvKey, PROVIDERS, parseSpec } from './providers/registry.js';
|
|
4
|
+
import { mergeModelOptions } from './providers/models.js';
|
|
5
|
+
import { CODEX_CHATGPT_UNSUPPORTED_MODELS } from './providers/codex.js';
|
|
4
6
|
import { appHomePath, BRAND } from './brand.js';
|
|
5
7
|
import { parseFrontmatter } from './skills.js';
|
|
6
8
|
import { projectConfigPathIfTrusted } from './trust.js';
|
|
@@ -84,15 +86,17 @@ function modelMenu(current) {
|
|
|
84
86
|
const { provider } = parseSpec(current);
|
|
85
87
|
const cfg = PROVIDERS[provider];
|
|
86
88
|
const list = cfg
|
|
87
|
-
?
|
|
88
|
-
.
|
|
89
|
-
.map(([alias, id]) => ` ${provider}:${alias} → ${id}`)
|
|
89
|
+
? mergeModelOptions(cfg)
|
|
90
|
+
.map((o) => ` ${provider}:${o.value} (${o.label})`)
|
|
90
91
|
.join('\n')
|
|
91
92
|
: '';
|
|
93
|
+
const codexNote = provider === 'codex'
|
|
94
|
+
? '\nChatGPT plan: ใช้ได้ gpt-5.5 · gpt-5.4 · gpt-5.4-mini (โมเดล *-codex เก่าไม่รองรับ)'
|
|
95
|
+
: '';
|
|
92
96
|
return [
|
|
93
97
|
`model ปัจจุบัน: ${current}`,
|
|
94
|
-
cfg ? `\nเลือกของ ${cfg.label}:\n${list}` : '',
|
|
95
|
-
`\nเปลี่ยน: /model <spec> (เช่น /model sonnet, /model
|
|
98
|
+
cfg ? `\nเลือกของ ${cfg.label}:\n${list}${codexNote}` : '',
|
|
99
|
+
`\nเปลี่ยน: /model <spec> (เช่น /model sonnet, /model codex:5.5)`,
|
|
96
100
|
`provider อื่น: ${Object.keys(PROVIDERS).join(' · ')}`,
|
|
97
101
|
]
|
|
98
102
|
.filter(Boolean)
|
|
@@ -147,11 +151,15 @@ function modelChange(spec) {
|
|
|
147
151
|
message: `model spec ไม่ครบ: "${spec}" — ใช้ /model <alias> หรือ /model <provider:model>`,
|
|
148
152
|
};
|
|
149
153
|
}
|
|
154
|
+
const rawModel = spec.includes(':') ? spec.slice(spec.indexOf(':') + 1).trim() : '';
|
|
155
|
+
const migratedNote = provider === 'codex' && rawModel && CODEX_CHATGPT_UNSUPPORTED_MODELS.has(rawModel)
|
|
156
|
+
? `\n⚠ โมเดล ${rawModel} ไม่รองรับ ChatGPT plan → ใช้ ${canonical} แทน`
|
|
157
|
+
: '';
|
|
150
158
|
const hint = missingKeyHint(provider);
|
|
151
159
|
return {
|
|
152
160
|
handled: true,
|
|
153
161
|
modelChange: canonical,
|
|
154
|
-
message: [`เปลี่ยน model → ${canonical}`, hint].filter(Boolean).join('\n'),
|
|
162
|
+
message: [`เปลี่ยน model → ${canonical}`, migratedNote, hint].filter(Boolean).join('\n'),
|
|
155
163
|
};
|
|
156
164
|
}
|
|
157
165
|
/** parse input — ถ้าขึ้นต้น / = slash command, ไม่งั้น handled=false (ส่งเข้า agent) */
|
package/dist/config.js
CHANGED
|
@@ -4,6 +4,7 @@ import { join } from 'node:path';
|
|
|
4
4
|
import { appHomePath, appProjectPath, BRAND } from './brand.js';
|
|
5
5
|
import { projectRoot, projectTrustStatus } from './trust.js';
|
|
6
6
|
import { registerPricing } from './cost.js';
|
|
7
|
+
import { migrateDeprecatedCodexModel } from './providers/codex.js';
|
|
7
8
|
export function configHomeDir() {
|
|
8
9
|
return appHomePath();
|
|
9
10
|
}
|
|
@@ -180,6 +181,11 @@ export async function loadConfig(overrides = {}, cwd = process.cwd()) {
|
|
|
180
181
|
}
|
|
181
182
|
const merged = { ...global, ...project, ...envConfig, ...cleanOverrides };
|
|
182
183
|
const config = parseConfigGraceful(merged);
|
|
184
|
+
const migratedModel = migrateDeprecatedCodexModel(config.model);
|
|
185
|
+
if (migratedModel !== config.model) {
|
|
186
|
+
config.model = migratedModel;
|
|
187
|
+
void saveGlobalConfig({ model: migratedModel }).catch(() => { });
|
|
188
|
+
}
|
|
183
189
|
// pricing override: config.pricing + env SANOOK_PRICING (JSON) → ลงทะเบียนเข้า cost table
|
|
184
190
|
registerPricing(config.pricing);
|
|
185
191
|
registerPricing(parseEnvPricing());
|
package/dist/i18n/en.js
CHANGED
|
@@ -36,6 +36,7 @@ export const en = {
|
|
|
36
36
|
codexOptionRecheck: 'Re-check (after install/login)',
|
|
37
37
|
codexOptionBack: '← Choose another provider',
|
|
38
38
|
codexInstallCmd: 'npm i -g @openai/codex',
|
|
39
|
+
codexModelHint: 'ChatGPT plan supports gpt-5.5 · gpt-5.4 · gpt-5.4-mini only (legacy *-codex ids are not available)',
|
|
39
40
|
keyEscHint: '(Esc = back)',
|
|
40
41
|
keyOpenAiCodexHint: 'Have ChatGPT Plus/Pro? Press Esc and pick OpenAI Codex (ChatGPT plan) — no API key needed.',
|
|
41
42
|
keyFormatHint: 'Key format',
|
package/dist/i18n/th.js
CHANGED
|
@@ -36,6 +36,7 @@ export const th = {
|
|
|
36
36
|
codexOptionRecheck: 'เช็กใหม่ (หลังติดตั้ง/login)',
|
|
37
37
|
codexOptionBack: '← กลับไปเลือก provider อื่น',
|
|
38
38
|
codexInstallCmd: 'npm i -g @openai/codex',
|
|
39
|
+
codexModelHint: 'ChatGPT plan ใช้ได้ gpt-5.5 · gpt-5.4 · gpt-5.4-mini เท่านั้น (โมเดล *-codex เก่าใช้ไม่ได้)',
|
|
39
40
|
keyEscHint: '(Esc = กลับ)',
|
|
40
41
|
keyOpenAiCodexHint: 'มี ChatGPT Plus/Pro? กด Esc แล้วเลือก OpenAI Codex (ChatGPT plan) — ไม่ต้อง API key',
|
|
41
42
|
keyFormatHint: 'รูปแบบ key',
|
package/dist/loop.js
CHANGED
|
@@ -174,10 +174,19 @@ async function runDelegate(opts) {
|
|
|
174
174
|
// auto (--yes / config auto) → workspace-write เพื่อให้ codex แก้ไฟล์ได้จริง (ไม่งั้นเป็น coding agent ที่แก้อะไรไม่ได้)
|
|
175
175
|
const sandbox = opts.planMode || (opts.permissionMode ?? 'ask') === 'ask' ? 'read-only' : 'workspace-write';
|
|
176
176
|
opts.onEvent?.({ type: 'status', detail: `Codex · ${model} · ${sandbox}` });
|
|
177
|
+
const { normalizeCodexChatGptModel } = await import('./providers/codex.js');
|
|
178
|
+
const normalized = normalizeCodexChatGptModel(model);
|
|
179
|
+
if (normalized.migratedFrom) {
|
|
180
|
+
opts.onEvent?.({
|
|
181
|
+
type: 'status',
|
|
182
|
+
detail: `Codex model ${normalized.migratedFrom} ไม่รองรับ ChatGPT plan → ใช้ ${normalized.model} แทน (sanook model เพื่ออัปเดต: /model codex)`,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
177
185
|
let text = '';
|
|
186
|
+
const execModel = normalized.model === PROVIDERS.codex.models.default ? undefined : normalized.model;
|
|
178
187
|
const out = await runCodex({
|
|
179
188
|
prompt,
|
|
180
|
-
model:
|
|
189
|
+
model: execModel,
|
|
181
190
|
sandbox,
|
|
182
191
|
cwd: opts.cwd, // worktree isolation ของ sub-agent
|
|
183
192
|
signal: opts.signal,
|
package/dist/model-picker.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { canonicalSpec, hasUsableEnvKey, PROVIDERS, parseSpec } from './providers/registry.js';
|
|
2
|
+
import { isCodexChatGptSupportedModel } from './providers/codex.js';
|
|
2
3
|
function statusFor(provider) {
|
|
3
4
|
const cfg = PROVIDERS[provider];
|
|
4
5
|
if (cfg.kind === 'delegate')
|
|
@@ -22,7 +23,9 @@ export function modelPickerOptions(current) {
|
|
|
22
23
|
grouped.set(model, aliases);
|
|
23
24
|
}
|
|
24
25
|
const status = statusFor(provider);
|
|
25
|
-
return [...grouped.entries()]
|
|
26
|
+
return [...grouped.entries()]
|
|
27
|
+
.filter(([model]) => provider !== 'codex' || isCodexChatGptSupportedModel(model))
|
|
28
|
+
.map(([model, aliases]) => {
|
|
26
29
|
const nonDefaultAliases = aliases.filter((alias) => alias !== 'default');
|
|
27
30
|
const displayAliases = nonDefaultAliases.length ? nonDefaultAliases.join('/') : 'default';
|
|
28
31
|
const spec = `${provider}:${model}`;
|
package/dist/providers/codex.js
CHANGED
|
@@ -47,6 +47,69 @@ export async function detectCodex() {
|
|
|
47
47
|
}
|
|
48
48
|
return { installed: true, loggedIn: false, reason: 'ยังไม่ได้ login — รัน: codex login' };
|
|
49
49
|
}
|
|
50
|
+
/** Models rejected by official `codex exec` when auth is ChatGPT plan (not OpenAI API key). */
|
|
51
|
+
export const CODEX_CHATGPT_UNSUPPORTED_MODELS = new Set([
|
|
52
|
+
'gpt-5-codex',
|
|
53
|
+
'gpt-5.2-codex',
|
|
54
|
+
'gpt-5.3-codex',
|
|
55
|
+
'gpt-5.3-codex-spark',
|
|
56
|
+
]);
|
|
57
|
+
/** Models verified to work with ChatGPT-plan auth via `codex exec` (Jun 2026). */
|
|
58
|
+
export const CODEX_CHATGPT_SUPPORTED_MODELS = ['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini'];
|
|
59
|
+
/** Curated aliases for setup + /model picker — only ChatGPT-plan-safe ids. */
|
|
60
|
+
export const CODEX_CHATGPT_MODEL_ALIASES = {
|
|
61
|
+
default: 'gpt-5.5',
|
|
62
|
+
codex: 'gpt-5.5',
|
|
63
|
+
smart: 'gpt-5.5',
|
|
64
|
+
'5.5': 'gpt-5.5',
|
|
65
|
+
'5.4': 'gpt-5.4',
|
|
66
|
+
'5.4-mini': 'gpt-5.4-mini',
|
|
67
|
+
fast: 'gpt-5.4-mini',
|
|
68
|
+
};
|
|
69
|
+
export function isCodexChatGptSupportedModel(model) {
|
|
70
|
+
return CODEX_CHATGPT_SUPPORTED_MODELS.includes(model.trim());
|
|
71
|
+
}
|
|
72
|
+
/** Migrate saved config specs that still point at deprecated Codex CLI model ids. */
|
|
73
|
+
export function migrateDeprecatedCodexModel(spec) {
|
|
74
|
+
const idx = spec.indexOf(':');
|
|
75
|
+
if (idx === -1)
|
|
76
|
+
return spec;
|
|
77
|
+
const provider = spec.slice(0, idx);
|
|
78
|
+
if (provider !== 'codex')
|
|
79
|
+
return spec;
|
|
80
|
+
const { model, migratedFrom } = normalizeCodexChatGptModel(spec.slice(idx + 1));
|
|
81
|
+
return migratedFrom ? `${provider}:${model}` : spec;
|
|
82
|
+
}
|
|
83
|
+
/** Map legacy/unsupported Codex CLI model ids to a ChatGPT-plan-safe default. */
|
|
84
|
+
export function normalizeCodexChatGptModel(model) {
|
|
85
|
+
const trimmed = model.trim();
|
|
86
|
+
if (!trimmed || !CODEX_CHATGPT_UNSUPPORTED_MODELS.has(trimmed)) {
|
|
87
|
+
return { model: trimmed };
|
|
88
|
+
}
|
|
89
|
+
return { model: 'gpt-5.5', migratedFrom: trimmed };
|
|
90
|
+
}
|
|
91
|
+
function extractCodexErrorMessage(raw) {
|
|
92
|
+
const t = raw.trim();
|
|
93
|
+
if (!t)
|
|
94
|
+
return '';
|
|
95
|
+
try {
|
|
96
|
+
const outer = JSON.parse(t);
|
|
97
|
+
const nested = typeof outer.message === 'string' ? outer.message : '';
|
|
98
|
+
if (nested.startsWith('{')) {
|
|
99
|
+
try {
|
|
100
|
+
const inner = JSON.parse(nested);
|
|
101
|
+
return inner.error?.message ?? inner.message ?? nested;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return nested;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return outer.error?.message ?? outer.message ?? t;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return t;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
50
113
|
/**
|
|
51
114
|
* รัน `codex exec` แบบ non-interactive — ส่ง prompt ทาง stdin, parse JSONL events
|
|
52
115
|
* tolerant ต่อ malformed JSONL (codex bug #15451: --json ถูก ignore เมื่อมี tools active)
|
|
@@ -69,6 +132,7 @@ export async function runCodex(opts) {
|
|
|
69
132
|
let threadId;
|
|
70
133
|
let buf = '';
|
|
71
134
|
let stderr = '';
|
|
135
|
+
let jsonlError = '';
|
|
72
136
|
let aborted = false;
|
|
73
137
|
const handleStdoutLine = (line) => {
|
|
74
138
|
const t = line.trim();
|
|
@@ -93,6 +157,13 @@ export async function runCodex(opts) {
|
|
|
93
157
|
else if (ev.type === 'turn.completed') {
|
|
94
158
|
opts.onEvent?.({ type: 'usage', usage: ev.usage });
|
|
95
159
|
}
|
|
160
|
+
else if (ev.type === 'error' || ev.type === 'turn.failed') {
|
|
161
|
+
const msg = extractCodexErrorMessage(ev.message ?? ev.error?.message ?? t);
|
|
162
|
+
if (msg) {
|
|
163
|
+
jsonlError = msg;
|
|
164
|
+
opts.onEvent?.({ type: 'error', message: msg });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
96
167
|
}
|
|
97
168
|
catch {
|
|
98
169
|
// malformed JSON line — ข้าม
|
|
@@ -139,8 +210,10 @@ export async function runCodex(opts) {
|
|
|
139
210
|
reject(new Error(`codex exec ถูกยกเลิก${stderr.trim() ? `: ${stderr.trim()}` : ''}`));
|
|
140
211
|
else if (code === 0)
|
|
141
212
|
resolve({ text: finalText.trim(), threadId });
|
|
142
|
-
else
|
|
143
|
-
|
|
213
|
+
else {
|
|
214
|
+
const detail = jsonlError.trim() || stderr.trim();
|
|
215
|
+
reject(new Error(`codex exec จบด้วย exit code ${code}${detail ? `: ${detail}` : ''}`));
|
|
216
|
+
}
|
|
144
217
|
});
|
|
145
218
|
});
|
|
146
219
|
}
|
package/dist/providers/models.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
import { isCodexChatGptSupportedModel, normalizeCodexChatGptModel } from './codex.js';
|
|
2
|
+
function curatedModels(cfg) {
|
|
3
|
+
if (cfg.id !== 'codex')
|
|
4
|
+
return cfg.models;
|
|
5
|
+
const out = {};
|
|
6
|
+
for (const [alias, id] of Object.entries(cfg.models)) {
|
|
7
|
+
const model = normalizeCodexChatGptModel(id).model;
|
|
8
|
+
if (isCodexChatGptSupportedModel(model))
|
|
9
|
+
out[alias] = model;
|
|
10
|
+
}
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
1
13
|
/**
|
|
2
14
|
* ดึงรายชื่อ model จริงจาก provider (GET /models) — "เลือกโมเดลที่เจ้าของมี" แบบ Hermes
|
|
3
15
|
* - provider เป็นคน authoritative เรื่อง id (เราไม่ต้อง hardcode/เดา id ที่อาจ stale)
|
|
@@ -48,11 +60,12 @@ export async function listRemoteModels(cfg, key, timeoutMs = 6000) {
|
|
|
48
60
|
* → ตัวเลือกโผล่ซ้ำ/หาย (bug "มีตัวเลือกสองตัวเลือกเป็น model เดียวกัน"). ใช้ทั้ง setup wizard และ /model picker
|
|
49
61
|
*/
|
|
50
62
|
export function mergeModelOptions(cfg, remote = []) {
|
|
63
|
+
const models = curatedModels(cfg);
|
|
51
64
|
// group alias ทั้งหมดตาม id (รวม 'default' ด้วย — กัน id ที่มีแต่ alias 'default' เช่น lmstudio:local-model,
|
|
52
65
|
// ollama:llama3.3 หายไปจนเลือกไม่ได้/Select ว่าง). ตอนทำ label ค่อยซ่อนคำ "default" ถ้ามีชื่ออื่นอยู่แล้ว
|
|
53
66
|
const aliasesById = new Map();
|
|
54
67
|
const order = []; // คง first-seen order ของ id
|
|
55
|
-
for (const [alias, id] of Object.entries(
|
|
68
|
+
for (const [alias, id] of Object.entries(models)) {
|
|
56
69
|
if (!aliasesById.has(id)) {
|
|
57
70
|
aliasesById.set(id, []);
|
|
58
71
|
order.push(id);
|
|
@@ -66,6 +79,8 @@ export function mergeModelOptions(cfg, remote = []) {
|
|
|
66
79
|
return { id, label: `${shown.join(' / ')} — ${id}` };
|
|
67
80
|
});
|
|
68
81
|
const seen = new Set(order);
|
|
69
|
-
const extra =
|
|
82
|
+
const extra = cfg.id === 'codex'
|
|
83
|
+
? []
|
|
84
|
+
: [...new Set(remote)].filter((id) => id && !seen.has(id)).map((id) => ({ id, label: id }));
|
|
70
85
|
return [...curated, ...extra].map((o) => ({ label: o.label, value: o.id }));
|
|
71
86
|
}
|
|
@@ -6,6 +6,7 @@ import { createMistral } from '@ai-sdk/mistral';
|
|
|
6
6
|
import { createGroq } from '@ai-sdk/groq';
|
|
7
7
|
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
8
8
|
import { resolveKeyFromEnv, assertDirectApiKey } from './keys.js';
|
|
9
|
+
import { CODEX_CHATGPT_MODEL_ALIASES, normalizeCodexChatGptModel } from './codex.js';
|
|
9
10
|
import { BRAND } from '../brand.js';
|
|
10
11
|
// ────────────────────────────────────────────────────────────────────────────
|
|
11
12
|
// PROVIDER TABLE — เพิ่มค่าย = เพิ่ม 1 entry (loop/cost/keys ไม่ต้องแตะ)
|
|
@@ -134,21 +135,11 @@ export const PROVIDERS = {
|
|
|
134
135
|
requiresKey: false,
|
|
135
136
|
localPlaceholderKey: 'codex',
|
|
136
137
|
keyFormat: null,
|
|
137
|
-
models: {
|
|
138
|
-
default: 'gpt-5.5',
|
|
139
|
-
codex: 'gpt-5.5',
|
|
140
|
-
'5.5': 'gpt-5.5',
|
|
141
|
-
'5.4': 'gpt-5.4',
|
|
142
|
-
'5.4-mini': 'gpt-5.4-mini',
|
|
143
|
-
'5.3-codex': 'gpt-5.3-codex',
|
|
144
|
-
'5.2-codex': 'gpt-5.2-codex',
|
|
145
|
-
'5-codex': 'gpt-5-codex',
|
|
146
|
-
spark: 'gpt-5.3-codex-spark',
|
|
147
|
-
},
|
|
138
|
+
models: { ...CODEX_CHATGPT_MODEL_ALIASES },
|
|
148
139
|
create: () => {
|
|
149
140
|
throw new Error('codex เป็น delegate provider — ใช้ผ่าน codex subprocess ไม่ใช่ Vercel AI SDK');
|
|
150
141
|
},
|
|
151
|
-
note: '
|
|
142
|
+
note: 'ChatGPT plan ผ่าน codex CLI — รองรับ gpt-5.5 / gpt-5.4 / gpt-5.4-mini เท่านั้น (ต้อง codex login)',
|
|
152
143
|
},
|
|
153
144
|
};
|
|
154
145
|
export const SUPPORTED_PROVIDERS = Object.keys(PROVIDERS);
|
|
@@ -177,7 +168,9 @@ export function parseSpec(spec) {
|
|
|
177
168
|
const rest = spec.slice(idx + 1);
|
|
178
169
|
const cfg = PROVIDERS[provider];
|
|
179
170
|
// ถ้าเป็น alias ของ provider นั้น → map เป็น model id จริง, ไม่งั้นใช้ rest เป็น raw model id
|
|
180
|
-
|
|
171
|
+
let model = cfg?.models[rest] ?? rest;
|
|
172
|
+
if (provider === 'codex')
|
|
173
|
+
model = normalizeCodexChatGptModel(model).model;
|
|
181
174
|
return { provider, model };
|
|
182
175
|
}
|
|
183
176
|
const g = GLOBAL_ALIAS[spec];
|
package/dist/ui/setup.js
CHANGED
|
@@ -35,11 +35,10 @@ export function SetupWizard({ onComplete }) {
|
|
|
35
35
|
const providerOptions = setupProviderOptions();
|
|
36
36
|
const providerMenuLines = setupProviderMenuLines();
|
|
37
37
|
const advanceIfCodexReady = (status) => {
|
|
38
|
-
if (!status.loggedIn)
|
|
38
|
+
if (!status.loggedIn || !status.installed)
|
|
39
39
|
return;
|
|
40
40
|
setModel(`codex:${PROVIDERS.codex.models.default}`);
|
|
41
|
-
|
|
42
|
-
setStep('agent');
|
|
41
|
+
setStep('model');
|
|
43
42
|
};
|
|
44
43
|
// codex-auth: เช็ก codex CLI ติดตั้ง + login ChatGPT (re-run เมื่อกด "เช็กใหม่")
|
|
45
44
|
useEffect(() => {
|
|
@@ -220,7 +219,7 @@ export function SetupWizard({ onComplete }) {
|
|
|
220
219
|
setKeyError('');
|
|
221
220
|
}, onSubmit: submitKey }), keyError ? _jsxs(Text, { color: "red", children: [" \u2717 ", keyError] }) : null] })), step === 'model' &&
|
|
222
221
|
cfg &&
|
|
223
|
-
(loadingModels ? (_jsxs(Text, { color: "gray", children: [' ', m.modelLoading, " ", cfg.label, "\u2026"] })) : (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [m.stepModel, " \u2014 ", m.modelPick, remote.length ? _jsxs(Text, { color: "gray", children: [" (", modelOptions.length, ")"] }) : null, ":"] }), _jsx(Select, { options: modelOptions, onChange: (v) => {
|
|
222
|
+
(loadingModels ? (_jsxs(Text, { color: "gray", children: [' ', m.modelLoading, " ", cfg.label, "\u2026"] })) : (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [m.stepModel, " \u2014 ", m.modelPick, remote.length ? _jsxs(Text, { color: "gray", children: [" (", modelOptions.length, ")"] }) : null, ":"] }), provider === 'codex' ? _jsxs(Text, { color: "gray", children: [" ", m.codexModelHint] }) : null, _jsx(Select, { options: modelOptions, onChange: (v) => {
|
|
224
223
|
setModel(`${provider}:${v}`);
|
|
225
224
|
setStep('agent');
|
|
226
225
|
} })] }))), step === 'agent' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: m.stepAgent }), _jsx(Text, { color: "gray", children: m.agentTitle }), _jsx(Select, { options: [
|
package/package.json
CHANGED