@swttch/extend-kit 0.6.1 → 0.7.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/dist/cli/index.js +25 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/stt.d.ts +38 -0
- package/dist/cli/stt.js +154 -0
- package/dist/cli/stt.js.map +1 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { getCredentials, getAccessToken } from '../battery/auth/index.js';
|
|
3
3
|
import { ClaudeCodeClient } from '../battery/api/index.js';
|
|
4
4
|
import { oauthCommand } from './oauth.js';
|
|
5
|
+
import { sttCommand } from './stt.js';
|
|
5
6
|
import { getAccountCredentials } from './account-credentials.js';
|
|
6
7
|
import { CcbError } from '../battery/errors.js';
|
|
7
8
|
import { readFileSync } from 'node:fs';
|
|
@@ -23,7 +24,10 @@ async function createClient() {
|
|
|
23
24
|
async function run() {
|
|
24
25
|
const [module, ...subcommand] = command;
|
|
25
26
|
if (flags.has('--capabilities')) {
|
|
26
|
-
|
|
27
|
+
// A caller checks this before using a command: the plugin has to know
|
|
28
|
+
// whether the kit on this machine is new enough to stream dictation, since
|
|
29
|
+
// the only alternative it once had (importing the module) is gone.
|
|
30
|
+
console.log(JSON.stringify({ capabilities: ['oauth.usage.account-file', 'stt.stream'] }));
|
|
27
31
|
return;
|
|
28
32
|
}
|
|
29
33
|
if (args.some(arg => arg.startsWith('--account-file')) && (!accountFile || module !== 'oauth' || subcommand[0] !== 'usage')) {
|
|
@@ -41,13 +45,32 @@ Usage: ccb <command> [options]
|
|
|
41
45
|
Commands:
|
|
42
46
|
oauth usage Show usage limits
|
|
43
47
|
oauth profile Show account profile
|
|
48
|
+
stt Transcribe raw PCM audio from stdin (see below)
|
|
49
|
+
stt --check Report whether this machine can dictate
|
|
44
50
|
|
|
45
51
|
Options:
|
|
46
52
|
--account-file=<path> Read usage for a CCG saved-account snapshot (no account switch)
|
|
53
|
+
--language=<code> BCP-47 language for stt (default: en)
|
|
54
|
+
--keyterms=<a,b,c> Extra vocabulary to bias stt toward
|
|
55
|
+
--interims Also emit interim stt guesses
|
|
47
56
|
--capabilities Output supported CLI capabilities as JSON
|
|
48
57
|
--json Output as JSON
|
|
49
58
|
-h, --help Show help
|
|
50
|
-
-v, --version Show version
|
|
59
|
+
-v, --version Show version
|
|
60
|
+
|
|
61
|
+
stt reads raw PCM on stdin (16-bit LE, 16 kHz, mono) and writes one JSON
|
|
62
|
+
object per line to stdout. Any other audio format transcribes to silence.
|
|
63
|
+
|
|
64
|
+
ffmpeg -f avfoundation -i ':0' -ar 16000 -ac 1 -f s16le - | ccb stt`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Handled before createClient(): stt reads the login inside the stream, and
|
|
68
|
+
// building a client up front would turn "not signed in" into a crash before
|
|
69
|
+
// `stt --check` could answer it calmly.
|
|
70
|
+
if (module === 'stt') {
|
|
71
|
+
const code = await sttCommand(subcommand, args, flags, jsonOutput);
|
|
72
|
+
if (code !== 0)
|
|
73
|
+
process.exit(code);
|
|
51
74
|
return;
|
|
52
75
|
}
|
|
53
76
|
const client = await createClient();
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AACxF,MAAM,OAAO,GAAW,GAAG,CAAC,OAAO,CAAC;AAEpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACrE,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACvC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAEzG,KAAK,UAAU,YAAY;IACzB,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,cAAc,EAAE,CAAC;IACpG,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC1C,OAAO,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,GAAG;IAChB,MAAM,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC;IAExC,IAAI,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ccb stt` — dictation as a process, not as a library.
|
|
3
|
+
*
|
|
4
|
+
* The plugin cannot call {@link openSpeechToTextStream} directly. Transcribing
|
|
5
|
+
* reads the machine's Claude Code login, and importing this package into the
|
|
6
|
+
* backend would put that read inside the plugin's own process — the exact thing
|
|
7
|
+
* that moved these tools out to a separate package. Spawning instead keeps the
|
|
8
|
+
* token on this side of the process boundary: the caller writes audio and reads
|
|
9
|
+
* text, and never holds a credential.
|
|
10
|
+
*
|
|
11
|
+
* So the wire format here is the public contract, the same way `oauth usage
|
|
12
|
+
* --json` is. A terminal user can drive it by hand:
|
|
13
|
+
*
|
|
14
|
+
* ffmpeg -f avfoundation -i ':0' -ar 16000 -ac 1 -f s16le - | ccb stt
|
|
15
|
+
*
|
|
16
|
+
* ── stdin ── raw PCM: 16-bit little-endian, 16 kHz, mono. Nothing else is
|
|
17
|
+
* accepted, and a wrong format transcribes to silence rather than
|
|
18
|
+
* failing (see CLAUDE.md), so the caller must convert first.
|
|
19
|
+
* ── stdout ── one JSON object per line, flushed as it happens.
|
|
20
|
+
* ── exit ─── 0 when the speaker finished, 1 when the stream failed to open.
|
|
21
|
+
*/
|
|
22
|
+
/** Line-oriented events written to stdout. */
|
|
23
|
+
export declare enum SttEventType {
|
|
24
|
+
/** The socket is open and audio is being transcribed. */
|
|
25
|
+
Open = "open",
|
|
26
|
+
/** Text arrived. `isFinal` false will be replaced by a later line. */
|
|
27
|
+
Transcript = "transcript",
|
|
28
|
+
/** The stream failed. `fatal` means retrying will not help. */
|
|
29
|
+
Error = "error"
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Entry point for the `stt` module of the CLI.
|
|
33
|
+
*
|
|
34
|
+
* Takes no {@link ClaudeCodeClient}: unlike `oauth`, this command reads the
|
|
35
|
+
* login itself inside the stream, and building a client up front would turn
|
|
36
|
+
* "not signed in" into a crash before `--check` could answer it.
|
|
37
|
+
*/
|
|
38
|
+
export declare function sttCommand(subcommand: string[], args: string[], flags: Set<string>, jsonOutput: boolean): Promise<number>;
|
package/dist/cli/stt.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { openSpeechToTextStream, isSpeechToTextAvailable } from '../stt/index.js';
|
|
2
|
+
import { CcbError } from '../battery/errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* `ccb stt` — dictation as a process, not as a library.
|
|
5
|
+
*
|
|
6
|
+
* The plugin cannot call {@link openSpeechToTextStream} directly. Transcribing
|
|
7
|
+
* reads the machine's Claude Code login, and importing this package into the
|
|
8
|
+
* backend would put that read inside the plugin's own process — the exact thing
|
|
9
|
+
* that moved these tools out to a separate package. Spawning instead keeps the
|
|
10
|
+
* token on this side of the process boundary: the caller writes audio and reads
|
|
11
|
+
* text, and never holds a credential.
|
|
12
|
+
*
|
|
13
|
+
* So the wire format here is the public contract, the same way `oauth usage
|
|
14
|
+
* --json` is. A terminal user can drive it by hand:
|
|
15
|
+
*
|
|
16
|
+
* ffmpeg -f avfoundation -i ':0' -ar 16000 -ac 1 -f s16le - | ccb stt
|
|
17
|
+
*
|
|
18
|
+
* ── stdin ── raw PCM: 16-bit little-endian, 16 kHz, mono. Nothing else is
|
|
19
|
+
* accepted, and a wrong format transcribes to silence rather than
|
|
20
|
+
* failing (see CLAUDE.md), so the caller must convert first.
|
|
21
|
+
* ── stdout ── one JSON object per line, flushed as it happens.
|
|
22
|
+
* ── exit ─── 0 when the speaker finished, 1 when the stream failed to open.
|
|
23
|
+
*/
|
|
24
|
+
/** Line-oriented events written to stdout. */
|
|
25
|
+
export var SttEventType;
|
|
26
|
+
(function (SttEventType) {
|
|
27
|
+
/** The socket is open and audio is being transcribed. */
|
|
28
|
+
SttEventType["Open"] = "open";
|
|
29
|
+
/** Text arrived. `isFinal` false will be replaced by a later line. */
|
|
30
|
+
SttEventType["Transcript"] = "transcript";
|
|
31
|
+
/** The stream failed. `fatal` means retrying will not help. */
|
|
32
|
+
SttEventType["Error"] = "error";
|
|
33
|
+
})(SttEventType || (SttEventType = {}));
|
|
34
|
+
/**
|
|
35
|
+
* Write one event as a single line.
|
|
36
|
+
*
|
|
37
|
+
* `process.stdout.write` rather than `console.log` because the caller parses
|
|
38
|
+
* this by newline: console.log is the same thing here, but going through the
|
|
39
|
+
* stream directly makes it explicit that one call must produce exactly one line
|
|
40
|
+
* and that nothing else may ever be printed to stdout by this command.
|
|
41
|
+
*/
|
|
42
|
+
function emit(event) {
|
|
43
|
+
process.stdout.write(`${JSON.stringify(event)}\n`);
|
|
44
|
+
}
|
|
45
|
+
/** Split a `--keyterms=a,b,c` value, dropping empties and surrounding spaces. */
|
|
46
|
+
function parseKeyterms(raw) {
|
|
47
|
+
if (!raw)
|
|
48
|
+
return [];
|
|
49
|
+
return raw
|
|
50
|
+
.split(',')
|
|
51
|
+
.map((term) => term.trim())
|
|
52
|
+
.filter(Boolean);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `ccb stt --check --json` — can this machine dictate at all?
|
|
56
|
+
*
|
|
57
|
+
* Separate from opening a stream because the answer drives different UI: a
|
|
58
|
+
* machine with no Claude Code login should be told to sign in, not shown a
|
|
59
|
+
* socket error. Always exits 0; "no" is an answer rather than a failure.
|
|
60
|
+
*/
|
|
61
|
+
async function checkAvailability(jsonOutput) {
|
|
62
|
+
const available = await isSpeechToTextAvailable().catch(() => false);
|
|
63
|
+
if (jsonOutput) {
|
|
64
|
+
console.log(JSON.stringify({ available }));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
console.log(available ? 'available' : 'unavailable (no Claude Code login on this machine)');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Open the stream and pump stdin into it until the caller stops writing.
|
|
71
|
+
*
|
|
72
|
+
* Audio written before the socket finishes opening is not lost: the stream
|
|
73
|
+
* buffers pre-open chunks itself, which matters more here than in-process
|
|
74
|
+
* because a pipe delivers the caller's first chunk almost immediately.
|
|
75
|
+
*/
|
|
76
|
+
async function runStream(options) {
|
|
77
|
+
if (process.stdin.isTTY) {
|
|
78
|
+
console.error('ccb stt reads raw PCM audio (16-bit LE, 16 kHz, mono) on stdin; pipe audio into it.');
|
|
79
|
+
return 1;
|
|
80
|
+
}
|
|
81
|
+
let stream;
|
|
82
|
+
try {
|
|
83
|
+
stream = await openSpeechToTextStream({
|
|
84
|
+
onTranscript: (text, isFinal) => emit({ type: SttEventType.Transcript, text, isFinal }),
|
|
85
|
+
onError: (message, info) => emit({ type: SttEventType.Error, message, fatal: info?.fatal ?? false }),
|
|
86
|
+
onOpen: () => emit({ type: SttEventType.Open }),
|
|
87
|
+
}, {
|
|
88
|
+
language: options.language,
|
|
89
|
+
extraKeyterms: options.extraKeyterms,
|
|
90
|
+
typedInterims: options.typedInterims,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
// Failing to open is reported on the same channel as everything else, so a
|
|
95
|
+
// caller parsing stdout never has to also watch stderr to learn why
|
|
96
|
+
// dictation did not start. A rejected login lands here.
|
|
97
|
+
emit({
|
|
98
|
+
type: SttEventType.Error,
|
|
99
|
+
message: err instanceof Error ? err.message : String(err),
|
|
100
|
+
fatal: true,
|
|
101
|
+
});
|
|
102
|
+
return 1;
|
|
103
|
+
}
|
|
104
|
+
return new Promise((resolve) => {
|
|
105
|
+
let finished = false;
|
|
106
|
+
/**
|
|
107
|
+
* Close once, then exit.
|
|
108
|
+
*
|
|
109
|
+
* `close()` waits for the service to flush the last words, so the trailing
|
|
110
|
+
* transcript is emitted before this resolves. Called from both stdin end
|
|
111
|
+
* and a termination signal, hence the guard.
|
|
112
|
+
*/
|
|
113
|
+
const finish = () => {
|
|
114
|
+
if (finished)
|
|
115
|
+
return;
|
|
116
|
+
finished = true;
|
|
117
|
+
stream
|
|
118
|
+
.close()
|
|
119
|
+
.then(() => resolve(0))
|
|
120
|
+
.catch(() => resolve(0));
|
|
121
|
+
};
|
|
122
|
+
process.stdin.on('data', (chunk) => {
|
|
123
|
+
stream.sendAudio(new Uint8Array(chunk));
|
|
124
|
+
});
|
|
125
|
+
process.stdin.on('end', finish);
|
|
126
|
+
// A parent that kills us instead of closing stdin still gets the last words.
|
|
127
|
+
process.on('SIGTERM', finish);
|
|
128
|
+
process.on('SIGINT', finish);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Entry point for the `stt` module of the CLI.
|
|
133
|
+
*
|
|
134
|
+
* Takes no {@link ClaudeCodeClient}: unlike `oauth`, this command reads the
|
|
135
|
+
* login itself inside the stream, and building a client up front would turn
|
|
136
|
+
* "not signed in" into a crash before `--check` could answer it.
|
|
137
|
+
*/
|
|
138
|
+
export async function sttCommand(subcommand, args, flags, jsonOutput) {
|
|
139
|
+
if (flags.has('--check') || subcommand[0] === 'check') {
|
|
140
|
+
await checkAvailability(jsonOutput);
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
if (subcommand.length > 0) {
|
|
144
|
+
throw new CcbError(`Unknown stt subcommand: ${subcommand[0]}`, 'invalid_argument');
|
|
145
|
+
}
|
|
146
|
+
const language = args.find((arg) => arg.startsWith('--language='))?.slice('--language='.length);
|
|
147
|
+
const keyterms = args.find((arg) => arg.startsWith('--keyterms='))?.slice('--keyterms='.length);
|
|
148
|
+
return runStream({
|
|
149
|
+
language,
|
|
150
|
+
extraKeyterms: parseKeyterms(keyterms),
|
|
151
|
+
typedInterims: flags.has('--interims'),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=stt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stt.js","sourceRoot":"","sources":["../../src/cli/stt.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swttch/extend-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Companion tools for Swttch that live outside the plugin bundle: Claude Code account/usage SDK, the ccb CLI, and speech-to-text.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|