@yhotamos/enja-cli 1.4.3 → 1.5.3
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/LICENSE +21 -21
- package/README.md +102 -102
- package/dist/index.js +29 -29
- package/package.json +62 -62
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 yhotta240
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 yhotta240
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
# Enja CLI
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-

|
|
5
|
-

|
|
6
|
-
|
|
7
|
-
英語を日本語に翻訳するシンプルなコマンドラインツール
|
|
8
|
-
|
|
9
|
-
## 特徴
|
|
10
|
-
|
|
11
|
-
- セットアップ不要で,インストール後すぐに利用可能
|
|
12
|
-
- Google Apps Script の LanguageApp を使用した軽量な翻訳
|
|
13
|
-
- 引数,標準入力(パイプ),ファイル入力に幅広く対応
|
|
14
|
-
- HTML タグを除去して Web コンテンツもそのまま翻訳
|
|
15
|
-
- OpenAI, Gemini, LM Studio などの各種 API による高品質な翻訳
|
|
16
|
-
- 英日・日英の翻訳方向の切り替えが可能
|
|
17
|
-
- 翻訳履歴の保存やプロファイル機能による複数 API の切り替えが可能
|
|
18
|
-
|
|
19
|
-
## インストール
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install -g @yhotamos/enja-cli
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## 使い方
|
|
26
|
-
|
|
27
|
-
### 基本的な使い方
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
# 引数で渡された文字列を翻訳
|
|
31
|
-
enja "Hello, world!"
|
|
32
|
-
|
|
33
|
-
# パイプで翻訳
|
|
34
|
-
echo "Hello, world!" | enja
|
|
35
|
-
|
|
36
|
-
# ファイルから読み込み
|
|
37
|
-
enja -f input.txt -o output.txt
|
|
38
|
-
|
|
39
|
-
# 翻訳方向を逆にする (日本語 → 英語)
|
|
40
|
-
enja "こんにちは" -F
|
|
41
|
-
|
|
42
|
-
# OpenAI API を一時的に使用して翻訳
|
|
43
|
-
enja "Hello, world!" --provider openai --api-key YOUR_OPENAI_API_KEY
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### 履歴と設定
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
# 翻訳履歴を表示
|
|
50
|
-
enja history
|
|
51
|
-
|
|
52
|
-
# 設定を表示/追加/アクティブ化
|
|
53
|
-
enja config
|
|
54
|
-
enja config add work --provider gemini --api-key YOUR_GEMINI_API_KEY --model gemini-2.5-flash
|
|
55
|
-
enja config use work
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### 実用例
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
# エラーメッセージの翻訳
|
|
62
|
-
npm install nonexistent-package 2>&1 | enja
|
|
63
|
-
|
|
64
|
-
# コマンドのヘルプを日本語化
|
|
65
|
-
docker --help | enja
|
|
66
|
-
|
|
67
|
-
# 英語で書かれたドキュメントを日本語に翻訳
|
|
68
|
-
enja -f README.md -o README.ja.md
|
|
69
|
-
|
|
70
|
-
# Webページの本文を翻訳(HTMLタグ除去)
|
|
71
|
-
curl -s https://example.com | enja -s
|
|
72
|
-
|
|
73
|
-
# APIドキュメントなどテキストコンテンツの翻訳
|
|
74
|
-
curl -s https://example.com/api/docs | enja
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## コマンド
|
|
78
|
-
|
|
79
|
-
[COMMANDS.md](docs/COMMANDS.md) を参照してください.
|
|
80
|
-
|
|
81
|
-
## セキュリティとプライバシー
|
|
82
|
-
|
|
83
|
-
### デフォルトプロバイダー(GAS)使用時
|
|
84
|
-
|
|
85
|
-
- 翻訳データは保存されません(その場で処理され,すぐに結果が返ります)
|
|
86
|
-
- 公開エンドポイントを使用しているため,機密情報の翻訳は避けてください
|
|
87
|
-
|
|
88
|
-
### その他のプロバイダー使用時
|
|
89
|
-
|
|
90
|
-
OpenAI,Gemini,LM Studio などを使用する場合は,各サービスのプライバシーポリシーに従います.
|
|
91
|
-
プロバイダーによっては,入力データが保存されたり,学習に利用されることがありますので,注意してください.
|
|
92
|
-
|
|
93
|
-
## 貢献
|
|
94
|
-
|
|
95
|
-
バグ報告や機能リクエストは [GitHub Issues](https://github.com/yhotamos/enja-cli/issues) へお願いします.
|
|
96
|
-
|
|
97
|
-
## 作者
|
|
98
|
-
|
|
99
|
-
yhotta240
|
|
100
|
-
|
|
101
|
-
- Email: yhotta240@gmail.com
|
|
102
|
-
- GitHub: [@yhotta240](https://github.com/yhotta240)
|
|
1
|
+
# Enja CLI
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
英語を日本語に翻訳するシンプルなコマンドラインツール
|
|
8
|
+
|
|
9
|
+
## 特徴
|
|
10
|
+
|
|
11
|
+
- セットアップ不要で,インストール後すぐに利用可能
|
|
12
|
+
- Google Apps Script の LanguageApp を使用した軽量な翻訳
|
|
13
|
+
- 引数,標準入力(パイプ),ファイル入力に幅広く対応
|
|
14
|
+
- HTML タグを除去して Web コンテンツもそのまま翻訳
|
|
15
|
+
- OpenAI, Gemini, LM Studio などの各種 API による高品質な翻訳
|
|
16
|
+
- 英日・日英の翻訳方向の切り替えが可能
|
|
17
|
+
- 翻訳履歴の保存やプロファイル機能による複数 API の切り替えが可能
|
|
18
|
+
|
|
19
|
+
## インストール
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g @yhotamos/enja-cli
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 使い方
|
|
26
|
+
|
|
27
|
+
### 基本的な使い方
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# 引数で渡された文字列を翻訳
|
|
31
|
+
enja "Hello, world!"
|
|
32
|
+
|
|
33
|
+
# パイプで翻訳
|
|
34
|
+
echo "Hello, world!" | enja
|
|
35
|
+
|
|
36
|
+
# ファイルから読み込み
|
|
37
|
+
enja -f input.txt -o output.txt
|
|
38
|
+
|
|
39
|
+
# 翻訳方向を逆にする (日本語 → 英語)
|
|
40
|
+
enja "こんにちは" -F
|
|
41
|
+
|
|
42
|
+
# OpenAI API を一時的に使用して翻訳
|
|
43
|
+
enja "Hello, world!" --provider openai --api-key YOUR_OPENAI_API_KEY
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 履歴と設定
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# 翻訳履歴を表示
|
|
50
|
+
enja history
|
|
51
|
+
|
|
52
|
+
# 設定を表示/追加/アクティブ化
|
|
53
|
+
enja config
|
|
54
|
+
enja config add work --provider gemini --api-key YOUR_GEMINI_API_KEY --model gemini-2.5-flash
|
|
55
|
+
enja config use work
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 実用例
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# エラーメッセージの翻訳
|
|
62
|
+
npm install nonexistent-package 2>&1 | enja
|
|
63
|
+
|
|
64
|
+
# コマンドのヘルプを日本語化
|
|
65
|
+
docker --help | enja
|
|
66
|
+
|
|
67
|
+
# 英語で書かれたドキュメントを日本語に翻訳
|
|
68
|
+
enja -f README.md -o README.ja.md
|
|
69
|
+
|
|
70
|
+
# Webページの本文を翻訳(HTMLタグ除去)
|
|
71
|
+
curl -s https://example.com | enja -s
|
|
72
|
+
|
|
73
|
+
# APIドキュメントなどテキストコンテンツの翻訳
|
|
74
|
+
curl -s https://example.com/api/docs | enja
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## コマンド
|
|
78
|
+
|
|
79
|
+
[COMMANDS.md](docs/COMMANDS.md) を参照してください.
|
|
80
|
+
|
|
81
|
+
## セキュリティとプライバシー
|
|
82
|
+
|
|
83
|
+
### デフォルトプロバイダー(GAS)使用時
|
|
84
|
+
|
|
85
|
+
- 翻訳データは保存されません(その場で処理され,すぐに結果が返ります)
|
|
86
|
+
- 公開エンドポイントを使用しているため,機密情報の翻訳は避けてください
|
|
87
|
+
|
|
88
|
+
### その他のプロバイダー使用時
|
|
89
|
+
|
|
90
|
+
OpenAI,Gemini,LM Studio などを使用する場合は,各サービスのプライバシーポリシーに従います.
|
|
91
|
+
プロバイダーによっては,入力データが保存されたり,学習に利用されることがありますので,注意してください.
|
|
92
|
+
|
|
93
|
+
## 貢献
|
|
94
|
+
|
|
95
|
+
バグ報告や機能リクエストは [GitHub Issues](https://github.com/yhotamos/enja-cli/issues) へお願いします.
|
|
96
|
+
|
|
97
|
+
## 作者
|
|
98
|
+
|
|
99
|
+
yhotta240
|
|
100
|
+
|
|
101
|
+
- Email: yhotta240@gmail.com
|
|
102
|
+
- GitHub: [@yhotta240](https://github.com/yhotta240)
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import*as E from'fs';import {readFileSync,promises}from'fs';import {Command}from'commander';import g from'kleur';import {select,confirm}from'@inquirer/prompts';import*as _ from'os';import*as $ from'path';import {GoogleGenAI,ApiError}from'@google/genai';import W from'openai';import {randomUUID,createHash}from'crypto';import Dt from'ora';async function F(o,t){let r=o.map(e=>({name:e===t?g.green(`${e} (active)`):e,value:e}));try{return await select({message:"\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",choices:r})}catch{throw new Error("\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u9078\u629E\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F")}}async function K(o){try{if(!await confirm({message:`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${o}' \u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F`}))return console.log("\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u524A\u9664\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F"),!1}catch{throw new Error("\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u524A\u9664\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F")}return true}function T(){if(process.platform==="win32"){let r=process.env.APPDATA||$.join(_.homedir(),"AppData","Roaming");if(!r)throw new Error("APPDATA \u74B0\u5883\u5909\u6570\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u304A\u3089\u305A\uFF0C\u4EE3\u66FF\u30D1\u30B9\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F");return $.join(r,"enja-cli")}let t=_.homedir();return $.join(t,".config","enja-cli")}function Y(){return $.join(T(),"history.json")}function z(){return $.join(T(),"config.json")}var C=class{static getDefaultProfile(){return {provider:"custom"}}apiUrl;apiKey;model;constructor(t,r,e){this.apiUrl=t,this.apiKey=r,this.model=e;}getModel(){return this.model||null}async translate(t,r,e){let i={"Content-Type":"application/json",Accept:"application/json"};this.apiKey&&(i.Authorization=`Bearer ${this.apiKey}`);let a=await fetch(this.apiUrl,{method:"POST",headers:i,body:JSON.stringify({text:t,sourceLang:r,targetLang:e,...this.model?{model:this.model}:{}})}),n=await a.text();if(!a.ok){let l;try{let c=JSON.parse(n);if(this.isRecord(c)){let f=this.asString(c.error)??(this.isRecord(c.error)?this.asString(c.error.message):null)??this.asString(c.message);f&&(l=f);}}catch{}throw new Error(`Custom: HTTP ${a.status} ${a.statusText}${l?` - ${l}`:""}`)}let p;try{p=JSON.parse(n);}catch{if(n.trim())return {text:n.trim(),detectedSourceLang:r};throw new Error("Custom: \u30EC\u30B9\u30DD\u30F3\u30B9\u306E JSON \u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F")}let s=this.extractText(p);if(s)return {text:s.trim(),detectedSourceLang:r};throw new Error("Custom: \u30EC\u30B9\u30DD\u30F3\u30B9\u304B\u3089\u7FFB\u8A33\u30C6\u30AD\u30B9\u30C8\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F")}extractText(t){if(!this.isRecord(t))return null;if(Array.isArray(t.choices)&&t.choices.length>0){let r=t.choices[0];if(this.isRecord(r)){let e=(this.isRecord(r.message)?this.asString(r.message.content):null)??this.asString(r.text);if(e)return e}}if(Array.isArray(t.output))for(let r of t.output){let e=this.extractFromItem(r);if(e)return e}if(Array.isArray(t.results)&&t.results.length>0){let r=t.results[0];if(this.isRecord(r)){let e=this.asString(r.content)??this.asString(r.text);if(e)return e}}return this.asString(t.translation)??this.asString(t.translated_text)??this.asString(t.translatedText)??this.asString(t.result)??this.asString(t.text)??this.asString(t.content)??this.asString(t.response)??this.asString(t.output)??null}extractFromItem(t){if(typeof t=="string")return t||null;if(!this.isRecord(t))return null;if(t.type==="message"||t.type==="text"){let r=this.asString(t.content)??this.asString(t.text);if(r)return r}return this.asString(t.content)??this.asString(t.text)??this.asString(t.response)??null}isRecord(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}asString(t){return typeof t=="string"&&t.length>0?t:null}};var x=class o{static DEFAULT_ENDPOINT="https://script.google.com/macros/s/AKfycbxOSbKD0aBTaQqIzHv00BMzp6WwrtWHBU3gJY0vhB2HblgUO-cgesfT1l-rrfttnWZzew/exec";static ENDPOINT_URL_PATTERN=/^https:\/\/script\.google\.com\/macros\/s\/[a-zA-Z0-9_-]+\/(exec|dev)(\?.*)?$/;static getDefaultProfile(){return {provider:"gas",endpoint:o.DEFAULT_ENDPOINT}}apiUrl;apiKey;constructor(t=o.DEFAULT_ENDPOINT,r){if(!o.ENDPOINT_URL_PATTERN.test(t))throw new Error("\u7121\u52B9\u306A GAS \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u3067\u3059");this.apiUrl=t,this.apiKey=r;}getModel(){return null}async translate(t,r,e){let i={"Content-Type":"application/json"};this.apiKey&&(i.Authorization=`Bearer ${this.apiKey}`);let a=await fetch(this.apiUrl,{method:"POST",headers:i,body:JSON.stringify({text:t,sourceLang:r,targetLang:e})});if(!a.ok)throw new Error(`HTTP ${a.status} ${a.statusText}`);let n=await a.json();if(n.code!==200||!n.translatedText)throw new Error(`${n.error||"\u7FFB\u8A33\u306B\u5931\u6557\u3057\u307E\u3057\u305F"}`);return {text:n.translatedText,detectedSourceLang:n.detectedSourceLang}}};var A=class o{static DEFAULT_MODEL="gemini-2.5-flash-lite";static getDefaultProfile(){return {provider:"gemini",model:o.DEFAULT_MODEL}}client;model;constructor(t,r=o.DEFAULT_MODEL){this.client=new GoogleGenAI({apiKey:t}),this.model=r;}getModel(){return this.model}async translate(t,r,e){try{let i=this.mapLanguageCode(r),a=this.mapLanguageCode(e),n=`You are a professional translator. Translate the following text from ${i} to ${a}. Only return the translated text without any additional explanation or comments.`,s=(await this.client.models.generateContent({model:this.model,contents:t,config:{systemInstruction:n}})).text;if(!s)throw new Error("\u7FFB\u8A33\u306B\u5931\u6557\u3057\u307E\u3057\u305F");return {text:s.trim(),detectedSourceLang:r}}catch(i){if(i instanceof ApiError){let a=JSON.parse(i.message).error.message;throw new Error(`Gemini\u7FFB\u8A33API\u30A8\u30E9\u30FC: ${a}`)}else if(i instanceof Error)throw new Error(`Gemini\u7FFB\u8A33\u30A8\u30E9\u30FC: ${i.message}`);throw i}}mapLanguageCode(t){return {en:"English",ja:"Japanese"}[t.toLowerCase()]||t}};var P=class o{static DEFAULT_ENDPOINT="http://localhost:1234/api/v1/chat";static getDefaultProfile(){return {provider:"lmstudio",endpoint:o.DEFAULT_ENDPOINT}}baseUrl;model;apiKey;constructor(t=o.DEFAULT_ENDPOINT,r,e){this.baseUrl=t,this.model=r,this.apiKey=e;}getModel(){return this.model||null}async translate(t,r,e){let i=`You are a professional translator. Translate the following text from ${r} to ${e}. Only return the translated text without any additional explanation.`,a=this.resolveEndpoint(this.baseUrl),n={"Content-Type":"application/json",Accept:"application/json",...this.apiKey?{Authorization:`Bearer ${this.apiKey}`}:{}},p=JSON.stringify({model:this.model,system_prompt:i,input:t}),s=await fetch(a.toString(),{method:"POST",headers:n,body:p}),l=await s.text(),c=this.parseJsonSafe(l,s);if(!s.ok){if(c?.error){if(typeof c.error=="string")throw new Error(`LMStudio: ${c.error}`);let{message:d,code:u}=c.error;if(u==="model_not_found")throw new Error(`LMStudio: \u30E2\u30C7\u30EB "${this.model}" \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u30E2\u30C7\u30EB\u540D\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);if(u==="invalid_api_key")throw new Error("LMStudio: API\u30AD\u30FC\u304C\u7121\u52B9\u3067\u3059\u3002API \u30AD\u30FC\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002");let v=d||"LMStudio: \u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F";throw new Error(v)}throw new Error(`LMStudio: HTTP ${s.status} ${s.statusText}`)}let f=this.extractTranslatedFromOutput(c);if(f)return {text:f.trim(),detectedSourceLang:r};throw c?.error?new Error(`LMStudio: ${c.error||"\u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"}`):new Error("LMStudio: \u51FA\u529B\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093")}resolveEndpoint(t){let r;try{r=new URL(t);}catch{throw new Error("LMStudio: \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306E URL \u304C\u4E0D\u6B63\u3067\u3059\uFF08\u4F8B: http://localhost:1234/\uFF09")}let e=r.pathname.replace(/\/+$/,"");if(e===""||e==="/")r.pathname="/api/v1/chat";else if(e!=="/api/v1/chat")throw new Error('LMStudio: \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u306F "/api/v1/chat" \u3092\u542B\u3081\u308B\u304B\uFF0C\u30D1\u30B9\u3092\u7A7A\u306B\u3057\u3066\u304F\u3060\u3055\u3044');return r}parseJsonSafe(t,r){if(t)try{return JSON.parse(t)}catch{if(!r.ok){let e=t?`${t.slice(0,200)}...`:"";throw new Error(`LMStudio: \u975EJSON\u30EC\u30B9\u30DD\u30F3\u30B9 (HTTP ${r.status} ${r.statusText}) ${e}`)}throw new Error("LMStudio: \u30EC\u30B9\u30DD\u30F3\u30B9\u306E JSON \u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F")}}extractTranslatedFromOutput(t){if(!t||!Array.isArray(t.output)||t.output.length===0)return null;for(let r of t.output)if(r&&typeof r=="object"&&r.type==="message"){let e=this.extractFromItem(r);if(e)return e}for(let r of t.output){let e=this.extractFromItem(r);if(e)return e}return null}extractFromItem(t){if(!t&&t!=="")return null;if(typeof t=="string")return t;if(Array.isArray(t)){for(let r of t){let e=this.extractFromItem(r);if(e)return e}return null}if(typeof t=="object"){if(typeof t=="object"&&typeof t.text=="string")return t.text;if(typeof t=="object"&&typeof t.response=="string")return t.response;if(typeof t.content=="string")return t.content;if(t.content&&typeof t.content=="object"){let r=t.content;if(typeof r.text=="string")return r.text;if(typeof r.content=="string")return r.content;let e=this.extractFromItem(r);if(e)return e}if(Array.isArray(t.content))for(let r of t.content){let e=this.extractFromItem(r);if(e)return e}if(Array.isArray(t.output)){let r=this.extractTranslatedFromOutput({output:t.output});if(r)return r}}return null}};var L=class o{static DEFAULT_MODEL="gpt-4o-mini";static getDefaultProfile(){return {provider:"openai",model:o.DEFAULT_MODEL}}client;model;constructor(t,r=o.DEFAULT_MODEL){this.client=new W({apiKey:t}),this.model=r;}getModel(){return this.model}async translate(t,r,e){try{let i=this.mapLanguageCode(r),a=this.mapLanguageCode(e),n=`You are a professional translator. Translate the following text from ${i} to ${a}. Only return the translated text without any additional explanation or comments.`,s=(await this.client.chat.completions.create({model:this.model,messages:[{role:"system",content:n},{role:"user",content:t}],temperature:.3})).choices[0]?.message?.content;if(!s)throw new Error("\u7FFB\u8A33\u306B\u5931\u6557\u3057\u307E\u3057\u305F");return {text:s.trim(),detectedSourceLang:r}}catch(i){throw i instanceof W.APIError?new Error(`OpenAI\u7FFB\u8A33API\u30A8\u30E9\u30FC: ${i.message}`):i instanceof Error?new Error(`OpenAI\u7FFB\u8A33\u30A8\u30E9\u30FC: ${i.message}`):i}}mapLanguageCode(t){return {en:"English",ja:"Japanese"}[t.toLowerCase()]||t}};var X=["ls","list","use","rm","delete","add","rename","copy","provider","endpoint","api-key","model","default"];function R(o){if(X.includes(o.toLowerCase()))throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D '${o}' \u306F\u4E88\u7D04\u8A9E\u306E\u305F\u3081\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);if(!o.match(/^[a-zA-Z0-9_-]+$/))throw new Error(`\u7121\u52B9\u306A\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D (${o}): \u82F1\u6570\u5B57\uFF0C\u30CF\u30A4\u30D5\u30F3\uFF0C\u30A2\u30F3\u30C0\u30FC\u30B9\u30B3\u30A2\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059`)}var b="gas",j={gas:x.getDefaultProfile,openai:L.getDefaultProfile,gemini:A.getDefaultProfile,lmstudio:P.getDefaultProfile,custom:C.getDefaultProfile},Z={version:"1.1",activeProfile:"default",profiles:{default:j[b]()}},h=class o{filePath;constructor(){this.filePath=z();}async get(){return await this.readConfig()}async getActiveProfileName(){return (await this.readAppConfig()).activeProfile}async getProfile(t){let e=(await this.readAppConfig()).profiles[t];if(!e)throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093`);return e}async listProfiles(){let t=await this.readAppConfig();return Object.keys(t.profiles)}async useProfile(t){let r=await this.readAppConfig();if(!r.profiles[t]){let e=Object.keys(r.profiles).join(", ");throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
|
|
3
|
-
\u5229\u7528\u53EF\u80FD\u306A\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB: ${e}`)}r.activeProfile=t,await this.writeAppConfig(r);}async addProfile(t,r){if(
|
|
2
|
+
import*as v from'fs';import {readFileSync,promises}from'fs';import {Command}from'commander';import d from'kleur';import {select,confirm}from'@inquirer/prompts';import*as K from'os';import*as T from'path';import {GoogleGenAI,ApiError}from'@google/genai';import X from'openai';import {randomUUID,createHash}from'crypto';import Ot from'ora';async function N(o,t){let r=o.map(e=>({name:e===t?d.green(`${e} (active)`):e,value:e}));try{return await select({message:"\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",choices:r})}catch{throw new Error("\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u9078\u629E\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F")}}async function _(o){try{if(!await confirm({message:`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${o}' \u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F`}))return console.log("\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u524A\u9664\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F"),!1}catch{throw new Error("\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u524A\u9664\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F")}return true}function C(){if(process.platform==="win32"){let r=process.env.APPDATA||T.join(K.homedir(),"AppData","Roaming");if(!r)throw new Error("APPDATA \u74B0\u5883\u5909\u6570\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u304A\u3089\u305A\uFF0C\u4EE3\u66FF\u30D1\u30B9\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F");return T.join(r,"enja-cli")}let t=K.homedir();return T.join(t,".config","enja-cli")}function z(){return T.join(C(),"history.json")}function W(){return T.join(C(),"config.json")}var x=class{static getDefaultProfile(){return {provider:"custom"}}apiUrl;apiKey;model;constructor(t,r,e){this.apiUrl=t,this.apiKey=r,this.model=e;}getModel(){return this.model||null}async translate(t,r,e){let i={"Content-Type":"application/json",Accept:"application/json"};this.apiKey&&(i.Authorization=`Bearer ${this.apiKey}`);let s=await fetch(this.apiUrl,{method:"POST",headers:i,body:JSON.stringify({text:t,sourceLang:r,targetLang:e,...this.model?{model:this.model}:{}})}),n=await s.text();if(!s.ok){let l;try{let c=JSON.parse(n);if(this.isRecord(c)){let f=this.asString(c.error)??(this.isRecord(c.error)?this.asString(c.error.message):null)??this.asString(c.message);f&&(l=f);}}catch{}throw new Error(`Custom: HTTP ${s.status} ${s.statusText}${l?` - ${l}`:""}`)}let p;try{p=JSON.parse(n);}catch{if(n.trim())return {text:n.trim(),detectedSourceLang:r};throw new Error("Custom: \u30EC\u30B9\u30DD\u30F3\u30B9\u306E JSON \u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F")}let a=this.extractText(p);if(a)return {text:a.trim(),detectedSourceLang:r};throw new Error("Custom: \u30EC\u30B9\u30DD\u30F3\u30B9\u304B\u3089\u7FFB\u8A33\u30C6\u30AD\u30B9\u30C8\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F")}extractText(t){if(!this.isRecord(t))return null;if(Array.isArray(t.choices)&&t.choices.length>0){let r=t.choices[0];if(this.isRecord(r)){let e=(this.isRecord(r.message)?this.asString(r.message.content):null)??this.asString(r.text);if(e)return e}}if(Array.isArray(t.output))for(let r of t.output){let e=this.extractFromItem(r);if(e)return e}if(Array.isArray(t.results)&&t.results.length>0){let r=t.results[0];if(this.isRecord(r)){let e=this.asString(r.content)??this.asString(r.text);if(e)return e}}return this.asString(t.translation)??this.asString(t.translated_text)??this.asString(t.translatedText)??this.asString(t.result)??this.asString(t.text)??this.asString(t.content)??this.asString(t.response)??this.asString(t.output)??null}extractFromItem(t){if(typeof t=="string")return t||null;if(!this.isRecord(t))return null;if(t.type==="message"||t.type==="text"){let r=this.asString(t.content)??this.asString(t.text);if(r)return r}return this.asString(t.content)??this.asString(t.text)??this.asString(t.response)??null}isRecord(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}asString(t){return typeof t=="string"&&t.length>0?t:null}};var A=class o{static DEFAULT_ENDPOINT="https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec";static ENDPOINT_URL_PATTERN=/^https:\/\/script\.google\.com\/macros\/s\/[a-zA-Z0-9_-]+\/(exec|dev)(\?.*)?$/;static getDefaultProfile(){return {provider:"gas",endpoint:o.DEFAULT_ENDPOINT}}apiUrl;apiKey;constructor(t=o.DEFAULT_ENDPOINT,r){if(!o.ENDPOINT_URL_PATTERN.test(t))throw new Error("\u7121\u52B9\u306A GAS \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u3067\u3059");this.apiUrl=t,this.apiKey=r;}getModel(){return null}async translate(t,r,e){let i={"Content-Type":"application/json"};this.apiKey&&(i.Authorization=`Bearer ${this.apiKey}`);let s=await fetch(this.apiUrl,{method:"POST",headers:i,body:JSON.stringify({text:t,sourceLang:r,targetLang:e})});if(!s.ok)throw new Error(`HTTP ${s.status} ${s.statusText}`);let n=await s.json();if(n.code!==200||!n.translatedText)throw new Error(`${n.error||"\u7FFB\u8A33\u306B\u5931\u6557\u3057\u307E\u3057\u305F"}`);return {text:n.translatedText,detectedSourceLang:n.detectedSourceLang}}};var L=class o{static DEFAULT_MODEL="gemini-2.5-flash-lite";static getDefaultProfile(){return {provider:"gemini",model:o.DEFAULT_MODEL}}client;model;constructor(t,r=o.DEFAULT_MODEL){this.client=new GoogleGenAI({apiKey:t}),this.model=r;}getModel(){return this.model}async translate(t,r,e){try{let i=this.mapLanguageCode(r),s=this.mapLanguageCode(e),n=`You are a professional translator. Translate the following text from ${i} to ${s}. Only return the translated text without any additional explanation or comments.`,a=(await this.client.models.generateContent({model:this.model,contents:t,config:{systemInstruction:n}})).text;if(!a)throw new Error("\u7FFB\u8A33\u306B\u5931\u6557\u3057\u307E\u3057\u305F");return {text:a.trim(),detectedSourceLang:r}}catch(i){if(i instanceof ApiError){let s=JSON.parse(i.message).error.message;throw new Error(`Gemini\u7FFB\u8A33API\u30A8\u30E9\u30FC: ${s}`)}else if(i instanceof Error)throw new Error(`Gemini\u7FFB\u8A33\u30A8\u30E9\u30FC: ${i.message}`);throw i}}mapLanguageCode(t){return {en:"English",ja:"Japanese"}[t.toLowerCase()]||t}};var P=class o{static DEFAULT_ENDPOINT="http://localhost:1234/api/v1/chat";static getDefaultProfile(){return {provider:"lmstudio",endpoint:o.DEFAULT_ENDPOINT}}baseUrl;model;apiKey;constructor(t=o.DEFAULT_ENDPOINT,r,e){this.baseUrl=t,this.model=r,this.apiKey=e;}getModel(){return this.model||null}async translate(t,r,e){let i=`You are a professional translator. Translate the following text from ${r} to ${e}. Only return the translated text without any additional explanation.`,s=this.resolveEndpoint(this.baseUrl),n={"Content-Type":"application/json",Accept:"application/json",...this.apiKey?{Authorization:`Bearer ${this.apiKey}`}:{}},p=JSON.stringify({model:this.model,system_prompt:i,input:t}),a=await fetch(s.toString(),{method:"POST",headers:n,body:p}),l=await a.text(),c=this.parseJsonSafe(l,a);if(!a.ok){if(c?.error){if(typeof c.error=="string")throw new Error(`LMStudio: ${c.error}`);let{message:g,code:u}=c.error;if(u==="model_not_found")throw new Error(`LMStudio: \u30E2\u30C7\u30EB "${this.model}" \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u30E2\u30C7\u30EB\u540D\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);if(u==="invalid_api_key")throw new Error("LMStudio: API\u30AD\u30FC\u304C\u7121\u52B9\u3067\u3059\u3002API \u30AD\u30FC\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002");let $=g||"LMStudio: \u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F";throw new Error($)}throw new Error(`LMStudio: HTTP ${a.status} ${a.statusText}`)}let f=this.extractTranslatedFromOutput(c);if(f)return {text:f.trim(),detectedSourceLang:r};throw c?.error?new Error(`LMStudio: ${c.error||"\u4E0D\u660E\u306A\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"}`):new Error("LMStudio: \u51FA\u529B\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093")}resolveEndpoint(t){let r;try{r=new URL(t);}catch{throw new Error("LMStudio: \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306E URL \u304C\u4E0D\u6B63\u3067\u3059\uFF08\u4F8B: http://localhost:1234/\uFF09")}let e=r.pathname.replace(/\/+$/,"");if(e===""||e==="/")r.pathname="/api/v1/chat";else if(e!=="/api/v1/chat")throw new Error('LMStudio: \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u306F "/api/v1/chat" \u3092\u542B\u3081\u308B\u304B\uFF0C\u30D1\u30B9\u3092\u7A7A\u306B\u3057\u3066\u304F\u3060\u3055\u3044');return r}parseJsonSafe(t,r){if(t)try{return JSON.parse(t)}catch{if(!r.ok){let e=t?`${t.slice(0,200)}...`:"";throw new Error(`LMStudio: \u975EJSON\u30EC\u30B9\u30DD\u30F3\u30B9 (HTTP ${r.status} ${r.statusText}) ${e}`)}throw new Error("LMStudio: \u30EC\u30B9\u30DD\u30F3\u30B9\u306E JSON \u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F")}}extractTranslatedFromOutput(t){if(!t||!Array.isArray(t.output)||t.output.length===0)return null;for(let r of t.output)if(r&&typeof r=="object"&&r.type==="message"){let e=this.extractFromItem(r);if(e)return e}for(let r of t.output){let e=this.extractFromItem(r);if(e)return e}return null}extractFromItem(t){if(!t&&t!=="")return null;if(typeof t=="string")return t;if(Array.isArray(t)){for(let r of t){let e=this.extractFromItem(r);if(e)return e}return null}if(typeof t=="object"){if(typeof t=="object"&&typeof t.text=="string")return t.text;if(typeof t=="object"&&typeof t.response=="string")return t.response;if(typeof t.content=="string")return t.content;if(t.content&&typeof t.content=="object"){let r=t.content;if(typeof r.text=="string")return r.text;if(typeof r.content=="string")return r.content;let e=this.extractFromItem(r);if(e)return e}if(Array.isArray(t.content))for(let r of t.content){let e=this.extractFromItem(r);if(e)return e}if(Array.isArray(t.output)){let r=this.extractTranslatedFromOutput({output:t.output});if(r)return r}}return null}};var E=class o{static PROVIDER_NAME="ollama";static DEFAULT_ENDPOINT="http://localhost:11434";static DEFAULT_MODEL="gpt-oss:120b-cloud";static getDefaultProfile(){return {provider:o.PROVIDER_NAME,endpoint:o.DEFAULT_ENDPOINT,model:o.DEFAULT_MODEL}}baseUrl;model;apiKey;constructor(t,r,e){this.baseUrl=t||o.DEFAULT_ENDPOINT,this.model=r||o.DEFAULT_MODEL,this.apiKey=e;}getModel(){return this.model||null}async translate(t,r,e){let i=`You are a professional translator. Translate the following text from ${r} to ${e}. Only return the translated text without any additional explanation or comments.`,s=this.baseUrl.endsWith("/api/generate")?this.baseUrl:`${this.baseUrl}/api/generate`,n={"Content-Type":"application/json",Accept:"application/json",...this.apiKey?{Authorization:`Bearer ${this.apiKey}`}:{}},p=JSON.stringify({model:this.model,prompt:t,system:i,stream:false}),a=await fetch(s,{method:"POST",headers:n,body:p});if(!a.ok){let f=await a.json();throw new Error(`Ollama HTTP ${a.status} ${a.statusText}: ${f.error}`)}let c=(await a.json()).response;if(!c)throw new Error("Ollama: \u5FDC\u7B54\u304B\u3089\u7FFB\u8A33\u30C6\u30AD\u30B9\u30C8\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F");return {text:String(c).trim(),detectedSourceLang:r}}};var D=class o{static DEFAULT_MODEL="gpt-4o-mini";static getDefaultProfile(){return {provider:"openai",model:o.DEFAULT_MODEL}}client;model;constructor(t,r=o.DEFAULT_MODEL){this.client=new X({apiKey:t}),this.model=r;}getModel(){return this.model}async translate(t,r,e){try{let i=this.mapLanguageCode(r),s=this.mapLanguageCode(e),n=`You are a professional translator. Translate the following text from ${i} to ${s}. Only return the translated text without any additional explanation or comments.`,a=(await this.client.chat.completions.create({model:this.model,messages:[{role:"system",content:n},{role:"user",content:t}],temperature:.3})).choices[0]?.message?.content;if(!a)throw new Error("\u7FFB\u8A33\u306B\u5931\u6557\u3057\u307E\u3057\u305F");return {text:a.trim(),detectedSourceLang:r}}catch(i){throw i instanceof X.APIError?new Error(`OpenAI\u7FFB\u8A33API\u30A8\u30E9\u30FC: ${i.message}`):i instanceof Error?new Error(`OpenAI\u7FFB\u8A33\u30A8\u30E9\u30FC: ${i.message}`):i}}mapLanguageCode(t){return {en:"English",ja:"Japanese"}[t.toLowerCase()]||t}};var Z=["ls","list","use","rm","delete","add","rename","copy","provider","endpoint","api-key","model","default"];function k(o){if(Z.includes(o.toLowerCase()))throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D '${o}' \u306F\u4E88\u7D04\u8A9E\u306E\u305F\u3081\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);if(!o.match(/^[a-zA-Z0-9_-]+$/))throw new Error(`\u7121\u52B9\u306A\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D (${o}): \u82F1\u6570\u5B57\uFF0C\u30CF\u30A4\u30D5\u30F3\uFF0C\u30A2\u30F3\u30C0\u30FC\u30B9\u30B3\u30A2\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059`)}var U="gas",I={gas:A.getDefaultProfile,openai:D.getDefaultProfile,gemini:L.getDefaultProfile,lmstudio:P.getDefaultProfile,ollama:E.getDefaultProfile,custom:x.getDefaultProfile},q={version:"1.1",activeProfile:"default",profiles:{default:I[U]()}},h=class o{filePath;constructor(){this.filePath=W();}async get(){return await this.readConfig()}async getActiveProfileName(){return (await this.readAppConfig()).activeProfile}async getProfile(t){let e=(await this.readAppConfig()).profiles[t];if(!e)throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093`);return e}async listProfiles(){let t=await this.readAppConfig();return Object.keys(t.profiles)}async useProfile(t){let r=await this.readAppConfig();if(!r.profiles[t]){let e=Object.keys(r.profiles).join(", ");throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
|
|
3
|
+
\u5229\u7528\u53EF\u80FD\u306A\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB: ${e}`)}r.activeProfile=t,await this.writeAppConfig(r);}async addProfile(t,r){if(k(t),r?.provider&&!this.isTranslatorProvider(r.provider)){let p=Object.keys(I).join(", ");throw new Error(`\u7121\u52B9\u306A\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC '${r.provider}': ${p} \u306E\u3044\u305A\u308C\u304B\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044`)}let e=await this.readAppConfig();if(e.profiles[t])throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059`);let i=r?.provider||U,n={...this.getDefaultProfileByProvider(i),...r};e.profiles[t]=n,await this.writeAppConfig(e);}async renameProfile(t,r){if(t==="default")throw new Error("'default' \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306F\u540D\u524D\u3092\u5909\u66F4\u3067\u304D\u307E\u305B\u3093");if(t===r)return;k(r);let e=await this.readAppConfig();if(!e.profiles[t])throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093`);if(e.profiles[r])throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${r}' \u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059`);e.profiles[r]=e.profiles[t],delete e.profiles[t],e.activeProfile===t&&(e.activeProfile=r),await this.writeAppConfig(e);}async copyProfile(t,r){if(t===r)throw new Error("\u30B3\u30D4\u30FC\u5143\u3068\u30B3\u30D4\u30FC\u5148\u306E\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D\u304C\u540C\u3058\u3067\u3059");k(r);let e=await this.readAppConfig();if(!e.profiles[t])throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093`);if(e.profiles[r])throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${r}' \u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059`);e.profiles[r]={...e.profiles[t]},await this.writeAppConfig(e);}async deleteProfile(t){if(t==="default")throw new Error("'default' \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306F\u524A\u9664\u3067\u304D\u307E\u305B\u3093");let r=await this.readAppConfig();if(!r.profiles[t])throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093`);delete r.profiles[t],r.activeProfile===t&&(r.activeProfile="default"),await this.writeAppConfig(r);}async setProfileConfig(t,r,e){let i=await this.readAppConfig();if(!i.profiles[t])throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\uFF0E'enja config add ${t}' \u3067\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044`);let s=i.profiles[t];switch(r){case "endpoint":s.endpoint=e;break;case "api-key":s.apiKey=e;break;case "provider":if(!this.isTranslatorProvider(e)){let n=Object.keys(I).join(", ");throw new Error(`\u7121\u52B9\u306A\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC (${e}): ${n} \u306E\u3044\u305A\u308C\u304B\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044`)}s.provider=e;break;case "model":s.model=e;break;default:throw new Error(`\u7121\u52B9\u306A\u8A2D\u5B9A\u30AD\u30FC (${r})`)}await this.writeAppConfig(i);}async unsetProfileConfig(t,r){let e=await this.readAppConfig();if(!e.profiles[t])throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093`);let i=e.profiles[t],s=i.provider||U,n=this.getDefaultProfileByProvider(s);switch(r){case "provider":i.provider=n.provider;break;case "endpoint":i.endpoint=n.endpoint;break;case "api-key":i.apiKey=n.apiKey;break;case "model":i.model=n.model;break;default:throw new Error(`\u7121\u52B9\u306A\u8A2D\u5B9A\u30AD\u30FC (${r})`)}await this.writeAppConfig(e);}async resetProfileConfig(t){let r=await this.readAppConfig();if(!r.profiles[t])throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${t}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093`);let e=this.getDefaultProfile();r.profiles[t]={...e},await this.writeAppConfig(r);}static isAppConfig(t){return !(!t||typeof t!="object"||!("profiles"in t)||!("activeProfile"in t)||typeof t.activeProfile!="string"||typeof t.profiles!="object"||t.profiles===null)}getDefaultProfile(){return I[U]()}getDefaultProfileByProvider(t){return I[t]()}isTranslatorProvider(t){return t in I}async ensureConfigDir(){let t=C();await promises.mkdir(t,{recursive:true});}async readAppConfig(){try{let t=await promises.readFile(this.filePath,"utf-8"),r=JSON.parse(t);return o.isAppConfig(r)?r:{...q}}catch{return {...q}}}async writeAppConfig(t){try{await this.ensureConfigDir();let r=`${this.filePath}.${Date.now()}.tmp`,e=JSON.stringify(t,null,2);await promises.writeFile(r,e,"utf-8"),await promises.rename(r,this.filePath);}catch{throw new Error("\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F")}}async readConfig(){let t=await this.readAppConfig();return t.profiles[t.activeProfile]||this.getDefaultProfile()}};function tt(o){o.command("config").usage("[profile|subcommand] [options]").description("\u8A2D\u5B9A\u3068\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u7BA1\u7406\u3059\u308B").allowExcessArguments(true).argument("[profile|subcommand]",`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D\u307E\u305F\u306F\u30B5\u30D6\u30B3\u30DE\u30F3\u30C9
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Profile:
|
|
6
6
|
<profile> \u6307\u5B9A\u3057\u305F\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u8A73\u7D30\u3092\u8868\u793A
|
|
7
7
|
<profile> [options] \u6307\u5B9A\u3057\u305F\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u8A2D\u5B9A\u3092\u5909\u66F4
|
|
8
8
|
|
|
@@ -12,9 +12,9 @@ Subcommands:
|
|
|
12
12
|
add <profile> [options] \u65B0\u3057\u3044\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u4F5C\u6210
|
|
13
13
|
rename <old> <new> \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u5909\u66F4
|
|
14
14
|
copy <source> <target> \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u30B3\u30D4\u30FC
|
|
15
|
-
delete, rm <profile> \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u524A\u9664`).option("--provider <name>","\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u8A2D\u5B9A
|
|
15
|
+
delete, rm <profile> \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u524A\u9664`).option("--provider <name>","\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u8A2D\u5B9A").option("--endpoint <url>","\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u8A2D\u5B9A").option("--api-key <api-key>","\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E API \u30AD\u30FC\u3092\u8A2D\u5B9A").option("--model <name>","\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u30E2\u30C7\u30EB\u3092\u8A2D\u5B9A").option("--unset <key>","\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u6307\u5B9A\u3057\u305F\u8A2D\u5B9A\u3092\u30EA\u30BB\u30C3\u30C8").option("--reset","\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u5168\u4F53\u3092\u30EA\u30BB\u30C3\u30C8").addHelpText("after",`
|
|
16
16
|
--provider Names:
|
|
17
|
-
gas,
|
|
17
|
+
gas, openai, gemini, lmstudio, ollama, custom
|
|
18
18
|
|
|
19
19
|
--unset Keys:
|
|
20
20
|
provider, endpoint, api-key, model
|
|
@@ -30,44 +30,44 @@ Examples:
|
|
|
30
30
|
$ enja config use work work \u3092\u30A2\u30AF\u30C6\u30A3\u30D6\u306B\u8A2D\u5B9A
|
|
31
31
|
$ enja config add personal personal \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u4F5C\u6210
|
|
32
32
|
$ enja config rm personal \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u524A\u9664
|
|
33
|
-
$ enja "Hello" -p work work \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3067\u7FFB\u8A33`).action(
|
|
33
|
+
$ enja "Hello" -p work work \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3067\u7FFB\u8A33`).action(mt);}async function mt(o,t,r){let e=new h,i=r?.opts()||{},n={...r?.parent?.opts()||{},...i};try{let p=r?.args??[],a=p.length,[,l,c]=p;if(o==="ls"||o==="list"){if(a>1)throw new Error(`\u5F15\u6570\u304C\u591A\u3059\u304E\u307E\u3059
|
|
34
34
|
|
|
35
35
|
\u4F7F\u7528\u4F8B:
|
|
36
|
-
enja config ls`);let f=await e.listProfiles(),
|
|
36
|
+
enja config ls`);let f=await e.listProfiles(),g=await e.getActiveProfileName();console.log(d.bold("Profiles:"));for(let u of f){let $=u===g,w=await e.getProfile(u),H=$?d.green("*"):" ",y=w.model?` - ${w.model}`:"";console.log(` ${H} ${u} (${w.provider})${y}`);}return}if(o==="use"){if(!l){let f=await e.listProfiles(),g=await e.getActiveProfileName(),u=await N(f,g);await e.useProfile(u),console.log(`${d.green("\u2714")} \u30A2\u30AF\u30C6\u30A3\u30D6\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092 '${u}' \u306B\u8A2D\u5B9A\u3057\u307E\u3057\u305F`);return}if(a>2)throw new Error(`\u5F15\u6570\u304C\u591A\u3059\u304E\u307E\u3059
|
|
37
37
|
|
|
38
38
|
\u4F7F\u7528\u4F8B:
|
|
39
|
-
enja config use <profile>`);await e.useProfile(l),console.log(`${
|
|
39
|
+
enja config use <profile>`);await e.useProfile(l),console.log(`${d.green("\u2714")} \u30A2\u30AF\u30C6\u30A3\u30D6\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092 '${l}' \u306B\u8A2D\u5B9A\u3057\u307E\u3057\u305F`);return}if(o==="rm"||o==="delete"){if(!l){let f=await e.listProfiles(),g=await e.getActiveProfileName(),u=await N(f,g);if(!await _(u))return;await e.deleteProfile(u),console.log(`${d.green("\u2714")} \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${u}' \u3092\u524A\u9664\u3057\u307E\u3057\u305F`);return}if(a>2)throw new Error(`\u5F15\u6570\u304C\u591A\u3059\u304E\u307E\u3059
|
|
40
40
|
|
|
41
41
|
\u4F7F\u7528\u4F8B:
|
|
42
|
-
enja config rm <profile>`);if(!await
|
|
42
|
+
enja config rm <profile>`);if(!await _(l))return;await e.deleteProfile(l),console.log(`${d.green("\u2714")} \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${l}' \u3092\u524A\u9664\u3057\u307E\u3057\u305F`);return}if(o==="add"){if(!l)throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044
|
|
43
43
|
|
|
44
44
|
\u4F7F\u7528\u4F8B:
|
|
45
|
-
enja config add <profile> [options]`);if(
|
|
45
|
+
enja config add <profile> [options]`);if(a>2)throw new Error(`\u5F15\u6570\u304C\u591A\u3059\u304E\u307E\u3059
|
|
46
46
|
|
|
47
47
|
\u4F7F\u7528\u4F8B:
|
|
48
|
-
enja config add <profile> [options]`);let f={};n?.provider&&(f.provider=n.provider),n?.endpoint&&(f.endpoint=n.endpoint),n?.apiKey&&(f.apiKey=n.apiKey),n?.model&&(f.model=n.model),await e.addProfile(l,f),console.log(`${
|
|
48
|
+
enja config add <profile> [options]`);let f={};n?.provider&&(f.provider=n.provider),n?.endpoint&&(f.endpoint=n.endpoint),n?.apiKey&&(f.apiKey=n.apiKey),n?.model&&(f.model=n.model),await e.addProfile(l,f),console.log(`${d.green("\u2714")} \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${l}' \u3092\u4F5C\u6210\u3057\u307E\u3057\u305F`);return}if(o==="rename"){if(!l)throw new Error(`\u5909\u66F4\u524D\u306E\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044
|
|
49
49
|
|
|
50
50
|
\u4F7F\u7528\u4F8B:
|
|
51
51
|
enja config rename <oldProfile> <newProfile>`);if(!c)throw new Error(`\u65B0\u3057\u3044\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044
|
|
52
52
|
|
|
53
53
|
\u4F7F\u7528\u4F8B:
|
|
54
|
-
enja config rename <oldProfile> <newProfile>`);if(
|
|
54
|
+
enja config rename <oldProfile> <newProfile>`);if(a>3)throw new Error(`\u5F15\u6570\u304C\u591A\u3059\u304E\u307E\u3059
|
|
55
55
|
|
|
56
56
|
\u4F7F\u7528\u4F8B:
|
|
57
|
-
enja config rename <oldProfile> <newProfile>`);await e.renameProfile(l,c),console.log(`${
|
|
57
|
+
enja config rename <oldProfile> <newProfile>`);await e.renameProfile(l,c),console.log(`${d.green("\u2714")} \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${l}' \u3092 '${c}' \u306B\u5909\u66F4\u3057\u307E\u3057\u305F`);return}if(o==="copy"){if(!l)throw new Error(`\u30B3\u30D4\u30FC\u5143\u306E\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044
|
|
58
58
|
|
|
59
59
|
\u4F7F\u7528\u4F8B:
|
|
60
60
|
enja config copy <sourceProfile> <targetProfile>`);if(!c)throw new Error(`\u30B3\u30D4\u30FC\u5148\u306E\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044
|
|
61
61
|
|
|
62
62
|
\u4F7F\u7528\u4F8B:
|
|
63
|
-
enja config copy <sourceProfile> <targetProfile>`);if(
|
|
63
|
+
enja config copy <sourceProfile> <targetProfile>`);if(a>3)throw new Error(`\u5F15\u6570\u304C\u591A\u3059\u304E\u307E\u3059
|
|
64
64
|
|
|
65
65
|
\u4F7F\u7528\u4F8B:
|
|
66
|
-
enja config copy <sourceProfile> <targetProfile>`);await e.copyProfile(l,c),console.log(`${
|
|
66
|
+
enja config copy <sourceProfile> <targetProfile>`);await e.copyProfile(l,c),console.log(`${d.green("\u2714")} \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${l}' \u3092 '${c}' \u306B\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F`);return}if(!o){if(n?.provider||n?.endpoint||n?.apiKey||n?.model||n?.reset||n?.unset)throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044
|
|
67
67
|
|
|
68
68
|
\u4F7F\u7528\u4F8B:
|
|
69
69
|
enja config work --provider openai \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u8A2D\u5B9A\u3092\u5909\u66F4
|
|
70
|
-
enja config add personal --provider gemini \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u4F5C\u6210`);let f=await e.getActiveProfileName(),
|
|
70
|
+
enja config add personal --provider gemini \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u4F5C\u6210`);let f=await e.getActiveProfileName(),g=await e.get();console.log(`${d.bold("Active Profile:")} ${f}`),console.log(`${d.blue("provider:")} ${g.provider}`),console.log(`${d.blue("endpoint:")} ${g.endpoint||"(not set)"}`),console.log(`${d.blue("apiKey:")} ${g.apiKey?Q(g.apiKey):"(not set)"}`),console.log(`${d.blue("model:")} ${g.model||"(not set)"}`);return}if(o&&!l&&(n?.provider||n?.endpoint||n?.apiKey||n?.model)){let f=!1;n.provider&&(await e.setProfileConfig(o,"provider",n.provider),f=!0),n.endpoint&&(await e.setProfileConfig(o,"endpoint",n.endpoint),f=!0),n.apiKey&&(await e.setProfileConfig(o,"api-key",n.apiKey),f=!0),n.model&&(await e.setProfileConfig(o,"model",n.model),f=!0),f&&console.log(`${d.green("\u2714")} \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${o}' \u306E\u8A2D\u5B9A\u3092\u66F4\u65B0\u3057\u307E\u3057\u305F`);return}if(o&&!l&&!n?.reset&&!n?.unset&&!n?.provider&&!n?.endpoint&&!n?.apiKey&&!n?.model){let f=await e.getProfile(o);console.log(`${d.bold("Profile:")} ${o}`),console.log(`${d.blue("provider:")} ${f.provider}`),console.log(`${d.blue("endpoint:")} ${f.endpoint||"(not set)"}`),console.log(`${d.blue("apiKey:")} ${f.apiKey?Q(f.apiKey):"(not set)"}`),console.log(`${d.blue("model:")} ${f.model||"(not set)"}`);return}if(o&&n?.reset){await e.resetProfileConfig(o),console.log(`${d.green("\u2714")} \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${o}' \u3092\u30EA\u30BB\u30C3\u30C8\u3057\u307E\u3057\u305F`);return}if(o&&n?.unset){await e.unsetProfileConfig(o,n.unset),console.log(`${d.green("\u2714")} \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${o}' \u306E ${n.unset} \u3092\u30EA\u30BB\u30C3\u30C8\u3057\u307E\u3057\u305F`);return}throw new Error(`\u7121\u52B9\u306A\u30B3\u30DE\u30F3\u30C9\u5F62\u5F0F\u3067\u3059\uFF0E
|
|
71
71
|
|
|
72
72
|
\u4F7F\u7528\u4F8B:
|
|
73
73
|
enja config \u73FE\u5728\u306E\u8A2D\u5B9A\u3092\u8868\u793A
|
|
@@ -81,27 +81,27 @@ Examples:
|
|
|
81
81
|
enja config rm profileName \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u524A\u9664
|
|
82
82
|
enja config work --reset \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u30EA\u30BB\u30C3\u30C8
|
|
83
83
|
enja config work --unset api-key \u8A2D\u5B9A\u30EA\u30BB\u30C3\u30C8
|
|
84
|
-
`)}catch(p){p instanceof Error?console.error(`error: ${p.message}`):console.error(p),process.exit(1);}}function
|
|
85
|
-
`];return o.forEach((r,e)=>{let i=
|
|
86
|
-
`)}function
|
|
87
|
-
`];return o.forEach((r,e)=>{e>0&&t.push("\u2500".repeat(60));let i=14;if(t.push(`${
|
|
88
|
-
`)}function
|
|
89
|
-
${
|
|
90
|
-
\u5229\u7528\u53EF\u80FD\u306A\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB: ${p.join(", ")}`)}else r=await t.get();let e=o?.provider||r.provider||"gas",i=o?.endpoint||r.endpoint,
|
|
84
|
+
`)}catch(p){p instanceof Error?console.error(`error: ${p.message}`):console.error(p),process.exit(1);}}function Q(o){if(o.length<=8)return "*".repeat(o.length);let t=4,r=o.slice(0,t),e=o.slice(-t),i="*".repeat(o.length-t*2);return `${r}${i}${e}`}function O(o,t=false){return o.length===0?"\u5C65\u6B74\u306F\u3042\u308A\u307E\u305B\u3093":t?wt(o):ht(o)}function ht(o){let t=[`\u5168 ${o.length} \u4EF6\u306E\u5C65\u6B74
|
|
85
|
+
`];return o.forEach((r,e)=>{let i=et(r.timestamp),s=yt(r),n=rt(r.sourceText,20),p=rt(r.translatedText||"",20),a=[d.cyan(`[${e+1}]`),r.id.substring(0,8),i,s||null].filter(Boolean).join(" | ");t.push(a),t.push(` ${r.sourceLang} \u2192 ${r.targetLang} | ${n} \u2192 ${p}`),t.push("");}),t.join(`
|
|
86
|
+
`)}function wt(o){let t=[`\u5168 ${o.length} \u4EF6\u306E\u5C65\u6B74\u306E\u8A73\u7D30
|
|
87
|
+
`];return o.forEach((r,e)=>{e>0&&t.push("\u2500".repeat(60));let i=14;if(t.push(`${d.cyan("ID:".padEnd(i))} ${r.id}`),t.push(`${d.cyan("Date:".padEnd(i))} ${et(r.timestamp)}`),t.push(`${d.cyan("Direction:".padEnd(i))} ${r.sourceLang} \u2192 ${r.targetLang}`),t.push(`${d.cyan("InputLength:".padEnd(i))} ${r.textLength} characters`),t.push(`${d.cyan("OutputLength:".padEnd(i))} ${r.translatedText.length} characters`),r.profile&&t.push(`${d.cyan("Profile:".padEnd(i))} ${r.profile}`),r.provider&&t.push(`${d.cyan("Provider:".padEnd(i))} ${r.provider}`),r.model&&t.push(`${d.cyan("Model:".padEnd(i))} ${r.model}`),r.options){let s=[r.options.inputMethod&&`input=${r.options.inputMethod}`,r.options.stripHtml&&"stripHtml=true",r.options.file&&`file=${r.options.file}`].filter(Boolean).join(", ");s&&t.push(`${d.cyan("Options:".padEnd(i))} ${s}`);}t.push("",`${d.cyan("Input:")}`,r.sourceText),t.push("",`${d.cyan("Output:")}`,r.translatedText||"","");}),t.join(`
|
|
88
|
+
`)}function et(o){return new Date(o).toLocaleString("ja-JP")}function rt(o,t){let r=o.replace(/[\r\n]+/g," ");return r.length>t?`${r.substring(0,t)}...`:r}function yt(o){return [o.profile,o.provider,o.model].filter(t=>!!t).map(t=>d.magenta(t)).join(d.dim("\u30FB"))}var ot=100,j=class{filePath;constructor(){this.filePath=z();}ensureConfigDir(){let t=C();v.existsSync(t)||v.mkdirSync(t,{recursive:true});}async readHistory(){try{let t=await promises.readFile(this.filePath,"utf-8");return JSON.parse(t)}catch(t){return t instanceof Error&&"code"in t&&t.code==="ENOENT"?[]:(console.warn("\u5C65\u6B74\u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF0E\u7A7A\u914D\u5217\u3092\u8FD4\u3057\u307E\u3059"),[])}}async writeHistory(t){try{this.ensureConfigDir();let r=`${this.filePath}.tmp`,e=JSON.stringify(t,null,2);await promises.writeFile(r,e,"utf-8"),await promises.rename(r,this.filePath);}catch{throw new Error("\u5C65\u6B74\u30D5\u30A1\u30A4\u30EB\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F")}}async add(t){let r=await this.readHistory(),e={...t,id:randomUUID(),timestamp:new Date().toISOString()};r.unshift(e),r.length>ot&&r.splice(ot),await this.writeHistory(r);}async getAll(){return await this.readHistory()}async getRecent(t){return (await this.readHistory()).slice(0,t)}async deleteById(t){let r=await this.readHistory(),e=r.filter(i=>i.id!==t);return e.length===r.length?false:(await this.writeHistory(e),true)}async clear(){await this.writeHistory([]);}async findById(t){return (await this.readHistory()).find(e=>e.id===t)||null}async findByShortId(t){return (await this.readHistory()).filter(e=>e.id.startsWith(t))}async findByHash(t,r,e){return (await this.readHistory()).find(s=>s.sourceHash===t&&s.sourceLang===r&&s.targetLang===e)||null}};function nt(o){o.command("history").description("\u7FFB\u8A33\u5C65\u6B74\u3092\u8868\u793A\u3059\u308B").argument("[id]","ID \u3067\u5C65\u6B74\u3092\u8868\u793A\u3059\u308B\uFF08\u5B8C\u5168 ID \u307E\u305F\u306F\u77ED\u7E2E ID\uFF09").option("-d, --detail","\u8A73\u7D30\u8868\u793A").option("-n, --number <number>","\u8868\u793A\u4EF6\u6570","10").option("--delete <id>","\u7279\u5B9A\u306E\u5C65\u6B74\u3092\u524A\u9664\u3059\u308B").option("--clear","\u5C65\u6B74\u3092\u30AF\u30EA\u30A2").action(Et);}async function Et(o,t){try{let r=new j;if(o){let n=o.trim();if(!n)throw new Error("\u7A7A\u306EID\u304C\u6307\u5B9A\u3055\u308C\u307E\u3057\u305F");if(n.length>=36){let l=await r.findById(n);if(!l)throw new Error(`\u6307\u5B9A\u3055\u308C\u305FID\u306E\u5C65\u6B74\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${o})`);console.log(O([l],t.detail));return}if(n.length<8)throw new Error(`\u77ED\u7E2EID\u306F\u5C11\u306A\u304F\u3068\u30828\u6587\u5B57\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044 (${n.length})`);let p=await r.findByShortId(n);if(p.length===0)throw new Error(`\u6307\u5B9A\u3055\u308C\u305FID\u306E\u5C65\u6B74\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${o})`);let a=O(p,t.detail);console.log(a);return}if(t.delete){let n=t.delete.trim();if(!n)throw new Error("\u7A7A\u306EID\u304C\u6307\u5B9A\u3055\u308C\u307E\u3057\u305F");if(n.length>=36){if(await r.deleteById(n))console.log(`${d.green("\u2714")} \u5C65\u6B74ID ${n} \u3092\u524A\u9664\u3057\u307E\u3057\u305F`);else throw new Error(`\u6307\u5B9A\u3055\u308C\u305FID\u306E\u5C65\u6B74\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${n})`);return}if(n.length<8)throw new Error(`\u77ED\u7E2EID\u3067\u524A\u9664\u3059\u308B\u5834\u5408\u306F\u5C11\u306A\u304F\u3068\u30828\u6587\u5B57\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044 (${n.length})`);let p=await r.findByShortId(n);if(p.length===0)throw new Error(`\u6307\u5B9A\u3055\u308C\u305FID\u306E\u5C65\u6B74\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${n})`);if(p.length>1)throw new Error(`\u6307\u5B9A\u3055\u308C\u305F\u77ED\u7E2EID\u306F\u8907\u6570\u306E\u5C65\u6B74\u306B\u4E00\u81F4\u3057\u307E\u3057\u305F\uFF0E\u5B8C\u5168\u306AID\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\uFF0E
|
|
89
|
+
${O(p,!1)}`);let a=p[0].id;if(await r.deleteById(a))console.log(`${d.green("\u2714")} \u5C65\u6B74ID ${a} \u3092\u524A\u9664\u3057\u307E\u3057\u305F`);else throw new Error(`\u524A\u9664\u306B\u5931\u6557\u3057\u307E\u3057\u305F (${a})`);return}if(t.clear){await r.clear(),console.log(`${d.green("\u2714")} \u5C65\u6B74\u3092\u30AF\u30EA\u30A2\u3057\u307E\u3057\u305F`);return}let e=Number(t.number)||10,i=await r.getRecent(e),s=O(i,t.detail);console.log(s);}catch(r){console.error(r instanceof Error?`error: ${r.message}`:r),process.exit(1);}}async function it(o){let t=new h,r;if(o?.profile)try{r=await t.getProfile(o.profile);}catch{let p=await t.listProfiles();throw new Error(`\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB '${o.profile}' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
|
|
90
|
+
\u5229\u7528\u53EF\u80FD\u306A\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB: ${p.join(", ")}`)}else r=await t.get();let e=o?.provider||r.provider||"gas",i=o?.endpoint||r.endpoint,s=o?.apiKey||r.apiKey,n=o?.model||r.model;return {endpoint:i,provider:e,apiKey:s,model:n}}var vt=new Set(["169.254.169.254"]);function $t(o){let t=o.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);if(!t)return null;let r=t.slice(1).map(e=>Number(e));return r.some(e=>!Number.isInteger(e)||e<0||e>255)?null:r}function Tt(o,t,r){return o[0]===t&&o[1]===r}function Ct(o){let[t,r]=o;return t===10||t===192&&r===168||t===172&&r>=16&&r<=31}function xt(o){return o[0]===127}function At(o){return Tt(o,169,254)}function Lt(o){return o==="::1"||o==="0:0:0:0:0:0:0:1"}function Dt(o){return o.toLowerCase().startsWith("fe80:")}var It=new Set(["localhost","127.0.0.1","::1"]),jt=new Set(["10.","192.168."]);function S(o,t={}){let{allowLocalEndpoint:r=false,allowPrivateEndpoint:e=false,allowHttp:i=false}=t,s;try{s=new URL(o);}catch{throw new Error("\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u304C\u4E0D\u6B63\u3067\u3059")}let n=s.protocol;if(n!=="https:"&&n!=="http:")throw new Error("\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u306F http:// \u307E\u305F\u306F https:// \u3067\u59CB\u307E\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");if(s.username||s.password)throw new Error("\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u306B\u8A8D\u8A3C\u60C5\u5831\u3092\u57CB\u3081\u8FBC\u3080\u3053\u3068\u306F\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093");let p=s.hostname;if(vt.has(p))throw new Error("\u6307\u5B9A\u3055\u308C\u305F\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306F\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u4E0A\u306E\u7406\u7531\u306B\u3088\u308A\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093");let a=$t(p),l=a!==null,c=It.has(p)||(l?xt(a):false)||Lt(p);if((l?At(a):false)||Dt(p))throw new Error("\u6307\u5B9A\u3055\u308C\u305F\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306F\u30EA\u30F3\u30AF\u30ED\u30FC\u30AB\u30EB\u30A2\u30C9\u30EC\u30B9\u306E\u305F\u3081\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093");let g=l?Ct(a):Array.from(jt).some(u=>p.startsWith(u));if(n==="http:"&&!(i||r&&c))throw new Error(`\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u306F https:// \u3067\u59CB\u307E\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059
|
|
91
91
|
HTTP \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u4F7F\u7528\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B\u5834\u5408\u306F\uFF0C--allow-http \u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044
|
|
92
92
|
\u30ED\u30FC\u30AB\u30EB\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3067\u3042\u308C\u3070 --allow-local-endpoint \u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u3082\u8A31\u53EF\u3055\u308C\u307E\u3059`);if(c&&!r)throw new Error(`\u30ED\u30FC\u30AB\u30EB\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306E\u4F7F\u7528\u306F\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u30EA\u30B9\u30AF\u304C\u3042\u308B\u305F\u3081\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093
|
|
93
|
-
\u30ED\u30FC\u30AB\u30EB\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u4F7F\u7528\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B\u5834\u5408\u306F\uFF0C--allow-local-endpoint \u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044`);if(
|
|
94
|
-
\u4F7F\u7528\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B\u5834\u5408\u306F\uFF0C--allow-private-endpoint \u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044`);return true}async function
|
|
93
|
+
\u30ED\u30FC\u30AB\u30EB\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u4F7F\u7528\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B\u5834\u5408\u306F\uFF0C--allow-local-endpoint \u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044`);if(g&&!e)throw new Error(`\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 IP \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306E\u4F7F\u7528\u306F\u65E2\u5B9A\u3067\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093
|
|
94
|
+
\u4F7F\u7528\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B\u5834\u5408\u306F\uFF0C--allow-private-endpoint \u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044`);return true}function st({defaultUrl:o,configUrl:t,optionUrl:r,validateOpts:e}){return r?(S(r,e),r):t?(S(t,e),t):(S(o,{allowLocalEndpoint:true,allowPrivateEndpoint:true,allowHttp:true}),o)}async function at(o){let t=new h,r=await it(o),e;o?.profile?e=o.profile:e=await t.getActiveProfileName();let i=o?.allowLocalEndpoint??false,s=o?.allowPrivateEndpoint??false,n=o?.allowHttp??false,p={allowLocalEndpoint:i,allowPrivateEndpoint:s,allowHttp:n},{provider:a,endpoint:l,apiKey:c,model:f}=r;switch(a){case "custom":{if(!l)throw new Error("\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u304C\u5FC5\u8981\u3067\u3059");return S(l,p),{translator:new x(l,c,f),config:r,activeProfile:e}}case "gas":{if(!l)throw new Error("\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8 URL \u304C\u5FC5\u8981\u3067\u3059");return S(l,p),{translator:new A(l,c),config:r,activeProfile:e}}case "openai":{if(!c)throw new Error("OpenAI \u3092\u4F7F\u7528\u3059\u308B\u306B\u306F API \u30AD\u30FC\u304C\u5FC5\u8981\u3067\u3059");return {translator:new D(c,f),config:r,activeProfile:e}}case "gemini":{if(!c)throw new Error("Gemini \u3092\u4F7F\u7528\u3059\u308B\u306B\u306F API \u30AD\u30FC\u304C\u5FC5\u8981\u3067\u3059");return {translator:new L(c,f),config:r,activeProfile:e}}case "lmstudio":{if(!f)throw new Error("LM Studio \u3092\u4F7F\u7528\u3059\u308B\u306B\u306F\u30E2\u30C7\u30EB\u540D\u304C\u5FC5\u8981\u3067\u3059");let g=st({defaultUrl:P.DEFAULT_ENDPOINT,configUrl:l,optionUrl:o?.endpoint,validateOpts:p});return {translator:new P(g,f,c),config:r,activeProfile:e}}case "ollama":{let g=st({defaultUrl:E.DEFAULT_ENDPOINT,configUrl:l,optionUrl:o?.endpoint,validateOpts:p});return {translator:new E(g,f,c),config:r,activeProfile:e}}default:throw new Error(`\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u306A\u3044\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC (${a}) \u3067\u3059`)}}function lt(o){return createHash("sha256").update(o).digest("hex")}function pt(o){o.argument("[text]","\u7FFB\u8A33\u3059\u308B\u30C6\u30AD\u30B9\u30C8\uFF08\u7701\u7565\u3057\u305F\u5834\u5408\u306F\u30D5\u30A1\u30A4\u30EB\u307E\u305F\u306F\u6A19\u6E96\u5165\u529B\u304B\u3089\u8AAD\u307F\u8FBC\u3080\uFF09").option("-f, --file <path>","\u30D5\u30A1\u30A4\u30EB\u3092\u7FFB\u8A33\u3059\u308B").option("-o, --output <path>","\u30D5\u30A1\u30A4\u30EB\u306B\u51FA\u529B\u3059\u308B (\u30C7\u30D5\u30A9\u30EB\u30C8: \u6A19\u6E96\u51FA\u529B)").option("-s, --strip-html","HTML\u30BF\u30B0\u3092\u9664\u53BB\u3057\u3066\u304B\u3089\u7FFB\u8A33\u3059\u308B").option("-N, --no-cache","\u30AD\u30E3\u30C3\u30B7\u30E5\u3092\u4F7F\u7528\u305B\u305A\u306B\u518D\u7FFB\u8A33\u3059\u308B").option("-F, --flip","\u7FFB\u8A33\u65B9\u5411\u3092\u9006\u306B\u3059\u308B (default: \u82F1\u8A9E\u2192\u65E5\u672C\u8A9E)").option("-p, --profile <name>","\u4F7F\u7528\u3059\u308B\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u6307\u5B9A").option("--endpoint <url>","\u4E00\u6642\u7684\u306B\u30AB\u30B9\u30BF\u30E0\u7FFB\u8A33\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u6307\u5B9A\uFF08\u73FE\u5728\u306E\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306B\u9069\u7528\uFF09").option("--api-key <key>","\u4E00\u6642\u7684\u306B API \u30AD\u30FC\u3092\u6307\u5B9A\uFF08\u73FE\u5728\u306E\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306B\u9069\u7528\uFF09").option("--provider <name>","\u4E00\u6642\u7684\u306B\u7FFB\u8A33\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u6307\u5B9A\uFF08\u73FE\u5728\u306E\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306B\u9069\u7528\uFF09").option("--model <name>","\u4E00\u6642\u7684\u306B\u4F7F\u7528\u3059\u308B\u30E2\u30C7\u30EB\u540D\u3092\u6307\u5B9A\uFF08\u73FE\u5728\u306E\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306B\u9069\u7528\uFF09").option("--allow-local-endpoint","localhost\uFF08127.0.0.1\uFF09\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u8A31\u53EF\u3059\u308B").option("--allow-private-endpoint","\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\uFF08\u4F8B: 192.168.x.x\uFF09\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u8A31\u53EF\u3059\u308B").option("--allow-http","HTTP\uFF08\u975E TLS\uFF09\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u8A31\u53EF\u3059\u308B").addHelpText("after",`
|
|
95
95
|
Examples:
|
|
96
96
|
$ enja "Hello, world!" # \u6587\u5B57\u5217\u3092\u7FFB\u8A33
|
|
97
97
|
$ docker --help | enja # \u6A19\u6E96\u5165\u529B\u3092\u7FFB\u8A33
|
|
98
98
|
$ enja -f input.txt -o output.txt # \u30D5\u30A1\u30A4\u30EB\u5165\u51FA\u529B
|
|
99
99
|
$ enja "Hello" -p work # \u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u6307\u5B9A\u3057\u3066\u7FFB\u8A33
|
|
100
|
-
$ enja "Hello" --provider openai --api-key YOUR_API_KEY # \u4E00\u6642\u7684\u306B\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u6307\u5B9A\u3057\u3066\u7FFB\u8A33`).action(
|
|
100
|
+
$ enja "Hello" --provider openai --api-key YOUR_API_KEY # \u4E00\u6642\u7684\u306B\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u6307\u5B9A\u3057\u3066\u7FFB\u8A33`).action(Rt);}async function Rt(o,t){try{if(!o&&!t.file&&!process.stdin.isTTY){let r=await kt();await V(r,t,"stdin");return}if(t.file){if(!v.existsSync(t.file))throw new Error(`\u30D5\u30A1\u30A4\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${t.file})`);let r=v.readFileSync(t.file,"utf-8");await V(r,t,"file");return}if(o){await V(o,t,"arg");return}throw new Error(`\u7FFB\u8A33\u3059\u308B\u30C6\u30AD\u30B9\u30C8\u304C\u63D0\u4F9B\u3055\u308C\u3066\u3044\u307E\u305B\u3093
|
|
101
101
|
|
|
102
102
|
\u4F7F\u7528\u4F8B:
|
|
103
103
|
enja "Hello, world!" # \u5F15\u6570\u3067\u6E21\u3055\u308C\u305F\u6587\u5B57\u5217\u3092\u7FFB\u8A33
|
|
104
104
|
enja -f input.txt # \u30D5\u30A1\u30A4\u30EB\u304B\u3089\u30C6\u30AD\u30B9\u30C8\u3092\u8AAD\u307F\u8FBC\u3093\u3067\u7FFB\u8A33
|
|
105
|
-
cat README.md | enja # \u30D1\u30A4\u30D7(\u6A19\u6E96\u5165\u529B)\u3067\u6E21\u3055\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u3092\u7FFB\u8A33`)}catch(r){console.error(`error: ${Ht(r)}`),process.exit(1);}}async function
|
|
106
|
-
`).trim()}var
|
|
107
|
-
Enja CLI v${
|
|
105
|
+
cat README.md | enja # \u30D1\u30A4\u30D7(\u6A19\u6E96\u5165\u529B)\u3067\u6E21\u3055\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u3092\u7FFB\u8A33`)}catch(r){console.error(`error: ${Ht(r)}`),process.exit(1);}}async function V(o,t,r){if(!o||o.trim().length===0)throw new Error("\u7FFB\u8A33\u3059\u308B\u30C6\u30AD\u30B9\u30C8\u304C\u7A7A\u3067\u3059");let e=o;if(t.stripHtml&&(e=bt(o),!e||e.trim().length===0))throw new Error("HTML\u30BF\u30B0\u3092\u9664\u53BB\u3057\u305F\u7D50\u679C\uFF0C\u7FFB\u8A33\u3059\u308B\u30C6\u30AD\u30B9\u30C8\u304C\u7A7A\u306B\u306A\u308A\u307E\u3057\u305F");let{translator:i,config:s,activeProfile:n}=await at(t),p=new j,a=t.flip?"ja":"en",l=t.flip?"en":"ja",c=lt(e),f=await p.findByHash(c,a,l);if(f&&t.cache!==false){console.log(`${d.green("\u2714")} \u30AD\u30E3\u30C3\u30B7\u30E5\u304B\u3089\u7FFB\u8A33\u7D50\u679C\u3092\u53D6\u5F97\u3057\u307E\u3057\u305F`);let y=f.translatedText;if(t.output)try{v.writeFileSync(t.output,y,"utf-8"),console.log(`${d.green("\u2714")} ${t.output} \u306B\u7FFB\u8A33\u7D50\u679C\u3092\u4FDD\u5B58\u3057\u307E\u3057\u305F`);}catch{throw new Error(`\u30D5\u30A1\u30A4\u30EB\u3078\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F (${t.output})`)}else console.log(y);return}let g=`(${a} \u2192 ${l})`,u=i.getModel()||s.model,$=n||"unknown",w=`[${$} | ${s.provider}${u?` | ${u}`:""}]`,H=Ot(`\u7FFB\u8A33\u4E2D... ${g} ${w}`).start();try{let F=(await i.translate(e,a,l)).text;if(H.succeed(`\u7FFB\u8A33\u5B8C\u4E86 ${g} ${w}`),await p.add({sourceText:e,translatedText:F,sourceLang:a,targetLang:l,textLength:e.length,sourceHash:c,profile:$,provider:s.provider,model:u,options:{stripHtml:t.stripHtml,file:t.file,inputMethod:r}}),t.output)try{v.writeFileSync(t.output,F,"utf-8"),console.log(`${d.green("\u2714")} ${t.output} \u306B\u7FFB\u8A33\u7D50\u679C\u3092\u4FDD\u5B58\u3057\u307E\u3057\u305F`);}catch{throw new Error(`\u30D5\u30A1\u30A4\u30EB\u3078\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F (${t.output})`)}else console.log(F);}catch(y){throw H.fail(`\u7FFB\u8A33\u5931\u6557 ${g} ${w}`),y}}function Ht(o){if(o instanceof Error)return o.message;try{return String(o)}catch{return "Unknown error"}}function kt(){return new Promise((o,t)=>{let r="";process.stdin.setEncoding("utf-8"),process.stdin.on("data",e=>{r+=e;}),process.stdin.on("end",()=>{o(r);}),process.stdin.on("error",e=>{t(e);});})}function bt(o){return o.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"").replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,"").replace(/<[^>]+>/g,"").replace(/ /g," ").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&").replace(/"/g,'"').replace(/'/g,"'").replace(/\n\s*\n/g,`
|
|
106
|
+
`).trim()}var Y=JSON.parse(readFileSync(new URL("../package.json",import.meta.url),"utf-8")),R=new Command;R.name("enja").usage("[arguments] [options]").description(Y.description).version(Y.version,"-v, --version","output the current version").addHelpText("afterAll",`
|
|
107
|
+
Enja CLI v${Y.version}`).addHelpText("afterAll","Copyright (c) 2025-2026 yhotta240").addHelpText("afterAll","GitHub: https://github.com/yhotamos/enja-cli");pt(R);nt(R);tt(R);R.parse();
|
package/package.json
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@yhotamos/enja-cli",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "英語を日本語に翻訳するシンプルなコマンドラインツール",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"files": [
|
|
8
|
-
"dist"
|
|
9
|
-
],
|
|
10
|
-
"bin": {
|
|
11
|
-
"enja": "dist/index.js"
|
|
12
|
-
},
|
|
13
|
-
"scripts": {
|
|
14
|
-
"check": "biome check src",
|
|
15
|
-
"check:fix": "biome check --write --unsafe src",
|
|
16
|
-
"typecheck": "tsc --noEmit",
|
|
17
|
-
"build": "npm run check && npm run typecheck && tsup",
|
|
18
|
-
"build:dev": "tsup --sourcemap",
|
|
19
|
-
"watch": "tsup --watch",
|
|
20
|
-
"test": "vitest"
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"translation",
|
|
24
|
-
"cli",
|
|
25
|
-
"english",
|
|
26
|
-
"japanese",
|
|
27
|
-
"enja"
|
|
28
|
-
],
|
|
29
|
-
"publishConfig": {
|
|
30
|
-
"access": "public"
|
|
31
|
-
},
|
|
32
|
-
"author": "yhotta240 <yhotta240@gmail.com> (https://github.com/yhotta240)",
|
|
33
|
-
"engines": {
|
|
34
|
-
"node": ">=18"
|
|
35
|
-
},
|
|
36
|
-
"license": "MIT",
|
|
37
|
-
"repository": {
|
|
38
|
-
"type": "git",
|
|
39
|
-
"url": "git+https://github.com/yhotamos/enja-cli.git"
|
|
40
|
-
},
|
|
41
|
-
"bugs": {
|
|
42
|
-
"url": "https://github.com/yhotamos/enja-cli/issues"
|
|
43
|
-
},
|
|
44
|
-
"homepage": "https://github.com/yhotamos/enja-cli#readme",
|
|
45
|
-
"dependencies": {
|
|
46
|
-
"@google/genai": "^1.33.0",
|
|
47
|
-
"@inquirer/prompts": "^8.3.2",
|
|
48
|
-
"commander": "^14.0.2",
|
|
49
|
-
"kleur": "^4.1.5",
|
|
50
|
-
"openai": "^6.9.1",
|
|
51
|
-
"ora": "^9.0.0"
|
|
52
|
-
},
|
|
53
|
-
"devDependencies": {
|
|
54
|
-
"@biomejs/biome": "^2.4.10",
|
|
55
|
-
"@types/node": "^24.10.1",
|
|
56
|
-
"dotenv": "^17.3.1",
|
|
57
|
-
"tsup": "^8.5.1",
|
|
58
|
-
"tsx": "^4.20.6",
|
|
59
|
-
"typescript": "^5.9.3",
|
|
60
|
-
"vitest": "^4.0.18"
|
|
61
|
-
}
|
|
62
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@yhotamos/enja-cli",
|
|
3
|
+
"version": "1.5.3",
|
|
4
|
+
"description": "英語を日本語に翻訳するシンプルなコマンドラインツール",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"bin": {
|
|
11
|
+
"enja": "dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"check": "biome check src",
|
|
15
|
+
"check:fix": "biome check --write --unsafe src",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"build": "npm run check && npm run typecheck && tsup",
|
|
18
|
+
"build:dev": "tsup --sourcemap",
|
|
19
|
+
"watch": "tsup --watch",
|
|
20
|
+
"test": "vitest"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"translation",
|
|
24
|
+
"cli",
|
|
25
|
+
"english",
|
|
26
|
+
"japanese",
|
|
27
|
+
"enja"
|
|
28
|
+
],
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"author": "yhotta240 <yhotta240@gmail.com> (https://github.com/yhotta240)",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/yhotamos/enja-cli.git"
|
|
40
|
+
},
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/yhotamos/enja-cli/issues"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/yhotamos/enja-cli#readme",
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@google/genai": "^1.33.0",
|
|
47
|
+
"@inquirer/prompts": "^8.3.2",
|
|
48
|
+
"commander": "^14.0.2",
|
|
49
|
+
"kleur": "^4.1.5",
|
|
50
|
+
"openai": "^6.9.1",
|
|
51
|
+
"ora": "^9.0.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@biomejs/biome": "^2.4.10",
|
|
55
|
+
"@types/node": "^24.10.1",
|
|
56
|
+
"dotenv": "^17.3.1",
|
|
57
|
+
"tsup": "^8.5.1",
|
|
58
|
+
"tsx": "^4.20.6",
|
|
59
|
+
"typescript": "^5.9.3",
|
|
60
|
+
"vitest": "^4.0.18"
|
|
61
|
+
}
|
|
62
|
+
}
|