Skip to content

feat(vscode): add workflow lanes, provider management and skill commands - #22

Merged
elkaix merged 36 commits into
mainfrom
feat/vscode-workflow-lanes
Aug 5, 2026
Merged

feat(vscode): add workflow lanes, provider management and skill commands#22
elkaix merged 36 commits into
mainfrom
feat/vscode-workflow-lanes

Conversation

@elkaix

@elkaix elkaix commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Related Issue

No issue — the problems were found while using the extension. They are described below.

Problem

Several unrelated defects in the VS Code extension and one naming problem in the engine:

  • Workflow lanes attributed every DynamicWorkflow step to the parent agent, so a lane's progress bar tracked the wrong work, and a finished lane still rendered a gap because its bar was drawn relative to the busiest agent.
  • /yolo did not survive re-attach. The global yoloMode setting overrode the session's own mode every time a session attached or resumed, the code meant to persist the mode called session.updateMetadata, which does not exist on the SDK, and the extension carried a legacy two-flag (yolo + afk) model in front of the engine's three-value PermissionMode.
  • Skills never appeared in the slash menu. getSlashCommands called harness.listWorkspaceSkills, which is not a method on the harness; the optional call swallowed it and returned an empty list. Commands were also fetched once, before any session existed, and built-in skills were only routable under a skill: prefix.
  • The slash menu ignored what was typed. A query was matched against command descriptions as a subsequence, so the letters of research were found scattered through nearly every description and the list came back unfiltered — typing appeared only to move a highlight that never left the first row.
  • A managed provider was reported as broken. A provider that authenticates over OAuth is required by the config schema to carry no apiKey, but the providers list flagged that as "No key configured" in red.
  • The managed provider was named after this product. It authenticates against auth.kimi.com and serves models from api.kimi.com, yet registered itself as managed:pythinker-code and installed pythinker-code/* model aliases. In a client that talks to several providers that reads as a first-party service rather than the one it is.
  • Ten test assertions were failing across six TUI suites for a single reason (see below).

What changed

Extension

  • Lanes attribute steps to their own subagent, and a finished lane always renders full.
  • Permission handling moved onto the engine's PermissionMode (manual / auto / yolo). The legacy flag-pair shim is deleted. A stored session mode is now authoritative; the global setting only seeds a session that has never recorded one, and applies to open sessions on an explicit change. The sensitive-file and git-control-path policies deliberately keep running ahead of yolo-approve.
  • Skills come from session.listSkills() and are re-broadcast when a session is created or resumed. Built-in skills keep their bare name. The catalog-to-slash-command projection moved into the SDK so the CLI and the extension share one implementation.
  • Slash matching is ranked and limited to the command name — a description is prose, and matching it surfaced commands unrelated to the query. It stays forgiving about skipped letters and dropped separators, and the selection resets when the query changes.
  • New Providers modal for adding and removing providers, backed by the same config.toml the CLI reads. The import routine it shares with the CLI moved into the SDK so both preserve existing defaults identically.
  • Reverted the periwinkle --primary to the neutral token and introduced a separate --brand accent, so accent surfaces no longer re-tint body chrome.

Engine

  • The managed provider is now managed:kimi-code, with kimi-code/* aliases and credentials under oauth/kimi-code. Its name also stops being redeclared as a bare literal in four places and comes from the single exported constant. This is a breaking change for an existing config: previous entries are not rewritten, so signing in again provisions the provider under its current name.

Tests

  • The SGR pattern used to strip colour from rendered frames matched the [0;…m tail but not the ESC byte introducing it, leaving a stray control character between styled spans. Any assertion spanning two spans could never match — Search: cwd and Kimi K2 Kimi ← current each had an invisible escape in the middle. Fixing the pattern clears all ten failures.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

Summary by CodeRabbit

  • New Features

    • Added richer subagent/workflow visualization with per-lane progress, statuses, durations, and result summaries.
    • Added provider management for viewing, adding, configuring, and removing model providers.
    • Added persistent permission modes, workspace skill discovery, improved slash-command matching and insertion, and extension release tooling.
  • Bug Fixes

    • Fixed subagent identity, status routing, replay handling, and batch-abort reporting.
    • Improved initial TUI rendering and publishing retries.
  • Style

    • Updated branding, download badges, interface colors, and welcome-logo animation.
  • Changes

    • Renamed the managed provider experience to Kimi Code.

Every subagent in a DynamicWorkflow batch shares one parentToolCallId, so the
webview funnelled all of them into a single flat subagent_steps array and
targeted the array tail as the "current step". Two agents streaming at once
wrote text, thinking, and tool calls into each other's steps.

Steps now carry the emitting agent's identity and are targeted per agent. The
subagent lifecycle events the adapter already received but discarded
(started/completed/failed/suspended) are mapped to a SubagentStatus event, which
gives each lane a status, a duration, and a result or error.

On top of that attribution, DynamicWorkflow renders as per-agent lanes instead
of an escaped-JSON argument dump: live activity, a step count, a status, and a
progress bar filled relative to the busiest lane. There is no per-agent step
total to divide by, so an absolute percentage would be fabricated; the caption
names the denominator.

Lane derivation lives in lib/workflow-lanes.ts rather than the store module, and
the pure tool-argument helpers move to lib/tool-args.ts. Tool rendering is
mutually recursive, so WorkflowCard receives its step-item renderer as a prop
rather than importing it and closing an import cycle.

The new test file is excluded from the extension tsconfig, which is where the
webview-side tests are kept out of the extension program.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds subagent lifecycle events and workflow rendering, provider management, permission-mode persistence, asynchronous skill commands, publishing automation, TUI updates, and a repository-wide migration from Pythinker Code identifiers to Kimi Code identifiers.

Changes

Subagent workflow lifecycle

Layer / File(s) Summary
Runtime lifecycle and agent-scoped state
apps/vscode/shared/legacy-sdk.ts, apps/vscode/src/runtime/*adapter.ts, apps/vscode/webview-ui/src/stores/*, apps/vscode/webview-ui/src/lib/*
Subagent events now include identity, lifecycle status, timestamps, errors, and result summaries. The webview scopes steps by agent and derives ordered workflow lanes.
Workflow rendering and validation
apps/vscode/webview-ui/src/components/WorkflowCard.tsx, apps/vscode/webview-ui/src/components/ToolRenderers.tsx, apps/vscode/test/event-handlers.test.ts
Dynamic workflows render lane progress, status, duration, errors, and nested steps. Tests cover interleaved output, lifecycle transitions, batch failures, ordering, and status-only lanes.

VS Code platform controls

Layer / File(s) Summary
Provider management
apps/vscode/shared/bridge.ts, apps/vscode/shared/types.ts, apps/vscode/src/handlers/provider.handler.ts, apps/vscode/webview-ui/src/services/bridge.ts, apps/vscode/webview-ui/src/components/ProvidersModal.tsx
The bridge and handlers support provider listing, catalog retrieval, catalog import, and provider removal. The webview displays configured providers, models, credential sources, import controls, and removal confirmation.
Permission modes and skill commands
apps/vscode/src/runtime/permission-mode.ts, apps/vscode/src/runtime/*runtime.ts, apps/vscode/src/handlers/slash-command.ts, apps/vscode/src/handlers/config.handler.ts, packages/agent-core/src/skill/*, packages/node-sdk/src/skill-commands.ts
Session permission modes replace legacy approval flags. Slash commands resolve active-session or workspace skills asynchronously. /yolo, /auto, and /afk apply explicit permission modes.
Input, bridge, and publishing integration
apps/vscode/src/bridge-handler.ts, apps/vscode/webview-ui/src/App.tsx, apps/vscode/webview-ui/src/components/inputarea/*, apps/vscode/scripts/*
Slash-command updates are broadcast to the webview. Slash selection inserts text into the active token. Publishing adds retries, duplicate detection, authentication modes, multi-target handling, and an extension release script.

Kimi Code provider migration

Layer / File(s) Summary
OAuth and managed-provider APIs
packages/oauth/src/*, packages/node-sdk/src/auth.ts, packages/agent-core/src/services/auth/*
Managed provider constants, types, OAuth keys, authentication helpers, model APIs, toolkit defaults, usage URLs, and feedback helpers use Kimi Code names.
Catalog import and CLI integration
packages/node-sdk/src/catalog.ts, packages/node-sdk/test/catalog.test.ts, apps/pythinker-code/src/cli/sub/provider.ts
Catalog imports validate credentials, connection support, models, and defaults. The CLI delegates provider persistence to importCatalogProvider.
Repository-wide validation
packages/*/test/*, apps/pythinker-code/test/*, packages/server/test/*, .changeset/*
Fixtures, assertions, release metadata, OAuth keys, model aliases, and provider identifiers use the Kimi Code namespace.

TUI and presentation updates

Layer / File(s) Summary
Logo animation and startup rendering
apps/pythinker-code/src/tui/components/chrome/*, apps/pythinker-code/src/tui/pythinker-tui.ts, apps/pythinker-code/src/tui/tui-state.ts
The welcome logo adds antenna animation. TUI startup gates rendering until the event loop starts and resets fixed-layout terminal positioning.
Downloads and visual styling
README.md, apps/site/src/*, apps/vscode/webview-ui/src/styles/*
Download badges use blue styling. The site adds a linked npm badge. VS Code brand and control colors are updated.

Estimated code review effort: 5 (Critical) | ~90 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Runtime as EventAdapter
  participant Store as event-handlers
  participant Lanes as workflow-lanes
  participant UI as WorkflowCard
  Runtime->>Store: dispatch SubagentStatus and SubagentEvent
  Store->>Lanes: provide agent-scoped steps and statuses
  Lanes->>UI: provide ordered workflow lanes
  UI-->>UI: render progress, status, errors, and nested steps
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title uses the feat prefix, stays within 72 characters, uses imperative wording, and accurately summarizes the main changes.
Description check ✅ Passed The description includes all required sections, explains the problems and changes, and marks the checklist items as complete.

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Aug 5, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@pythoughts/pythinker-code@84e0334
npx https://pkg.pr.new/@pythoughts/pythinker-code@84e0334

commit: 84e0334

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
apps/vscode/test/event-adapter.test.ts (1)

477-478: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove conditional expected-payload construction from this test.

Put the expected status-specific fields in each it.each row. Then compare the supplied complete payload directly. This removes both Oxlint warnings and makes each test case explicit.

As per coding guidelines, use oxlint for linting.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/test/event-adapter.test.ts` around lines 477 - 478, Update the
test cases using it.each so every row supplies its complete expected payload,
including status-specific error or result_summary fields. Remove the conditional
expectedPayload construction and compare each supplied payload directly,
eliminating the related Oxlint warnings.

Sources: Coding guidelines, Linters/SAST tools

apps/vscode/webview-ui/src/components/WorkflowCard.tsx (1)

66-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add aria-expanded to the lane toggle.

The button controls a collapsible region at Lines 78-91. Without aria-expanded, assistive technology cannot report whether the lane is open or closed.

♿ Proposed fix
-      <button onClick={() => setExpanded(!expanded)} className="w-full flex items-center gap-2 py-1 hover:bg-muted/50 transition-colors text-left" disabled={lane.stepCount === 0}>
+      <button onClick={() => setExpanded(!expanded)} aria-expanded={expanded} className="w-full flex items-center gap-2 py-1 hover:bg-muted/50 transition-colors text-left" disabled={lane.stepCount === 0}>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/webview-ui/src/components/WorkflowCard.tsx` at line 66, Add
aria-expanded to the button in WorkflowCard’s lane toggle, binding it to the
expanded state so assistive technology receives the current open or closed
status. Keep the existing click handler and disabled behavior unchanged.
apps/vscode/test/event-handlers.test.ts (1)

27-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the imports above the vi.mock calls.

oxlint reports import(first) for Lines 30-32. Vitest hoists vi.mock above all imports, so placing the three import statements before the vi.mock calls keeps the mocks effective and clears the lint warnings.

♻️ Proposed import reordering
 import { beforeEach, describe, expect, it, vi } from "vitest";
+import { useChatStore } from "../webview-ui/src/stores/chat.store";
+import { deriveWorkflowLanes, maxLaneStepCount } from "../webview-ui/src/lib/workflow-lanes";
+import type { UIStepItem } from "../webview-ui/src/stores/chat.store";
 
 const boundary = vi.hoisted(() => ({
@@
 vi.mock("`@/components/ui/sonner`", () => ({
   toast: { error: boundary.toastError, warning: boundary.toastWarning },
 }));
-
-import { useChatStore } from "../webview-ui/src/stores/chat.store";
-import { deriveWorkflowLanes, maxLaneStepCount } from "../webview-ui/src/lib/workflow-lanes";
-import type { UIStepItem } from "../webview-ui/src/stores/chat.store";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/test/event-handlers.test.ts` around lines 27 - 33, Move the three
import statements for useChatStore, deriveWorkflowLanes/maxLaneStepCount, and
UIStepItem above the vi.mock call in event-handlers.test.ts so the file follows
the import(first) rule while still allowing Vitest to hoist the mock correctly.
Keep the existing vi.mock("`@/components/ui/sonner`", ...) setup unchanged and
only reorder the import block relative to the mock.

Source: Linters/SAST tools

apps/vscode/webview-ui/src/lib/tool-args.ts (1)

19-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Merge the three identical path cases.

ReadFile, WriteFile, and StrReplaceFile return the same expression. Use case fallthrough to remove the duplication.

♻️ Proposed consolidation
     case "ReadFile":
-      return (args.path as string)?.split("/").pop() || "file";
     case "WriteFile":
-      return (args.path as string)?.split("/").pop() || "file";
     case "StrReplaceFile":
       return (args.path as string)?.split("/").pop() || "file";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/webview-ui/src/lib/tool-args.ts` around lines 19 - 24, Merge the
ReadFile, WriteFile, and StrReplaceFile branches in the tool-argument switch by
using shared case fallthrough, keeping one copy of the existing path-expression
return.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/vscode/webview-ui/src/components/WorkflowCard.tsx`:
- Around line 70-73: Update the step-count label in WorkflowCard so the text
rendered from lane.stepCount uses the singular form for 1 and the plural form
otherwise, matching the existing agent pluralization pattern elsewhere in the
same component. Keep the queued and duration rendering unchanged, and adjust
only the step-count string logic in WorkflowCard.

In `@apps/vscode/webview-ui/src/lib/tool-args.ts`:
- Around line 3-12: Update parseArgs in tool-args.ts to validate the result of
JSON.parse before returning it, since scalar JSON like null or 12 does not
satisfy the Record<string, unknown> contract. Keep the existing empty-input and
parse-failure fallback behavior, but reject any non-object or null parse result
and return the raw-args fallback instead so WorkflowCard.tsx can safely read
parseArgs(call.arguments).description without a TypeError.

In `@apps/vscode/webview-ui/src/stores/event-handlers.ts`:
- Around line 284-295: Gate the subagent-status failure sweep in
apps/vscode/webview-ui/src/stores/event-handlers.ts (lines 284-295) on
result.return_value.is_error alongside toolItem?.subagent_status, preserving the
existing spawned/running updates only for aborted parent results. Add a
companion non-error test in apps/vscode/test/event-handlers.test.ts (lines
188-222) asserting spawned and running lanes remain unchanged when is_error is
false.

---

Nitpick comments:
In `@apps/vscode/test/event-adapter.test.ts`:
- Around line 477-478: Update the test cases using it.each so every row supplies
its complete expected payload, including status-specific error or result_summary
fields. Remove the conditional expectedPayload construction and compare each
supplied payload directly, eliminating the related Oxlint warnings.

In `@apps/vscode/test/event-handlers.test.ts`:
- Around line 27-33: Move the three import statements for useChatStore,
deriveWorkflowLanes/maxLaneStepCount, and UIStepItem above the vi.mock call in
event-handlers.test.ts so the file follows the import(first) rule while still
allowing Vitest to hoist the mock correctly. Keep the existing
vi.mock("`@/components/ui/sonner`", ...) setup unchanged and only reorder the
import block relative to the mock.

In `@apps/vscode/webview-ui/src/components/WorkflowCard.tsx`:
- Line 66: Add aria-expanded to the button in WorkflowCard’s lane toggle,
binding it to the expanded state so assistive technology receives the current
open or closed status. Keep the existing click handler and disabled behavior
unchanged.

In `@apps/vscode/webview-ui/src/lib/tool-args.ts`:
- Around line 19-24: Merge the ReadFile, WriteFile, and StrReplaceFile branches
in the tool-argument switch by using shared case fallthrough, keeping one copy
of the existing path-expression return.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b4d666f4-d986-483b-8895-45f3f93cfd57

📥 Commits

Reviewing files that changed from the base of the PR and between 070d902 and bd1ba9b.

📒 Files selected for processing (16)
  • apps/vscode/shared/legacy-sdk.ts
  • apps/vscode/src/runtime/event-adapter.ts
  • apps/vscode/src/runtime/replay-adapter.ts
  • apps/vscode/test/event-adapter.test.ts
  • apps/vscode/test/event-handlers.test.ts
  • apps/vscode/test/replay-adapter.test.ts
  • apps/vscode/test/replay-resume.integration.test.ts
  • apps/vscode/tsconfig.json
  • apps/vscode/webview-ui/src/components/ChatMessage.tsx
  • apps/vscode/webview-ui/src/components/ToolRenderers.tsx
  • apps/vscode/webview-ui/src/components/WorkflowCard.tsx
  • apps/vscode/webview-ui/src/lib/tool-args.ts
  • apps/vscode/webview-ui/src/lib/workflow-lanes.ts
  • apps/vscode/webview-ui/src/stores/chat.store.ts
  • apps/vscode/webview-ui/src/stores/event-handlers.ts
  • apps/vscode/webview-ui/tsconfig.json

Comment thread apps/vscode/webview-ui/src/components/WorkflowCard.tsx
Comment thread apps/vscode/webview-ui/src/lib/tool-args.ts
Comment thread apps/vscode/webview-ui/src/stores/event-handlers.ts
elkaix added 2 commits August 5, 2026 11:23
Surface live monthly npm downloads for @pythoughts/pythinker-code in the
hero, above the install command. Unify the badge accent across the site
and README on the brand blue (#2b89ff).
Pluralize the lane step count, add aria-expanded to the lane toggle,
guard parseArgs against non-object JSON.parse results, merge duplicate
tool-label cases, and gate the lane-failure sweep on the parent
ToolResult's is_error flag so a successful batch result no longer
marks still-running lanes as failed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/vscode/test/event-handlers.test.ts`:
- Around line 223-243: Update the success-path test around workflowToolItem and
processEvent so it asserts the parent tool item stores the successful
ToolResult, proving the event was handled. Add a second agent that remains in
spawned status, then assert both agents retain their expected statuses and have
undefined endedAt after the successful result.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 79a959f8-dbfa-400a-8e1e-60fb7880f3b9

📥 Commits

Reviewing files that changed from the base of the PR and between bd1ba9b and 653612e.

📒 Files selected for processing (7)
  • README.md
  • apps/site/src/App.vue
  • apps/site/src/components/LegacyDownloadsPopup.vue
  • apps/vscode/test/event-handlers.test.ts
  • apps/vscode/webview-ui/src/components/WorkflowCard.tsx
  • apps/vscode/webview-ui/src/lib/tool-args.ts
  • apps/vscode/webview-ui/src/stores/event-handlers.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/vscode/webview-ui/src/lib/tool-args.ts
  • apps/vscode/webview-ui/src/stores/event-handlers.ts
  • apps/vscode/webview-ui/src/components/WorkflowCard.tsx

Comment thread apps/vscode/test/event-handlers.test.ts
elkaix added 11 commits August 5, 2026 11:31
Assert the successful ToolResult actually lands on the tool item, and
cover a still-spawned lane alongside the running one so the test can
fail if the is_error gate regresses.
The periwinkle that #21 wrote into --primary and --muted-foreground tinted
every neutral surface, so both tokens go back to their original oklch values.
The accent it was compensating for now lives in its own --brand token, applied
only where an accent is actually wanted: inline code in Markdown, and the
DynamicWorkflow lane bars and running status dot, which were invisible against
--muted once --primary went back to a near-black neutral.

The scroll-to-bottom button and the effort toggle return to their blue accents
for the same reason.

Also:
- a finished workflow lane renders a full bar. The bar is scaled to the busiest
  agent, so a lane that completed in fewer steps kept a permanent gap.
- the generation-speed pill in the thinking row no longer wraps "46.0" and
  "t/s" onto two lines, and uses tabular-nums so it stops resizing.
The extension modelled approval as a yolo/afk flag pair that it mapped onto the
engine's permission mode on every change. Three things were wrong with it:

- `withGlobalYoloMode` re-applied the `pythinker.yoloMode` setting on every
  attach and resume, so a `/yolo` a user typed was silently reverted the next
  time the session was opened.
- `applyLegacyApproval` never wrote the flags back, so nothing was persisted
  for a resume to restore in the first place.
- the two call sites that did try to persist called `session.updateMetadata`,
  which does not exist on the SDK session — the optional call quietly did
  nothing, and the tests passed because the fake implemented that same
  non-existent method.

The flag pair is gone. A session now carries the engine's `PermissionMode`
directly, persisted in session metadata (`vscode_permission_mode`, in the
`custom` bag the SDK actually reads back) whenever it changes. The setting
seeds sessions that have never recorded a mode and is applied to the live
sessions when the user changes it — it no longer overrides on attach.

`/yolo` and `/auto` now toggle between their mode and manual and accept
`on`/`off`, matching the CLI. The one behaviour change: `/auto off` returns to
manual instead of falling back to a remembered yolo, because a single mode has
no second flag to fall back to.

Sessions saved before this change have no stored mode and start from the
setting; their old `vscode_legacy_approval` metadata is ignored.
The extension already read the same ~/.pythinker-code/config.toml the CLI
does, so providers added in the terminal appeared in the model picker — but
there was no way to add one without leaving the editor.

A Providers modal, reached from the gear menu, lists what config.toml defines
and adds a provider from the models.dev catalog: search, paste a key or point
at an environment variable, optionally pick a default model. Removal goes
through the same harness call the CLI uses. Keys are written to config.toml
exactly as the CLI writes them, so a provider added here works in the terminal
too; the key itself never crosses into the Webview, which only learns whether
one is configured and where it comes from.

The import rules — dropping stale aliases before a re-import, and restoring
the previous defaults only while they still resolve against the refreshed
catalog — now live in one SDK routine that both the CLI and the extension
call, instead of only in the CLI.
Skills never appeared in the extension's command menu, so they could only be
run by typing the command by hand. The listing called
`harness.listWorkspaceSkills`, which does not exist on the SDK harness — the
optional call resolved to nothing every time, and the test that covered it
mocked the same non-existent method, so the suite agreed.

The catalog is session-scoped, so the list now comes from `session.listSkills`
as it does in the CLI, and the commands are re-broadcast when a session is
created or resumed — the Webview loads before a session exists, which is why a
one-shot fetch at startup could never carry them.

Built-in skills keep their bare command name, which the host parser previously
could not route: it only recognized the `skill:` prefix, so a built-in skill
invoked by name was sent to the model as plain text. The projection from a
skill catalog to slash commands now lives in the SDK, shared with the CLI
instead of duplicated per client.
A provider that authenticates over OAuth is required by the config schema to
carry no apiKey at all, so the providers list flagged it in red as "No key
configured" — a warning about a provider that is working. It now reads as
signed in, and each row shows the provider's API host rather than only its
wire type, which is what identifies a managed provider at a glance.
The menu matched a query against command descriptions as a loose subsequence,
so the letters of "research" were found scattered through almost every
description and the list came back unfiltered. Typing then looked like it did
nothing but move a highlight that never left the first row.

Matching is now ranked, with every way of matching a command name ordered ahead
of a description match, and it stays forgiving about skipped letters and
dropped separators. The selection also resets when the query changes, since a
reordered list left it pointing at an unrelated command.
The managed OAuth provider authenticates against auth.kimi.com and serves its
models from api.kimi.com, but it was registered as `managed:pythinker-code`.
In a client that talks to several providers that reads as a first-party
service rather than the one it actually is, and the models it installed
carried a `pythinker-code/` prefix that said the same thing.

It is now `managed:kimi-code`, with `kimi-code/*` model aliases and
credentials under `oauth/kimi-code`. The provider name also stops being
redeclared as a bare literal in four places and comes from the single
exported constant instead.

Existing configs are not rewritten: signing in again provisions the provider
under its current name.
A description is prose, so matching it pulled in commands unrelated to what
was typed: "/sk" reached "/yolo" because its description contains those
letters, and the selection sat on it. Matching is now limited to the command
name, which is what the user is typing and the only part they can predict.
The SGR pattern these tests used matched the `[0;…m` tail but not the ESC
that introduces it, so every stripped frame kept a stray control byte between
the styled spans. Assertions spanning two spans could then never match: a
label and its value are coloured separately, so `Search: cwd` and
`Kimi K2  Kimi ← current` had an invisible escape sitting in the middle.

Ten assertions across six suites were failing on this. The pattern now
includes the escape, and the two startup assertions that compared raw frames
strip them like the rest.
@elkaix elkaix changed the title fix(vscode): attribute DynamicWorkflow steps to their own subagent [skip changeset] fix(vscode): workflow lanes, permission modes, skills and provider management Aug 5, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/oauth/src/toolkit.ts (1)

261-273: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Sensitive Data Exposure (CWE-319): Cleartext Transmission of Sensitive Information

Exploitability: Moderate

Reachability path
● Entry
  packages/oauth/src/managed-usage.ts:199
  fetchManagedUsage
│
▼
● Sink
  packages/oauth/src/toolkit.ts

Reject non-HTTPS custom base URLs before authenticated requests.

managedUsageUrl and managedFeedbackUrl accept http: URLs, then send the bearer token to them. Apply HTTPS validation in a shared URL normalizer for usage, feedback, and model requests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/oauth/src/toolkit.ts` around lines 261 - 273, Update the shared URL
normalization used by managed usage, managed feedback, and model requests to
reject custom base URLs whose protocol is not HTTPS before obtaining or sending
an access token. Ensure managedUsageUrl and managedFeedbackUrl, along with the
model-request URL path, all use this validator while preserving existing default
URL behavior.
🟡 Minor comments (19)
apps/pythinker-code/test/cli/export.test.ts-83-83 (1)

83-83: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the managed provider key in the OAuth mock.

KIMI_CODE_PROVIDER_NAME must remain 'managed:kimi-code'. The current override makes telemetry request tokens with the stale 'pythinker-code' key and can hide provider-key migration failures. Preserve the actual export or set the mock to 'managed:kimi-code'.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/pythinker-code/test/cli/export.test.ts` at line 83, Update the
KIMI_CODE_PROVIDER_NAME override in the OAuth mock to use the managed provider
key "managed:kimi-code", or preserve the actual export so telemetry requests
exercise the migrated key; do not use the stale "pythinker-code" value.

Source: Path instructions

packages/node-sdk/test/catalog.test.ts-238-246 (1)

238-246: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use neutral provider fixture values.

Replace anthropic, Anthropic, api.anthropic.com, @ai-sdk/anthropic, and ANTHROPIC_API_KEY with neutral example values. Use identifiers such as example-provider, https://api.example.test, and EXAMPLE_PROVIDER_API_KEY.

As per coding guidelines, “Use neutral placeholders such as example.com, example.test, and YOUR_API_KEY instead of real internal identifiers in public text and test data.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/node-sdk/test/catalog.test.ts` around lines 238 - 246, Update the
fixture object in the catalog test to use neutral provider values: replace the
Anthropic provider name, API host, npm package, and environment variable with
example-provider equivalents such as example-provider, api.example.test,
`@ai-sdk/example-provider`, and EXAMPLE_PROVIDER_API_KEY, while preserving the
fixture structure.

Source: Coding guidelines

packages/oauth/src/toolkit.ts-398-398 (1)

398-398: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the Unicode flag to the regular expressions in packages/oauth/src/toolkit.ts:398 and packages/node-sdk/test/catalog.test.ts:301,313. Run pnpm lint:fix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/oauth/src/toolkit.ts` at line 398, Update the regular expressions in
packages/oauth/src/toolkit.ts at 398 and packages/node-sdk/test/catalog.test.ts
at 301 and 313 to include the Unicode flag, then run pnpm lint:fix.

Sources: Coding guidelines, Linters/SAST tools

packages/oauth/src/toolkit.ts-50-50 (1)

50-50: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove redundant undefined from the optional properties.

Use configAdapter?: ManagedKimiConfigAdapter<TConfig> and provision?: ManagedKimiCodeProvisionResult.

Proposed fix
-  readonly configAdapter?: ManagedKimiConfigAdapter<TConfig> | undefined;
+  readonly configAdapter?: ManagedKimiConfigAdapter<TConfig>;
@@
-  readonly provision?: ManagedKimiCodeProvisionResult | undefined;
+  readonly provision?: ManagedKimiCodeProvisionResult;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/oauth/src/toolkit.ts` at line 50, Remove the explicit undefined
union from the optional configAdapter and provision properties, leaving
configAdapter typed as ManagedKimiConfigAdapter<TConfig> and provision typed as
ManagedKimiCodeProvisionResult while preserving their optionality.

Source: Coding guidelines

packages/node-sdk/test/catalog.test.ts-199-199 (1)

199-199: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use type-safe fixtures instead of type assertions.

Normalize initial into a valid PythinkerConfig before assigning config, and remove the assertion on the rebuilt state. Type entry with satisfies Parameters<typeof importCatalogProvider>[1]['entry'] instead of as unknown as ... so contract changes remain visible to the test compiler.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/node-sdk/test/catalog.test.ts` at line 199, Update the catalog test
fixture setup around config and entry construction: normalize initial into a
valid PythinkerConfig before assigning config, remove the rebuilt-state type
assertion, and type entry using satisfies Parameters<typeof
importCatalogProvider>[1]['entry'] instead of an unknown-based assertion.

Source: Path instructions

packages/node-sdk/test/auth-facade.test.ts-540-543 (1)

540-543: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Replace the production-like endpoint in this fixture.

The logout path removes pythoughtsFetch by its service key. It does not require https://api.pythinker.com/coding/v1/fetch as test data. Use a neutral endpoint such as https://api.example.test/coding/v1/fetch.

As per coding guidelines, use neutral placeholders such as example.com, example.test, and YOUR_API_KEY instead of real internal identifiers in public text and test data.

Proposed fix
- base_url = "https://api.pythinker.com/coding/v1/fetch"
+ base_url = "https://api.example.test/coding/v1/fetch"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/node-sdk/test/auth-facade.test.ts` around lines 540 - 543, Update
the [services.pythoughts_fetch] fixture endpoint to a neutral placeholder such
as https://api.example.test/coding/v1/fetch, preserving the service key and
other fixture fields unchanged.

Source: Coding guidelines

packages/oauth/test/managed-kimi-code.test.ts-63-63 (1)

63-63: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the u flag to this regular expression.

Oxlint reports require-unicode-regexp for this pattern.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/oauth/test/managed-kimi-code.test.ts` at line 63, Update the regular
expression in the devKey assertion to include the Unicode (`u`) flag, while
preserving its existing matching pattern.

Source: Linters/SAST tools

packages/agent-core/src/services/modelCatalog/modelCatalogService.ts-163-166 (1)

163-166: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Complete the Kimi Code provider-label migration.

These changed paths use Kimi provider identifiers but still expose Pythinker labels. Update each path to use one canonical Kimi Code identity.

  • packages/agent-core/src/services/modelCatalog/modelCatalogService.ts#L163-L166: replace 'Pythinker Code' in provider_name with the canonical Kimi Code display name.
  • apps/pythinker-code/src/tui/commands/auth.ts#L57-L59: route to a Kimi-named handler and update the handler's stale Pythinker OAuth text to Kimi (OAuth).
  • packages/agent-core/src/services/auth/managedAuth.ts#L68-L73: update the provisioning failure text from Pythinker to Kimi terminology.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-core/src/services/modelCatalog/modelCatalogService.ts` around
lines 163 - 166, Complete the Kimi Code provider-label migration across all
three sites: in
packages/agent-core/src/services/modelCatalog/modelCatalogService.ts lines
163-166, use the canonical Kimi Code display name for provider_name; in
apps/pythinker-code/src/tui/commands/auth.ts lines 57-59, route to a Kimi-named
handler and change its stale Pythinker OAuth text to Kimi (OAuth); in
packages/agent-core/src/services/auth/managedAuth.ts lines 68-73, replace
Pythinker terminology in the provisioning failure message with Kimi terminology.
apps/pythinker-code/test/tui/pythinker-tui-startup.test.ts-45-48 (1)

45-48: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the u flag to both ANSI SGR regular expressions.

Change /g to /gu for ANSI_SGR and the inline expression at line 398.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/pythinker-code/test/tui/pythinker-tui-startup.test.ts` around lines 45 -
48, Add the Unicode flag to both ANSI SGR regular expressions: update the
ANSI_SGR constant and the inline expression near the referenced startup test
location from /g to /gu, without changing their matching behavior.

Source: Linters/SAST tools

apps/pythinker-code/test/tui/components/dialogs/model-selector.test.ts-9-9 (1)

9-9: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the Unicode flag to the changed regular expressions.

Oxlint reports require-unicode-regexp for these expressions. Add u to each regular-expression literal.

  • apps/pythinker-code/test/tui/components/dialogs/model-selector.test.ts#L9-L9: change the ANSI expression suffix from /g to /gu.
  • apps/pythinker-code/test/tui/components/dialogs/model-selector.test.ts#L98-L98: add u to the provider-output assertion.
  • apps/pythinker-code/test/cli/provider.test.ts#L536-L536: add u to the provider-list assertion.
  • apps/pythinker-code/test/tui/components/dialogs/provider-manager.test.ts#L104-L104: change the ANSI expression suffix from /g to /gu.
  • apps/pythinker-code/test/tui/components/messages/goal-markers.test.ts#L8-L8: change the ANSI expression suffix from /g to /gu.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/pythinker-code/test/tui/components/dialogs/model-selector.test.ts` at
line 9, Update every affected regular-expression literal to include the Unicode
flag: in apps/pythinker-code/test/tui/components/dialogs/model-selector.test.ts
lines 9-9 and 98-98, apps/pythinker-code/test/cli/provider.test.ts lines
536-536,
apps/pythinker-code/test/tui/components/dialogs/provider-manager.test.ts lines
104-104, and
apps/pythinker-code/test/tui/components/messages/goal-markers.test.ts lines 8-8.
Preserve the existing patterns and flags while adding u, including changing the
ANSI expressions from g to gu.

Source: Linters/SAST tools

apps/pythinker-code/test/cli/provider.test.ts-500-500 (1)

500-500: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use a neutral host in this test fixture.

Line 500 uses the production host https://api.pythinker.com/coding/v1. If this test does not validate that exact host, replace it with https://example.com/coding/v1 or another neutral fixture host.

As per coding guidelines, use neutral placeholders such as example.com, example.test, and YOUR_API_KEY instead of real internal identifiers in public text and test data.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/pythinker-code/test/cli/provider.test.ts` at line 500, Replace the
production URL assigned to baseUrl in the test fixture with a neutral host such
as https://example.com/coding/v1, preserving the existing path and test
behavior.

Source: Coding guidelines

apps/pythinker-code/test/cli/run-prompt.test.ts-121-121 (1)

121-121: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Use managed:kimi-code in both OAuth mocks.

KIMI_CODE_PROVIDER_NAME is managed:kimi-code, but both mocks override it with pythinker-code. Update both values and add an assertion against the production constant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/pythinker-code/test/cli/run-prompt.test.ts` at line 121, Update both
OAuth mocks in apps/pythinker-code/test/cli/run-prompt.test.ts:121-121 and
apps/pythinker-code/test/cli/run-shell.test.ts:114-114 to use managed:kimi-code
for KIMI_CODE_PROVIDER_NAME, and add assertions in the relevant tests comparing
the mock value with the production KIMI_CODE_PROVIDER_NAME constant.
packages/agent-core/test/config/configs.test.ts-62-72 (1)

62-72: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use a reserved host in the changed fixture.

Line 64 hard-codes https://api.pythinker.com/coding/v1 in test data. Replace it with https://api.example.test/coding/v1. This parser test does not need a product endpoint.

Proposed change
- base_url = "https://api.pythinker.com/coding/v1"
+ base_url = "https://api.example.test/coding/v1"

As per coding guidelines, use neutral placeholders such as example.com, example.test, and YOUR_API_KEY instead of real internal identifiers in public text and test data.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-core/test/config/configs.test.ts` around lines 62 - 72, Update
the changed fixture’s base_url in the providers."managed:kimi-code"
configuration to use the reserved placeholder host
https://api.example.test/coding/v1 instead of the product endpoint, leaving the
rest of the parser test data unchanged.

Source: Coding guidelines

packages/agent-core/test/services/oauth-service.test.ts-82-83 (1)

82-83: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the provider forwarded to facade.logout. Pass 'managed:kimi-code' to impl.logout and assert mock.logoutCalls[0].providerName. This prevents the result assertion from relying on the mock's fallback value.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-core/test/services/oauth-service.test.ts` around lines 82 -
83, Update the OAuth logout test around the mocked logout result to pass
providerName 'managed:kimi-code' explicitly to impl.logout, then assert
mock.logoutCalls[0].providerName matches it. Keep the existing result assertion
while ensuring it no longer depends on the mock's fallback provider value.

Source: Path instructions

apps/vscode/src/handlers/slash-command.ts-160-167 (1)

160-167: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

An unrecognized argument toggles the permission mode.

Line 162 maps only on and off to an explicit mode. Every other argument yields undefined, so line 171 toggles. A typo such as /yolo of therefore enables auto-approval of tool actions when the user intended to disable it. The emitted message reports the new mode, but the action has already been applied.

Reject an unknown argument instead of toggling.

🐛 Proposed fix
   const subcommand = args.trim().toLowerCase();
+  if (subcommand !== "" && subcommand !== "on" && subcommand !== "off") {
+    emit(`Usage: /${mode} [on|off]`);
+    return;
+  }
   const requested =
     subcommand === "on" ? mode : subcommand === "off" ? "manual" : undefined;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/src/handlers/slash-command.ts` around lines 160 - 167, Update the
slash-command argument handling around subcommand and requested so unrecognized
non-empty arguments are rejected rather than treated as a toggle. Preserve the
existing explicit on/off mode behavior and ensure invalid input returns before
applying or reporting any permission-mode change.
apps/vscode/test/pythinker-harness.integration.test.ts-432-439 (1)

432-439: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Strengthen the no-session fallback assertion.

Line 438 asserts only that no command name starts with skill:. That assertion also passes if the handler returns an empty array, so it does not prove the fallback returns the released commands. Assert the returned list equals SLASH_COMMANDS.

💚 Proposed fix
-    expect((commands as Array<{ name: string }>).some((command) => command.name.startsWith("skill:"))).toBe(false);
+    expect(commands).toEqual(SLASH_COMMANDS);

Import SLASH_COMMANDS from the module that defines it if it is not already in scope.

As per path instructions: "Tests must be able to fail: flag assertions that pass vacuously (empty-set matches...)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/test/pythinker-harness.integration.test.ts` around lines 432 -
439, Update the no-session fallback test around
configHandlers[Methods.GetSlashCommands] to assert that the returned command
list equals SLASH_COMMANDS, importing that symbol from its defining module if
needed. Replace the startsWith("skill:")-only assertion so the test verifies the
released command set rather than allowing an empty result.

Source: Path instructions

packages/node-sdk/src/skill-commands.ts-44-64 (1)

44-64: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Duplicate command names collapse silently.

commandMap.set(commandName, skill.name) at line 55 overwrites any earlier entry with the same key, while commands still contains both entries. Two skills can produce the same command name: an explicit skill.commandName can equal another skill's derived name, and a built-in name can equal a user skill's commandName. The result is a duplicated slash-command entry in the menu that always dispatches to the last skill in sort order.

Built-ins sort first, so the user skill wins the map. Drop later duplicates instead, so the first (built-in) skill keeps the name.

🐛 Proposed fix
-    .map((skill) => {
+    .flatMap((skill) => {
       const commandName =
         skill.commandName ??
         (skill.source === 'builtin' || skill.isSubSkill === true
           ? skill.name
           : `skill:${skill.name}`);
+      if (commandMap.has(commandName)) return [];
       commandMap.set(commandName, skill.name);
-      return {
+      return [{
         name: commandName,
         aliases: [] as readonly string[],
         description: skill.description ?? '',
         argumentHint: skill.argumentHint,
-      };
+      }];
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/node-sdk/src/skill-commands.ts` around lines 44 - 64, Update
buildSkillSlashCommands so duplicate command names are excluded from commands
and commandMap after the first occurrence; check whether commandMap already
contains commandName before adding the skill, preserving sorted order so the
first skill—especially a built-in—retains the name and later duplicates are
dropped.
apps/vscode/webview-ui/src/components/ChatArea.tsx-18-18 (1)

18-18: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use semantic theme tokens with a theme-specific foreground.

bg-brand and text-primary-foreground are defined, but the dark-theme --brand value has only 1.97:1 contrast with --primary-foreground. Use bg-brand text-primary-foreground dark:text-primary with hover:opacity-90 so the icon remains readable in both themes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/webview-ui/src/components/ChatArea.tsx` at line 18, Update the
button’s className in ChatArea to use the semantic theme tokens bg-brand and
text-primary-foreground, add dark:text-primary for dark-theme readability, and
replace the hover background color with hover:opacity-90 while preserving the
existing layout and visual utility classes.
apps/vscode/webview-ui/src/components/inputarea/hooks/useSlashMenu.ts-52-57 (1)

52-57: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reset the selection when slashCommands changes.

A live command refresh can reorder or shorten filteredCommands while query is unchanged. The old index can then select a different command or point past the list end. Include the command collection, or the memoized filtered list, in this reset effect.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/webview-ui/src/components/inputarea/hooks/useSlashMenu.ts` around
lines 52 - 57, Update the selection-reset useEffect in useSlashMenu to also
depend on slashCommands or the memoized filteredCommands, so setSelectedIndex(0)
runs when the command collection changes even if query is unchanged. Preserve
the existing reset behavior for query changes.
🧹 Nitpick comments (13)
packages/oauth/src/managed-feedback.ts (1)

33-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the Unicode flag to the trailing-slash expressions.

Oxlint reports require-unicode-regexp at all three sites. Change /\/+$/ to /\/+$/u.

  • packages/oauth/src/managed-feedback.ts#L33-L33: Add the u flag.
  • packages/oauth/src/managed-kimi-code.ts#L222-L222: Add the u flag.
  • packages/oauth/src/managed-usage.ts#L38-L38: Add the u flag.

As per coding guidelines, use oxlint for linting and pnpm lint:fix for automatic formatting fixes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/oauth/src/managed-feedback.ts` at line 33, Add the Unicode flag to
each trailing-slash regular expression: update `/\/+$/` to use the `u` flag in
packages/oauth/src/managed-feedback.ts lines 33-33,
packages/oauth/src/managed-kimi-code.ts lines 222-222, and
packages/oauth/src/managed-usage.ts lines 38-38. Run oxlint and use pnpm
lint:fix for formatting.

Sources: Coding guidelines, Linters/SAST tools

packages/oauth/src/managed-kimi-code.ts (1)

38-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove explicit | undefined from optional property types.

Use property?: Type, not property?: Type | undefined. Keep passing undefined directly at object construction sites.

  • packages/oauth/src/managed-kimi-code.ts#L38-L95: Update optional model, result, OAuth-reference, and environment properties.
  • packages/oauth/src/managed-kimi-code.ts#L115-L183: Update optional configuration, adapter, and provisioning properties.
  • packages/oauth/src/openai-codex-oauth.ts#L567-L575: Update optional OAuth configuration properties.

As per coding guidelines, “Optional properties should not additionally include undefined in their types.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/oauth/src/managed-kimi-code.ts` around lines 38 - 95, Remove
explicit “| undefined” unions from all optional property declarations in
packages/oauth/src/managed-kimi-code.ts at lines 38-95 and 115-183, including
model, result, OAuth-reference, environment, configuration, adapter, and
provisioning properties; retain direct undefined values at object construction
sites. Apply the same optional-property cleanup in
packages/oauth/src/openai-codex-oauth.ts at lines 567-575 for the OAuth
configuration properties.

Source: Coding guidelines

apps/pythinker-code/test/tui/components/dialogs/effort-selector.test.ts (1)

7-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the Unicode flag to every updated ANSI regex.

Oxlint reports require-unicode-regexp at all eight locations. Change each /g suffix to /gu. This preserves the explicit ESC matching behavior.

  • apps/pythinker-code/test/tui/components/dialogs/effort-selector.test.ts#L7-L7: Change the ANSI regex to use /gu.
  • apps/pythinker-code/test/tui/components/messages/tool-renderers/chip.test.ts#L11-L11: Change the ANSI regex to use /gu.
  • apps/pythinker-code/test/tui/components/messages/tool-renderers/media.test.ts#L13-L13: Change the ANSI regex to use /gu.
  • apps/pythinker-code/test/tui/components/messages/tool-renderers/registry.test.ts#L12-L12: Change the ANSI regex to use /gu.
  • apps/pythinker-code/test/tui/components/panels/footer-goal-badge.test.ts#L8-L8: Change the SGR regex to use /gu.
  • apps/pythinker-code/test/tui/controllers/session-event-handler-goal-queue.test.ts#L235-L235: Change the transcript regex to use /gu.
  • apps/pythinker-code/test/tui/task-output-viewer.test.ts#L8-L8: Change the SGR regex to use /gu.
  • apps/pythinker-code/test/tui/tasks-browser.test.ts#L13-L13: Change the SGR regex to use /gu.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/pythinker-code/test/tui/components/dialogs/effort-selector.test.ts` at
line 7, Update the ANSI/SGR/transcript regular expressions to use the Unicode
flag by changing their global suffix from /g to /gu at
apps/pythinker-code/test/tui/components/dialogs/effort-selector.test.ts:7-7,
apps/pythinker-code/test/tui/components/messages/tool-renderers/chip.test.ts:11-11,
apps/pythinker-code/test/tui/components/messages/tool-renderers/media.test.ts:13-13,
apps/pythinker-code/test/tui/components/messages/tool-renderers/registry.test.ts:12-12,
apps/pythinker-code/test/tui/components/panels/footer-goal-badge.test.ts:8-8,
apps/pythinker-code/test/tui/controllers/session-event-handler-goal-queue.test.ts:235-235,
apps/pythinker-code/test/tui/task-output-viewer.test.ts:8-8, and
apps/pythinker-code/test/tui/tasks-browser.test.ts:13-13; preserve the existing
explicit ESC matching patterns.

Source: Linters/SAST tools

apps/vscode/test/bridge-handler.test.ts (1)

651-651: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add the u flag to the regex.

Oxlint reports require-unicode-regexp on this line.

🧹 Proposed fix
-    expect((response as { error?: string }).error).toMatch(/needs an API key/);
+    expect((response as { error?: string }).error).toMatch(/needs an API key/u);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/test/bridge-handler.test.ts` at line 651, Update the regular
expression in the response error assertion to include the Unicode flag required
by the require-unicode-regexp lint rule, while preserving the existing /needs an
API key/ match behavior.

Source: Linters/SAST tools

apps/vscode/webview-ui/src/components/inputarea/hooks/slash-command-match.ts (1)

16-25: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add the u flag to both regexes.

Oxlint reports require-unicode-regexp on lines 17 and 23. The flag does not change the semantics of these character classes.

🧹 Proposed fix
 function letters(text: string): string {
-  return text.toLowerCase().replaceAll(/[^a-z0-9]/g, "");
+  return text.toLowerCase().replaceAll(/[^a-z0-9]/gu, "");
 }
 
 function matchesAnyWordPrefix(text: string, query: string): boolean {
   return text
     .toLowerCase()
-    .split(/[^a-z0-9]+/)
+    .split(/[^a-z0-9]+/u)
     .some((word) => word.startsWith(query));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/webview-ui/src/components/inputarea/hooks/slash-command-match.ts`
around lines 16 - 25, Add the Unicode (`u`) flag to the regular expressions used
in letters and matchesAnyWordPrefix, preserving their existing character classes
and matching behavior.

Source: Linters/SAST tools

apps/vscode/src/bridge-handler.ts (1)

156-168: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Re-broadcast the slash commands only when the session changes.

getOrCreateSession runs on every prompt. chat.handler.ts calls it before each turn, so line 166 triggers a listSkills() call and a webview post on every message, even when the session already exists. The comment at line 201 states the intent is a one-time refresh after create or resume.

Broadcast only when the returned runtime is new for this view.

♻️ Proposed refactor
       getOrCreateSession: async (model, effort, sessionId) => {
+        const previous = this.runtime.getSessionForView(webviewId);
         const runtime = await this.runtime.openSession({
           webviewId,
           workDir: this.requireWorkDir(webviewId),
           model,
           effort,
           yoloMode: VSCodeSettings.yoloMode,
           ...(sessionId === undefined ? {} : { sessionId }),
         });
         this.fileManager.setSession(webviewId, baselineSession(runtime));
-        void this.broadcastSlashCommands(webviewId);
+        if (previous?.id !== runtime.id) void this.broadcastSlashCommands(webviewId);
         return runtime;
       },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/src/bridge-handler.ts` around lines 156 - 168, Update
getOrCreateSession so broadcastSlashCommands is called only when openSession
returns a runtime that is new for the current webview, while retaining the
broadcast for newly created or resumed sessions. Avoid rebroadcasting when the
existing session is reused on subsequent prompts, and preserve the existing
session setup and return behavior.
apps/vscode/src/handlers/provider.handler.ts (2)

20-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Confirm the catalog cache cannot serve a stale document for the host lifetime.

catalogCache is a module-level promise that is cleared only when the fetch rejects. After one successful fetch, GetProviderCatalog returns the same document until the extension host restarts. A user who cannot find a newly published provider has no way to force a refresh.

The failure path is correct: the .catch handler runs after the ??= assignment, so a rejected fetch clears the field and the next call retries.

Consider adding a time-to-live or a refresh parameter on Methods.GetProviderCatalog.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/src/handlers/provider.handler.ts` around lines 20 - 32, Update
loadCatalog and the GetProviderCatalog request flow so a successful catalog
fetch cannot remain cached for the entire extension-host lifetime. Add an
appropriate TTL or explicit refresh mechanism, while preserving the existing
rejection cleanup that retries failed fetches.

42-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the any parameters with the imported catalog and config types.

toConfiguredProvider types both provider and config as any, and toCatalogSummary types entry as any. The file already imports Catalog, so entry can be CatalogProviderEntry, and ctx.harness.getConfig() returns a typed config. With any, every field access here is unchecked: provider.oauth, provider.source?.kind, and model.capability?.max_context_tokens would not fail the build if the schema renamed a field.

The optional chaining at line 139 is one symptom. catalogProviderModels returns CatalogModel, whose capability is accessed without ?. inside the SDK, so the guard here only exists because the type was erased.

♻️ Proposed typing
-import {
+import {
   CatalogProviderError,
   DEFAULT_CATALOG_URL,
   catalogConnectionWire,
   catalogProviderModels,
   fetchCatalog,
   importCatalogProvider,
   type Catalog,
+  type CatalogProviderEntry,
 } from "`@pythoughts/pythinker-code-sdk`";
-function toCatalogSummary(id: string, entry: any): CatalogProviderSummary {
+function toCatalogSummary(id: string, entry: CatalogProviderEntry): CatalogProviderSummary {

Derive the provider and config parameter types from the return type of ctx.harness.getConfig.

Also applies to: 129-141

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/src/handlers/provider.handler.ts` around lines 42 - 45, Replace
the any annotations in toConfiguredProvider and toCatalogSummary with the
imported catalog types and the config type derived from ctx.harness.getConfig().
Type entry as CatalogProviderEntry, and derive provider/config parameter types
from the harness configuration return type so accesses such as provider.oauth,
provider.source?.kind, config.models, and model.capability are schema-checked;
preserve the existing behavior.
packages/node-sdk/src/catalog.ts (1)

214-235: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Make the transient invalid default explicit.

Line 222 passes selectedModelId: '' when the caller requests no default. applyCatalogProvider then writes config.defaultModel = "<providerId>/", which is not a resolvable alias. Lines 226-230 replace it, so the value never persists. The correctness of the whole function depends on that later assignment, which is easy to break during a refactor.

Consider deriving the placeholder from the first imported model instead, so the intermediate config stays valid on its own.

♻️ Optional refactor
-    selectedModelId: options.defaultModel ?? '',
+    selectedModelId: options.defaultModel ?? models[0]!.id,

Note that this changes the intermediate value only; lines 226-230 still decide the persisted defaultModel.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/node-sdk/src/catalog.ts` around lines 214 - 235, Update the catalog
provider setup around applyCatalogProvider to avoid passing an empty
selectedModelId when options.defaultModel is undefined. Derive the placeholder
selected model from the first imported model so applyCatalogProvider produces a
resolvable intermediate default, while preserving the existing lines that
restore previousDefaultModel or clear config.defaultModel for the persisted
result.
apps/vscode/src/handlers/slash-command.ts (1)

62-63: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the duplicated skill: fallback.

Lines 63 and 70 contain the identical expression. Extract it into a small local helper so the prefix length 6 and the shape appear once.

♻️ Optional refactor
+  const skillPrefixFallback = (): HostSlashCommand | undefined =>
+    name.startsWith("skill:") ? { name, args, raw, skillName: name.slice("skill:".length) } : undefined;
+
-  if (listSkills === undefined) {
-    return name.startsWith("skill:") ? { name, args, raw, skillName: name.slice(6) } : undefined;
-  }
+  if (listSkills === undefined) return skillPrefixFallback();

Also applies to: 70-70

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/src/handlers/slash-command.ts` around lines 62 - 63, Extract the
duplicated `skill:` fallback expression used in the `listSkills === undefined`
branch and the corresponding later branch into a local helper near the
surrounding slash-command logic. Have the helper centralize the `skill:` prefix
check, `name.slice(6)`, and returned object shape, then reuse it at both call
sites while preserving the existing undefined behavior for non-skill names.
apps/vscode/test/pythinker-harness.integration.test.ts (1)

389-400: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Type the listSkills fixture instead of casting to never.

listSkills as never at lines 395 and 398 removes all type checking from the fixture. A missing or renamed SkillSummary field would not surface here. Cast through the parameter type so the fixture stays honest.

♻️ Optional refactor
-    const listSkills = async () => [
+    const listSkills = async (): Promise<readonly SkillSummary[]> => [
       { name: "gen-changesets", description: "", path: "/s", source: "builtin", type: "prompt" },
     ];

     await expect(
-      parseHostSlashCommand("/gen-changesets", listSkills as never),
+      parseHostSlashCommand("/gen-changesets", listSkills),
     ).resolves.toMatchObject({ skillName: "gen-changesets" });

If SkillSummary requires fields the test does not care about, add them to the fixture rather than widening the type.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/test/pythinker-harness.integration.test.ts` around lines 389 -
400, Update the listSkills fixture in the “resolves a built-in skill invoked
under its bare name” test to use the actual parameter type expected by
parseHostSlashCommand instead of casting it to never. Add any required
SkillSummary fields to the fixture while preserving the existing assertions and
behavior.
apps/vscode/webview-ui/src/components/WorkflowCard.tsx (1)

42-46: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Give the status dot a text equivalent.

StatusDot conveys the lane status through color only. The adjacent label at line 74 reports queued and done · N steps, but a running lane and a failed lane both render just N steps. A user who cannot distinguish the colors has no status signal for a failed lane unless lane.error is also set.

Add an accessible name to the dot.

♿ Proposed change
-function StatusDot({ status }: { status: WorkflowLane["status"] }) {
+function StatusDot({ status }: { status: WorkflowLane["status"] }) {
   const color =
     status === "running" ? "bg-brand" : status === "done" ? "bg-success" : status === "failed" ? "bg-destructive" : "bg-muted-foreground";
-  return <span className={cn("inline-block size-2 rounded-full shrink-0", color)} />;
+  return <span role="img" aria-label={status} title={status} className={cn("inline-block size-2 rounded-full shrink-0", color)} />;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/webview-ui/src/components/WorkflowCard.tsx` around lines 42 - 46,
Update the StatusDot component to provide an accessible text equivalent for each
status, including running and failed, rather than conveying status through color
alone. Add an appropriate accessible name to the rendered span while preserving
its existing visual classes and status-to-color mapping.
packages/node-sdk/src/skill-commands.ts (1)

17-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add direct Vitest coverage for the public skill-command helpers.

Add tests in packages/node-sdk/test for skill: namespacing, built-in ordering, userInvocable === false, and type === 'reference'. Existing coverage is in application-level tests, not the public SDK package.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/node-sdk/src/skill-commands.ts` around lines 17 - 25, Add direct
Vitest tests under the node-sdk test suite for the public skill-command helpers,
including skill: namespacing, built-in ordering, and exclusion behavior for
userInvocable === false and type === 'reference'. Exercise the exported helpers
from skill-commands.ts directly and verify the expected results without relying
on application-level coverage.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/vscode/src/handlers/slash-command.ts`:
- Around line 62-70: Wrap the awaited listSkills() call in parseHostSlashCommand
with error handling so a rejection falls back to the existing skill: prefix
check, matching the behavior for unlisted skills. Preserve the current
commandMap resolution when listing succeeds and return undefined for
non-skill-prefixed commands on failure.

In `@apps/vscode/webview-ui/src/components/ProvidersModal.tsx`:
- Around line 315-321: Update the provider selection handler around setSelected
and the modal’s Back handler to reset apiKey whenever the user changes or leaves
a provider. Preserve the existing resets for useEnvVar and defaultModel, and
clear the key in both interaction paths so credentials cannot carry over between
providers.

In `@packages/node-sdk/src/auth.ts`:
- Line 213: Update the managed authentication flow around
resolveKimiCodeRuntimeAuth and normalizeBaseUrl to validate that the configured
endpoint uses HTTPS before sending bearer-token requests. Reject HTTP or
otherwise unsafe managed endpoints and prevent redirects from bypassing this
scheme requirement, while preserving existing behavior for valid HTTPS
endpoints.

In `@packages/node-sdk/src/catalog.ts`:
- Around line 203-243: Serialize the read-modify-write sequence in the catalog
configuration update around ensureConfigFile, getConfig, applyCatalogProvider,
and setConfig. Use the store’s atomic update operation or mutation lock to hold
exclusive access across the complete sequence, preventing concurrent writers
from being overwritten by the final whole-section update.

---

Outside diff comments:
In `@packages/oauth/src/toolkit.ts`:
- Around line 261-273: Update the shared URL normalization used by managed
usage, managed feedback, and model requests to reject custom base URLs whose
protocol is not HTTPS before obtaining or sending an access token. Ensure
managedUsageUrl and managedFeedbackUrl, along with the model-request URL path,
all use this validator while preserving existing default URL behavior.

---

Minor comments:
In `@apps/pythinker-code/test/cli/export.test.ts`:
- Line 83: Update the KIMI_CODE_PROVIDER_NAME override in the OAuth mock to use
the managed provider key "managed:kimi-code", or preserve the actual export so
telemetry requests exercise the migrated key; do not use the stale
"pythinker-code" value.

In `@apps/pythinker-code/test/cli/provider.test.ts`:
- Line 500: Replace the production URL assigned to baseUrl in the test fixture
with a neutral host such as https://example.com/coding/v1, preserving the
existing path and test behavior.

In `@apps/pythinker-code/test/cli/run-prompt.test.ts`:
- Line 121: Update both OAuth mocks in
apps/pythinker-code/test/cli/run-prompt.test.ts:121-121 and
apps/pythinker-code/test/cli/run-shell.test.ts:114-114 to use managed:kimi-code
for KIMI_CODE_PROVIDER_NAME, and add assertions in the relevant tests comparing
the mock value with the production KIMI_CODE_PROVIDER_NAME constant.

In `@apps/pythinker-code/test/tui/components/dialogs/model-selector.test.ts`:
- Line 9: Update every affected regular-expression literal to include the
Unicode flag: in
apps/pythinker-code/test/tui/components/dialogs/model-selector.test.ts lines 9-9
and 98-98, apps/pythinker-code/test/cli/provider.test.ts lines 536-536,
apps/pythinker-code/test/tui/components/dialogs/provider-manager.test.ts lines
104-104, and
apps/pythinker-code/test/tui/components/messages/goal-markers.test.ts lines 8-8.
Preserve the existing patterns and flags while adding u, including changing the
ANSI expressions from g to gu.

In `@apps/pythinker-code/test/tui/pythinker-tui-startup.test.ts`:
- Around line 45-48: Add the Unicode flag to both ANSI SGR regular expressions:
update the ANSI_SGR constant and the inline expression near the referenced
startup test location from /g to /gu, without changing their matching behavior.

In `@apps/vscode/src/handlers/slash-command.ts`:
- Around line 160-167: Update the slash-command argument handling around
subcommand and requested so unrecognized non-empty arguments are rejected rather
than treated as a toggle. Preserve the existing explicit on/off mode behavior
and ensure invalid input returns before applying or reporting any
permission-mode change.

In `@apps/vscode/test/pythinker-harness.integration.test.ts`:
- Around line 432-439: Update the no-session fallback test around
configHandlers[Methods.GetSlashCommands] to assert that the returned command
list equals SLASH_COMMANDS, importing that symbol from its defining module if
needed. Replace the startsWith("skill:")-only assertion so the test verifies the
released command set rather than allowing an empty result.

In `@apps/vscode/webview-ui/src/components/ChatArea.tsx`:
- Line 18: Update the button’s className in ChatArea to use the semantic theme
tokens bg-brand and text-primary-foreground, add dark:text-primary for
dark-theme readability, and replace the hover background color with
hover:opacity-90 while preserving the existing layout and visual utility
classes.

In `@apps/vscode/webview-ui/src/components/inputarea/hooks/useSlashMenu.ts`:
- Around line 52-57: Update the selection-reset useEffect in useSlashMenu to
also depend on slashCommands or the memoized filteredCommands, so
setSelectedIndex(0) runs when the command collection changes even if query is
unchanged. Preserve the existing reset behavior for query changes.

In `@packages/agent-core/src/services/modelCatalog/modelCatalogService.ts`:
- Around line 163-166: Complete the Kimi Code provider-label migration across
all three sites: in
packages/agent-core/src/services/modelCatalog/modelCatalogService.ts lines
163-166, use the canonical Kimi Code display name for provider_name; in
apps/pythinker-code/src/tui/commands/auth.ts lines 57-59, route to a Kimi-named
handler and change its stale Pythinker OAuth text to Kimi (OAuth); in
packages/agent-core/src/services/auth/managedAuth.ts lines 68-73, replace
Pythinker terminology in the provisioning failure message with Kimi terminology.

In `@packages/agent-core/test/config/configs.test.ts`:
- Around line 62-72: Update the changed fixture’s base_url in the
providers."managed:kimi-code" configuration to use the reserved placeholder host
https://api.example.test/coding/v1 instead of the product endpoint, leaving the
rest of the parser test data unchanged.

In `@packages/agent-core/test/services/oauth-service.test.ts`:
- Around line 82-83: Update the OAuth logout test around the mocked logout
result to pass providerName 'managed:kimi-code' explicitly to impl.logout, then
assert mock.logoutCalls[0].providerName matches it. Keep the existing result
assertion while ensuring it no longer depends on the mock's fallback provider
value.

In `@packages/node-sdk/src/skill-commands.ts`:
- Around line 44-64: Update buildSkillSlashCommands so duplicate command names
are excluded from commands and commandMap after the first occurrence; check
whether commandMap already contains commandName before adding the skill,
preserving sorted order so the first skill—especially a built-in—retains the
name and later duplicates are dropped.

In `@packages/node-sdk/test/auth-facade.test.ts`:
- Around line 540-543: Update the [services.pythoughts_fetch] fixture endpoint
to a neutral placeholder such as https://api.example.test/coding/v1/fetch,
preserving the service key and other fixture fields unchanged.

In `@packages/node-sdk/test/catalog.test.ts`:
- Around line 238-246: Update the fixture object in the catalog test to use
neutral provider values: replace the Anthropic provider name, API host, npm
package, and environment variable with example-provider equivalents such as
example-provider, api.example.test, `@ai-sdk/example-provider`, and
EXAMPLE_PROVIDER_API_KEY, while preserving the fixture structure.
- Line 199: Update the catalog test fixture setup around config and entry
construction: normalize initial into a valid PythinkerConfig before assigning
config, remove the rebuilt-state type assertion, and type entry using satisfies
Parameters<typeof importCatalogProvider>[1]['entry'] instead of an unknown-based
assertion.

In `@packages/oauth/src/toolkit.ts`:
- Line 398: Update the regular expressions in packages/oauth/src/toolkit.ts at
398 and packages/node-sdk/test/catalog.test.ts at 301 and 313 to include the
Unicode flag, then run pnpm lint:fix.
- Line 50: Remove the explicit undefined union from the optional configAdapter
and provision properties, leaving configAdapter typed as
ManagedKimiConfigAdapter<TConfig> and provision typed as
ManagedKimiCodeProvisionResult while preserving their optionality.

In `@packages/oauth/test/managed-kimi-code.test.ts`:
- Line 63: Update the regular expression in the devKey assertion to include the
Unicode (`u`) flag, while preserving its existing matching pattern.

---

Nitpick comments:
In `@apps/pythinker-code/test/tui/components/dialogs/effort-selector.test.ts`:
- Line 7: Update the ANSI/SGR/transcript regular expressions to use the Unicode
flag by changing their global suffix from /g to /gu at
apps/pythinker-code/test/tui/components/dialogs/effort-selector.test.ts:7-7,
apps/pythinker-code/test/tui/components/messages/tool-renderers/chip.test.ts:11-11,
apps/pythinker-code/test/tui/components/messages/tool-renderers/media.test.ts:13-13,
apps/pythinker-code/test/tui/components/messages/tool-renderers/registry.test.ts:12-12,
apps/pythinker-code/test/tui/components/panels/footer-goal-badge.test.ts:8-8,
apps/pythinker-code/test/tui/controllers/session-event-handler-goal-queue.test.ts:235-235,
apps/pythinker-code/test/tui/task-output-viewer.test.ts:8-8, and
apps/pythinker-code/test/tui/tasks-browser.test.ts:13-13; preserve the existing
explicit ESC matching patterns.

In `@apps/vscode/src/bridge-handler.ts`:
- Around line 156-168: Update getOrCreateSession so broadcastSlashCommands is
called only when openSession returns a runtime that is new for the current
webview, while retaining the broadcast for newly created or resumed sessions.
Avoid rebroadcasting when the existing session is reused on subsequent prompts,
and preserve the existing session setup and return behavior.

In `@apps/vscode/src/handlers/provider.handler.ts`:
- Around line 20-32: Update loadCatalog and the GetProviderCatalog request flow
so a successful catalog fetch cannot remain cached for the entire extension-host
lifetime. Add an appropriate TTL or explicit refresh mechanism, while preserving
the existing rejection cleanup that retries failed fetches.
- Around line 42-45: Replace the any annotations in toConfiguredProvider and
toCatalogSummary with the imported catalog types and the config type derived
from ctx.harness.getConfig(). Type entry as CatalogProviderEntry, and derive
provider/config parameter types from the harness configuration return type so
accesses such as provider.oauth, provider.source?.kind, config.models, and
model.capability are schema-checked; preserve the existing behavior.

In `@apps/vscode/src/handlers/slash-command.ts`:
- Around line 62-63: Extract the duplicated `skill:` fallback expression used in
the `listSkills === undefined` branch and the corresponding later branch into a
local helper near the surrounding slash-command logic. Have the helper
centralize the `skill:` prefix check, `name.slice(6)`, and returned object
shape, then reuse it at both call sites while preserving the existing undefined
behavior for non-skill names.

In `@apps/vscode/test/bridge-handler.test.ts`:
- Line 651: Update the regular expression in the response error assertion to
include the Unicode flag required by the require-unicode-regexp lint rule, while
preserving the existing /needs an API key/ match behavior.

In `@apps/vscode/test/pythinker-harness.integration.test.ts`:
- Around line 389-400: Update the listSkills fixture in the “resolves a built-in
skill invoked under its bare name” test to use the actual parameter type
expected by parseHostSlashCommand instead of casting it to never. Add any
required SkillSummary fields to the fixture while preserving the existing
assertions and behavior.

In
`@apps/vscode/webview-ui/src/components/inputarea/hooks/slash-command-match.ts`:
- Around line 16-25: Add the Unicode (`u`) flag to the regular expressions used
in letters and matchesAnyWordPrefix, preserving their existing character classes
and matching behavior.

In `@apps/vscode/webview-ui/src/components/WorkflowCard.tsx`:
- Around line 42-46: Update the StatusDot component to provide an accessible
text equivalent for each status, including running and failed, rather than
conveying status through color alone. Add an appropriate accessible name to the
rendered span while preserving its existing visual classes and status-to-color
mapping.

In `@packages/node-sdk/src/catalog.ts`:
- Around line 214-235: Update the catalog provider setup around
applyCatalogProvider to avoid passing an empty selectedModelId when
options.defaultModel is undefined. Derive the placeholder selected model from
the first imported model so applyCatalogProvider produces a resolvable
intermediate default, while preserving the existing lines that restore
previousDefaultModel or clear config.defaultModel for the persisted result.

In `@packages/node-sdk/src/skill-commands.ts`:
- Around line 17-25: Add direct Vitest tests under the node-sdk test suite for
the public skill-command helpers, including skill: namespacing, built-in
ordering, and exclusion behavior for userInvocable === false and type ===
'reference'. Exercise the exported helpers from skill-commands.ts directly and
verify the expected results without relying on application-level coverage.

In `@packages/oauth/src/managed-feedback.ts`:
- Line 33: Add the Unicode flag to each trailing-slash regular expression:
update `/\/+$/` to use the `u` flag in packages/oauth/src/managed-feedback.ts
lines 33-33, packages/oauth/src/managed-kimi-code.ts lines 222-222, and
packages/oauth/src/managed-usage.ts lines 38-38. Run oxlint and use pnpm
lint:fix for formatting.

In `@packages/oauth/src/managed-kimi-code.ts`:
- Around line 38-95: Remove explicit “| undefined” unions from all optional
property declarations in packages/oauth/src/managed-kimi-code.ts at lines 38-95
and 115-183, including model, result, OAuth-reference, environment,
configuration, adapter, and provisioning properties; retain direct undefined
values at object construction sites. Apply the same optional-property cleanup in
packages/oauth/src/openai-codex-oauth.ts at lines 567-575 for the OAuth
configuration properties.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

Comment thread apps/vscode/src/handlers/slash-command.ts Outdated
Comment thread apps/vscode/webview-ui/src/components/ProvidersModal.tsx
Comment thread packages/node-sdk/src/auth.ts
Comment thread packages/node-sdk/src/catalog.ts
elkaix added 10 commits August 5, 2026 14:34
…essage

The logo only rendered inside the streaming thinking indicator, so a finished
message showed a bare step dot and nothing identified the assistant.
A step opens with its thinking or tool block, so a marker in the step gutter sat
beside that block rather than beside the text the logo is meant to label.
The step-less branch rendered its markdown behind a bare left padding, so a plain
text reply carried no logo. Both branches now share one logo gutter row.
Picking a command sent it on its own and cleared the input, so a command written
into a longer message discarded that message. It now fills the token in place,
like a file mention, and the user keeps typing.
- Blink repeats every 5s instead of playing once (WELCOME_BLINK_INTERVAL_MS)
- Antenna bulb spins through ◐◓◑◒ frames for 6s at banner load, then
  restores the static ● (WELCOME_ANTENNA_SPIN_* constants)
- Logo renderer gains renderPythinkerLogoAntennaRow + antennaFrame param
- Animator renamed WelcomeLogoEyeAnimator → WelcomeLogoAnimator with
  per-loop timers (blink + spin) and a setAntennaFrame host hook
Shrinks pythinker-logo.png from 264 KB to 59 KB and adds the animated logo
variant beside it.
A multi-step reply draws a connector between its step markers. The logo sits in
that same gutter, so it cut the line in half. Multi-step replies now keep the
timeline and drop the logo; single-step replies still show it.
The extension shipped from its own 0.6.x line while the CLI was on 0.8.x, so the
two versions could not be matched up when reporting an issue.
VSCE_AZURE_CREDENTIAL=1 passes vsce's --azure-credential, so a maintainer can
publish as the identity az login already established instead of minting a PAT.
CI keeps using VSCE_PAT.
elkaix added 11 commits August 5, 2026 15:30
Bumping, building, packaging six targets, publishing and tagging were separate
manual steps, and the Marketplace token had to be pasted in by hand each time.
The script runs them in order behind preflight checks and reads the token from
the keychain.
The icon was a raw Windows DIB carrying a .png extension, so the storefront
rendered a broken image. Re-encodes it as a real 256x256 PNG and drops the
unreferenced duplicate beside it.
A timeout mid-run aborted the loop, leaving one target live, four unattempted
and the release untagged. Transient failures now retry with backoff, a failed
target no longer stops the others, an auth failure stops everything at once,
and the summary names which targets are live so a re-run can finish the job.
pi-tui paints on requestRender before ui.start(), so frames rendered during
construction and mounting were anchored at the shell cursor and the fixed
layout's scroll-to-home pushed the panel border into scrollback. Rendering is
now gated until the event loop starts, which runs before the main TUI mounts.

The gate writes a private pi-tui field, so a test asserts both the gate and
ui.start() clearing it — an upgrade that changes either fails there.
Skill resolution was reachable only through a live session, so a freshly opened
panel showed the built-in commands alone and skills appeared only after the
first message. Resolution now also runs at workspace scope, using the same
roots a session resolves, and the panel calls that when it has no session yet.
A live session is still preferred, since only it knows its MCP prompts.
A skill-catalog failure rejected out of the slash parser, whose caller awaits it
outside any try block, so every message starting with "/" was dropped. It now
degrades to the skill prefix check, matching how an unlisted skill is handled.

Selecting a different provider, or leaving the form, kept the API key already
typed, so a key entered for one provider could be saved under another's id.
@elkaix elkaix changed the title fix(vscode): workflow lanes, permission modes, skills and provider management feat(vscode): add workflow lanes, provider management and skill commands Aug 5, 2026
@elkaix

elkaix commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

All 4 inline findings triaged in d76fa06 — 2 fixed, 2 deferred with rationale on their threads (now resolved).

Fixed

  • slash-command.ts — a listSkills() rejection escaped the parser, whose caller awaits it outside any try block, dropping every message that starts with /. It now degrades to the skill: prefix check. Regression test added; it fails against the previous unguarded await.
  • ProvidersModal.tsx — provider-select and Back now clear apiKey, so a key typed for one provider can no longer be submitted under another's id.

Deferred (rationale on each thread)

  • HTTPS enforcement for managed base URLs (auth.ts, and the outside-diff toolkit.ts:261-273 item — same root cause). The URL is operator-supplied via their own config or PYTHINKER_CODE_BASE_URL; no remote party can set it, matching the reported Reachability: Internal. Enforcing HTTPS unconditionally would also break loopback and proxy setups. Worth doing deliberately — allow loopback, require https elsewhere, with a release note — not as a silent behaviour change in a PR that only renamed identifiers in these files.
  • Catalog config read-modify-write serialization. The window is real and the multi-process case is not hypothetical, since the CLI and the extension write the same file. The fix is a lock or atomic update on PythinkerCore, affecting every config writer; a partial lock over this one call site would give false confidence without closing the window.

Title shortened to 72 chars and made imperative, per the title check.

Also in this push: skills now list in the slash menu before a session exists, the TUI no longer anchors its first frames to the shell cursor, publishing retries transient registry failures, and the Marketplace icon is a decodable PNG.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/agent-core/src/rpc/core-impl.ts (1)

1159-1159: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve managed:pythinker-code during provider migration.

Existing configs retain the legacy key. Normalize the legacy provider and OAuth references before both lookups, or support the legacy alias. Add Vitest coverage for legacy and native configurations.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-core/src/rpc/core-impl.ts` at line 1159, Update the provider
migration flow around the KIMI_CODE_PROVIDER_NAME lookup to preserve the legacy
managed:pythinker-code key. Normalize legacy provider and OAuth references
before both lookups, or make the native lookup accept the legacy alias, and add
Vitest coverage for both legacy and native configurations.
🧹 Nitpick comments (3)
apps/vscode/test/publish-retry.test.ts (1)

54-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove conditionals from the test bodies.

Oxlint flags both conditionals. Configure publishOne with ordered mockResolvedValueOnce and mockRejectedValueOnce results instead. This keeps each test branch explicit.

Also applies to: 78-81

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/test/publish-retry.test.ts` around lines 54 - 58, Remove the
conditional logic from the publishOne mock in the affected tests. Configure its
ordered outcomes with mockResolvedValueOnce and mockRejectedValueOnce so the
failing darwin-arm64 attempt and subsequent successful publishes are explicit,
while preserving the existing test behavior.

Source: Linters/SAST tools

packages/agent-core/src/rpc/core-impl.ts (1)

620-632: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add Vitest coverage for the public workspace-skills RPC.

CoreAPI, CoreRPCClient, SDKRpcClientBase, PythinkerHarness, and the generic bridge already forward listWorkspaceSkills. Add a contract test that invokes PythinkerHarness.listWorkspaceSkills() and asserts the returned SkillSummary[].

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-core/src/rpc/core-impl.ts` around lines 620 - 632, Add Vitest
contract coverage for the public listWorkspaceSkills RPC by invoking
PythinkerHarness.listWorkspaceSkills() through the existing bridge and asserting
the returned SkillSummary[] contents. Reuse the established harness setup and
fixture patterns, covering the workspace root resolution exposed by
CoreAPI.listWorkspaceSkills without changing the RPC implementation.

Source: Path instructions

apps/pythinker-code/src/tui/tui-state.ts (1)

74-78: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Avoid coupling startup to pi-tui's private field.

Line 78 writes an implementation detail through a runtime cast and assumes that TUI.start() restores the field correctly. The dependency in package.json, Line 69, is ranged as ^0.83.0, so a package update can change this behavior without a TypeScript error. Prefer a supported pi-tui lifecycle hook. If none exists, pin the tested version and keep the regression test as the upgrade gate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/pythinker-code/src/tui/tui-state.ts` around lines 74 - 78, Remove the
direct private-field mutation of ui.stopped in the TUI initialization flow and
replace it with a supported pi-tui lifecycle hook that prevents
construction-time rendering until ui.start() begins. If no suitable public hook
exists, pin the tested pi-tui version in package.json and retain or add the
regression test covering startup rendering before allowing dependency upgrades.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/pythinker-code/test/tui/create-tui-state.test.ts`:
- Line 49: Remove the duplicate const ui declaration in the test block, keeping
a single declaration with the existing stopped/start type assertion so the test
can be collected successfully.

In `@apps/vscode/scripts/release-extension.mjs`:
- Around line 114-122: Update the release flow around the manifest write and
dryRun branch to capture the original manifest content before modification, then
restore it in a finally block whenever dryRun is enabled, including if build or
packaging fails. Preserve the existing dry-run logging and return behavior while
ensuring the manifest is restored after all paths.

In `@apps/vscode/src/handlers/config.handler.ts`:
- Around line 99-104: Update the skills selection expression around
session.listSkills and ctx.harness.listWorkspaceSkills to eliminate negated
conditions by reversing each conditional and swapping its corresponding
branches, while preserving the existing fallback to an empty array. Run pnpm
lint:fix to apply the required Oxlint formatting.

In `@apps/vscode/test/publish-retry.test.ts`:
- Around line 14-15: Replace the real publisher identifier in the classifyError
test case with a neutral placeholder such as “example,” while preserving the
timeout message and expected “transient” classification.

In `@packages/agent-core/src/rpc/core-impl.ts`:
- Around line 627-630: Update the workspace-skill listing method around
listWorkspaceSkills to call reloadRuntimeConfig() before resolving session skill
configuration, matching the runtime configuration path used during session
creation instead of directly calling readConfigForWrite(). Add regression
coverage verifying invalid skill settings fall back to salvaged or existing
runtime configuration without throwing.

In `@packages/agent-core/src/skill/workspace.ts`:
- Around line 33-51: Add Vitest coverage in matching test files for
packages/agent-core/src/skill/workspace.ts lines 33-51, covering root discovery
and summary projection without creating a session;
packages/agent-core/src/rpc/core-api.ts lines 390-393 and 501, covering the
ListWorkspaceSkillsPayload contract and CoreAPI.listWorkspaceSkills operation;
packages/node-sdk/src/rpc.ts lines 252-256, verifying SDKRpcClientBase forwards
{ workDir }; and packages/node-sdk/src/pythinker-harness.ts lines 239-243,
verifying PythinkerHarness.listWorkspaceSkills delegates and returns the RPC
result.

---

Outside diff comments:
In `@packages/agent-core/src/rpc/core-impl.ts`:
- Line 1159: Update the provider migration flow around the
KIMI_CODE_PROVIDER_NAME lookup to preserve the legacy managed:pythinker-code
key. Normalize legacy provider and OAuth references before both lookups, or make
the native lookup accept the legacy alias, and add Vitest coverage for both
legacy and native configurations.

---

Nitpick comments:
In `@apps/pythinker-code/src/tui/tui-state.ts`:
- Around line 74-78: Remove the direct private-field mutation of ui.stopped in
the TUI initialization flow and replace it with a supported pi-tui lifecycle
hook that prevents construction-time rendering until ui.start() begins. If no
suitable public hook exists, pin the tested pi-tui version in package.json and
retain or add the regression test covering startup rendering before allowing
dependency upgrades.

In `@apps/vscode/test/publish-retry.test.ts`:
- Around line 54-58: Remove the conditional logic from the publishOne mock in
the affected tests. Configure its ordered outcomes with mockResolvedValueOnce
and mockRejectedValueOnce so the failing darwin-arm64 attempt and subsequent
successful publishes are explicit, while preserving the existing test behavior.

In `@packages/agent-core/src/rpc/core-impl.ts`:
- Around line 620-632: Add Vitest contract coverage for the public
listWorkspaceSkills RPC by invoking PythinkerHarness.listWorkspaceSkills()
through the existing bridge and asserting the returned SkillSummary[] contents.
Reuse the established harness setup and fixture patterns, covering the workspace
root resolution exposed by CoreAPI.listWorkspaceSkills without changing the RPC
implementation.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a197d492-ba6c-4457-ad35-40068f81a263

📥 Commits

Reviewing files that changed from the base of the PR and between 976acdb and 580a174.

⛔ Files ignored due to path filters (5)
  • apps/vscode/resources/pythinker-icon-from-ico.png is excluded by !**/*.png, !**/*.png
  • apps/vscode/resources/pythinker-icon-storefront.png is excluded by !**/*.png, !**/*.png
  • apps/vscode/webview-ui/public/pythinker-logo.png is excluded by !**/*.png, !**/*.png
  • apps/vscode/webview-ui/public/pythinker_animated.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !**/pnpm-lock.yaml
📒 Files selected for processing (29)
  • .changeset/session-free-skill-listing.md
  • .changeset/tui-render-gate.md
  • .changeset/vscode-chat-logo-and-slash-insert.md
  • apps/pythinker-code/package.json
  • apps/pythinker-code/src/tui/components/chrome/pythinker-logo.ts
  • apps/pythinker-code/src/tui/components/chrome/welcome-logo-animation.ts
  • apps/pythinker-code/src/tui/components/chrome/welcome.ts
  • apps/pythinker-code/src/tui/pythinker-tui.ts
  • apps/pythinker-code/src/tui/tui-state.ts
  • apps/pythinker-code/test/tui/components/chrome/pythinker-logo.test.ts
  • apps/pythinker-code/test/tui/components/chrome/welcome-eye-animation.test.ts
  • apps/pythinker-code/test/tui/create-tui-state.test.ts
  • apps/vscode/package.json
  • apps/vscode/scripts/ovsx-publish.mjs
  • apps/vscode/scripts/publish-retry.mjs
  • apps/vscode/scripts/release-extension.mjs
  • apps/vscode/scripts/vsix-publish.mjs
  • apps/vscode/src/handlers/config.handler.ts
  • apps/vscode/test/publish-retry.test.ts
  • apps/vscode/webview-ui/src/components/ChatMessage.tsx
  • apps/vscode/webview-ui/src/components/inputarea/InputArea.tsx
  • flake.nix
  • package.json
  • packages/agent-core/src/rpc/core-api.ts
  • packages/agent-core/src/rpc/core-impl.ts
  • packages/agent-core/src/skill/index.ts
  • packages/agent-core/src/skill/workspace.ts
  • packages/node-sdk/src/pythinker-harness.ts
  • packages/node-sdk/src/rpc.ts

Comment thread apps/pythinker-code/test/tui/create-tui-state.test.ts
Comment thread apps/vscode/scripts/release-extension.mjs Outdated
Comment thread apps/vscode/src/handlers/config.handler.ts
Comment thread apps/vscode/test/publish-retry.test.ts Outdated
Comment thread packages/agent-core/src/rpc/core-impl.ts
Comment thread packages/agent-core/src/skill/workspace.ts
Listing workspace skills used the strict config read, so a warning in an
unrelated section could make it throw where session creation would not; it now
uses the same lenient runtime read. A dry-run release left the bumped manifest
behind, tripping the next run's own clean-tree check. Adds coverage for the
session-free skill catalog and drops a real publisher name from test data.
@elkaix
elkaix merged commit 45be822 into main Aug 5, 2026
11 checks passed
@elkaix
elkaix deleted the feat/vscode-workflow-lanes branch August 5, 2026 20:18
elkaix pushed a commit that referenced this pull request Aug 5, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @pythoughts/pythinker-code@0.9.0

### Minor Changes

- [#22](#22)
[`45be822`](45be822)
- Name the managed OAuth provider after the platform that serves it. It
is reached over `auth.kimi.com` and `api.kimi.com`, but it was
registered as `managed:pythinker-code`, which read as a first-party
service in a client that talks to several providers. The provider id is
now `managed:kimi-code`, its models are aliased `kimi-code/*`, and its
credentials are stored under `oauth/kimi-code`.

This is a breaking change for an existing config: the previous entries
are not rewritten, so run `pythinker login` once to provision the
managed provider under its current name, then remove the stale
`managed:pythinker-code` entry.

- [#22](#22)
[`45be822`](45be822)
- Resolve a workspace's skills without opening a session, so an editor
panel can list them before its first message.

### Patch Changes

- [#22](#22)
[`45be822`](45be822)
- Add an SDK routine that imports a catalog provider and its models into
the persisted config, and use it for the CLI provider import so both
entry points preserve existing defaults the same way.

- [#22](#22)
[`45be822`](45be822)
- Stop the fixed-layout TUI anchoring its first frames to the shell
cursor, which pushed the panel border into scrollback.
## @pythoughts/pythinker-code-sdk@0.11.0

### Minor Changes

- [#22](#22)
[`45be822`](45be822)
- Name the managed OAuth provider after the platform that serves it. It
is reached over `auth.kimi.com` and `api.kimi.com`, but it was
registered as `managed:pythinker-code`, which read as a first-party
service in a client that talks to several providers. The provider id is
now `managed:kimi-code`, its models are aliased `kimi-code/*`, and its
credentials are stored under `oauth/kimi-code`.

This is a breaking change for an existing config: the previous entries
are not rewritten, so run `pythinker login` once to provision the
managed provider under its current name, then remove the stale
`managed:pythinker-code` entry.

- [#22](#22)
[`45be822`](45be822)
- Add an SDK routine that imports a catalog provider and its models into
the persisted config, and use it for the CLI provider import so both
entry points preserve existing defaults the same way.
## pythinker-code@0.8.4

### Patch Changes

- [#22](#22)
[`45be822`](45be822)
- Show the assistant logo beside replies without breaking the step
timeline, complete a picked slash command in the input instead of
sending it on its own, ship a decodable Marketplace icon, and retry
transient registry failures when publishing.

- Updated dependencies
[[`45be822`](45be822),
[`45be822`](45be822)]:
  - @pythoughts/pythinker-code-sdk@0.11.0

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant