Unify the --kb resolver (accepts name or UUID) across kb/doc/chunk/session/
search/chat/link; `agent create` attaches knowledge bases via --attach-kb
(no longer --kb). Rename the MCP tool agent_invoke → session_ask and drop dead
MCP error codes. Add `session stop` (StopSession), completing the
start / continue-stream / stop triad.
Across these commands, bring the agent contract up to par: --dry-run previews
on mutations (incl. kb pin/unpin, session stop), agent-help blobs on the
read/health surface, accurate destructive-confirmation verbs, and search
has_more truncation signalling so an agent can tell its results were capped.
Upstream commit 5c0243cd ("feat: Support filtering chunks by multiple
chunk_type params") extended client.Client.ListKnowledgeChunks with a
trailing `chunkTypes ...string` variadic. The two narrow service
interfaces in cli/ — ListService in cli/cmd/chunk/list.go and
chunkListService in cli/internal/mcp/tools.go — plus the two fake
implementations in their *_test.go siblings, are updated to match so
*client.Client continues to satisfy them via duck typing.
No CLI flag surfaced yet; both call sites pass no filter and behavior
is unchanged. Exposing `--chunk-type` as a flag on `weknora chunk list`
and as an input field on the MCP `chunk_list` tool is a candidate for a
follow-up commit, per the broader SDK-required → CLI-required alignment
discussion.
Pre-flight: go build ./... clean; go test -count=1 ./... 28/28 packages
pass; go vet ./... clean; gofmt -l . empty.
Sweep every CLI output path through the v0.7 envelope contract.
FormatOptions.Emit signature changes to (w, data, meta *output.Meta)
so list commands surface meta.count / has_more in the wire envelope.
TTY indent decision plumbed via FormatOptions.TTY (set by
ResolveDefault). --format and --jq promoted to persistent root flags
so unknown-subcommand paths still reach the typed-envelope guard
(per-command registration would have rejected --format on unknown
commands as cobra-prose exit 2). WEKNORA_FORMAT env-var fallback
honored before TTY-resolved default. AddFormatFlag retained for the
per-command --jq field-hint Long-text addendum.
~55 production Emit call sites swept across cli/cmd/**: list paths
populate meta.count; mutation paths pass nil meta; envelope.profile
threaded via globalProfile. Existing JSON-shape tests migrated to
decode the envelope wrapper.
Multi-target batch operations get a unified shape via new helpers:
- output.BatchItem + output.WriteBatchEnvelope (§4.5 per-item ok
pattern; data:[{id, ok, result?|error?}], meta:{count, successes*,
failures*}; Successes/Failures *int so explicit zero survives
omitempty in all-fail case).
- cmdutil.RunBatch + cmdutil.EmitBatch + cmdutil.DeletedAtNow +
cmdutil.ClassifyContextErr collapse the three previously-duplicated
multi-delete pipelines (doc / chunk / session) into one call site
pattern. doc upload --recursive uses the same helpers with a per-
file resultFn. Summary error sets Silent:true so the stderr
envelope path doesn't duplicate the stdout batch detail (exit 1
preserved via Code → ExitCode).
ConfirmDestructive / ConfirmDestructiveBatch extended with action +
retryCmd parameters. Every destructive command (kb delete, kb edit,
doc delete, doc delete --all, agent delete, agent edit, session
delete, chunk delete, auth logout, api -X DELETE) now attaches
error.risk.{level:"destructive", action:"<noun.verb>"} +
error.retry_command on the exit-10 envelope. kb edit / agent edit
also gain the destructive guard wiring (CHANGELOG listed them as
gated but they were silently executing without -y).
MCP tool handlers' 31 error paths return CallToolResult with
IsError + Content text fallback + StructuredContent (envelope.error
shape via cmdutil.ErrorToDetail). Handler Out type changed from
typed *sdk.X to any so the go-sdk auto-marshal doesn't overwrite
StructuredContent with a zero-struct on error returns. Success path
manually populates CallToolResult.StructuredContent via successResult
helper.
weknora api cleanup:
- -d/--data flag removed; body via --input <file> or --input -
(stdin) only. Aligns with gh / curl convention.
- HTTP method whitelist removed; any non-empty method accepted.
- HTTP Retry-After header → cmdutil.Error.RetryAfterSeconds →
envelope.error.retry_after_seconds.
- runAPIPaginated raw-passthrough fallback now wraps response in
envelope so --paginate never emits bare JSON to stdout.
Test sweep: ~60 cmd/** tests migrated to decode envelope shape.
9 wire-contract goldens updated under cli/acceptance/testdata/wire/.
Spec: docs/superpowers/specs/2026-05-20-weknora-cli-v0.7-design.md §4 / §5
Batch-write surface and pagination consistency:
* weknora doc delete <doc-id> [<doc-id>...] — positional multi-id, default
keep-going on failure. Single -y confirms entire batch.
* weknora session delete <session-id> [<session-id>...] — same shape.
* weknora chunk delete <chunk-id> [<chunk-id>...] --doc <doc-id> — multi-id
with shared --doc parent.
* Multi-id partial-failure rolls up as operation.failed (exit 1), not
server.error (exit 7) — failures are operation outcomes, not transient
transport issues, and the retry-with-backoff hint for server.* would
mislead callers.
* weknora api <path> --paginate — auto-walks offset pagination and merges
pages into a single {data, total} JSON response.
* Paginate truncation fix across 6 list/follower call sites.
* All doc / search / chunk / session / kb list commands migrated to
FormatOptions API.
Multi-id RunE only emits the {ok, failed} envelope when the operation
actually ran — pre-flight failures (e.g. confirmation_required) leave
stdout empty per the wire contract.
doc upload's missing-positional-or-flag check is wrapped as FlagError so
the exit code (2) matches the convention used by other commands that
require a positional argument directly.
Code-reuse polish (post-implementation review pass):
- Extract text.OneLine(maxWidth, s) helper combining preview-row
normalization (newline/CR/tab → space) with text.Truncate's
UTF-8-safe truncation. Replaces agent/view.go truncate1Line (ASCII
'...' + byte-slice CJK-unsafe) and chunk/list.go singleLine.
- Lift cmdutil.OpenInput(path) for the '-' = stdin / else os.Open
pattern shared across agent create/edit and the api command.
Replaces agent/create.go's private openInput.
- Strip inline doc-spec parentheticals from source comments — those
belong in commit messages and project docs, not in source where
they rot.
Pre-PR audit fixes:
- doc upload: reject `--metadata` paired with `--from-url` as
input.invalid_argument up-front (the URL-ingest request type has
no metadata field server-side, so the pair would otherwise silently
drop). Long help and CHANGELOG updated to call out the asymmetry.
- doc upload (file path): map sdk.ErrDuplicateFile sentinel to
resource.already_exists. The sentinel arrives with no "HTTP error <n>:"
prefix because the SDK short-circuits on file-hash before reading the
HTTP status, so the previous WrapHTTP fall-through misclassified it
as network.error with a misleading "check base URL reachability" hint.
The --from-url branch already handled ErrDuplicateURL this way; this
closes the asymmetry. Caught by e2e re-upload of an already-ingested
file; regression test added.
- README exit-10 enumeration adds `agent delete` and `chunk delete`
(these were missing alongside the v0.5 destructive verbs they were
meant to gate).
Docs sync:
- cli/README.md: command tree now includes the chunk subtree; adds
agent / chunk lines to the 5-minute quickstart; adds a "Contributing
/ Reporting issues" section pointing at the repo's SECURITY.md and
AGENTS.md; drops third-party CLI parallels from the surface
description.
- cli/AGENTS.md: "Command surface design SOP" gains the
flag-vs-escape-hatch step. "CRUD command flag canon" renamed to the
hard-required-flags pattern with the contrast (TTY-prompts-fill)
defined inline rather than via opaque shorthand.
- cli/CHANGELOG.md: search docs case-sensitivity shift promoted to its
own #### Breaking changes subsection. MCP doc_list filter count
corrected from 5 to 6. Drops the bogus go.mod yaml.v3 entry (yaml.v3
was already a dependency on main; v0.5 added zero go.mod lines).
Replaces internal-Go identifiers (fuzzyTime, NoOptDefVal) with
user-language and drops the § section-symbol jargon.
New subtree (chunk list / view / delete) exposes RAG retrieval
debugging primitives with SDK-grounded field set (23 Chunk fields).
Pagination follows v0.4 canon: --limit / --page-size (1..1000) /
--all-pages.
- chunk list --doc <id>: enumerate by ChunkIndex (separate from
search chunks which is hybrid retrieval; Long help documents the
distinction)
- chunk view <id>: scope-less render via /chunks/by-id route; full
content verbatim
- chunk delete <id> --doc <id>: scope-flag + scope-id; L-13
destructive; 404 NOT idempotent; resource.not_found /
auth.forbidden / input.confirmation_required typed exit codes
documented in Long help
MCP server gains chunk_list as 10th curated tool. Schema deliberately
exposes only doc_id + limit (no pagination workflow on MCP); response
includes truncated_at_limit flag when total > limit.
cli/AGENTS.md MCP curation rationale rewritten: curated read-only is
a deliberate product call because the server side does not yet
enforce per-token scope. When server scope ships, mutation tools can
land in the MCP surface.
Shared helper cli/internal/text/timeago_string.go (FuzzyAgoStr)
extracted from session list during the C2 quality-review pass.