verbalcoding 0.2.11 → 0.2.12
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/.env.example +27 -1
- package/README.es.md +132 -0
- package/README.fr.md +132 -0
- package/README.ja.md +132 -0
- package/README.ko.md +132 -0
- package/README.md +116 -74
- package/README.ru.md +132 -0
- package/README.zh.md +131 -0
- package/app-node/agent_adapters.mjs +37 -5
- package/app-node/agent_adapters.test.mjs +13 -1
- package/app-node/agent_detect.mjs +73 -0
- package/app-node/agent_detect.test.mjs +77 -0
- package/app-node/install_config.mjs +3 -0
- package/app-node/main.mjs +339 -4
- package/app-node/notify.mjs +73 -0
- package/app-node/notify.test.mjs +68 -0
- package/app-node/plan_mode.mjs +174 -0
- package/app-node/plan_mode.test.mjs +153 -0
- package/app-node/smart_progress.mjs +94 -0
- package/app-node/smart_progress.test.mjs +66 -0
- package/app-node/stream_sentencer.mjs +61 -0
- package/app-node/stream_sentencer.test.mjs +64 -0
- package/app-node/streaming_tts_queue.mjs +48 -0
- package/app-node/streaming_tts_queue.test.mjs +58 -0
- package/app-node/text_routing.mjs +20 -0
- package/app-node/text_routing.test.mjs +23 -1
- package/docs/CONFIGURATION.md +69 -96
- package/docs/FRESH_INSTALL.md +105 -63
- package/docs/HERMES_VOICE.md +65 -0
- package/docs/MULTI_INSTANCE.md +16 -0
- package/docs/README.md +49 -0
- package/docs/RELEASE.md +42 -19
- package/docs/ROADMAP.md +38 -0
- package/docs/TROUBLESHOOTING.md +126 -0
- package/docs/USAGE.md +72 -40
- package/docs/assets/figures/verbalcoding-flow.svg +1 -1
- package/docs/i18n/CONFIGURATION.es.md +25 -0
- package/docs/i18n/CONFIGURATION.fr.md +25 -0
- package/docs/i18n/CONFIGURATION.ja.md +25 -0
- package/docs/i18n/CONFIGURATION.ko.md +25 -0
- package/docs/i18n/CONFIGURATION.ru.md +25 -0
- package/docs/i18n/CONFIGURATION.zh.md +25 -0
- package/docs/i18n/FRESH_INSTALL.es.md +27 -2
- package/docs/i18n/FRESH_INSTALL.fr.md +27 -2
- package/docs/i18n/FRESH_INSTALL.ja.md +27 -2
- package/docs/i18n/FRESH_INSTALL.ko.md +27 -2
- package/docs/i18n/FRESH_INSTALL.ru.md +27 -2
- package/docs/i18n/FRESH_INSTALL.zh.md +27 -2
- package/docs/i18n/HERMES_VOICE.es.md +46 -0
- package/docs/i18n/HERMES_VOICE.fr.md +46 -0
- package/docs/i18n/HERMES_VOICE.ja.md +46 -0
- package/docs/i18n/HERMES_VOICE.ko.md +65 -0
- package/docs/i18n/HERMES_VOICE.ru.md +46 -0
- package/docs/i18n/HERMES_VOICE.zh.md +46 -0
- package/docs/i18n/MULTI_INSTANCE.es.md +25 -0
- package/docs/i18n/MULTI_INSTANCE.fr.md +25 -0
- package/docs/i18n/MULTI_INSTANCE.ja.md +25 -0
- package/docs/i18n/MULTI_INSTANCE.ko.md +25 -0
- package/docs/i18n/MULTI_INSTANCE.ru.md +25 -0
- package/docs/i18n/MULTI_INSTANCE.zh.md +25 -0
- package/docs/i18n/README.es.md +20 -134
- package/docs/i18n/README.fr.md +20 -134
- package/docs/i18n/README.ja.md +20 -134
- package/docs/i18n/README.ko.md +20 -133
- package/docs/i18n/README.ru.md +20 -134
- package/docs/i18n/README.zh.md +20 -133
- package/docs/i18n/RELEASE.es.md +26 -1
- package/docs/i18n/RELEASE.fr.md +26 -1
- package/docs/i18n/RELEASE.ja.md +26 -1
- package/docs/i18n/RELEASE.ko.md +26 -1
- package/docs/i18n/RELEASE.ru.md +26 -1
- package/docs/i18n/RELEASE.zh.md +26 -1
- package/docs/i18n/TROUBLESHOOTING.es.md +39 -0
- package/docs/i18n/TROUBLESHOOTING.fr.md +39 -0
- package/docs/i18n/TROUBLESHOOTING.ja.md +39 -0
- package/docs/i18n/TROUBLESHOOTING.ko.md +39 -0
- package/docs/i18n/TROUBLESHOOTING.ru.md +39 -0
- package/docs/i18n/TROUBLESHOOTING.zh.md +39 -0
- package/docs/i18n/USAGE.es.md +25 -0
- package/docs/i18n/USAGE.fr.md +25 -0
- package/docs/i18n/USAGE.ja.md +25 -0
- package/docs/i18n/USAGE.ko.md +25 -0
- package/docs/i18n/USAGE.ru.md +25 -0
- package/docs/i18n/USAGE.zh.md +25 -0
- package/docs/superpowers/plans/2026-05-13-phase1-streaming-pipeline.md +122 -0
- package/docs/superpowers/plans/2026-05-13-phase10-push-notifications.md +152 -0
- package/docs/superpowers/plans/2026-05-13-phase2-agent-adapters.md +242 -0
- package/docs/superpowers/plans/2026-05-13-phase6-smart-progress.md +172 -0
- package/docs/superpowers/plans/2026-05-13-phase7-voice-plan-mode.md +108 -0
- package/package.json +2 -1
- package/scripts/cli.mjs +4 -3
- package/scripts/doctor.mjs +11 -0
- package/scripts/install.mjs +15 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Phase 7 — Voice Plan Mode Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development or superpowers:executing-plans.
|
|
4
|
+
|
|
5
|
+
**Goal:** Let the user say "plan it first" and the agent returns a numbered plan, narrated step-by-step; the user can say "skip step 3", "add a test for X after step 2", or "approve" to run the modified plan.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Stateful plan session in `app-node/plan_mode.mjs`. The first user request is wrapped with a planning preamble in `voiceBridgePrompt`. Agent returns a numbered plan in a `PLAN_BEGIN ... PLAN_END` envelope; we parse, narrate, and listen for follow-up voice commands. Commands mutate the plan; the approval command sends the modified plan back to the agent with an "act on this plan now" preamble.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Node 20 ESM, existing adapter + sentencer, regex grammar (no external NLP).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Spec
|
|
14
|
+
|
|
15
|
+
### Plan envelope
|
|
16
|
+
|
|
17
|
+
Agent returns:
|
|
18
|
+
```
|
|
19
|
+
PLAN_BEGIN
|
|
20
|
+
1. <step>
|
|
21
|
+
2. <step>
|
|
22
|
+
PLAN_END
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Parser strips envelope and yields `{ id, text, status }`.
|
|
26
|
+
|
|
27
|
+
### Voice command grammar
|
|
28
|
+
|
|
29
|
+
- enter: `plan it first` / `plan first` / `먼저 계획`
|
|
30
|
+
- skip: `skip step N` / `step N 건너뛰어`
|
|
31
|
+
- insert: `add <text> after step N` / `step N 다음에 <text> 추가`
|
|
32
|
+
- approve: `approve` / `go ahead` / `실행`
|
|
33
|
+
- cancel: `cancel` / `취소`
|
|
34
|
+
|
|
35
|
+
### Session state
|
|
36
|
+
|
|
37
|
+
`{ active: boolean, steps: Step[], language: 'en'|'ko' }` stored in `bridge_state.mjs` per channel.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## File Structure
|
|
42
|
+
|
|
43
|
+
- Create: `app-node/plan_mode.mjs`, `app-node/plan_mode.test.mjs`.
|
|
44
|
+
- Modify: `app-node/agent_adapters.mjs::voiceBridgePrompt` — add `planMode` branch.
|
|
45
|
+
- Modify: `app-node/discord_text.mjs` and `app-node/main.mjs` — route plan-mode utterances.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Tasks
|
|
50
|
+
|
|
51
|
+
### Task 1: TDD — parsers
|
|
52
|
+
|
|
53
|
+
- [ ] Write tests in `app-node/plan_mode.test.mjs`:
|
|
54
|
+
1. `parsePlanOutput` extracts numbered steps between markers.
|
|
55
|
+
2. `parseVoiceCommand` recognises skip (en + ko).
|
|
56
|
+
3. `parseVoiceCommand` recognises insert (en + ko).
|
|
57
|
+
4. `parseVoiceCommand` recognises approve in both languages.
|
|
58
|
+
5. `applyCommand` skip flips a step's status.
|
|
59
|
+
6. `applyCommand` insert places a new step after the named one.
|
|
60
|
+
|
|
61
|
+
- [ ] Run, expect FAIL.
|
|
62
|
+
|
|
63
|
+
### Task 2: Implement `plan_mode.mjs`
|
|
64
|
+
|
|
65
|
+
- [ ] Functions to export:
|
|
66
|
+
- `parsePlanOutput(text)` — regex on `/PLAN_BEGIN\s*\n([\s\S]*?)\nPLAN_END/`, then split lines matching `^\s*(\d+)\.\s*(.+)$`.
|
|
67
|
+
- `parseVoiceCommand(text, language)` — small regex set, returns discriminated union `{ type: 'skip'|'insert'|'approve'|'cancel'|'unknown', ...}`.
|
|
68
|
+
- `applyCommand(steps, cmd)` — pure reducer.
|
|
69
|
+
- `renderFinalPlan(steps)` — re-numbers active steps for the approval prompt.
|
|
70
|
+
|
|
71
|
+
- [ ] Run tests: PASS.
|
|
72
|
+
- [ ] Commit: `feat(plan-mode): parsers and reducer`.
|
|
73
|
+
|
|
74
|
+
### Task 3: Wire `voiceBridgePrompt`
|
|
75
|
+
|
|
76
|
+
- [ ] In `agent_adapters.mjs::voiceBridgePrompt`, accept `options.planMode`. When set, append:
|
|
77
|
+
```
|
|
78
|
+
You are in PLAN MODE. Do NOT modify any files. Reply ONLY with a plan:
|
|
79
|
+
PLAN_BEGIN
|
|
80
|
+
1. ...
|
|
81
|
+
2. ...
|
|
82
|
+
PLAN_END
|
|
83
|
+
Each step under 12 words.
|
|
84
|
+
```
|
|
85
|
+
Korean variant included.
|
|
86
|
+
- [ ] Test: `voiceBridgePrompt('do X', { planMode: true })` contains `PLAN_BEGIN`.
|
|
87
|
+
- [ ] Commit.
|
|
88
|
+
|
|
89
|
+
### Task 4: Bridge wiring
|
|
90
|
+
|
|
91
|
+
- [ ] In `main.mjs`:
|
|
92
|
+
- Detect enter phrase → call agent with `planMode: true` → parse output → store in channel state → speak each step.
|
|
93
|
+
- Each follow-up utterance while `state.active` → `parseVoiceCommand` → mutate state OR on approve call agent again with `renderFinalPlan(...)` as the user prompt and clear state.
|
|
94
|
+
- [ ] Add integration test using a fake adapter.
|
|
95
|
+
- [ ] Commit.
|
|
96
|
+
|
|
97
|
+
### Task 5: Document
|
|
98
|
+
|
|
99
|
+
- [ ] Add a "Voice plan mode" section to `docs/USAGE.md` with example transcript.
|
|
100
|
+
- [ ] Commit.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Self-Review
|
|
105
|
+
|
|
106
|
+
- Spec covered.
|
|
107
|
+
- No placeholders.
|
|
108
|
+
- Names consistent: `parsePlanOutput`, `parseVoiceCommand`, `applyCommand`, `renderFinalPlan`, `planMode`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "verbalcoding",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.12",
|
|
4
4
|
"description": "Discord voice bridge for CLI coding agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"run.sh",
|
|
39
39
|
".env.example",
|
|
40
40
|
"README.md",
|
|
41
|
+
"README.*.md",
|
|
41
42
|
"LICENSE"
|
|
42
43
|
],
|
|
43
44
|
"scripts": {
|
package/scripts/cli.mjs
CHANGED
|
@@ -48,9 +48,10 @@ Usage:
|
|
|
48
48
|
vc doctor
|
|
49
49
|
|
|
50
50
|
Examples:
|
|
51
|
-
npx verbalcoding setup
|
|
52
|
-
vc setup
|
|
53
|
-
vc setup
|
|
51
|
+
npx verbalcoding setup
|
|
52
|
+
vc setup
|
|
53
|
+
vc setup --yes # automation/non-interactive starter config
|
|
54
|
+
vc setup token # later token update
|
|
54
55
|
vc setup channels "General,Team Voice"
|
|
55
56
|
vc start
|
|
56
57
|
vc language en
|
package/scripts/doctor.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
5
5
|
import { parseKeyValueEnv } from '../app-node/install_config.mjs';
|
|
6
6
|
import { checkInstanceConfigs, formatInstanceDoctor } from '../app-node/instance_doctor.mjs';
|
|
7
7
|
import { autoRestartVoiceBotEnabled } from '../app-node/restart_policy.mjs';
|
|
8
|
+
import { detectInstalledAgents, formatAgentDetectionReport } from '../app-node/agent_detect.mjs';
|
|
8
9
|
|
|
9
10
|
const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..');
|
|
10
11
|
const args = process.argv.slice(2);
|
|
@@ -210,6 +211,16 @@ if (!autoFixEnabled) note('Automatic prerequisite bootstrap', 'off');
|
|
|
210
211
|
if (autoFixAttempted) note('Automatic prerequisite bootstrap', 'attempted');
|
|
211
212
|
console.log('');
|
|
212
213
|
|
|
214
|
+
try {
|
|
215
|
+
const detection = await detectInstalledAgents(env);
|
|
216
|
+
console.log(formatAgentDetectionReport(detection));
|
|
217
|
+
const selected = detection.find(r => r.backend === backend || r.backend === backend.replace(/-/g, ''));
|
|
218
|
+
if (selected && !selected.present) note(`Selected backend "${backend}"`, `binary ${selected.bin} not on PATH`);
|
|
219
|
+
console.log('');
|
|
220
|
+
} catch (e) {
|
|
221
|
+
note('Agent backend detection', `skipped: ${e?.message || e}`);
|
|
222
|
+
}
|
|
223
|
+
|
|
213
224
|
const nodeCommand = commandExists('node');
|
|
214
225
|
const npmCommand = commandExists('npm');
|
|
215
226
|
const ffmpegCommand = commandExists('ffmpeg');
|
package/scripts/install.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import readline from 'node:readline/promises';
|
|
5
5
|
import { stdin as input, stdout as output } from 'node:process';
|
|
6
6
|
import { buildEnvFile, normalizeInstallAnswers, renderInstallSummary, SUPPORTED_HARNESSES } from '../app-node/install_config.mjs';
|
|
7
|
+
import { detectInstalledAgents, pickDefaultBackend, formatAgentDetectionReport } from '../app-node/agent_detect.mjs';
|
|
7
8
|
|
|
8
9
|
const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..');
|
|
9
10
|
|
|
@@ -138,7 +139,20 @@ async function main() {
|
|
|
138
139
|
try {
|
|
139
140
|
console.log('VerbalCoding installer');
|
|
140
141
|
console.log(`Supported harnesses: ${SUPPORTED_HARNESSES.join(', ')}`);
|
|
141
|
-
|
|
142
|
+
console.log('Discord setup: keep https://discord.com/developers/applications open.');
|
|
143
|
+
console.log('Create an application/bot, enable Message Content intent, then paste the bot token and application/client ID below.');
|
|
144
|
+
console.log('If you are not ready, press Enter to skip and run `vc setup token` / `vc setup channels` later.');
|
|
145
|
+
let detectionDefault = 'hermes';
|
|
146
|
+
try {
|
|
147
|
+
const detection = await detectInstalledAgents(process.env);
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log(formatAgentDetectionReport(detection));
|
|
150
|
+
detectionDefault = pickDefaultBackend(detection, process.env.AGENT_BACKEND);
|
|
151
|
+
console.log('');
|
|
152
|
+
} catch (e) {
|
|
153
|
+
console.log(`(agent detection skipped: ${e?.message || e})`);
|
|
154
|
+
}
|
|
155
|
+
const harness = await ask('Harness/backend', detectionDefault);
|
|
142
156
|
let agentCommand = '';
|
|
143
157
|
let agentLabel = '';
|
|
144
158
|
if (harness.toLowerCase() === 'custom') {
|