A generic envelope schema feature that lets a single CLI command orchestrate
an ordered sequence of MCP tool calls plus optional HTTP-download sinks,
declared entirely in the envelope JSON. The motivating use case is the
"submit-job + poll-status + download-result" pattern (e.g. sheet export),
which previously required hardcoded helper commands per product.
## Schema additions
- `CLIToolOverride.Pipeline []PipelineStep` — when non-empty, dispatch
ignores the parent map key (no single "primary tool") and walks the
steps in order. CLI surface (CLIName / Group / Flags) still applies.
- `PipelineStep` struct — supports two step types:
- `type:"call"` (default) invokes Tool with templated Args. Optional
PollUntilField/Value turn it into a polling loop with configurable
PollIntervalSec / PollTimeoutSec.
- `type:"download"` resolves DownloadURLField, fetches via HTTP GET,
and writes the body to the path supplied by OutputFlag's value
(with directory-path filename inference).
- `CLIFlagOverride.PipelineLocal bool` — marks a flag as CLI-side only;
CollectBindings skips it so the value never reaches MCP params, but
the pipeline executor reads it via extractFlagValuesByAlias.
## Template language
Two prefixes supported in PipelineStep.Args / DownloadURLField:
$flag.<name> — value of the user's CLI flag whose alias is <name>
$step.<idx>.<dotPath> — field from a prior step's response (idx 0-based)
literal — passed through
dotPath walks nested map[string]any so "$step.1.content.downloadUrl"
resolves through wrapped MCP envelopes correctly.
## Stdout contract
The download step always emits machine-parseable plain-text lines
("jobId: <id>\\n", "downloadUrl: <url>\\n") in addition to the standard
JSON output, so shell pipelines and regex-based test suites can extract
key values without parsing JSON. Structured callers continue to consume
the output.WriteCommandPayload JSON envelope.
## Why this is schema enhancement, not product hardcode
- The executor is product-agnostic: any envelope can declare a Pipeline
and benefit (sheet export today; doc/drive/aitable async patterns
tomorrow).
- The template language is the only product-coupling, and it lives in
the envelope JSON — not in Go code.
- No sheet/wiki/aitable-specific code in dingtalk-workspace-cli.
Files: 1 new + 3 modified (~250 LOC of executor + ~30 LOC of schema
plumbing). Existing tests pass; new pipeline tests TBA in a follow-up
once the schema fields are in upstream.