@swttch/extend-kit 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ko.md CHANGED
@@ -8,7 +8,7 @@
8
8
  | --- | --- |
9
9
  | **battery** | *사용자 본인의* 머신에 저장된 Claude Code 로그인 정보(keychain 또는 자격증명 파일)를 읽어야 합니다 |
10
10
  | **stt** | 받아쓰기는 OAuth 토큰을 전송하는데, JetBrains 플러그인은 자격증명을 다룰 수 없습니다 |
11
- | **swttch-ext** | 저장된 로그인으로 내 계정에 대해 호출합니다(아티팩트: 목록, 이름 변경, 고정, 삭제) |
11
+ | **swttch-ext** | 저장된 로그인으로 내 계정에 대해 호출합니다(아티팩트: 목록, 이름 변경, 고정, 삭제. `tts`: 글을 소리로 읽기) |
12
12
 
13
13
  ## battery
14
14
 
@@ -41,12 +41,14 @@ Claude가 게시한 [아티팩트](https://code.claude.com/docs/en/artifacts)를
41
41
  | `frame retitle` | 이름 바꾸기. 페이지의 `<title>`이 고쳐지고, 새 버전으로 저장됩니다 | `--slug`, `--title` |
42
42
  | `frame pin` | 고정 | `--slug` |
43
43
  | `frame unpin` | 고정 해제 | `--slug` |
44
+ | `frame duplicate` | 아티팩트를 내 계정에 복제합니다. 응답에 복사본의 `slug`가 들어 있고, 이름은 "<이름> (Copy)"가 됩니다 | `--slug` |
44
45
  | `frame delete` | 완전히 삭제. 링크가 모두에게 열리지 않게 되고 되돌릴 수 없습니다 | `--slug`, `--yes` |
45
46
 
46
47
  ```bash
47
48
  swttch-ext api frame list --limit 10
48
49
  swttch-ext api frame retitle --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d --title "분기 보고서"
49
50
  swttch-ext api frame pin --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d
51
+ swttch-ext api frame duplicate --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d
50
52
  swttch-ext api frame delete --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d --yes
51
53
  ```
52
54
 
@@ -54,6 +56,16 @@ swttch-ext api frame delete --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d --yes
54
56
  - **`<title>`이 없는 페이지는 이름을 바꿀 수 없습니다**(`rejected`). 페이지에 `<title>`을 넣고 다시 게시한 뒤에 바꾸세요.
55
57
  - 이름 변경·고정·삭제는 내가 소유한 아티팩트에만 됩니다. 남의 것은 `not_found`로 답합니다.
56
58
 
59
+ ### 글을 소리로 읽기: `swttch-ext tts`
60
+
61
+ 표준 입력으로 받은 글을 Claude 데스크탑 앱의 "소리 내어 읽기"와 같은 음성 서비스로 읽고, 소리를 원시 PCM(16비트 리틀엔디언, 16kHz, 모노)으로 표준 출력에 내보냅니다. API 키가 아니라 Claude 계정 로그인이 필요합니다. 엔드포인트는 공식 문서에 없습니다.
62
+
63
+ ```bash
64
+ echo "터미널에서 읽어 줍니다." | swttch-ext tts --language ko | play -t raw -r 16000 -e signed -b 16 -c 1 -
65
+ ```
66
+
67
+ 옵션: `--language <코드>`(`ko` 같은 힌트), `--speed <0.7~1.5>`, `--voice <이름>`. 다 읽으면 0으로, 실패하면 1로 끝나며 표준 오류에 한 줄 JSON(`{"ok":false,"error":{"code","message","fatal"}}`)을 씁니다. 프로세스를 끄면 읽기가 멈춥니다.
68
+
57
69
  ### 이 버전이 할 수 있는 일 알아보기
58
70
 
59
71
  ```bash
package/README.md CHANGED
@@ -8,7 +8,7 @@ The companion tools [Swttch](https://github.com/Swttch/swttch) needs but cannot
8
8
  | --- | --- |
9
9
  | **battery** | Reads the Claude Code login stored on *your* machine (keychain, or a credentials file) |
10
10
  | **stt** | Dictation sends your OAuth token, and a JetBrains plugin may not handle credentials |
11
- | **swttch-ext** | Acts on your account with the saved login (artifacts: list, rename, pin, delete) |
11
+ | **swttch-ext** | Acts on your account with the saved login (artifacts: list, rename, pin, delete; `tts`: read text aloud) |
12
12
 
13
13
  ## battery
14
14
 
@@ -41,12 +41,14 @@ Manage the pages Claude published as [Artifacts](https://code.claude.com/docs/en
41
41
  | `frame retitle` | Renames an artifact. The page's `<title>` is rewritten, and the change is saved as a new version | `--slug`, `--title` |
42
42
  | `frame pin` | Pins an artifact | `--slug` |
43
43
  | `frame unpin` | Removes the pin | `--slug` |
44
+ | `frame duplicate` | Makes a copy of an artifact under your account. The answer carries the copy's `slug`; the copy is named "<name> (Copy)" | `--slug` |
44
45
  | `frame delete` | Deletes an artifact for good. Its link stops working for everyone and it cannot be restored | `--slug`, `--yes` |
45
46
 
46
47
  ```bash
47
48
  swttch-ext api frame list --limit 10
48
49
  swttch-ext api frame retitle --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d --title "Quarterly report"
49
50
  swttch-ext api frame pin --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d
51
+ swttch-ext api frame duplicate --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d
50
52
  swttch-ext api frame delete --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d --yes
51
53
  ```
52
54
 
@@ -54,6 +56,16 @@ swttch-ext api frame delete --slug 3627498c-4893-4ce8-bfaf-524f7b041c1d --yes
54
56
  - **A page with no `<title>` cannot be renamed** (`rejected`): add a `<title>` to the page and publish it again first.
55
57
  - Only artifacts you own can be renamed, pinned or deleted; for anyone else's the answer is `not_found`.
56
58
 
59
+ ### Reading text aloud: `swttch-ext tts`
60
+
61
+ Reads the text on stdin aloud with the same voice service the Claude desktop app's "Read aloud" uses, and writes the audio to stdout as raw PCM (16-bit little-endian, 16 kHz, mono). It needs a Claude account login, not an API key. The endpoint is undocumented.
62
+
63
+ ```bash
64
+ echo "Hello from the terminal." | swttch-ext tts | play -t raw -r 16000 -e signed -b 16 -c 1 -
65
+ ```
66
+
67
+ Options: `--language <code>` (a hint such as `ko`), `--speed <0.7-1.5>`, `--voice <name>`. It exits 0 when everything was read and 1 on failure, with one JSON line on stderr: `{"ok":false,"error":{"code","message","fatal"}}`. Killing the process stops the reading.
68
+
57
69
  ### Finding out what this version can do
58
70
 
59
71
  ```bash
package/dist/ext/index.js CHANGED
@@ -5,6 +5,7 @@ import { dirname, resolve } from 'node:path';
5
5
  import { applySettingsEnv } from '../settings-env.js';
6
6
  import { OPERATIONS, operationCapabilities } from './operations.js';
7
7
  import { describeError, runOperation } from './run.js';
8
+ import { runTextToSpeech, TTS_CAPABILITY } from './tts.js';
8
9
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
10
  const VERSION = JSON.parse(readFileSync(resolve(__dirname, '../../package.json'), 'utf-8')).version;
10
11
  const args = process.argv.slice(2);
@@ -65,6 +66,8 @@ Usage: swttch-ext api <service> <call> [--param value ...] [--yes] [--json]
65
66
 
66
67
  swttch-ext api --list List the calls this version can make
67
68
  swttch-ext --capabilities List what this version can do, as JSON
69
+ swttch-ext tts [--language ko] [--speed 1.0] [--voice <name>]
70
+ Read the text on stdin aloud: raw audio on stdout
68
71
  swttch-ext api frame retitle --slug <id> --title "New name"
69
72
  swttch-ext api frame pin --slug <id>
70
73
  swttch-ext api frame delete --slug <id> --yes
@@ -78,7 +81,7 @@ async function main() {
78
81
  return 0;
79
82
  }
80
83
  if (flags.has('capabilities')) {
81
- console.log(JSON.stringify({ capabilities: operationCapabilities() }));
84
+ console.log(JSON.stringify({ capabilities: [...operationCapabilities(), TTS_CAPABILITY] }));
82
85
  return 0;
83
86
  }
84
87
  if (flags.has('help') || positionals.length === 0) {
@@ -86,6 +89,12 @@ async function main() {
86
89
  return 0;
87
90
  }
88
91
  const [command, service, call] = positionals;
92
+ if (command === 'tts') {
93
+ for (const [name, value] of env)
94
+ process.env[name] = value;
95
+ await applySettingsEnv(process.cwd(), new Set(env.map(([name]) => name)));
96
+ return runTextToSpeech({ language: values.language, speed: values.speed, voice: values.voice });
97
+ }
89
98
  if (command !== 'api') {
90
99
  console.error(`Unknown command: ${command}\n\n${HELP}`);
91
100
  return 1;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ext/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ext/index.ts"],"names":[],"mappings":"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"}
@@ -80,6 +80,22 @@ export const OPERATIONS = [
80
80
  errors: [NOT_OWNER_OR_GONE],
81
81
  about: 'Unpin an artifact',
82
82
  },
83
+ {
84
+ service: 'frame',
85
+ name: 'duplicate',
86
+ method: 'POST',
87
+ path: '/api/frame/duplicate/{slug}',
88
+ params: [SLUG],
89
+ capability: 'api.frame.duplicate',
90
+ destructive: false,
91
+ errors: [
92
+ { status: 404, code: 'not_found', message: 'Artifact not found, or it cannot be copied.' },
93
+ { status: 403, code: 'refused', message: 'This artifact cannot be copied by you.' },
94
+ { status: 409, code: 'refused', message: 'The copy was refused.' },
95
+ { status: 429, code: 'rate_limited', message: 'Too many copies today. Try again later.' },
96
+ ],
97
+ about: 'Make a copy of an artifact; the answer carries the copy\'s id',
98
+ },
83
99
  {
84
100
  service: 'frame',
85
101
  name: 'delete',
@@ -1 +1 @@
1
- {"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/ext/operations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/ext/operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /** The name `--capabilities` lists for this command, so the plugin can tell a kit that has it from one that does not. */
2
+ export declare const TTS_CAPABILITY = "tts";
3
+ /**
4
+ * `swttch-ext tts` — reading text aloud as a process, not as a library.
5
+ *
6
+ * ── stdin ── the text to read, UTF-8, until it closes.
7
+ * ── stdout ── raw audio and nothing else: 16-bit little-endian PCM, 16 kHz, mono, as it arrives.
8
+ * ── stderr ── on failure, one JSON line: {"ok":false,"error":{"code","message","fatal"}}.
9
+ * ── exit ─── 0 when the service said everything, 1 when it failed. Killing the process stops the reading.
10
+ *
11
+ * A terminal user can drive it by hand (macOS):
12
+ *
13
+ * echo "Hello" | swttch-ext tts | play -t raw -r 16000 -e signed -b 16 -c 1 -
14
+ *
15
+ * The plugin cannot ask the service itself: that sends the account's OAuth token, and a JetBrains plugin may not
16
+ * handle credentials. It runs this command and relays the audio.
17
+ */
18
+ export declare function runTextToSpeech(options: {
19
+ language?: string;
20
+ speed?: string;
21
+ voice?: string;
22
+ }): Promise<number>;
@@ -0,0 +1,48 @@
1
+ import { openTextToSpeechStream } from '../tts/index.js';
2
+ /** The name `--capabilities` lists for this command, so the plugin can tell a kit that has it from one that does not. */
3
+ export const TTS_CAPABILITY = 'tts';
4
+ /**
5
+ * `swttch-ext tts` — reading text aloud as a process, not as a library.
6
+ *
7
+ * ── stdin ── the text to read, UTF-8, until it closes.
8
+ * ── stdout ── raw audio and nothing else: 16-bit little-endian PCM, 16 kHz, mono, as it arrives.
9
+ * ── stderr ── on failure, one JSON line: {"ok":false,"error":{"code","message","fatal"}}.
10
+ * ── exit ─── 0 when the service said everything, 1 when it failed. Killing the process stops the reading.
11
+ *
12
+ * A terminal user can drive it by hand (macOS):
13
+ *
14
+ * echo "Hello" | swttch-ext tts | play -t raw -r 16000 -e signed -b 16 -c 1 -
15
+ *
16
+ * The plugin cannot ask the service itself: that sends the account's OAuth token, and a JetBrains plugin may not
17
+ * handle credentials. It runs this command and relays the audio.
18
+ */
19
+ export async function runTextToSpeech(options) {
20
+ const chunks = [];
21
+ for await (const chunk of process.stdin)
22
+ chunks.push(Buffer.from(chunk));
23
+ const text = Buffer.concat(chunks).toString('utf8');
24
+ const speed = options.speed === undefined || options.speed === '' ? undefined : Number(options.speed);
25
+ return new Promise((resolve) => {
26
+ const stopOnPipeClosed = () => {
27
+ // The reader went away (the plugin stopped listening): there is nobody to read to.
28
+ stream?.then((s) => s.cancel()).finally(() => resolve(0));
29
+ };
30
+ process.stdout.on('error', stopOnPipeClosed);
31
+ const stream = openTextToSpeechStream(text, {
32
+ onAudio: (audio) => {
33
+ process.stdout.write(audio);
34
+ },
35
+ onDone: () => resolve(0),
36
+ onError: (message, info) => {
37
+ process.stderr.write(`${JSON.stringify({ ok: false, error: { code: 'tts_failed', message, fatal: info?.fatal ?? false } })}\n`);
38
+ resolve(1);
39
+ },
40
+ }, { language: options.language || undefined, voice: options.voice || undefined, speed }).catch((err) => {
41
+ const message = err instanceof Error ? err.message : String(err);
42
+ process.stderr.write(`${JSON.stringify({ ok: false, error: { code: 'not_logged_in', message, fatal: true } })}\n`);
43
+ resolve(1);
44
+ return undefined;
45
+ });
46
+ });
47
+ }
48
+ //# sourceMappingURL=tts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts.js","sourceRoot":"","sources":["../../src/ext/tts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,yHAAyH;AACzH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC;AAEpC;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA8D;IAClG,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC,CAAC;IACnF,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEpD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAEtG,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;QACrC,MAAM,gBAAgB,GAAG,GAAS,EAAE;YAClC,mFAAmF;YACnF,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,CAAC,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;QAE7C,MAAM,MAAM,GAAG,sBAAsB,CACnC,IAAI,EACJ;YACE,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;YACD,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YACxB,OAAO,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE;gBACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;gBAChI,OAAO,CAAC,CAAC,CAAC,CAAC;YACb,CAAC;SACF,EACD,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS,EAAE,KAAK,EAAE,CACtF,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACvB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;YACnH,OAAO,CAAC,CAAC,CAAC,CAAC;YACX,OAAO,SAAkB,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Text-to-speech: reading a reply aloud with the service the Claude desktop app uses.
3
+ *
4
+ * Outside the plugin bundle for the same reason as dictation: it sends the account's OAuth token.
5
+ */
6
+ export { openTextToSpeechStream, isTextToSpeechAvailable, splitForSpeech, SPEECH_AUDIO_FORMAT, SPEECH_SPEED_RANGE } from './stream.js';
7
+ export type { TextToSpeechOptions, TextToSpeechHandlers, TextToSpeechStream } from './stream.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Text-to-speech: reading a reply aloud with the service the Claude desktop app uses.
3
+ *
4
+ * Outside the plugin bundle for the same reason as dictation: it sends the account's OAuth token.
5
+ */
6
+ export { openTextToSpeechStream, isTextToSpeechAvailable, splitForSpeech, SPEECH_AUDIO_FORMAT, SPEECH_SPEED_RANGE } from './stream.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tts/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,cAAc,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,51 @@
1
+ /** What the service sends back: 16-bit little-endian PCM, 16 kHz, mono. */
2
+ export declare const SPEECH_AUDIO_FORMAT: {
3
+ readonly encoding: "pcm_16000";
4
+ readonly sampleRate: 16000;
5
+ readonly channels: 1;
6
+ };
7
+ /** The speed range the service accepts, as the official clients clamp it. */
8
+ export declare const SPEECH_SPEED_RANGE: {
9
+ readonly min: 0.7;
10
+ readonly max: 1.5;
11
+ };
12
+ export interface TextToSpeechOptions {
13
+ /** A voice name the service knows; the service's own default when omitted. */
14
+ voice?: string;
15
+ /** Playback speed, kept within {@link SPEECH_SPEED_RANGE}. */
16
+ speed?: number;
17
+ /** A BCP-47 language hint such as "ko". */
18
+ language?: string;
19
+ }
20
+ export interface TextToSpeechHandlers {
21
+ /** A piece of audio, in {@link SPEECH_AUDIO_FORMAT}. Arrives in order. */
22
+ onAudio: (chunk: Buffer) => void;
23
+ /** The service said everything it was given. Fired once, after the last audio. */
24
+ onDone: () => void;
25
+ /** The reading failed. `fatal` means retrying will not help (the account is refused). */
26
+ onError: (message: string, info?: {
27
+ fatal?: boolean;
28
+ }) => void;
29
+ }
30
+ export interface TextToSpeechStream {
31
+ /** Stop now. No handler fires after this. */
32
+ cancel: () => void;
33
+ }
34
+ /**
35
+ * Cut `text` into pieces of at most {@link MAX_CHUNK_CHARS}, at sentence ends and blank lines where it can.
36
+ * The service reads each piece as it arrives, so the first audio comes before the last piece is sent.
37
+ */
38
+ export declare function splitForSpeech(text: string): string[];
39
+ /**
40
+ * Read `text` aloud by streaming it to the same service the Claude desktop app's "Read aloud" uses.
41
+ *
42
+ * Lives in this package, outside the plugin bundle, for the reason dictation does: asking for speech sends the
43
+ * account's OAuth token, and a JetBrains plugin may not handle credentials. The plugin runs `swttch-ext tts` and
44
+ * only ever sees audio coming back.
45
+ *
46
+ * The endpoint is undocumented. It is called the way the desktop app calls it, and every message is treated as
47
+ * untrusted: an unknown message type is ignored rather than raised, so a type added server-side breaks nothing.
48
+ */
49
+ export declare function openTextToSpeechStream(text: string, handlers: TextToSpeechHandlers, options?: TextToSpeechOptions, token?: string): Promise<TextToSpeechStream>;
50
+ /** Whether this machine can ask for speech: a Claude Code login that has not expired. */
51
+ export declare function isTextToSpeechAvailable(): Promise<boolean>;
@@ -0,0 +1,211 @@
1
+ import WebSocket from 'ws';
2
+ import { getCredentials, getAccessToken, isTokenExpired } from '../battery/auth/index.js';
3
+ import { CcbError } from '../battery/errors.js';
4
+ import { proxyAgentFor } from '../proxy.js';
5
+ const TEXT_TO_SPEECH_URL = 'wss://api.anthropic.com/api/ws/text_to_speech/text_stream';
6
+ /** What the service sends back: 16-bit little-endian PCM, 16 kHz, mono. */
7
+ export const SPEECH_AUDIO_FORMAT = { encoding: 'pcm_16000', sampleRate: 16000, channels: 1 };
8
+ /** The speed range the service accepts, as the official clients clamp it. */
9
+ export const SPEECH_SPEED_RANGE = { min: 0.7, max: 1.5 };
10
+ /** Longest text one `text_chunk` carries; longer text is cut at sentence ends. */
11
+ const MAX_CHUNK_CHARS = 800;
12
+ /** The service drops idle sockets; this is well inside its window. */
13
+ const KEEPALIVE_INTERVAL_MS = 4000;
14
+ /** How long to wait for the first audio before giving up on a socket that opened but says nothing. */
15
+ const FIRST_AUDIO_TIMEOUT_MS = 25000;
16
+ /**
17
+ * Cut `text` into pieces of at most {@link MAX_CHUNK_CHARS}, at sentence ends and blank lines where it can.
18
+ * The service reads each piece as it arrives, so the first audio comes before the last piece is sent.
19
+ */
20
+ export function splitForSpeech(text) {
21
+ const trimmed = text.trim();
22
+ if (trimmed === '')
23
+ return [];
24
+ if (trimmed.length <= MAX_CHUNK_CHARS)
25
+ return [trimmed];
26
+ const sentences = trimmed.split(/(?<=[.!?。!?])\s+|\n{2,}/);
27
+ const chunks = [];
28
+ let current = '';
29
+ for (const sentence of sentences) {
30
+ if (current && current.length + sentence.length + 1 > MAX_CHUNK_CHARS) {
31
+ chunks.push(current);
32
+ current = sentence;
33
+ }
34
+ else {
35
+ current = current ? `${current} ${sentence}` : sentence;
36
+ }
37
+ }
38
+ if (current)
39
+ chunks.push(current);
40
+ // A single sentence longer than the limit is cut where it stands: the service takes no more than this at once.
41
+ return chunks.flatMap((chunk) => {
42
+ if (chunk.length <= MAX_CHUNK_CHARS)
43
+ return [chunk];
44
+ const parts = [];
45
+ for (let at = 0; at < chunk.length; at += MAX_CHUNK_CHARS)
46
+ parts.push(chunk.slice(at, at + MAX_CHUNK_CHARS));
47
+ return parts;
48
+ });
49
+ }
50
+ function clampSpeed(speed) {
51
+ if (speed === undefined || !Number.isFinite(speed))
52
+ return undefined;
53
+ return Math.min(SPEECH_SPEED_RANGE.max, Math.max(SPEECH_SPEED_RANGE.min, speed));
54
+ }
55
+ /**
56
+ * Read `text` aloud by streaming it to the same service the Claude desktop app's "Read aloud" uses.
57
+ *
58
+ * Lives in this package, outside the plugin bundle, for the reason dictation does: asking for speech sends the
59
+ * account's OAuth token, and a JetBrains plugin may not handle credentials. The plugin runs `swttch-ext tts` and
60
+ * only ever sees audio coming back.
61
+ *
62
+ * The endpoint is undocumented. It is called the way the desktop app calls it, and every message is treated as
63
+ * untrusted: an unknown message type is ignored rather than raised, so a type added server-side breaks nothing.
64
+ */
65
+ export async function openTextToSpeechStream(text, handlers, options = {}, token) {
66
+ const accessToken = token ?? getAccessToken(await getCredentials());
67
+ const chunks = splitForSpeech(text);
68
+ const speed = clampSpeed(options.speed);
69
+ const query = new URLSearchParams({
70
+ output_format: SPEECH_AUDIO_FORMAT.encoding,
71
+ ...(options.voice ? { voice: options.voice } : {}),
72
+ ...(speed === undefined ? {} : { tts_speed: speed.toFixed(2) }),
73
+ client_platform: 'claude_code_swttch',
74
+ ...(options.language ? { language: options.language } : {}),
75
+ });
76
+ const url = `${TEXT_TO_SPEECH_URL}?${query.toString()}`;
77
+ const socket = new WebSocket(url, {
78
+ headers: {
79
+ Authorization: `Bearer ${accessToken}`,
80
+ 'x-app': 'swttch',
81
+ 'anthropic-client-platform': 'claude_code_swttch',
82
+ },
83
+ // The upgrade request needs the same proxy the other calls use.
84
+ agent: proxyAgentFor(url),
85
+ });
86
+ let finished = false;
87
+ let audioSeen = false;
88
+ let keepalive = null;
89
+ let firstAudioTimer = null;
90
+ const stopTimers = () => {
91
+ if (keepalive)
92
+ clearInterval(keepalive);
93
+ if (firstAudioTimer)
94
+ clearTimeout(firstAudioTimer);
95
+ keepalive = null;
96
+ firstAudioTimer = null;
97
+ };
98
+ const finish = () => {
99
+ if (finished)
100
+ return false;
101
+ finished = true;
102
+ stopTimers();
103
+ return true;
104
+ };
105
+ const fail = (message, info) => {
106
+ if (!finish())
107
+ return;
108
+ try {
109
+ socket.close();
110
+ }
111
+ catch { /* already gone */ }
112
+ handlers.onError(message, info);
113
+ };
114
+ if (chunks.length === 0) {
115
+ finished = true;
116
+ handlers.onDone();
117
+ return { cancel: () => undefined };
118
+ }
119
+ socket.on('open', () => {
120
+ for (const piece of chunks)
121
+ socket.send(JSON.stringify({ type: 'text_chunk', text: piece }));
122
+ socket.send(JSON.stringify({ type: 'close_stream' }));
123
+ keepalive = setInterval(() => {
124
+ if (socket.readyState === WebSocket.OPEN)
125
+ socket.send(JSON.stringify({ type: 'keep_alive' }));
126
+ }, KEEPALIVE_INTERVAL_MS);
127
+ firstAudioTimer = setTimeout(() => {
128
+ if (!audioSeen)
129
+ fail('The speech service did not answer in time.');
130
+ }, FIRST_AUDIO_TIMEOUT_MS);
131
+ });
132
+ socket.on('message', (data, isBinary) => {
133
+ if (finished)
134
+ return;
135
+ if (isBinary) {
136
+ const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
137
+ audioSeen = true;
138
+ if (firstAudioTimer) {
139
+ clearTimeout(firstAudioTimer);
140
+ firstAudioTimer = null;
141
+ }
142
+ handlers.onAudio(chunk);
143
+ return;
144
+ }
145
+ let message;
146
+ try {
147
+ message = JSON.parse(data.toString());
148
+ }
149
+ catch {
150
+ return;
151
+ }
152
+ if (message.type === 'SpeechComplete') {
153
+ if (!finish())
154
+ return;
155
+ try {
156
+ socket.close();
157
+ }
158
+ catch { /* already gone */ }
159
+ handlers.onDone();
160
+ }
161
+ else if (message.type === 'SpeechError' || message.type === 'error') {
162
+ fail(message.message ?? message.description ?? 'The speech service reported an error.');
163
+ }
164
+ // Any other type (SpeechStalled and whatever comes next) says nothing we have to act on.
165
+ });
166
+ socket.on('unexpected-response', (_request, response) => {
167
+ // A handshake the service refused: 401 and 403 are the account's problem, and retrying will not help.
168
+ const status = response.statusCode ?? 0;
169
+ fail(`The speech service refused the connection (${status}).`, { fatal: status >= 400 && status < 500 });
170
+ });
171
+ socket.on('error', (err) => {
172
+ if (finished)
173
+ return;
174
+ fail(`WebSocket error: ${err.message}`);
175
+ });
176
+ socket.on('close', () => {
177
+ // Closed with neither a completion nor an error: whatever audio came is all there will be.
178
+ if (finish()) {
179
+ if (audioSeen)
180
+ handlers.onDone();
181
+ else
182
+ handlers.onError('The speech service closed without audio.');
183
+ }
184
+ });
185
+ return {
186
+ cancel() {
187
+ if (finished)
188
+ return;
189
+ finished = true;
190
+ stopTimers();
191
+ try {
192
+ socket.close();
193
+ }
194
+ catch { /* already gone */ }
195
+ },
196
+ };
197
+ }
198
+ /** Whether this machine can ask for speech: a Claude Code login that has not expired. */
199
+ export async function isTextToSpeechAvailable() {
200
+ try {
201
+ const credentials = await getCredentials();
202
+ getAccessToken(credentials);
203
+ return !isTokenExpired(credentials);
204
+ }
205
+ catch (err) {
206
+ if (err instanceof CcbError)
207
+ return false;
208
+ throw err;
209
+ }
210
+ }
211
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/tts/stream.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@swttch/extend-kit",
3
- "version": "0.8.0",
4
- "description": "Companion tools for Swttch that live outside the plugin bundle: Claude Code account/usage SDK, the ccb CLI, and speech-to-text.",
3
+ "version": "0.10.0",
4
+ "description": "Companion tools for Swttch that live outside the plugin bundle: Claude Code account/usage SDK, the ccb CLI, speech-to-text and text-to-speech.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",