@voiceclaw/voiceclaw-plugin 1.0.4 → 1.0.8
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.md +12 -21
- package/dist/index.js +32 -36
- package/openclaw.plugin.json +1 -18
- package/package.json +17 -2
package/README.md
CHANGED
|
@@ -12,30 +12,19 @@ OpenClaw channel plugin for **VoiceClaw** — control your AI agent with Siri on
|
|
|
12
12
|
openclaw plugins install @voiceclaw/voiceclaw-plugin
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Setup
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
### Interactive (recommended)
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
```json
|
|
23
|
-
{
|
|
24
|
-
"plugins": {
|
|
25
|
-
"entries": {
|
|
26
|
-
"voiceclaw-plugin": {
|
|
27
|
-
"enabled": true,
|
|
28
|
-
"config": {
|
|
29
|
-
"pairingCode": "<6-digit code>"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
19
|
+
```bash
|
|
20
|
+
openclaw channels add --channel voiceclaw
|
|
35
21
|
```
|
|
36
22
|
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
This will prompt you for the 6-digit pairing code from the VoiceClaw app.
|
|
24
|
+
|
|
25
|
+
### Manual
|
|
26
|
+
|
|
27
|
+
Add to your `openclaw.config.json`:
|
|
39
28
|
|
|
40
29
|
```json
|
|
41
30
|
{
|
|
@@ -51,13 +40,15 @@ If you want to manage multiple VoiceClaw clients, you can use the channel config
|
|
|
51
40
|
}
|
|
52
41
|
```
|
|
53
42
|
|
|
43
|
+
Then restart OpenClaw.
|
|
44
|
+
|
|
54
45
|
> **Note:** The pairing code is only used for the initial connection. After that, a session token is saved locally and the code is no longer needed.
|
|
55
46
|
|
|
56
47
|
## Pairing
|
|
57
48
|
|
|
58
49
|
1. Open the **VoiceClaw** app on your iPhone or Mac
|
|
59
50
|
2. Copy the 6-digit pairing code
|
|
60
|
-
3.
|
|
51
|
+
3. Run `openclaw channels add --channel voiceclaw` or paste it into your config
|
|
61
52
|
4. Restart OpenClaw
|
|
62
53
|
5. Tap **"I've Configured It"** in the app to verify the connection
|
|
63
54
|
|
package/dist/index.js
CHANGED
|
@@ -47,15 +47,13 @@ async function exchangePairingCode(code, workerUrl, logger) {
|
|
|
47
47
|
* 2. Otherwise, exchange the pairing code and save the result.
|
|
48
48
|
*/
|
|
49
49
|
async function resolveToken(accountId, account, logger) {
|
|
50
|
-
// Check for a previously saved session token.
|
|
51
50
|
const saved = loadSavedToken(accountId);
|
|
52
51
|
if (saved) {
|
|
53
52
|
logger.info(`VoiceClaw: Using saved session token for "${accountId}"`);
|
|
54
53
|
return saved;
|
|
55
54
|
}
|
|
56
|
-
// No saved token — exchange the pairing code.
|
|
57
55
|
if (!account.pairingCode) {
|
|
58
|
-
throw new Error(`No pairing code configured for "${accountId}"`);
|
|
56
|
+
throw new Error(`No pairing code configured for "${accountId}" and no saved session token found`);
|
|
59
57
|
}
|
|
60
58
|
const workerUrl = account.workerUrl ?? DEFAULT_WORKER_URL;
|
|
61
59
|
const sessionToken = await exchangePairingCode(account.pairingCode, workerUrl, logger);
|
|
@@ -77,30 +75,9 @@ export default function register(api) {
|
|
|
77
75
|
},
|
|
78
76
|
capabilities: { chatTypes: ['direct'] },
|
|
79
77
|
config: {
|
|
80
|
-
listAccountIds: (cfg) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const topLevelConfig = cfg.plugins?.entries?.['voiceclaw-plugin']?.config;
|
|
84
|
-
console.log(`[VoiceClaw Plugin] listAccountIds called. topLevelConfig exists: ${!!topLevelConfig}, explicit channels: ${ids.join(',')}`);
|
|
85
|
-
// If top-level config exists, ensure 'default' is in the list
|
|
86
|
-
if (topLevelConfig && !ids.includes('default')) {
|
|
87
|
-
ids.push('default');
|
|
88
|
-
}
|
|
89
|
-
console.log(`[VoiceClaw Plugin] listAccountIds returning: ${ids.join(',')}`);
|
|
90
|
-
return ids;
|
|
91
|
-
},
|
|
92
|
-
resolveAccount: (cfg, accountId) => {
|
|
93
|
-
const accounts = cfg.channels?.voiceclaw?.accounts ?? {};
|
|
94
|
-
const id = accountId ?? 'default';
|
|
95
|
-
const account = accounts[id] ?? {};
|
|
96
|
-
let finalAccount = account;
|
|
97
|
-
// Merge with top-level plugin config if this is the default account
|
|
98
|
-
if (id === 'default') {
|
|
99
|
-
const topLevelConfig = cfg.plugins?.entries?.['voiceclaw-plugin']?.config ?? {};
|
|
100
|
-
finalAccount = { ...topLevelConfig, ...account };
|
|
101
|
-
}
|
|
102
|
-
console.log(`[VoiceClaw Plugin] resolveAccount for ${id} returning:`, finalAccount);
|
|
103
|
-
return finalAccount;
|
|
78
|
+
listAccountIds: (cfg) => Object.keys(cfg.channels?.voiceclaw?.accounts ?? {}),
|
|
79
|
+
resolveAccount: (cfg, accountId) => cfg.channels?.voiceclaw?.accounts?.[accountId ?? 'default'] ?? {
|
|
80
|
+
accountId,
|
|
104
81
|
},
|
|
105
82
|
},
|
|
106
83
|
outbound: {
|
|
@@ -122,19 +99,38 @@ export default function register(api) {
|
|
|
122
99
|
return { ok: true };
|
|
123
100
|
},
|
|
124
101
|
},
|
|
102
|
+
onboarding: {
|
|
103
|
+
configure: async (ctx) => {
|
|
104
|
+
// Support: openclaw channels add --channel voiceclaw --token <code>
|
|
105
|
+
let pairingCode = ctx.options?.token;
|
|
106
|
+
if (!pairingCode) {
|
|
107
|
+
pairingCode = await ctx.prompter.text({
|
|
108
|
+
message: 'Enter the 6-digit pairing code from the VoiceClaw app:',
|
|
109
|
+
validate: (v) => v.trim().length >= 4 ? undefined : 'Pairing code must be at least 4 characters',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (!pairingCode || pairingCode.trim() === '') {
|
|
113
|
+
return 'skip';
|
|
114
|
+
}
|
|
115
|
+
const cfg = { ...ctx.config };
|
|
116
|
+
if (!cfg.channels)
|
|
117
|
+
cfg.channels = {};
|
|
118
|
+
if (!cfg.channels.voiceclaw)
|
|
119
|
+
cfg.channels.voiceclaw = {};
|
|
120
|
+
if (!cfg.channels.voiceclaw.accounts)
|
|
121
|
+
cfg.channels.voiceclaw.accounts = {};
|
|
122
|
+
cfg.channels.voiceclaw.accounts.default = {
|
|
123
|
+
pairingCode: pairingCode.trim(),
|
|
124
|
+
};
|
|
125
|
+
return { cfg, accountId: 'default' };
|
|
126
|
+
},
|
|
127
|
+
},
|
|
125
128
|
gateway: {
|
|
126
129
|
start: async (ctx) => {
|
|
127
130
|
api.logger.info('VoiceClaw: gateway.start() called');
|
|
128
131
|
handleInbound = ctx.processInbound;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const topLevelConfig = ctx.config.plugins?.entries?.['voiceclaw-plugin']?.config;
|
|
132
|
-
if (topLevelConfig && !accounts['default']) {
|
|
133
|
-
accounts = { ...accounts, default: {} };
|
|
134
|
-
}
|
|
135
|
-
for (const [accountId, baseAccount] of Object.entries(accounts)) {
|
|
136
|
-
// Resolve full account config (merges top-level for 'default')
|
|
137
|
-
const account = voiceClawChannel.config.resolveAccount(ctx.config, accountId);
|
|
132
|
+
const accounts = ctx.config.channels?.voiceclaw?.accounts ?? {};
|
|
133
|
+
for (const [accountId, account] of Object.entries(accounts)) {
|
|
138
134
|
if (account.enabled === false)
|
|
139
135
|
continue;
|
|
140
136
|
try {
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,22 +2,5 @@
|
|
|
2
2
|
"id": "voiceclaw-plugin",
|
|
3
3
|
"name": "VoiceClaw",
|
|
4
4
|
"version": "1.0.0",
|
|
5
|
-
"description": "VoiceClaw channel plugin — Siri & iOS/macOS voice entry for OpenClaw"
|
|
6
|
-
"configSchema": {
|
|
7
|
-
"type": "object",
|
|
8
|
-
"additionalProperties": false,
|
|
9
|
-
"properties": {
|
|
10
|
-
"pairingCode": {
|
|
11
|
-
"type": "string",
|
|
12
|
-
"description": "6-digit pairing code from the VoiceClaw app (only needed for initial setup)"
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"required": []
|
|
16
|
-
},
|
|
17
|
-
"uiHints": {
|
|
18
|
-
"pairingCode": {
|
|
19
|
-
"label": "Pairing Code",
|
|
20
|
-
"placeholder": "The 6-digit code shown in the VoiceClaw app"
|
|
21
|
-
}
|
|
22
|
-
}
|
|
5
|
+
"description": "VoiceClaw channel plugin — Siri & iOS/macOS voice entry for OpenClaw"
|
|
23
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voiceclaw/voiceclaw-plugin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "OpenClaw channel plugin for VoiceClaw — relay messages between your AI agent and the VoiceClaw iOS/macOS app via Siri",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -28,7 +28,22 @@
|
|
|
28
28
|
"openclaw": {
|
|
29
29
|
"extensions": [
|
|
30
30
|
"dist/index.js"
|
|
31
|
-
]
|
|
31
|
+
],
|
|
32
|
+
"channel": {
|
|
33
|
+
"id": "voiceclaw",
|
|
34
|
+
"label": "VoiceClaw",
|
|
35
|
+
"selectionLabel": "VoiceClaw (Siri / iOS / macOS)",
|
|
36
|
+
"docsPath": "/channels/voiceclaw",
|
|
37
|
+
"blurb": "Voice entry for OpenClaw via Siri & native iOS/macOS app.",
|
|
38
|
+
"aliases": [
|
|
39
|
+
"vc",
|
|
40
|
+
"siri"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"install": {
|
|
44
|
+
"npmSpec": "@voiceclaw/voiceclaw-plugin",
|
|
45
|
+
"defaultChoice": "npm"
|
|
46
|
+
}
|
|
32
47
|
},
|
|
33
48
|
"scripts": {
|
|
34
49
|
"build": "tsc",
|