@@ -18,6 +18,62 @@ import { PineVoice, AuthError } from "pine-voice";
1818// ---------------------------------------------------------------------------
1919const pendingAuth = new Map < string , string > ( ) ; // email → requestToken
2020
21+ // ---------------------------------------------------------------------------
22+ // Shared helpers
23+ // ---------------------------------------------------------------------------
24+
25+ const VOICE_TOOLS = [
26+ "pine_voice_call_and_wait" ,
27+ "pine_voice_call" ,
28+ "pine_voice_call_status" ,
29+ ] as const ;
30+
31+ /**
32+ * Build an updated config that stores credentials and ensures voice tools
33+ * are present in `tools.allow`. Pure function — no side effects.
34+ */
35+ export function buildAuthConfig (
36+ cfg : Record < string , any > ,
37+ accessToken : string ,
38+ userId : string ,
39+ ) : { updatedConfig : Record < string , any > ; addedTools : string [ ] } {
40+ const plugins = ( cfg . plugins ?? { } ) as Record < string , any > ;
41+ const entries = ( plugins . entries ?? { } ) as Record < string , any > ;
42+ const pluginEntry = ( entries [ "openclaw-pine-voice" ] ?? { } ) as Record < string , any > ;
43+ const tools = ( cfg . tools ?? { } ) as Record < string , any > ;
44+ const existingAllow = Array . isArray ( tools . allow )
45+ ? tools . allow . filter ( ( t : unknown ) : t is string => typeof t === "string" )
46+ : [ ] ;
47+
48+ const addedTools = VOICE_TOOLS . filter ( t => ! existingAllow . includes ( t ) ) ;
49+ const mergedAllow = [ ...existingAllow , ...addedTools ] ;
50+
51+ return {
52+ updatedConfig : {
53+ ...cfg ,
54+ plugins : {
55+ ...plugins ,
56+ entries : {
57+ ...entries ,
58+ "openclaw-pine-voice" : {
59+ ...pluginEntry ,
60+ config : {
61+ ...( pluginEntry . config ?? { } ) ,
62+ access_token : accessToken ,
63+ user_id : userId ,
64+ } ,
65+ } ,
66+ } ,
67+ } ,
68+ tools : {
69+ ...tools ,
70+ allow : mergedAllow ,
71+ } ,
72+ } ,
73+ addedTools : [ ...addedTools ] ,
74+ } ;
75+ }
76+
2177// ---------------------------------------------------------------------------
2278// Tool registration (primary path)
2379// ---------------------------------------------------------------------------
@@ -107,54 +163,18 @@ export function registerAuthTools(api: any) {
107163 params . code ,
108164 ) ;
109165
110- // Write credentials + ensure voice tools are in tools.allow
111166 const cfg = api . runtime . config . loadConfig ( ) ;
112- const plugins = ( cfg . plugins ?? { } ) as Record < string , any > ;
113- const entries = ( plugins . entries ?? { } ) as Record < string , any > ;
114- const pluginEntry = ( entries [ "openclaw-pine-voice" ] ?? { } ) as Record < string , any > ;
115- const tools = ( cfg . tools ?? { } ) as Record < string , any > ;
116- const existingAllow = Array . isArray ( tools . allow ) ? tools . allow as string [ ] : [ ] ;
117-
118- const requiredTools = [
119- "pine_voice_call_and_wait" ,
120- "pine_voice_call" ,
121- "pine_voice_call_status" ,
122- ] ;
123- const missingTools = requiredTools . filter ( t => ! existingAllow . includes ( t ) ) ;
124- const mergedAllow = [ ...existingAllow , ...missingTools ] ;
125-
126- const updatedConfig = {
127- ...cfg ,
128- plugins : {
129- ...plugins ,
130- entries : {
131- ...entries ,
132- "openclaw-pine-voice" : {
133- ...pluginEntry ,
134- config : {
135- ...( pluginEntry . config ?? { } ) ,
136- access_token : accessToken ,
137- user_id : userId ,
138- } ,
139- } ,
140- } ,
141- } ,
142- tools : {
143- ...tools ,
144- allow : mergedAllow ,
145- } ,
146- } ;
147-
167+ const { updatedConfig, addedTools } = buildAuthConfig ( cfg , accessToken , userId ) ;
148168 await api . runtime . config . writeConfigFile ( updatedConfig ) ;
149169 pendingAuth . delete ( params . email ) ;
150170
151- const toolsNote = missingTools . length > 0
152- ? ` Voice tools (${ missingTools . join ( ", " ) } ) have been added to tools.allow.`
171+ const toolsNote = addedTools . length > 0
172+ ? ` Voice tools (${ addedTools . join ( ", " ) } ) have been added to tools.allow.`
153173 : "" ;
154174
155175 api . log ?. info ?.( `pine-voice: auth successful for ${ params . email } , credentials saved` ) ;
156- if ( missingTools . length > 0 ) {
157- api . log ?. info ?.( `pine-voice: added ${ missingTools . join ( ", " ) } to tools.allow` ) ;
176+ if ( addedTools . length > 0 ) {
177+ api . log ?. info ?.( `pine-voice: added ${ addedTools . join ( ", " ) } to tools.allow` ) ;
158178 }
159179
160180 return {
@@ -239,21 +259,15 @@ export function registerAuthCommands(api: any) {
239259 opts . code ,
240260 ) ;
241261
242- console . log ( "Authentication successful!" ) ;
243- console . log ( `Add this to your plugin config in ~/.openclaw/openclaw.json:` ) ;
244- console . log ( "" ) ;
245- console . log ( ` "plugins": {` ) ;
246- console . log ( ` "entries": {` ) ;
247- console . log ( ` "openclaw-pine-voice": {` ) ;
248- console . log ( ` "config": {` ) ;
249- console . log ( ` "access_token": "${ accessToken } ",` ) ;
250- console . log ( ` "user_id": "${ userId } "` ) ;
251- console . log ( ` }` ) ;
252- console . log ( ` }` ) ;
253- console . log ( ` }` ) ;
254- console . log ( ` }` ) ;
255- console . log ( "" ) ;
256- console . log ( "Then restart the gateway:" ) ;
262+ const cfg = api . runtime . config . loadConfig ( ) ;
263+ const { updatedConfig, addedTools } = buildAuthConfig ( cfg , accessToken , userId ) ;
264+ await api . runtime . config . writeConfigFile ( updatedConfig ) ;
265+
266+ console . log ( "Authentication successful! Credentials saved to openclaw.json." ) ;
267+ if ( addedTools . length > 0 ) {
268+ console . log ( `Voice tools (${ addedTools . join ( ", " ) } ) added to tools.allow.` ) ;
269+ }
270+ console . log ( "\nRestart the gateway for changes to take effect:" ) ;
257271 console . log ( " openclaw gateway restart" ) ;
258272 } catch ( err : unknown ) {
259273 const message = err instanceof Error ? err . message : String ( err ) ;
0 commit comments