cctrans 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MOTIVATION.md +78 -0
- package/README.hi.md +48 -30
- package/README.ja.md +48 -30
- package/README.ko.md +48 -30
- package/README.md +48 -30
- package/README.ru.md +48 -30
- package/README.zh-Hans.md +48 -30
- package/README.zh-Hant.md +48 -30
- package/ROADMAP.md +3 -3
- package/bin/{tt.js → cctrans.js} +39 -39
- package/hook/message-display.js +4 -4
- package/hook/user-prompt-submit.js +3 -3
- package/package.json +4 -3
- package/src/backends/anthropic.js +1 -1
- package/src/backends/azure.js +1 -1
- package/src/backends/claude-code.js +3 -3
- package/src/backends/deepl.js +1 -1
- package/src/backends/index.js +1 -1
- package/src/backends/openai.js +1 -1
- package/src/config.js +3 -3
- package/src/keys.js +3 -3
- package/src/setup.js +3 -3
- package/src/transcript.js +1 -1
package/bin/{tt.js → cctrans.js}
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
|
-
//
|
|
3
|
+
// cctrans — control + test CLI for the Claude Code bilingual overlay.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
5
|
+
// cctrans on | off | toggle | status
|
|
6
|
+
// cctrans backend <openai|google>
|
|
7
|
+
// cctrans install | uninstall register/remove the MessageDisplay hook
|
|
8
|
+
// cctrans last [N] translate the latest (or Nth-back) reply -> stdout
|
|
9
|
+
// cctrans test <text...> translate ad-hoc text -> stdout
|
|
10
|
+
// cctrans help
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const os = require('os');
|
|
@@ -36,8 +36,8 @@ function readSettings() {
|
|
|
36
36
|
try { return JSON.parse(fs.readFileSync(SETTINGS, 'utf8')); } catch (e) { return {}; }
|
|
37
37
|
}
|
|
38
38
|
function writeSettings(s) {
|
|
39
|
-
try { fs.copyFileSync(SETTINGS, SETTINGS + '.bak-
|
|
40
|
-
const tmp = SETTINGS + '.
|
|
39
|
+
try { fs.copyFileSync(SETTINGS, SETTINGS + '.bak-cctrans'); } catch (e) {}
|
|
40
|
+
const tmp = SETTINGS + '.cctrans.tmp';
|
|
41
41
|
fs.writeFileSync(tmp, JSON.stringify(s, null, 2));
|
|
42
42
|
fs.renameSync(tmp, SETTINGS);
|
|
43
43
|
}
|
|
@@ -62,7 +62,7 @@ function install() {
|
|
|
62
62
|
changed = true;
|
|
63
63
|
}
|
|
64
64
|
if (!inputHookInstalled(s)) {
|
|
65
|
-
// Registered always; the hook exits instantly unless `
|
|
65
|
+
// Registered always; the hook exits instantly unless `cctrans input on`.
|
|
66
66
|
s.hooks.UserPromptSubmit = s.hooks.UserPromptSubmit || [];
|
|
67
67
|
s.hooks.UserPromptSubmit.push({ hooks: [{ type: 'command', command: 'node ' + INPUT_HOOK_PATH }] });
|
|
68
68
|
changed = true;
|
|
@@ -73,23 +73,23 @@ function install() {
|
|
|
73
73
|
} else {
|
|
74
74
|
console.log(C.green('✓') + ' hooks already registered in ' + SETTINGS);
|
|
75
75
|
}
|
|
76
|
-
// Make `
|
|
76
|
+
// Make `cctrans` runnable from anywhere (best-effort symlink on a common PATH dir).
|
|
77
77
|
const linkDir = path.join(os.homedir(), '.local', 'bin');
|
|
78
|
-
const link = path.join(linkDir, '
|
|
78
|
+
const link = path.join(linkDir, 'cctrans');
|
|
79
79
|
try {
|
|
80
80
|
fs.mkdirSync(linkDir, { recursive: true });
|
|
81
81
|
try { fs.unlinkSync(link); } catch (e) {}
|
|
82
|
-
fs.symlinkSync(path.resolve(__dirname, '
|
|
83
|
-
fs.chmodSync(path.resolve(__dirname, '
|
|
84
|
-
console.log(C.green('✓') + ' linked `
|
|
82
|
+
fs.symlinkSync(path.resolve(__dirname, 'cctrans.js'), link);
|
|
83
|
+
fs.chmodSync(path.resolve(__dirname, 'cctrans.js'), 0o755);
|
|
84
|
+
console.log(C.green('✓') + ' linked `cctrans` -> ' + link + (process.env.PATH.includes(linkDir) ? '' : C.dim(' (add ' + linkDir + ' to PATH)')));
|
|
85
85
|
} catch (e) {
|
|
86
|
-
console.log(C.dim(' (could not symlink
|
|
86
|
+
console.log(C.dim(' (could not symlink cctrans; add alias: alias cctrans=\'node ' + path.resolve(__dirname, 'cctrans.js') + '\')'));
|
|
87
87
|
}
|
|
88
88
|
console.log('');
|
|
89
89
|
console.log('Next:');
|
|
90
90
|
console.log(' 1. Restart Claude Code (new session) so the hook loads.');
|
|
91
91
|
console.log(' 2. Send any message — replies now show ' + C.bold('English + 中文') + ' inline.');
|
|
92
|
-
console.log(' 3. Toggle anytime: ' + C.bold('!
|
|
92
|
+
console.log(' 3. Toggle anytime: ' + C.bold('!cctrans off') + ' / ' + C.bold('!cctrans on') + ' (typed inside Claude Code).');
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
function uninstall() {
|
|
@@ -114,11 +114,11 @@ function status() {
|
|
|
114
114
|
const lang = getLang(st.target);
|
|
115
115
|
console.log(C.bold('cctranslate status'));
|
|
116
116
|
console.log(' enabled : ' + (st.enabled ? C.green('ON') : C.red('OFF')));
|
|
117
|
-
console.log(' hook : ' + (installed ? C.green('installed') : C.red('not installed') + C.dim(' (run:
|
|
117
|
+
console.log(' hook : ' + (installed ? C.green('installed') : C.red('not installed') + C.dim(' (run: cctrans install)')));
|
|
118
118
|
console.log(' backend : ' + st.backend + (b ? (b.available() ? C.green(' (ready)') : C.red(' (missing: ' + b.needs + ')')) : C.red(' (unknown backend)')));
|
|
119
|
-
console.log(' lang : ' + st.target + (lang ? C.dim(' (' + lang.name + ')') : C.red(' (unsupported — see:
|
|
120
|
-
console.log(' input : ' + (st.inputEn ? C.green('ON') : 'off') + C.dim(' (prompt -> English; toggle:
|
|
121
|
-
console.log(' keys : ' + Object.keys(keys.readKeys()).length + ' in ' + keys.KEYS_FILE + C.dim(' (manage:
|
|
119
|
+
console.log(' lang : ' + st.target + (lang ? C.dim(' (' + lang.name + ')') : C.red(' (unsupported — see: cctrans lang)')));
|
|
120
|
+
console.log(' input : ' + (st.inputEn ? C.green('ON') : 'off') + C.dim(' (prompt -> English; toggle: cctrans input on|off)'));
|
|
121
|
+
console.log(' keys : ' + Object.keys(keys.readKeys()).length + ' in ' + keys.KEYS_FILE + C.dim(' (manage: cctrans key)'));
|
|
122
122
|
console.log(' state : ' + STATE_FILE);
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -141,7 +141,7 @@ function keyCmd(rest) {
|
|
|
141
141
|
|
|
142
142
|
function backends() {
|
|
143
143
|
const st = getState();
|
|
144
|
-
console.log(C.bold('backends') + C.dim(' (switch:
|
|
144
|
+
console.log(C.bold('backends') + C.dim(' (switch: cctrans backend <id>)'));
|
|
145
145
|
for (const b of listBackends()) {
|
|
146
146
|
const mark = b.id === st.backend ? C.cyan('▶ ') : ' ';
|
|
147
147
|
const ok = b.available() ? C.green('ready ') : C.red('missing ');
|
|
@@ -175,29 +175,29 @@ async function last(nBack) {
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
function help() {
|
|
178
|
-
console.log(`${C.bold('
|
|
178
|
+
console.log(`${C.bold('cctrans')} — bilingual overlay for Claude Code
|
|
179
179
|
|
|
180
180
|
${C.bold('Control')}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
181
|
+
cctrans on | off | toggle turn the inline translation on/off
|
|
182
|
+
cctrans input on | off translate non-English input to English (as context)
|
|
183
|
+
cctrans status show current state
|
|
184
|
+
cctrans lang [code] show/set target language (zh-Hans, zh-Hant, ja, ko, ru, hi)
|
|
185
|
+
cctrans backend <id> choose translation engine
|
|
186
|
+
cctrans backends list engines + availability
|
|
187
187
|
|
|
188
188
|
${C.bold('Setup')}
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
cctrans install register hooks (+ link cctrans), then run setup
|
|
190
|
+
cctrans setup interactive wizard: language, backend, API keys
|
|
191
191
|
(flags: --lang --backend --key --yes)
|
|
192
|
-
|
|
192
|
+
cctrans key [id] [value] manage API keys in ~/.cc-translate/keys.json
|
|
193
193
|
(ids: openai, anthropic, deepl, azure, azure-region)
|
|
194
|
-
|
|
194
|
+
cctrans uninstall remove the hooks
|
|
195
195
|
|
|
196
196
|
${C.bold('Manual / test')}
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
cctrans last [N] translate the latest (or N-back) assistant reply
|
|
198
|
+
cctrans test <text...> translate ad-hoc English text
|
|
199
199
|
|
|
200
|
-
${C.dim('Tip: toggle from inside Claude Code by typing !
|
|
200
|
+
${C.dim('Tip: toggle from inside Claude Code by typing !cctrans off / !cctrans on')}`);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
async function main() {
|
|
@@ -210,7 +210,7 @@ async function main() {
|
|
|
210
210
|
const id = rest[0];
|
|
211
211
|
const b = id && getBackend(id);
|
|
212
212
|
if (!b) {
|
|
213
|
-
console.error('usage:
|
|
213
|
+
console.error('usage: cctrans backend <' + listBackends().map((x) => x.id).join('|') + '>');
|
|
214
214
|
process.exit(1);
|
|
215
215
|
}
|
|
216
216
|
setState({ backend: id });
|
|
@@ -253,7 +253,7 @@ async function main() {
|
|
|
253
253
|
else if (sub === 'toggle') setState({ inputEn: !getState().inputEn });
|
|
254
254
|
const st = getState();
|
|
255
255
|
console.log('input translation (prompt -> English): ' + (st.inputEn ? C.green('ON') : C.red('OFF')) +
|
|
256
|
-
(inputHookInstalled() ? '' : C.red(' (hook not installed — run:
|
|
256
|
+
(inputHookInstalled() ? '' : C.red(' (hook not installed — run: cctrans install)')));
|
|
257
257
|
break;
|
|
258
258
|
}
|
|
259
259
|
case 'uninstall': uninstall(); break;
|
|
@@ -261,7 +261,7 @@ async function main() {
|
|
|
261
261
|
case 'last': await last(parseInt(rest[0], 10) || 0); break;
|
|
262
262
|
case 'test': {
|
|
263
263
|
const text = rest.join(' ');
|
|
264
|
-
if (!text) { console.error('usage:
|
|
264
|
+
if (!text) { console.error('usage: cctrans test <text>'); process.exit(1); }
|
|
265
265
|
await renderText(text); break;
|
|
266
266
|
}
|
|
267
267
|
case 'help': case '--help': case '-h': case undefined: help(); break;
|
package/hook/message-display.js
CHANGED
|
@@ -42,8 +42,8 @@ function saveFence(id, index, inFence, final) {
|
|
|
42
42
|
let data = '';
|
|
43
43
|
process.stdin.on('data', (d) => (data += d));
|
|
44
44
|
process.stdin.on('end', async () => {
|
|
45
|
-
if (process.env.
|
|
46
|
-
try { fs.appendFileSync(process.env.
|
|
45
|
+
if (process.env.CCTRANS_DEBUG_STDIN) {
|
|
46
|
+
try { fs.appendFileSync(process.env.CCTRANS_DEBUG_STDIN, '\n===== delta =====\n' + data + '\n'); } catch (e) {}
|
|
47
47
|
}
|
|
48
48
|
let inp = {};
|
|
49
49
|
try { inp = JSON.parse(data); } catch (e) { return showOriginal(); }
|
|
@@ -52,8 +52,8 @@ process.stdin.on('end', async () => {
|
|
|
52
52
|
if (!delta) return showOriginal();
|
|
53
53
|
|
|
54
54
|
// Recursion guard: the claude-code backend spawns `claude -p` with
|
|
55
|
-
//
|
|
56
|
-
if (process.env.
|
|
55
|
+
// CCTRANS_DISABLE=1 so a child Claude process can never re-enter this hook.
|
|
56
|
+
if (process.env.CCTRANS_DISABLE) return showOriginal();
|
|
57
57
|
|
|
58
58
|
let st;
|
|
59
59
|
try { st = getState(); } catch (e) { return showOriginal(); }
|
|
@@ -23,10 +23,10 @@ function passThrough() { process.exit(0); }
|
|
|
23
23
|
let data = '';
|
|
24
24
|
process.stdin.on('data', (d) => (data += d));
|
|
25
25
|
process.stdin.on('end', async () => {
|
|
26
|
-
if (process.env.
|
|
27
|
-
try { require('fs').appendFileSync(process.env.
|
|
26
|
+
if (process.env.CCTRANS_DEBUG_STDIN) {
|
|
27
|
+
try { require('fs').appendFileSync(process.env.CCTRANS_DEBUG_STDIN, '\n===== prompt =====\n' + data + '\n'); } catch (e) {}
|
|
28
28
|
}
|
|
29
|
-
if (process.env.
|
|
29
|
+
if (process.env.CCTRANS_DISABLE) return passThrough();
|
|
30
30
|
|
|
31
31
|
let inp = {};
|
|
32
32
|
try { inp = JSON.parse(data); } catch (e) { return passThrough(); }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cctrans",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Bilingual inline translation overlay for Claude Code: a translated line (zh/ja/ko/ru/hi) under each English line, right in the conversation — non-destructive, zero main-loop tokens.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Roy Jiang",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"korean"
|
|
25
25
|
],
|
|
26
26
|
"bin": {
|
|
27
|
-
"
|
|
27
|
+
"cctrans": "bin/cctrans.js"
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"bin/",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"src/",
|
|
33
33
|
"README*.md",
|
|
34
34
|
"ROADMAP.md",
|
|
35
|
-
"LICENSE"
|
|
35
|
+
"LICENSE",
|
|
36
|
+
"MOTIVATION.md"
|
|
36
37
|
],
|
|
37
38
|
"engines": {
|
|
38
39
|
"node": ">=18"
|
|
@@ -16,7 +16,7 @@ const SCHEMA = {
|
|
|
16
16
|
module.exports = {
|
|
17
17
|
id: 'anthropic',
|
|
18
18
|
kind: 'llm',
|
|
19
|
-
needs: 'anthropic key (
|
|
19
|
+
needs: 'anthropic key (cctrans key anthropic <value>)',
|
|
20
20
|
available() { return !!getKey('anthropic'); },
|
|
21
21
|
async translate(lines, langCode, opts) {
|
|
22
22
|
opts = opts || {};
|
package/src/backends/azure.js
CHANGED
|
@@ -8,7 +8,7 @@ const { getKey } = require('../keys');
|
|
|
8
8
|
module.exports = {
|
|
9
9
|
id: 'azure',
|
|
10
10
|
kind: 'mt',
|
|
11
|
-
needs: 'azure key (
|
|
11
|
+
needs: 'azure key (cctrans key azure <value>; region: cctrans key azure-region <value>)',
|
|
12
12
|
available() { return !!getKey('azure'); },
|
|
13
13
|
async translate(lines, langCode) {
|
|
14
14
|
const key = getKey('azure');
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// on the user's Claude subscription (no separate API key). Measured ~3s per
|
|
4
4
|
// call (CLI startup) — usable within the hook's 10s budget but noticeably
|
|
5
5
|
// slower than HTTP backends; offered as the no-key option, not the default.
|
|
6
|
-
//
|
|
6
|
+
// CCTRANS_DISABLE=1 is set on the child as a recursion guard (the hook exits early
|
|
7
7
|
// when it sees it), and --settings {} -style hook loading is avoided by -p
|
|
8
8
|
// print mode having no display path.
|
|
9
9
|
const { execFile } = require('child_process');
|
|
@@ -16,7 +16,7 @@ function runClaude(prompt, timeoutMs) {
|
|
|
16
16
|
['-p', '--model', 'claude-haiku-4-5', '--output-format', 'text'],
|
|
17
17
|
{
|
|
18
18
|
timeout: timeoutMs,
|
|
19
|
-
env: Object.assign({}, process.env, {
|
|
19
|
+
env: Object.assign({}, process.env, { CCTRANS_DISABLE: '1' }),
|
|
20
20
|
maxBuffer: 1024 * 1024,
|
|
21
21
|
},
|
|
22
22
|
(err, stdout) => (err ? reject(err) : resolve(stdout)),
|
|
@@ -29,7 +29,7 @@ module.exports = {
|
|
|
29
29
|
id: 'claude-code',
|
|
30
30
|
kind: 'cli',
|
|
31
31
|
needs: 'claude CLI logged in (uses your subscription; ~3s/call)',
|
|
32
|
-
available() { return !process.env.
|
|
32
|
+
available() { return !process.env.CCTRANS_DISABLE; },
|
|
33
33
|
async translate(lines, langCode, opts) {
|
|
34
34
|
opts = opts || {};
|
|
35
35
|
const lang = getLang(langCode);
|
package/src/backends/deepl.js
CHANGED
|
@@ -8,7 +8,7 @@ const { getKey } = require('../keys');
|
|
|
8
8
|
module.exports = {
|
|
9
9
|
id: 'deepl',
|
|
10
10
|
kind: 'mt',
|
|
11
|
-
needs: 'deepl key (
|
|
11
|
+
needs: 'deepl key (cctrans key deepl <value>)',
|
|
12
12
|
available() { return !!getKey('deepl'); },
|
|
13
13
|
async translate(lines, langCode) {
|
|
14
14
|
const key = getKey('deepl');
|
package/src/backends/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Backend registry. Each backend implements:
|
|
3
3
|
// id - string
|
|
4
4
|
// kind - 'llm' | 'mt' | 'cli' (informational)
|
|
5
|
-
// needs - human-readable requirement shown by `
|
|
5
|
+
// needs - human-readable requirement shown by `cctrans backends`
|
|
6
6
|
// available() -> boolean (are its prerequisites present?)
|
|
7
7
|
// translate(lines, langCode, opts) -> Promise<string[]> (same length/order)
|
|
8
8
|
|
package/src/backends/openai.js
CHANGED
|
@@ -6,7 +6,7 @@ const { getKey } = require('../keys');
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
id: 'openai',
|
|
8
8
|
kind: 'llm',
|
|
9
|
-
needs: 'openai key (
|
|
9
|
+
needs: 'openai key (cctrans key openai <value>)',
|
|
10
10
|
available() { return !!getKey('openai'); },
|
|
11
11
|
async translate(lines, langCode, opts) {
|
|
12
12
|
opts = opts || {};
|
package/src/config.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
// Persistent settings for the translator. Everything user-configurable lives
|
|
3
3
|
// in files under ~/.cc-translate/ — never in shell environment variables:
|
|
4
|
-
// state.json — settings (this module); edit by hand or via
|
|
4
|
+
// state.json — settings (this module); edit by hand or via cctrans commands
|
|
5
5
|
// keys.json — API secrets (src/keys.js); chmod 600
|
|
6
|
-
//
|
|
6
|
+
// CCTRANS_HOME (test plumbing) and CCTRANS_DISABLE/CCTRANS_DEBUG_STDIN (hook internals) are
|
|
7
7
|
// the only env vars the tool reads.
|
|
8
8
|
|
|
9
9
|
const fs = require('fs');
|
|
@@ -11,7 +11,7 @@ const os = require('os');
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
|
|
13
13
|
const HOME = os.homedir();
|
|
14
|
-
const BASE = process.env.
|
|
14
|
+
const BASE = process.env.CCTRANS_HOME || path.join(HOME, '.cc-translate');
|
|
15
15
|
const STATE_FILE = path.join(BASE, 'state.json');
|
|
16
16
|
const CACHE_DIR = path.join(BASE, 'cache');
|
|
17
17
|
|
package/src/keys.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
// API-key store. Keys come from exactly ONE place: ~/.cc-translate/keys.json
|
|
3
|
-
// (chmod 600), written by `
|
|
3
|
+
// (chmod 600), written by `cctrans setup` / `cctrans key` or edited by hand. Shell
|
|
4
4
|
// environment variables are never consulted — this tool's keys and the
|
|
5
5
|
// terminal's keys cannot contaminate each other.
|
|
6
6
|
//
|
|
7
7
|
// NOTE: keys.js must not require config.js (config.js requires us for the
|
|
8
|
-
// default-backend decision).
|
|
8
|
+
// default-backend decision). CCTRANS_HOME is internal plumbing for tests only.
|
|
9
9
|
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const os = require('os');
|
|
12
12
|
const path = require('path');
|
|
13
13
|
|
|
14
|
-
const BASE = process.env.
|
|
14
|
+
const BASE = process.env.CCTRANS_HOME || path.join(os.homedir(), '.cc-translate');
|
|
15
15
|
const KEYS_FILE = path.join(BASE, 'keys.json');
|
|
16
16
|
|
|
17
17
|
const KEY_IDS = ['openai', 'anthropic', 'deepl', 'azure', 'azure-region'];
|
package/src/setup.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
// Interactive setup wizard: language -> backend -> API-key entry -> live
|
|
3
|
-
// verification -> save. Re-runnable via `
|
|
3
|
+
// verification -> save. Re-runnable via `cctrans setup`; non-interactive with
|
|
4
4
|
// flags (--lang, --backend, --key, --yes). Keys go to keys.json only — the
|
|
5
5
|
// shell environment is never read.
|
|
6
6
|
|
|
@@ -32,7 +32,7 @@ async function runSetup(opts) {
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
try {
|
|
35
|
-
console.log(C.bold('cctranslate setup') + C.dim(' (re-run anytime:
|
|
35
|
+
console.log(C.bold('cctranslate setup') + C.dim(' (re-run anytime: cctrans setup)'));
|
|
36
36
|
|
|
37
37
|
// 1. Target language
|
|
38
38
|
let lang = opts.lang;
|
|
@@ -89,7 +89,7 @@ async function runSetup(opts) {
|
|
|
89
89
|
console.log(C.red('verification failed: ' + e.message));
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
console.log(C.dim('\nNext: restart Claude Code (new session). Toggle with `!
|
|
92
|
+
console.log(C.dim('\nNext: restart Claude Code (new session). Toggle with `!cctrans off` / `!cctrans on`; input translation: `cctrans input on`.'));
|
|
93
93
|
return true;
|
|
94
94
|
} finally {
|
|
95
95
|
if (rl) rl.close();
|
package/src/transcript.js
CHANGED
|
@@ -49,7 +49,7 @@ function newestJsonlIn(dir) {
|
|
|
49
49
|
// 3) globally newest .jsonl across all projects (the active session is
|
|
50
50
|
// almost always the most recently written one).
|
|
51
51
|
function findTranscript(cwd) {
|
|
52
|
-
if (process.env.
|
|
52
|
+
if (process.env.CCTRANS_TRANSCRIPT) return process.env.CCTRANS_TRANSCRIPT;
|
|
53
53
|
|
|
54
54
|
const root = projectsRoot();
|
|
55
55
|
const dir = path.join(root, slugForCwd(cwd || process.cwd()));
|