lingyao-ai 0.2.0 → 0.2.2

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 CHANGED
@@ -5,7 +5,9 @@ A customizable setup CLI that behaves like `npx leishen-ai`, with your own confi
5
5
  ## Features
6
6
 
7
7
  - Configure Codex and/or Claude Code in one interactive flow.
8
+ - Prompt for gateway URL first, then API key, with a config default.
8
9
  - Optional auto-install checks for `@openai/codex` and `@anthropic-ai/claude-code`.
10
+ - API key validation supports `sk-` and `cr_` formats.
9
11
  - Writes and backs up:
10
12
  - `~/.claude/config.json`
11
13
  - `~/.codex/config.toml`
@@ -51,3 +53,7 @@ Then users can run:
51
53
  ```bash
52
54
  npx lingyao-ai
53
55
  ```
56
+
57
+ During setup, the CLI will ask for a gateway URL first. Press Enter to use
58
+ `project.config.json`'s default `endpoints.baseOrigin`, or enter a different
59
+ `http://` / `https://` URL before providing the API key.
package/cli.js CHANGED
@@ -257,6 +257,32 @@ async function promptApiKey(apiKeyRegex, example) {
257
257
  }
258
258
  }
259
259
 
260
+ function isValidHttpUrl(value) {
261
+ try {
262
+ const parsed = new URL(String(value || '').trim())
263
+ return parsed.protocol === 'http:' || parsed.protocol === 'https:'
264
+ } catch (_) {
265
+ return false
266
+ }
267
+ }
268
+
269
+ function normalizeBaseOrigin(value) {
270
+ return String(value || '').trim().replace(/\/+$/, '')
271
+ }
272
+
273
+ async function promptBaseOrigin(defaultBaseOrigin) {
274
+ const fallback = normalizeBaseOrigin(defaultBaseOrigin)
275
+
276
+ while (true) {
277
+ const answer = await askLine(
278
+ fallback ? `Input gateway URL [${fallback}]: ` : 'Input gateway URL: '
279
+ )
280
+ const baseOrigin = normalizeBaseOrigin(answer || fallback)
281
+ if (isValidHttpUrl(baseOrigin)) return baseOrigin
282
+ console.log('Invalid URL. Use http:// or https://')
283
+ }
284
+ }
285
+
260
286
  async function promptTargets() {
261
287
  while (true) {
262
288
  console.log('\nSelect target:')
@@ -684,8 +710,8 @@ function tomlString(value) {
684
710
  return String(value).replace(/\\/g, '\\\\').replace(/"/g, '\\"')
685
711
  }
686
712
 
687
- function renderCodexToml(cfg) {
688
- const codexBaseUrl = joinUrl(cfg.endpoints.baseOrigin, cfg.endpoints.codexPath)
713
+ function renderCodexToml(cfg, baseOrigin) {
714
+ const codexBaseUrl = joinUrl(baseOrigin, cfg.endpoints.codexPath)
689
715
  const provider = cfg.codex.providerName
690
716
  const migrations = Object.entries(cfg.codex.modelMigrations || {})
691
717
  const migrationSection =
@@ -713,11 +739,11 @@ requires_openai_auth = ${cfg.codex.requiresOpenAIAuth ? 'true' : 'false'}
713
739
  env_key = "${tomlString(cfg.apiKey.envKey)}"${envInstructionLine}${migrationSection}`
714
740
  }
715
741
 
716
- function configureClaude(cfg, apiKey) {
742
+ function configureClaude(cfg, apiKey, baseOrigin) {
717
743
  const home = os.homedir()
718
744
  const claudeConfigPath = path.join(home, cfg.claude.configPath)
719
745
  const info = writeJson(claudeConfigPath, { primaryApiKey: cfg.claude.primaryApiKey })
720
- const claudeBaseUrl = joinUrl(cfg.endpoints.baseOrigin, cfg.endpoints.claudePath)
746
+ const claudeBaseUrl = joinUrl(baseOrigin, cfg.endpoints.claudePath)
721
747
 
722
748
  return {
723
749
  env: {
@@ -734,14 +760,14 @@ function configureClaude(cfg, apiKey) {
734
760
  }
735
761
  }
736
762
 
737
- function configureCodex(cfg, apiKey) {
763
+ function configureCodex(cfg, apiKey, baseOrigin) {
738
764
  const home = os.homedir()
739
765
  const codexDir = path.join(home, cfg.codex.configDir)
740
766
  const tomlPath = path.join(codexDir, 'config.toml')
741
767
  const authPath = path.join(codexDir, 'auth.json')
742
768
  const envPath = path.join(codexDir, '.env')
743
769
 
744
- const tomlInfo = writeText(tomlPath, renderCodexToml(cfg))
770
+ const tomlInfo = writeText(tomlPath, renderCodexToml(cfg, baseOrigin))
745
771
  const authInfo = writeJson(authPath, cfg.codex.authJson || { OPENAI_API_KEY: null })
746
772
  const envInfo = upsertDotenvFile(envPath, { [cfg.apiKey.envKey]: apiKey })
747
773
 
@@ -775,8 +801,9 @@ async function main() {
775
801
 
776
802
  console.log(`\n${cfg.brand.name}`)
777
803
  console.log(`Config file: ${configPath}`)
778
- console.log(`Base origin: ${cfg.endpoints.baseOrigin}`)
779
804
 
805
+ const baseOrigin = await promptBaseOrigin(cfg.endpoints.baseOrigin)
806
+ console.log(`Using gateway URL: ${baseOrigin}`)
780
807
  const apiKeyRegex = new RegExp(cfg.apiKey.regex)
781
808
  const apiKey = await promptApiKey(apiKeyRegex, cfg.apiKey.example)
782
809
  const targets = await promptTargets()
@@ -811,13 +838,13 @@ async function main() {
811
838
  const fileSummaries = []
812
839
 
813
840
  if (targets.includes('claude')) {
814
- const result = configureClaude(cfg, apiKey)
841
+ const result = configureClaude(cfg, apiKey, baseOrigin)
815
842
  envVars = { ...envVars, ...result.env }
816
843
  fileSummaries.push(...result.files)
817
844
  }
818
845
 
819
846
  if (targets.includes('codex')) {
820
- const result = configureCodex(cfg, apiKey)
847
+ const result = configureCodex(cfg, apiKey, baseOrigin)
821
848
  envVars = { ...envVars, ...result.env }
822
849
  fileSummaries.push(...result.files)
823
850
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lingyao-ai",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Lingyao setup CLI for Codex and Claude Code.",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -4,8 +4,8 @@
4
4
  "shellMarker": "lingyao-ai"
5
5
  },
6
6
  "apiKey": {
7
- "regex": "^cr_[0-9a-f]{64}$",
8
- "example": "cr_<64_hex>",
7
+ "regex": "^(?:sk-[A-Za-z0-9]{48}|cr_[0-9a-fA-F]{64})$",
8
+ "example": "sk-<48_alnum> or cr_<64_hex>",
9
9
  "envKey": "CRS_OAI_KEY"
10
10
  },
11
11
  "endpoints": {