@@ -254,6 +254,11 @@ func init() {
254254 slidesCmd .AddCommand (slidesUpdateShapeCmd )
255255 slidesCmd .AddCommand (slidesReorderSlidesCmd )
256256
257+ // Notes flags for read commands
258+ slidesInfoCmd .Flags ().Bool ("notes" , false , "Include speaker notes in output" )
259+ slidesListCmd .Flags ().Bool ("notes" , false , "Include speaker notes in output" )
260+ slidesReadCmd .Flags ().Bool ("notes" , false , "Include speaker notes in output" )
261+
257262 // Create flags
258263 slidesCreateCmd .Flags ().String ("title" , "" , "Presentation title (required)" )
259264 slidesCreateCmd .MarkFlagRequired ("title" )
@@ -296,6 +301,9 @@ func init() {
296301 slidesAddTextCmd .Flags ().Int ("col" , - 1 , "Column index, 0-based (required with --table-id)" )
297302 slidesAddTextCmd .Flags ().String ("text" , "" , "Text to insert (required)" )
298303 slidesAddTextCmd .Flags ().Int ("at" , 0 , "Position to insert at (0 = beginning)" )
304+ slidesAddTextCmd .Flags ().Bool ("notes" , false , "Target speaker notes shape (mutually exclusive with --object-id and --table-id)" )
305+ slidesAddTextCmd .Flags ().String ("slide-id" , "" , "Slide object ID (required with --notes)" )
306+ slidesAddTextCmd .Flags ().Int ("slide-number" , 0 , "Slide number, 1-indexed (required with --notes)" )
299307 slidesAddTextCmd .MarkFlagRequired ("text" )
300308
301309 // Replace-text flags
@@ -310,10 +318,12 @@ func init() {
310318 slidesDeleteObjectCmd .MarkFlagRequired ("object-id" )
311319
312320 // Delete-text flags
313- slidesDeleteTextCmd .Flags ().String ("object-id" , "" , "Shape containing text (required)" )
321+ slidesDeleteTextCmd .Flags ().String ("object-id" , "" , "Shape containing text (required unless --notes )" )
314322 slidesDeleteTextCmd .Flags ().Int ("from" , 0 , "Start index (default 0)" )
315323 slidesDeleteTextCmd .Flags ().Int ("to" , - 1 , "End index (if omitted, deletes to end)" )
316- slidesDeleteTextCmd .MarkFlagRequired ("object-id" )
324+ slidesDeleteTextCmd .Flags ().Bool ("notes" , false , "Target speaker notes shape (alternative to --object-id)" )
325+ slidesDeleteTextCmd .Flags ().String ("slide-id" , "" , "Slide object ID (required with --notes)" )
326+ slidesDeleteTextCmd .Flags ().Int ("slide-number" , 0 , "Slide number, 1-indexed (required with --notes)" )
317327
318328 // Update-text-style flags
319329 slidesUpdateTextStyleCmd .Flags ().String ("object-id" , "" , "Shape containing text (required)" )
@@ -442,6 +452,8 @@ func runSlidesInfo(cmd *cobra.Command, args []string) error {
442452 }
443453 }
444454
455+ includeNotes , _ := cmd .Flags ().GetBool ("notes" )
456+
445457 // List slide IDs and titles
446458 slideInfo := make ([]map [string ]interface {}, 0 , len (presentation .Slides ))
447459 for i , slide := range presentation .Slides {
@@ -456,6 +468,13 @@ func runSlidesInfo(cmd *cobra.Command, args []string) error {
456468 info ["title" ] = title
457469 }
458470
471+ if includeNotes {
472+ notes := extractSpeakerNotes (slide )
473+ if notes != "" {
474+ info ["notes" ] = notes
475+ }
476+ }
477+
459478 slideInfo = append (slideInfo , info )
460479 }
461480 result ["slides" ] = slideInfo
@@ -484,6 +503,8 @@ func runSlidesList(cmd *cobra.Command, args []string) error {
484503 return p .PrintError (fmt .Errorf ("failed to get presentation: %w" , err ))
485504 }
486505
506+ includeNotes , _ := cmd .Flags ().GetBool ("notes" )
507+
487508 slidesList := make ([]map [string ]interface {}, 0 , len (presentation .Slides ))
488509 for i , slide := range presentation .Slides {
489510 slideData := map [string ]interface {}{
@@ -500,6 +521,13 @@ func runSlidesList(cmd *cobra.Command, args []string) error {
500521 // Count elements
501522 slideData ["element_count" ] = len (slide .PageElements )
502523
524+ if includeNotes {
525+ notes := extractSpeakerNotes (slide )
526+ if notes != "" {
527+ slideData ["notes" ] = notes
528+ }
529+ }
530+
503531 slidesList = append (slidesList , slideData )
504532 }
505533
@@ -531,6 +559,8 @@ func runSlidesRead(cmd *cobra.Command, args []string) error {
531559 return p .PrintError (fmt .Errorf ("failed to get presentation: %w" , err ))
532560 }
533561
562+ includeNotes , _ := cmd .Flags ().GetBool ("notes" )
563+
534564 // If slide number provided, read specific slide
535565 if len (args ) > 1 {
536566 var slideNum int
@@ -543,13 +573,22 @@ func runSlidesRead(cmd *cobra.Command, args []string) error {
543573 slide := presentation .Slides [slideNum - 1 ]
544574 text := extractSlideText (slide )
545575
546- return p . Print ( map [string ]interface {}{
576+ result := map [string ]interface {}{
547577 "slide" : slideNum ,
548578 "id" : slide .ObjectId ,
549579 "text" : text ,
550580 "title" : extractSlideTitle (slide ),
551581 "layout" : slide .SlideProperties .LayoutObjectId ,
552- })
582+ }
583+
584+ if includeNotes {
585+ notes := extractSpeakerNotes (slide )
586+ if notes != "" {
587+ result ["notes" ] = notes
588+ }
589+ }
590+
591+ return p .Print (result )
553592 }
554593
555594 // Read all slides
@@ -566,6 +605,13 @@ func runSlidesRead(cmd *cobra.Command, args []string) error {
566605 slideData ["title" ] = title
567606 }
568607
608+ if includeNotes {
609+ notes := extractSpeakerNotes (slide )
610+ if notes != "" {
611+ slideData ["notes" ] = notes
612+ }
613+ }
614+
569615 slidesContent = append (slidesContent , slideData )
570616 }
571617
@@ -649,6 +695,59 @@ func extractTableText(table *slides.Table) string {
649695 return strings .Join (rows , "\n " )
650696}
651697
698+ // extractSpeakerNotes extracts speaker notes text from a slide's notes page.
699+ func extractSpeakerNotes (slide * slides.Page ) string {
700+ if slide .SlideProperties == nil {
701+ return ""
702+ }
703+ notesPage := slide .SlideProperties .NotesPage
704+ if notesPage == nil {
705+ return ""
706+ }
707+ if notesPage .NotesProperties == nil || notesPage .NotesProperties .SpeakerNotesObjectId == "" {
708+ return ""
709+ }
710+
711+ notesObjectID := notesPage .NotesProperties .SpeakerNotesObjectId
712+ for _ , element := range notesPage .PageElements {
713+ if element .ObjectId == notesObjectID && element .Shape != nil {
714+ return extractShapeText (element .Shape )
715+ }
716+ }
717+ return ""
718+ }
719+
720+ // getSpeakerNotesObjectID returns the object ID of the speaker notes shape for a slide.
721+ func getSpeakerNotesObjectID (slide * slides.Page ) (string , error ) {
722+ if slide .SlideProperties == nil || slide .SlideProperties .NotesPage == nil {
723+ return "" , fmt .Errorf ("slide has no notes page" )
724+ }
725+ notesPage := slide .SlideProperties .NotesPage
726+ if notesPage .NotesProperties == nil || notesPage .NotesProperties .SpeakerNotesObjectId == "" {
727+ return "" , fmt .Errorf ("slide has no speaker notes shape" )
728+ }
729+ return notesPage .NotesProperties .SpeakerNotesObjectId , nil
730+ }
731+
732+ // findSlide resolves a slide from a presentation by --slide-id or --slide-number.
733+ func findSlide (presentation * slides.Presentation , slideIDFlag string , slideNumber int ) (* slides.Page , error ) {
734+ if slideIDFlag != "" && slideNumber > 0 {
735+ return nil , fmt .Errorf ("specify only one of --slide-id or --slide-number, not both" )
736+ }
737+ if slideIDFlag != "" {
738+ for _ , s := range presentation .Slides {
739+ if s .ObjectId == slideIDFlag {
740+ return s , nil
741+ }
742+ }
743+ return nil , fmt .Errorf ("slide with ID '%s' not found" , slideIDFlag )
744+ }
745+ if slideNumber < 1 || slideNumber > len (presentation .Slides ) {
746+ return nil , fmt .Errorf ("slide number %d out of range (1-%d)" , slideNumber , len (presentation .Slides ))
747+ }
748+ return presentation .Slides [slideNumber - 1 ], nil
749+ }
750+
652751func runSlidesCreate (cmd * cobra.Command , args []string ) error {
653752 p := printer .New (os .Stdout , GetFormat ())
654753 ctx := context .Background ()
@@ -1264,13 +1363,26 @@ func runSlidesAddText(cmd *cobra.Command, args []string) error {
12641363 col , _ := cmd .Flags ().GetInt ("col" )
12651364 text , _ := cmd .Flags ().GetString ("text" )
12661365 insertionIndex , _ := cmd .Flags ().GetInt ("at" )
1366+ notesMode , _ := cmd .Flags ().GetBool ("notes" )
1367+ slideIDFlag , _ := cmd .Flags ().GetString ("slide-id" )
1368+ slideNumber , _ := cmd .Flags ().GetInt ("slide-number" )
12671369
12681370 // Validate mutually exclusive flags (fail fast before network calls)
1269- if objectID != "" && tableID != "" {
1270- return p .PrintError (fmt .Errorf ("cannot specify both --object-id and --table-id" ))
1371+ modeCount := 0
1372+ if objectID != "" {
1373+ modeCount ++
1374+ }
1375+ if tableID != "" {
1376+ modeCount ++
1377+ }
1378+ if notesMode {
1379+ modeCount ++
12711380 }
1272- if objectID == "" && tableID == "" {
1273- return p .PrintError (fmt .Errorf ("must specify either --object-id or --table-id" ))
1381+ if modeCount > 1 {
1382+ return p .PrintError (fmt .Errorf ("--object-id, --table-id, and --notes are mutually exclusive" ))
1383+ }
1384+ if modeCount == 0 {
1385+ return p .PrintError (fmt .Errorf ("must specify --object-id, --table-id, or --notes" ))
12741386 }
12751387
12761388 // Validate table cell mode requires row and col
@@ -1283,6 +1395,11 @@ func runSlidesAddText(cmd *cobra.Command, args []string) error {
12831395 }
12841396 }
12851397
1398+ // Validate notes mode requires slide targeting
1399+ if notesMode && slideIDFlag == "" && slideNumber == 0 {
1400+ return p .PrintError (fmt .Errorf ("--notes requires --slide-id or --slide-number" ))
1401+ }
1402+
12861403 // Now create the client after validation passes
12871404 ctx := context .Background ()
12881405 factory , err := client .NewFactory (ctx )
@@ -1295,6 +1412,25 @@ func runSlidesAddText(cmd *cobra.Command, args []string) error {
12951412 return p .PrintError (err )
12961413 }
12971414
1415+ // Resolve notes mode to an object ID
1416+ if notesMode {
1417+ presentation , err := svc .Presentations .Get (presentationID ).Do ()
1418+ if err != nil {
1419+ return p .PrintError (fmt .Errorf ("failed to get presentation: %w" , err ))
1420+ }
1421+
1422+ slide , err := findSlide (presentation , slideIDFlag , slideNumber )
1423+ if err != nil {
1424+ return p .PrintError (err )
1425+ }
1426+
1427+ notesObjID , err := getSpeakerNotesObjectID (slide )
1428+ if err != nil {
1429+ return p .PrintError (fmt .Errorf ("cannot target speaker notes: %w" , err ))
1430+ }
1431+ objectID = notesObjID
1432+ }
1433+
12981434 // Build the InsertText request
12991435 insertTextReq := & slides.InsertTextRequest {
13001436 Text : text ,
@@ -1319,9 +1455,12 @@ func runSlidesAddText(cmd *cobra.Command, args []string) error {
13191455 result ["row" ] = row
13201456 result ["col" ] = col
13211457 } else {
1322- // Shape/text box mode
1458+ // Shape/text box mode (including resolved notes mode)
13231459 insertTextReq .ObjectId = objectID
13241460 result ["object_id" ] = objectID
1461+ if notesMode {
1462+ result ["target" ] = "speaker_notes"
1463+ }
13251464 }
13261465
13271466 requests := []* slides.Request {
@@ -1453,8 +1592,29 @@ func runSlidesDeleteObject(cmd *cobra.Command, args []string) error {
14531592
14541593func runSlidesDeleteText (cmd * cobra.Command , args []string ) error {
14551594 p := printer .New (os .Stdout , GetFormat ())
1456- ctx := context .Background ()
14571595
1596+ presentationID := args [0 ]
1597+ objectID , _ := cmd .Flags ().GetString ("object-id" )
1598+ fromIndex , _ := cmd .Flags ().GetInt ("from" )
1599+ toIndex , _ := cmd .Flags ().GetInt ("to" )
1600+ notesMode , _ := cmd .Flags ().GetBool ("notes" )
1601+ slideIDFlag , _ := cmd .Flags ().GetString ("slide-id" )
1602+ slideNumber , _ := cmd .Flags ().GetInt ("slide-number" )
1603+
1604+ // Validate: need either --object-id or --notes
1605+ if objectID == "" && ! notesMode {
1606+ return p .PrintError (fmt .Errorf ("must specify --object-id or --notes" ))
1607+ }
1608+ if objectID != "" && notesMode {
1609+ return p .PrintError (fmt .Errorf ("--object-id and --notes are mutually exclusive" ))
1610+ }
1611+
1612+ // Validate notes mode requires slide targeting
1613+ if notesMode && slideIDFlag == "" && slideNumber == 0 {
1614+ return p .PrintError (fmt .Errorf ("--notes requires --slide-id or --slide-number" ))
1615+ }
1616+
1617+ ctx := context .Background ()
14581618 factory , err := client .NewFactory (ctx )
14591619 if err != nil {
14601620 return p .PrintError (err )
@@ -1465,10 +1625,24 @@ func runSlidesDeleteText(cmd *cobra.Command, args []string) error {
14651625 return p .PrintError (err )
14661626 }
14671627
1468- presentationID := args [0 ]
1469- objectID , _ := cmd .Flags ().GetString ("object-id" )
1470- fromIndex , _ := cmd .Flags ().GetInt ("from" )
1471- toIndex , _ := cmd .Flags ().GetInt ("to" )
1628+ // Resolve notes mode to an object ID
1629+ if notesMode {
1630+ presentation , err := svc .Presentations .Get (presentationID ).Do ()
1631+ if err != nil {
1632+ return p .PrintError (fmt .Errorf ("failed to get presentation: %w" , err ))
1633+ }
1634+
1635+ slide , err := findSlide (presentation , slideIDFlag , slideNumber )
1636+ if err != nil {
1637+ return p .PrintError (err )
1638+ }
1639+
1640+ notesObjID , err := getSpeakerNotesObjectID (slide )
1641+ if err != nil {
1642+ return p .PrintError (fmt .Errorf ("cannot target speaker notes: %w" , err ))
1643+ }
1644+ objectID = notesObjID
1645+ }
14721646
14731647 startIdx := int64 (fromIndex )
14741648 textRange := & slides.Range {
0 commit comments