Move 121/210 parameter-level Schema field overlays from schema_hints/metadata JSON into in-code ParamDecl declarations on DeclareLeafMetadata commands. The declared values are emitted as dws.schema.* annotations at assembly time via ApplyParamDecls, outranking tool_schema_hint (rank 620 > 500) so the hint overlay becomes redundant once the declaration is in place. Key mechanism changes: - Add SchemaDecl.Parameters []ParamDecl with property/required/ interface_type/description/required_when/enum fields - Add cli.ParamDecl type carried inside ContractFinalPayload - ApplyParamDecls emits dws.schema.* annotations from the payload at assembly time (no sync.Map, no tree-rebuild key issue) - Add cli.AnnotateRuntimeFlagInterfaceType (41 overlays needed it) - Add cli.AnnotateRuntimeFlagRequiredValue for explicit true/false - Compatibility alias check tolerates dws.schema.* annotation differences between primary and alias commands - Remove runtime source_hash recomputation (87ms/997k allocs saved; enforced by check-generated-drift.sh at build time instead) - Add shortcut.Flag.RequiredWhen and wire through FromShortcut - Add boolFlag OR semantics to fix confirmationBypass disagreement - Add bindKey default kebab-to-camel for forgotten Bind - Add schema consumption benchmarks (catalog decode 1.5s/817MB, shortcut load 1.9ms/3MB — three orders of magnitude apart) - Add catalog codegen feasibility probe (34 tools: 0.06s compile, 31ns access, 87KB linked — extrapolates to 2.1MB for 845 tools) Migrated products (29 tools, 121 fields): aisearch(1), chat(12), contact(4), doc(3), drive(1), hrbrain(10), mail(2), report(1), sheet(3), todo(6) Remaining 89 fields across 11 products blocked by: - RPCName not found as string literal (19 tools, shortcut/variable) - No matching DeclareLeafMetadata near callMCPTool (11 tools) - No single RPCName for multi-step commands (drive.upload etc.) All tests green: corecmd, cli, helpers. Generation and drift clean.
129 lines
3.9 KiB
Go
129 lines
3.9 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package cli
|
|
|
|
import (
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
// ContractFinalPayload is the Contract-authored final Schema leaf overlay.
|
|
// Registered in-process by the framework; Schema assembly reads it as
|
|
// pass-through. No JSON bridge. Treat as read-only after Register.
|
|
type ContractFinalPayload struct {
|
|
Title string
|
|
Description string
|
|
Positionals []RuntimeSchemaPositional
|
|
Parameters []ParamDecl
|
|
Safety *SafetySpec
|
|
DryRun *DryRunSpec
|
|
Interface *InterfaceSpec
|
|
Selection *SelectionSpec
|
|
Identity *ToolIdentitySpec
|
|
}
|
|
|
|
var contractFinalByCommand sync.Map // *cobra.Command → *ContractFinalPayload
|
|
|
|
// ParamDecl is one parameter-level Schema fact declared on a command. It is
|
|
// stored at DeclareLeafMetadata time and applied as annotations at assembly
|
|
// time, when all flags are guaranteed to exist on the fully-built command tree.
|
|
type ParamDecl struct {
|
|
Name string
|
|
Property string
|
|
Required *bool
|
|
InterfaceType string
|
|
Description string
|
|
RequiredWhen string
|
|
Enum []string
|
|
}
|
|
|
|
// ApplyParamDecls emits parameter declarations as dws.schema.* annotations on the
|
|
// command's flags. Called at assembly time (runtimeToolSpecFromContractFinal)
|
|
// when all flags exist on the fully-built command tree. The decls come from
|
|
// the ContractFinalPayload, so no separate storage is needed.
|
|
func ApplyParamDecls(cmd *cobra.Command, decls []ParamDecl) {
|
|
if cmd == nil || len(decls) == 0 {
|
|
return
|
|
}
|
|
for _, p := range decls {
|
|
name := strings.TrimSpace(p.Name)
|
|
if name == "" {
|
|
continue
|
|
}
|
|
if prop := strings.TrimSpace(p.Property); prop != "" {
|
|
AnnotateRuntimeFlagProperty(cmd, name, prop)
|
|
}
|
|
if p.Required != nil {
|
|
AnnotateRuntimeFlagRequiredValue(cmd, name, *p.Required)
|
|
}
|
|
if it := strings.TrimSpace(p.InterfaceType); it != "" {
|
|
AnnotateRuntimeFlagInterfaceType(cmd, name, it)
|
|
}
|
|
if desc := strings.TrimSpace(p.Description); desc != "" {
|
|
AnnotateRuntimeFlagDescription(cmd, name, desc)
|
|
}
|
|
if rw := strings.TrimSpace(p.RequiredWhen); rw != "" {
|
|
AnnotateRuntimeFlagRequiredWhen(cmd, name, rw)
|
|
}
|
|
if len(p.Enum) > 0 {
|
|
AnnotateRuntimeFlagEnum(cmd, name, p.Enum...)
|
|
}
|
|
}
|
|
}
|
|
|
|
// RegisterRuntimeContractFinal stores the typed final Schema overlay for a leaf.
|
|
// Light runtime write: one map store, no JSON, no deep clone.
|
|
func RegisterRuntimeContractFinal(cmd *cobra.Command, payload ContractFinalPayload) {
|
|
if cmd == nil {
|
|
return
|
|
}
|
|
AnnotateRuntimeContract(cmd)
|
|
p := payload
|
|
contractFinalByCommand.Store(cmd, &p)
|
|
}
|
|
|
|
// RuntimeContractFinal returns the registered final Schema overlay (read-only).
|
|
func RuntimeContractFinal(cmd *cobra.Command) (ContractFinalPayload, bool) {
|
|
if cmd == nil {
|
|
return ContractFinalPayload{}, false
|
|
}
|
|
raw, ok := contractFinalByCommand.Load(cmd)
|
|
if !ok {
|
|
return ContractFinalPayload{}, false
|
|
}
|
|
p, ok := raw.(*ContractFinalPayload)
|
|
if !ok || p == nil {
|
|
return ContractFinalPayload{}, false
|
|
}
|
|
return *p, true
|
|
}
|
|
|
|
// HasRuntimeContractFinal reports whether the leaf has a registered final overlay.
|
|
func HasRuntimeContractFinal(cmd *cobra.Command) bool {
|
|
if cmd == nil {
|
|
return false
|
|
}
|
|
_, ok := contractFinalByCommand.Load(cmd)
|
|
return ok
|
|
}
|
|
|
|
// ClearRuntimeContractFinalForTest removes a registration (tests only).
|
|
func ClearRuntimeContractFinalForTest(cmd *cobra.Command) {
|
|
if cmd != nil {
|
|
contractFinalByCommand.Delete(cmd)
|
|
}
|
|
}
|