@@ -395,6 +395,196 @@ export async function runQuickAction(): Promise<void> {
395395 await previewAndMaybeApply ( binaryPath , target , buildDocAppendQuickAction ( target . absolutePath , selector , value ) ) ;
396396 }
397397 } ,
398+ {
399+ label : "Prepend to array" ,
400+ description : "Prepend a value to a JSON, YAML, or TOML array" ,
401+ detail : "Builds `patchloom doc prepend <file> <selector> <value>`" ,
402+ run : async ( ) => {
403+ const target = await pickWorkspaceFileTarget ( "Select a JSON, YAML, or TOML file for Patchloom doc prepend" ) ;
404+ if ( ! target ) {
405+ return ;
406+ }
407+
408+ if ( ! isStructuredDocumentPath ( target . absolutePath ) ) {
409+ await vscode . window . showWarningMessage (
410+ `${ target . relativePath } is not a supported JSON, YAML, or TOML file for Patchloom doc prepend.`
411+ ) ;
412+ return ;
413+ }
414+
415+ const selector = await vscode . window . showInputBox ( {
416+ prompt : "Selector path to the array" ,
417+ placeHolder : "dependencies" ,
418+ validateInput : ( value ) => value . length > 0 ? undefined : "Selector is required."
419+ } ) ;
420+ if ( selector === undefined ) {
421+ return ;
422+ }
423+
424+ const value = await vscode . window . showInputBox ( {
425+ prompt : "Value to prepend" ,
426+ placeHolder : '"new-item"' ,
427+ validateInput : ( input ) => input . length > 0 ? undefined : "Value is required."
428+ } ) ;
429+ if ( value === undefined ) {
430+ return ;
431+ }
432+
433+ await previewAndMaybeApply ( binaryPath , target , buildDocPrependQuickAction ( target . absolutePath , selector , value ) ) ;
434+ }
435+ } ,
436+ {
437+ label : "Ensure structured value" ,
438+ description : "Idempotent set: only write if the key is missing" ,
439+ detail : "Builds `patchloom doc ensure <file> <selector> <value>`" ,
440+ run : async ( ) => {
441+ const target = await pickWorkspaceFileTarget ( "Select a JSON, YAML, or TOML file for Patchloom doc ensure" ) ;
442+ if ( ! target ) {
443+ return ;
444+ }
445+
446+ if ( ! isStructuredDocumentPath ( target . absolutePath ) ) {
447+ await vscode . window . showWarningMessage (
448+ `${ target . relativePath } is not a supported JSON, YAML, or TOML file for Patchloom doc ensure.`
449+ ) ;
450+ return ;
451+ }
452+
453+ const selector = await vscode . window . showInputBox ( {
454+ prompt : "Selector path" ,
455+ placeHolder : "server.port" ,
456+ validateInput : ( value ) => value . length > 0 ? undefined : "Selector is required."
457+ } ) ;
458+ if ( selector === undefined ) {
459+ return ;
460+ }
461+
462+ const value = await vscode . window . showInputBox ( {
463+ prompt : "Default value (set only if missing)" ,
464+ placeHolder : "8080" ,
465+ validateInput : ( input ) => input . length > 0 ? undefined : "Value is required."
466+ } ) ;
467+ if ( value === undefined ) {
468+ return ;
469+ }
470+
471+ await previewAndMaybeApply ( binaryPath , target , buildDocEnsureQuickAction ( target . absolutePath , selector , value ) ) ;
472+ }
473+ } ,
474+ {
475+ label : "Move/rename key" ,
476+ description : "Move or rename a selector path in JSON, YAML, or TOML" ,
477+ detail : "Builds `patchloom doc move <file> <from> <to>`" ,
478+ run : async ( ) => {
479+ const target = await pickWorkspaceFileTarget ( "Select a JSON, YAML, or TOML file for Patchloom doc move" ) ;
480+ if ( ! target ) {
481+ return ;
482+ }
483+
484+ if ( ! isStructuredDocumentPath ( target . absolutePath ) ) {
485+ await vscode . window . showWarningMessage (
486+ `${ target . relativePath } is not a supported JSON, YAML, or TOML file for Patchloom doc move.`
487+ ) ;
488+ return ;
489+ }
490+
491+ const from = await vscode . window . showInputBox ( {
492+ prompt : "Source selector path" ,
493+ placeHolder : "old.key" ,
494+ validateInput : ( value ) => value . length > 0 ? undefined : "Source selector is required."
495+ } ) ;
496+ if ( from === undefined ) {
497+ return ;
498+ }
499+
500+ const to = await vscode . window . showInputBox ( {
501+ prompt : "Destination selector path" ,
502+ placeHolder : "new.key" ,
503+ validateInput : ( value ) => value . length > 0 ? undefined : "Destination selector is required."
504+ } ) ;
505+ if ( to === undefined ) {
506+ return ;
507+ }
508+
509+ await previewAndMaybeApply ( binaryPath , target , buildDocMoveQuickAction ( target . absolutePath , from , to ) ) ;
510+ }
511+ } ,
512+ {
513+ label : "Insert after heading" ,
514+ description : "Insert content after a markdown heading" ,
515+ detail : "Builds `patchloom md insert-after-heading <file> --heading <h> --content <text>`" ,
516+ run : async ( ) => {
517+ const target = await pickWorkspaceFileTarget ( "Select a markdown file for Patchloom insert-after-heading" ) ;
518+ if ( ! target ) {
519+ return ;
520+ }
521+
522+ if ( ! isMarkdownPath ( target . absolutePath ) ) {
523+ await vscode . window . showWarningMessage (
524+ `${ target . relativePath } is not a markdown file.`
525+ ) ;
526+ return ;
527+ }
528+
529+ const heading = await vscode . window . showInputBox ( {
530+ prompt : "Heading to insert content after" ,
531+ placeHolder : "## Installation" ,
532+ validateInput : ( value ) => value . length > 0 ? undefined : "Heading is required."
533+ } ) ;
534+ if ( heading === undefined ) {
535+ return ;
536+ }
537+
538+ const content = await vscode . window . showInputBox ( {
539+ prompt : "Content to insert" ,
540+ placeHolder : "New paragraph text" ,
541+ validateInput : ( value ) => value . length > 0 ? undefined : "Content is required."
542+ } ) ;
543+ if ( content === undefined ) {
544+ return ;
545+ }
546+
547+ await previewAndMaybeApply ( binaryPath , target , buildMdInsertAfterHeadingQuickAction ( target . absolutePath , heading , content ) ) ;
548+ }
549+ } ,
550+ {
551+ label : "Insert before heading" ,
552+ description : "Insert content before a markdown heading" ,
553+ detail : "Builds `patchloom md insert-before-heading <file> --heading <h> --content <text>`" ,
554+ run : async ( ) => {
555+ const target = await pickWorkspaceFileTarget ( "Select a markdown file for Patchloom insert-before-heading" ) ;
556+ if ( ! target ) {
557+ return ;
558+ }
559+
560+ if ( ! isMarkdownPath ( target . absolutePath ) ) {
561+ await vscode . window . showWarningMessage (
562+ `${ target . relativePath } is not a markdown file.`
563+ ) ;
564+ return ;
565+ }
566+
567+ const heading = await vscode . window . showInputBox ( {
568+ prompt : "Heading to insert content before" ,
569+ placeHolder : "## Changelog" ,
570+ validateInput : ( value ) => value . length > 0 ? undefined : "Heading is required."
571+ } ) ;
572+ if ( heading === undefined ) {
573+ return ;
574+ }
575+
576+ const content = await vscode . window . showInputBox ( {
577+ prompt : "Content to insert" ,
578+ placeHolder : "New section text" ,
579+ validateInput : ( value ) => value . length > 0 ? undefined : "Content is required."
580+ } ) ;
581+ if ( content === undefined ) {
582+ return ;
583+ }
584+
585+ await previewAndMaybeApply ( binaryPath , target , buildMdInsertBeforeHeadingQuickAction ( target . absolutePath , heading , content ) ) ;
586+ }
587+ } ,
398588 {
399589 label : "Append table row" ,
400590 description : "Append a row to a markdown table under a heading" ,
@@ -686,6 +876,51 @@ export function buildMdReplaceSectionQuickAction(targetPath: string, heading: st
686876 } ;
687877}
688878
879+ export function buildDocPrependQuickAction ( targetPath : string , selector : string , value : string ) : PlannedQuickAction {
880+ return {
881+ title : `Prepend to ${ selector } in ${ path . basename ( targetPath ) } ` ,
882+ targetPath,
883+ targetArgIndices : [ 2 ] ,
884+ args : [ "doc" , "prepend" , targetPath , selector , value ]
885+ } ;
886+ }
887+
888+ export function buildDocEnsureQuickAction ( targetPath : string , selector : string , value : string ) : PlannedQuickAction {
889+ return {
890+ title : `Ensure ${ selector } in ${ path . basename ( targetPath ) } ` ,
891+ targetPath,
892+ targetArgIndices : [ 2 ] ,
893+ args : [ "doc" , "ensure" , targetPath , selector , value ]
894+ } ;
895+ }
896+
897+ export function buildDocMoveQuickAction ( targetPath : string , from : string , to : string ) : PlannedQuickAction {
898+ return {
899+ title : `Move ${ from } to ${ to } in ${ path . basename ( targetPath ) } ` ,
900+ targetPath,
901+ targetArgIndices : [ 2 ] ,
902+ args : [ "doc" , "move" , targetPath , from , to ]
903+ } ;
904+ }
905+
906+ export function buildMdInsertAfterHeadingQuickAction ( targetPath : string , heading : string , content : string ) : PlannedQuickAction {
907+ return {
908+ title : `Insert after "${ heading } " in ${ path . basename ( targetPath ) } ` ,
909+ targetPath,
910+ targetArgIndices : [ 2 ] ,
911+ args : [ "md" , "insert-after-heading" , targetPath , "--heading" , heading , "--content" , content ]
912+ } ;
913+ }
914+
915+ export function buildMdInsertBeforeHeadingQuickAction ( targetPath : string , heading : string , content : string ) : PlannedQuickAction {
916+ return {
917+ title : `Insert before "${ heading } " in ${ path . basename ( targetPath ) } ` ,
918+ targetPath,
919+ targetArgIndices : [ 2 ] ,
920+ args : [ "md" , "insert-before-heading" , targetPath , "--heading" , heading , "--content" , content ]
921+ } ;
922+ }
923+
689924export function buildUndoQuickAction ( workspacePath : string ) : PlannedQuickAction {
690925 return {
691926 title : "Undo last patchloom change" ,
0 commit comments