@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 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
- ## Configuration
15
+ ## Setup
16
16
 
17
- There are two ways to configure the plugin in your `openclaw.config.json` depending on how you use it.
17
+ ### Interactive (recommended)
18
18
 
19
- ### Option A: Standard (Single Account)
20
- Add the configuration directly to the plugin entry. This is the simplest way.
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
- ### Option B: Advanced (Multi-Account)
38
- If you want to manage multiple VoiceClaw clients, you can use the channel configuration block:
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. Paste it as `pairingCode` in your OpenClaw config
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
- const accounts = cfg.channels?.voiceclaw?.accounts ?? {};
82
- const ids = Object.keys(accounts);
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
- let accounts = ctx.config.channels?.voiceclaw?.accounts ?? {};
130
- // Auto-inject default account if top-level config exists and default isn't explicitly defined
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 {
@@ -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.4",
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",