Cross-cutting findings surfaced by the branch-completion review.
Perf bug:
- Factory.Client closure was not memoized. Factory.ResolveKB internally
calls f.Client() to resolve --kb name → id, then the command's RunE
calls f.Client() again. Two SDK clients, two keyring reads, two
AuthRetryTransport allocations per name-resolved invocation, with
*independent* token state (a refresh in one was invisible to the
other). Switched to sync.Once like Secrets already does.
Silent bug bait:
- cmdutil.NormalizeHost docstring claimed CodeInputMissingFlag for the
empty case; code returned CodeInputInvalidArgument. Aligned doc to
code (present-but-empty is a bad value, not a missing flag).
Agent contract gaps:
- Five user-facing subcommands lacked SetAgentHelp: auth login /
logout / list / status and chat. Added concise strings with error-
code call-outs so agents can branch without parsing human strings.
Helper extraction (≥3 callers):
- text.KnowledgeDisplayName(fileName, title, id) — byte-identical
formatter that was in both cmd/doc/list.go and cmd/search/docs.go.
Takes fields directly so internal/text stays SDK-free.
- cmdutil.WrapHTTP(cause, fmt, args...) *Error — replaces the
`Wrapf(ClassifyHTTPError(err), err, ...)` pattern across 24 SDK
call sites. Sed-driven migration; off-pattern shapes in chat.go
(used streamErr) and cmdutil/kb.go (in-package) hand-edited.
Contract test gains a comment update: post-migration the dominant
pattern is WrapHTTP which the AST scanner skips entirely (only
NewError/Wrapf selectors inspected); ClassifyHTTPErrorOutputs()
bridge still covers the dynamic codes those paths can yield.
UX consistency:
- cmd/doc/list.go --page-size help now reads "Items per page
(1..1000)" matching cmd/session/list.go. The bounds validation
already enforced 1..1000; the help text was the last drift.
Comment-discipline sweep:
- Deleted the WHAT-only "*Options captures `weknora ...` flag state"
docstring across 23 files (context, kb, auth, doc, session, search,
chat, doctor, link). Where the line carried a real WHY clause
(kb/delete, doc/delete, session/delete, kb/edit), kept the WHY and
dropped only the leading WHAT phrase.
- Stripped third-party project-name attribution from inline comments
and one user-visible flag-help string across ~40 files in cli/cmd
and cli/internal (plus 4 test-file comments). Removed phrases like
"Mirrors `gh X`", "borrowed from lark-cli", "kubectl-style",
"gcloud `--project`", "Stripe pattern", and the embedded GitHub
URLs pointing at those projects. Behavioral descriptions and the
WHY behind each comment are preserved; only the upstream-name
attribution is gone. Inspiration / north-star references belong in
cli/AGENTS.md (the design doc) and commit messages, not scattered
through every file.
Triggered by an audit round that surfaced several false / fragile
parity claims (e.g. "Mirrors `gh repo edit`" — gh repo edit has no
--name flag; "matches gcloud `--project` id-or-name" — gcloud's
--project accepts ID only). Rather than fix them one by one, the
whole category of in-comment external-project references was
stripped uniformly.
Roadmap items 3-5 (session) and 3-6/7/8 (kb manage).
cli/cmd/session/ (new package; sessioncmd to avoid shadowing stdlib):
- session list: paginated table (ID/TITLE/UPDATED). --page / --page-size
with 1..1000 validation. _meta.has_more from page*size < total.
- session view <id>: prints metadata; non-empty fields only. Server
timestamps arrive as strings; parsed best-effort as RFC3339.
- session delete <id>: high-risk-write; exit-10 confirmation in non-
TTY/--json paths; --dry-run emits envelope.risk + dry_run:true.
cli/cmd/kb (extended):
- kb edit <id> [--name N] [--description D]: at least one flag required;
*string options so unset fields stay unset in the PUT body. SDK
UpdateKnowledgeBaseRequest has no embedding_model field, so the
roadmap's --embedding-model dropped.
- kb pin <id> / kb unpin <id>: direct parity with gh issue pin /
gh issue unpin (verified against gh manual). Idempotent: GetKnowledgeBase
reads IsPinned, TogglePinKnowledgeBase fires only on state change.
SDK KnowledgeBase struct gained the IsPinned field (server already
returned it; SDK just hadn't modeled it — non-breaking additive).
- kb empty <id>: high-risk-write; exit-10 confirmation;
--dry-run. Returns deleted_count from the async clear response.
weknora-specific operation; no mainstream parallel.
Golden envelopes for kb_list and kb_view updated to include the new
is_pinned field — strict-additive change.
Cleanups surfaced by the post-commit reviewer round:
- ConfirmPrompter promoted to cli/internal/testutil/ (4-copy threshold
reached: context/remove, kb/delete, kb/empty, session/delete).
kb/delete_test.go's pre-existing local copy left untouched per the
upstream-respect convention.
- kb pin/unpin idempotent no-op path no longer emits a write-class
envelope. Added _meta.warnings "already {un}pinned — no server
call made" and dropped the risk classification on the no-op branch.
- doc list --page-size was unbounded while session list enforces
1..1000. Same validation added to doc list.
18 + 18 unit tests; e2e exit codes verified.
Roadmap: 3-5, 3-6, 3-7, 3-8.