1212import {
1313 buildInternalContractSchemas ,
1414 COMMAND_CATALOG ,
15+ NODE_TYPES ,
1516 OPERATION_REQUIRES_DOCUMENT_CONTEXT_MAP ,
1617 type OperationId ,
1718} from '@superdoc/document-api' ;
@@ -446,7 +447,47 @@ const PARAM_FLAG_OVERRIDES: Partial<Record<string, Record<string, { name?: strin
446447// adjustment for CLI metadata (e.g. simplifying or enriching).
447448// ---------------------------------------------------------------------------
448449
449- const PARAM_SCHEMA_OVERRIDES : Partial < Record < string , Record < string , CliTypeSpec > > > = { } ;
450+ // The document-api contract schema for `select` is a strict oneOf(text, node)
451+ // that rejects shorthand selectors like `{ type: "paragraph" }`. The CLI
452+ // normalizes these shorthands in resolveFindQuery() → validateQuery(), so
453+ // the schema-level validation must accept all three supported forms.
454+ const DOC_FIND_SELECT_SCHEMA : CliTypeSpec = {
455+ oneOf : [
456+ // { type: 'text', pattern: '...', mode?, caseSensitive? }
457+ {
458+ type : 'object' ,
459+ properties : {
460+ type : { const : 'text' } ,
461+ pattern : { type : 'string' } ,
462+ mode : { oneOf : [ { const : 'contains' } , { const : 'regex' } ] } ,
463+ caseSensitive : { type : 'boolean' } ,
464+ } ,
465+ required : [ 'type' , 'pattern' ] ,
466+ } ,
467+ // { type: 'node', nodeType?, kind? }
468+ {
469+ type : 'object' ,
470+ properties : {
471+ type : { const : 'node' } ,
472+ nodeType : { type : 'string' } ,
473+ kind : { oneOf : [ { const : 'block' } , { const : 'inline' } ] } ,
474+ } ,
475+ required : [ 'type' ] ,
476+ } ,
477+ // Shorthand: { type: '<NodeType>' } — normalized to { type: 'node', nodeType }
478+ {
479+ type : 'object' ,
480+ properties : {
481+ type : { oneOf : NODE_TYPES . map ( ( t ) => ( { const : t } ) as CliTypeSpec ) } ,
482+ } ,
483+ required : [ 'type' ] ,
484+ } ,
485+ ] ,
486+ } ;
487+
488+ const PARAM_SCHEMA_OVERRIDES : Partial < Record < string , Record < string , CliTypeSpec > > > = {
489+ 'doc.find' : { select : DOC_FIND_SELECT_SCHEMA } ,
490+ } ;
450491
451492// ---------------------------------------------------------------------------
452493// Schema-derived param exclusions
@@ -455,11 +496,7 @@ const PARAM_SCHEMA_OVERRIDES: Partial<Record<string, Record<string, CliTypeSpec>
455496// exposed in CLI metadata because the CLI provides an alternative interface.
456497// ---------------------------------------------------------------------------
457498
458- const PARAM_EXCLUSIONS : Partial < Record < string , ReadonlySet < string > > > = {
459- // CLI uses flat flags (--type, --pattern, --mode) or --query-json; `select`
460- // is an internal document-api field that the invoker builds from flat flags.
461- 'doc.find' : new Set ( [ 'select' ] ) ,
462- } ;
499+ const PARAM_EXCLUSIONS : Partial < Record < string , ReadonlySet < string > > > = { } ;
463500
464501// ---------------------------------------------------------------------------
465502// Extra CLI-specific params for doc-backed operations
@@ -494,36 +531,47 @@ const FORMAT_OPERATION_IDS = CLI_DOC_OPERATIONS.filter((operationId): operationI
494531) ;
495532
496533const EXTRA_CLI_PARAMS : Partial < Record < string , CliOperationParamSpec [ ] > > = {
534+ // Flat flags are CLI convenience alternatives to --select-json. Marked
535+ // agentVisible: false so that if doc.find is ever exposed as a tool
536+ // (currently skipAsATool), agents see only the structured `select` param.
497537 'doc.find' : [
498538 {
499539 name : 'type' ,
500540 kind : 'flag' ,
501541 type : 'string' ,
502542 description : "Selector type: 'text' for text search or 'node' for node type search." ,
543+ agentVisible : false ,
503544 } ,
504545 {
505546 name : 'nodeType' ,
506547 kind : 'flag' ,
507548 flag : 'node-type' ,
508549 type : 'string' ,
509550 description : 'Node type to match (paragraph, heading, table, listItem, etc.).' ,
551+ agentVisible : false ,
552+ } ,
553+ { name : 'kind' , kind : 'flag' , type : 'string' , description : "Filter: 'block' or 'inline'." , agentVisible : false } ,
554+ {
555+ name : 'pattern' ,
556+ kind : 'flag' ,
557+ type : 'string' ,
558+ description : 'Text or regex pattern to match.' ,
559+ agentVisible : false ,
560+ } ,
561+ {
562+ name : 'mode' ,
563+ kind : 'flag' ,
564+ type : 'string' ,
565+ description : "Match mode: 'contains' (substring) or 'regex'." ,
566+ agentVisible : false ,
510567 } ,
511- { name : 'kind' , kind : 'flag' , type : 'string' , description : "Filter: 'block' or 'inline'." } ,
512- { name : 'pattern' , kind : 'flag' , type : 'string' , description : 'Text or regex pattern to match.' } ,
513- { name : 'mode' , kind : 'flag' , type : 'string' , description : "Match mode: 'contains' (substring) or 'regex'." } ,
514568 {
515569 name : 'caseSensitive' ,
516570 kind : 'flag' ,
517571 flag : 'case-sensitive' ,
518572 type : 'boolean' ,
519573 description : 'Case-sensitive matching. Default: false.' ,
520- } ,
521- {
522- name : 'select' ,
523- kind : 'jsonFlag' ,
524- flag : 'select-json' ,
525- type : 'json' ,
526- description : "Search selector as JSON: {type:'text', pattern:'...'} or {type:'node', nodeType:'...'}." ,
574+ agentVisible : false ,
527575 } ,
528576 { name : 'query' , kind : 'jsonFlag' , flag : 'query-json' , type : 'json' , description : 'Query filter as JSON object.' } ,
529577 ] ,
0 commit comments