Skip to content

Commit 3d9e678

Browse files
authored
Merge branch 'main' into changeset-release/main
2 parents 8a9fb9d + 45be822 commit 3d9e678

176 files changed

Lines changed: 4588 additions & 1555 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@pythoughts/pythinker-code": minor
3+
"@pythoughts/pythinker-code-sdk": minor
4+
---
5+
6+
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`.
7+
8+
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.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@pythoughts/pythinker-code": minor
3+
---
4+
5+
Resolve a workspace's skills without opening a session, so an editor panel can list them before its first message.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@pythoughts/pythinker-code-sdk": minor
3+
"@pythoughts/pythinker-code": patch
4+
---
5+
6+
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.

.changeset/tui-render-gate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@pythoughts/pythinker-code": patch
3+
---
4+
5+
Stop the fixed-layout TUI anchoring its first frames to the shell cursor, which pushed the panel border into scrollback.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"pythinker-code": patch
3+
---
4+
5+
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.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<br />
1111

1212
[![npm version](https://img.shields.io/npm/v/@pythoughts/pythinker-code?style=for-the-badge&logo=npm&logoColor=white&color=CB3837&label=pythinker-code)](https://www.npmjs.com/package/@pythoughts/pythinker-code)
13-
[![Downloads](https://img.shields.io/npm/dm/@pythoughts/pythinker-code?style=for-the-badge&logo=npm&logoColor=white&color=16a34a&label=downloads)](https://www.npmjs.com/package/@pythoughts/pythinker-code)
13+
[![Downloads](https://img.shields.io/npm/dm/@pythoughts/pythinker-code?style=for-the-badge&logo=npm&logoColor=white&color=2b89ff&label=downloads)](https://www.npmjs.com/package/@pythoughts/pythinker-code)
1414
[![Node.js](https://img.shields.io/badge/Node.js-26%2B-339933?style=for-the-badge&logo=nodedotjs&logoColor=white)](https://github.com/Pythoughts-labs/pythinker-code/blob/main/package.json)
1515
[![License: MIT](https://img.shields.io/badge/License-MIT-16a34a.svg?style=for-the-badge)](https://github.com/Pythoughts-labs/pythinker-code/blob/main/LICENSE)
1616
[![CI](https://img.shields.io/github/actions/workflow/status/Pythoughts-labs/pythinker-code/ci.yml?branch=main&label=CI&style=for-the-badge&logo=githubactions&logoColor=white)](https://github.com/Pythoughts-labs/pythinker-code/actions/workflows/ci.yml?query=branch%3Amain)

apps/pythinker-code/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
"web-tree-sitter": "0.25.10"
9696
},
9797
"devDependencies": {
98-
"@earendil-works/pi-tui": "^0.81.1",
98+
"@earendil-works/pi-tui": "^0.83.0",
9999
"@pythoughts/acp-adapter": "workspace:^",
100100
"@pythoughts/dashboard-server": "workspace:^",
101101
"@pythoughts/dashboard-web": "workspace:*",

apps/pythinker-code/src/cli/sub/provider.ts

Lines changed: 16 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,16 @@ import {
1717
CustomRegistryApiError,
1818
fetchCustomRegistry,
1919
type CustomRegistrySource,
20-
type ManagedPythinkerConfigShape,
20+
type ManagedKimiConfigShape,
2121
} from '@pythoughts/pythinker-code-oauth';
2222
import {
23-
applyCatalogProvider,
24-
catalogBaseUrl,
2523
catalogConnectionWire,
2624
catalogProviderModels,
2725
CatalogFetchError,
2826
createPythinkerHarness,
2927
DEFAULT_CATALOG_URL,
3028
fetchCatalog,
29+
importCatalogProvider,
3130
inferWireType,
3231
type Catalog,
3332
type CatalogProviderEntry,
@@ -366,74 +365,20 @@ export async function handleCatalogAdd(
366365
}
367366

368367
const harness = deps.getHarness();
369-
await harness.ensureConfigFile();
370-
371-
let config = await harness.getConfig();
372-
373-
// Capture defaults BEFORE `removeProvider`, because that call clears
374-
// `defaultModel` when it points at one of this provider's aliases (see
375-
// `core-impl.ts removePythinkerProvider`). Without this, re-importing an
376-
// already-configured provider would lose the user's previously-set default
377-
// even when `--default-model` is not supplied.
378-
const previousDefaultProvider = config.defaultProvider;
379-
const previousDefaultModel = config.defaultModel;
380-
const previousDefaultThinking = config.defaultThinking;
381-
382-
if (config.providers[providerId] !== undefined) {
383-
config = await harness.removeProvider(providerId);
384-
}
385-
386-
const baseUrl = catalogBaseUrl(entry, wire);
387-
// `applyCatalogProvider` always overwrites both `defaultModel` and
388-
// `defaultThinking`. The values we pass here are temporary; we restore
389-
// a consistent state in the post-apply block below.
390-
applyCatalogProvider(config, {
391-
providerId,
392-
catalogUrl: url,
393-
wire,
394-
baseUrl,
395-
apiKey: useEnvVar ? undefined : literalApiKey,
396-
apiKeyEnvVar: useEnvVar ? apiKeyEnvVar : undefined,
397-
models,
398-
selectedModelId: opts.defaultModel ?? '',
399-
thinking: false,
400-
});
401-
402-
// Resolve the final `defaultModel`:
403-
// - If the caller asked for one, `applyCatalogProvider` already set it.
404-
// - Else, restore the previous default ONLY when its alias still resolves
405-
// after the catalog refresh; the catalog may have dropped the old
406-
// model, in which case restoring would point default_model at a
407-
// non-existent alias and break the next session.
408-
if (opts.defaultModel === undefined) {
409-
const stillResolves =
410-
previousDefaultModel !== undefined &&
411-
config.models?.[previousDefaultModel] !== undefined;
412-
config.defaultModel = stillResolves ? previousDefaultModel : undefined;
368+
try {
369+
await importCatalogProvider(harness, {
370+
providerId,
371+
entry,
372+
catalogUrl: url,
373+
apiKey: useEnvVar ? undefined : literalApiKey,
374+
apiKeyEnvVar: useEnvVar ? apiKeyEnvVar : undefined,
375+
defaultModel: opts.defaultModel,
376+
});
377+
} catch (error) {
378+
deps.stderr.write(`${errorMessage(error)}\n`);
379+
deps.exit(1);
413380
}
414381

415-
// Mirror the defaultModel handling for defaultProvider: `removeProvider`
416-
// cleared it, and the catalog refresh may have dropped the provider id.
417-
config.defaultProvider =
418-
previousDefaultProvider !== undefined && config.providers[previousDefaultProvider] !== undefined
419-
? previousDefaultProvider
420-
: undefined;
421-
422-
// Always restore `defaultThinking` from what was there before — including
423-
// `undefined`. Persisting `false` when the user never set it would make
424-
// `resolveThinkingLevel` (agent-core/src/agent/config/thinking.ts) treat
425-
// it as an explicit "off" request and silently disable thinking, even
426-
// for thinking-capable models.
427-
config.defaultThinking = previousDefaultThinking;
428-
429-
await harness.setConfig({
430-
providers: config.providers,
431-
models: config.models,
432-
defaultProvider: config.defaultProvider,
433-
defaultModel: config.defaultModel,
434-
defaultThinking: config.defaultThinking,
435-
});
436-
437382
const displayName = entry.name ?? providerId;
438383
deps.stdout.write(
439384
`Imported ${displayName} (${providerId}) with ${String(models.length)} model${models.length === 1 ? '' : 's'} from ${url}.\n`,
@@ -572,8 +517,8 @@ function resolveApiKey(flag: string | undefined, env: NodeJS.ProcessEnv): string
572517
return undefined;
573518
}
574519

575-
function asManaged(config: PythinkerConfig): ManagedPythinkerConfigShape {
576-
return config as unknown as ManagedPythinkerConfigShape;
520+
function asManaged(config: PythinkerConfig): ManagedKimiConfigShape {
521+
return config as unknown as ManagedKimiConfigShape;
577522
}
578523

579524
function providerSourceLabel(provider: PythinkerConfig['providers'][string]): string {

apps/pythinker-code/src/cli/telemetry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createPythinkerDeviceId, PYTHINKER_CODE_PROVIDER_NAME } from '@pythoughts/pythinker-code-oauth';
1+
import { createPythinkerDeviceId, KIMI_CODE_PROVIDER_NAME } from '@pythoughts/pythinker-code-oauth';
22
import {
33
PythinkerAuthFacade,
44
loadRuntimeConfigSafe,
@@ -55,7 +55,7 @@ export function initializeCliTelemetry(options: InitializeCliTelemetryOptions):
5555
uiMode: options.uiMode,
5656
model: options.model ?? options.config.defaultModel,
5757
getAccessToken: async () =>
58-
(await options.harness.auth.getCachedAccessToken(PYTHINKER_CODE_PROVIDER_NAME)) ?? null,
58+
(await options.harness.auth.getCachedAccessToken(KIMI_CODE_PROVIDER_NAME)) ?? null,
5959
});
6060
if (options.bootstrap.firstLaunch) {
6161
options.harness.track('first_launch');
@@ -102,7 +102,7 @@ export function initializeServerTelemetry(
102102
version: options.version,
103103
uiMode: WEB_UI_MODE,
104104
model: config.defaultModel,
105-
getAccessToken: async () => (await auth.getCachedAccessToken(PYTHINKER_CODE_PROVIDER_NAME)) ?? null,
105+
getAccessToken: async () => (await auth.getCachedAccessToken(KIMI_CODE_PROVIDER_NAME)) ?? null,
106106
});
107107

108108
return {

apps/pythinker-code/src/constant/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const PYTHINKER_CODE_BANNER_DIR_NAME = 'banner';
3434
export const PYTHINKER_CODE_BANNER_STATE_FILE_NAME = 'state.json';
3535

3636
// Managed Pythinker auth provider key shared with OAuth/SDK config.
37-
export const DEFAULT_OAUTH_PROVIDER_NAME = 'managed:pythinker-code';
37+
export { KIMI_CODE_PROVIDER_NAME as DEFAULT_OAUTH_PROVIDER_NAME } from '@pythoughts/pythinker-code-oauth';
3838

3939
// SDK/core error code that tells the TUI to show a login-required startup
4040
// notice. Derived from sdk's ErrorCodes so a future rename in core

0 commit comments

Comments
 (0)