@kuralle-syrinx/cli 4.4.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kuralle
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.
22
+
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # @kuralle-syrinx/cli
2
+
3
+ The agent-facing CLI for a Syrinx voice agent. A coding agent cannot verify its
4
+ own work on a voice agent by ear — there is no deterministic, machine-readable
5
+ way to run a turn or a text exchange. The [Studio](../../apps/studio) is for
6
+ the human (ears, barge-in feel, warmth); this CLI is for a coding agent
7
+ (fixtures, text, exit codes).
8
+
9
+ **This is not a console.** No REPL, no chat loop, no microphone. If a check
10
+ needs ears, run it in the Studio instead — this CLI refuses rather than
11
+ approximating.
12
+
13
+ **This CLI brings no providers of its own.** It does not depend on Deepgram,
14
+ Cartesia, OpenAI, or any STT/TTS/reasoner SDK — a global `npm install -g
15
+ @kuralle-syrinx/cli` does not download a single provider package. Every
16
+ provider-touching command takes `--agent <module>#<export>`, pointing the CLI
17
+ at *your* code; your module brings its own providers.
18
+
19
+ ## Install
20
+
21
+ ```
22
+ npm install -g @kuralle-syrinx/cli
23
+ ```
24
+
25
+ Installs a `syrinx` binary — a single self-contained, built JavaScript file
26
+ (no `ts-node`/`tsx` required to run it).
27
+
28
+ ## `--agent` (required for `turn` and `text`)
29
+
30
+ ```
31
+ --agent <module>[#namedExport]
32
+ ```
33
+
34
+ `<module>` is a path to your own code (resolved relative to cwd unless
35
+ absolute); the export must be a zero-arg factory returning a
36
+ `VoiceAgentSession` — or a `Promise` of one — the same contract
37
+ [`examples/02-hello-voice-headless/scripts/dev-server.ts`](../../examples/02-hello-voice-headless/scripts/dev-server.ts)'s
38
+ own `--agent` flag already uses (not a second convention). Omit `#export` for
39
+ a default export (or a `createSession` export, checked in that order).
40
+
41
+ ```ts
42
+ // my-agent.ts
43
+ import { VoiceAgentSession } from "@kuralle-syrinx/core";
44
+ import { DeepgramSTTPlugin } from "@kuralle-syrinx/deepgram";
45
+ // ...your own providers...
46
+
47
+ export default function createSession() {
48
+ const session = new VoiceAgentSession({ plugins: { /* ... */ } });
49
+ session.registerPlugin("stt", new DeepgramSTTPlugin());
50
+ // ...
51
+ return session;
52
+ }
53
+ ```
54
+
55
+ Resolution failures are loud and specific, never a silent fallback:
56
+ - Module not found, or the named export doesn't exist / isn't callable →
57
+ `USAGE`, naming the callable exports that *were* found.
58
+ - The export resolves and is callable but **throws when invoked** → `CONFIG`
59
+ — most plausibly your module is missing something it needs (an env var, a
60
+ key file, ...).
61
+
62
+ ## Commands
63
+
64
+ ### `syrinx turn --in <fixture.wav|fixture.json> --agent <module>#<export> [options]`
65
+
66
+ Run one turn through the resolved agent and report the transcript, the reply,
67
+ and per-stage timings.
68
+
69
+ Given a `fixture.json` sidecar produced by the Studio's "Save as fixture"
70
+ (format `syrinx.fixture.v1`, paired with the WAV it captured), the command
71
+ honours the sidecar's recorded capture config and **refuses** — a `USAGE`
72
+ exit, not a silently-wrong replay — when it cannot honestly satisfy it (an
73
+ unrecognised fixture format, or audio that isn't mono 16 kHz). When the
74
+ sidecar carries an `expectedTranscript`, the replayed transcript is asserted
75
+ against it; a mismatch is an `ASSERTION` exit, not a passing run.
76
+
77
+ ```
78
+ syrinx turn --in ./captured.json --agent ./my-agent.ts --json
79
+ syrinx turn --in ./hello.wav --agent ./my-agent.ts#createSession
80
+ ```
81
+
82
+ ### `syrinx text "<message>" --agent <module>#<export>`
83
+
84
+ Send a typed turn (no STT, no microphone) to the resolved agent and report the
85
+ reply — pushes the same `user.text_received` packet a real typed turn would.
86
+
87
+ ```
88
+ syrinx text "What's the cancellation policy?" --agent ./my-agent.ts --json
89
+ ```
90
+
91
+ ### `syrinx doctor [--agent <module>#<export>]`
92
+
93
+ Reports the Node runtime and whether `@kuralle-syrinx/core` is installed in
94
+ the current project and which version. Also reports, informationally only,
95
+ which well-known provider keys (`DEEPGRAM_API_KEY`, `OPENAI_API_KEY`, ...) are
96
+ present in the environment (**never** their values) — this CLI does not
97
+ require any specific one; whatever `--agent` resolves to owns its own
98
+ requirements. Pass `--agent` to check whether a *specific* agent module
99
+ resolves, without invoking it. Always exits `SUCCESS` — this command
100
+ diagnoses, it does not assert.
101
+
102
+ ```
103
+ syrinx doctor --json
104
+ syrinx doctor --agent ./my-agent.ts --json
105
+ ```
106
+
107
+ ## `--json`
108
+
109
+ `--json` is a first-class output mode on every command, not a side flag: it
110
+ emits exactly one parseable JSON object on stdout, `{ ok, verb, ... }` on
111
+ success or `{ ok: false, verb, error: { code, message, ... } }` on failure.
112
+ Diagnostics — currently just the version-skew warning below — always go to
113
+ stderr, never stdout, so `--json` output stays parseable no matter what.
114
+ Without `--json`, commands print a short human-readable summary to stdout and
115
+ errors to stderr.
116
+
117
+ ## Version skew
118
+
119
+ On start, the CLI resolves the invoking project's installed
120
+ `@kuralle-syrinx/core` from the nearest `node_modules` (not its own bundled
121
+ version). If the major version differs from the CLI's own major, it prints a
122
+ warning naming both versions to stderr and keeps going — it warns, it does not
123
+ refuse.
124
+
125
+ ## Exit codes
126
+
127
+ | Code | Name | Meaning |
128
+ | --- | --- | --- |
129
+ | 0 | `SUCCESS` | the command completed and, where applicable, any assertion matched |
130
+ | 1 | `INTERNAL` | an unexpected error inside the CLI itself — treat as a bug |
131
+ | 2 | `USAGE` | bad invocation: unknown verb/flag, a missing required argument, a `--agent` that could not be resolved, or a fixture the CLI cannot honour |
132
+ | 3 | `CONFIG` | the resolved `--agent` module threw constructing a session — most plausibly its own missing configuration |
133
+ | 4 | `BACKEND` | the agent or backend failed while running the turn (provider/network error, timeout, pipeline error) |
134
+ | 5 | `ASSERTION` | a replayed fixture's transcript drifted from the expected transcript |
135
+
136
+ The same table is printed by `syrinx --help`.
137
+
138
+ ## Reuse, not reimplementation
139
+
140
+ `packages/cli/src/turn-runner.ts` owns exactly one thing: feeding audio into
141
+ an already-built `VoiceAgentSession` and capturing the transcript/reply/
142
+ timings/artifacts (`driveTurn`) — it never constructs a provider. Two callers
143
+ share it:
144
+ - The CLI's own `turn` command, via the `--agent` seam above.
145
+ - `examples/02-hello-voice-headless/src/run-one-turn.ts`'s `runOneTurn`, which
146
+ keeps its own hardcoded Deepgram+OpenAI+Cartesia+Silero default kernel
147
+ (legitimate there — it's a demo harness, not a shipped package) and
148
+ delegates the actual turn-driving mechanics to `driveTurn` here, imported
149
+ as `@kuralle-syrinx/cli/turn-runner`.
150
+
151
+ There is exactly one implementation of "drive a turn"; only the (necessarily
152
+ different) provider wiring differs between the two callers.