@@ -9,6 +9,7 @@ import { GCalClient } from '../services/gcal/client';
99import { printGCalCalendarList , printGCalEventList , printGCalEvent , printGCalEventCreated , printGCalEventDeleted , printGCalFreeBusy } from '../utils/output' ;
1010import { CliError , handleError } from '../utils/errors' ;
1111import { readStdin } from '../utils/stdin' ;
12+ import { enforceWriteAccess } from '../utils/read-only' ;
1213
1314async function getGCalClient ( profileName ?: string ) : Promise < { client : GCalClient ; profile : string } > {
1415 const { tokens, profile } = await getValidTokens ( 'gcal' , profileName ) ;
@@ -155,7 +156,8 @@ export function registerGCalCommands(program: Command): void {
155156 return { method : method as 'email' | 'popup' , minutes : parseInt ( minutes , 10 ) } ;
156157 } ) ;
157158
158- const { client } = await getGCalClient ( options . profile ) ;
159+ const { client, profile } = await getGCalClient ( options . profile ) ;
160+ await enforceWriteAccess ( 'gcal' , profile , 'create event' ) ;
159161 const event = await client . createEvent ( {
160162 calendarId : calendarId || 'primary' ,
161163 summary : options . summary ,
@@ -210,7 +212,8 @@ export function registerGCalCommands(program: Command): void {
210212 throw new CliError ( 'INVALID_PARAMS' , 'Cannot use both --attendee and --add-attendee' ) ;
211213 }
212214
213- const { client } = await getGCalClient ( options . profile ) ;
215+ const { client, profile } = await getGCalClient ( options . profile ) ;
216+ await enforceWriteAccess ( 'gcal' , profile , 'update event' ) ;
214217 const event = await client . updateEvent ( {
215218 calendarId,
216219 eventId,
@@ -243,7 +246,8 @@ export function registerGCalCommands(program: Command): void {
243246 . option ( '--send-updates <mode>' , 'Send notifications: all, externalOnly, none' , 'all' )
244247 . action ( async ( calendarId : string , eventId : string , options ) => {
245248 try {
246- const { client } = await getGCalClient ( options . profile ) ;
249+ const { client, profile } = await getGCalClient ( options . profile ) ;
250+ await enforceWriteAccess ( 'gcal' , profile , 'delete event' ) ;
247251 await client . deleteEvent ( calendarId , eventId , options . sendUpdates ) ;
248252 printGCalEventDeleted ( calendarId , eventId ) ;
249253 } catch ( error ) {
@@ -300,7 +304,8 @@ export function registerGCalCommands(program: Command): void {
300304 throw new CliError ( 'INVALID_PARAMS' , `Invalid status: ${ options . status } ` , 'Use: accepted, declined, or tentative' ) ;
301305 }
302306
303- const { client } = await getGCalClient ( options . profile ) ;
307+ const { client, profile } = await getGCalClient ( options . profile ) ;
308+ await enforceWriteAccess ( 'gcal' , profile , 'respond to event' ) ;
304309 const event = await client . respond ( {
305310 calendarId,
306311 eventId,
@@ -353,6 +358,7 @@ export function registerGCalCommands(program: Command): void {
353358 . command ( 'add' )
354359 . description ( 'Add a new Google Calendar profile' )
355360 . option ( '--profile <name>' , 'Profile name (auto-detected from email if not provided)' )
361+ . option ( '--read-only' , 'Create as read-only profile (blocks write operations)' )
356362 . action ( async ( options ) => {
357363 try {
358364 console . error ( 'Starting OAuth flow for Google Calendar...\n' ) ;
@@ -371,11 +377,14 @@ export function registerGCalCommands(program: Command): void {
371377
372378 const profileName = options . profile || email ;
373379
374- await setProfile ( 'gcal' , profileName ) ;
380+ await setProfile ( 'gcal' , profileName , { readOnly : options . readOnly } ) ;
375381 await setCredentials ( 'gcal' , profileName , { ...tokens , email } ) ;
376382
377383 console . log ( `\nSuccess! Profile "${ profileName } " configured.` ) ;
378384 console . log ( ` Email: ${ email } ` ) ;
385+ if ( options . readOnly ) {
386+ console . log ( ` Access: read-only` ) ;
387+ }
379388 } catch ( error ) {
380389 handleError ( error ) ;
381390 }
0 commit comments