Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/graduate-database-and-remote-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pymodel/pythinker-code": major
---

Remote Control is always available — `pythinker rc`, `pythinker web --remote-control` and `/remote-control` no longer need an experimental flag. Session indexing and global search move to the new `[database]` section: set `PYTHINKER_CODE_PERSISTENCE_MINIDB_READMODEL` (was `PYTHINKER_CODE_EXPERIMENTAL_PERSISTENCE_MINIDB_READMODEL`) and `PYTHINKER_CODE_SEARCH_WORKER` (was `PYTHINKER_CODE_EXPERIMENTAL_SEARCH_WORKER`), or `[database] base` and `[database] search` in `config.toml`.
5 changes: 5 additions & 0 deletions .changeset/graduate-subagent-model-pool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pymodel/pythinker-code": major
Comment thread
coderabbitai[bot] marked this conversation as resolved.
---

The subagent model pool is always available. Remove `PYTHINKER_CODE_EXPERIMENTAL_SECONDARY_MODEL` from your environment — it no longer does anything, and `[secondary_model]` takes effect with no opt-in.
5 changes: 5 additions & 0 deletions .changeset/remote-control-local-ui-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pymodel/pythinker-code": patch
---

The Remote Control banner's Local UI link now carries the server token, so it opens without a second sign-in.
5 changes: 5 additions & 0 deletions .changeset/remote-control-toggle-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pymodel/pythinker-code": minor
---

The server can now start and stop Remote Control while it runs, through `GET` and `POST /api/v1/remote-control`.
5 changes: 5 additions & 0 deletions .changeset/remote-control-tunnel-gzip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pymodel/pythinker-code": patch
---

Remote Control now gzips text, JSON, JavaScript, XML and SVG responses over the tunnel.
5 changes: 5 additions & 0 deletions .changeset/remove-now-template-variable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pymodel/pythinker-code": major
---

Remove the `${now}` variable from custom system prompt templates. Delete `${now}` from your `SYSTEM.md` and agent files — the agent still receives the current date.
5 changes: 5 additions & 0 deletions .changeset/search-index-self-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pymodel/pythinker-code": patch
---

Global search now rebuilds its index instead of staying broken when the stored data is corrupt or a write keeps failing.
5 changes: 5 additions & 0 deletions .changeset/silent-late-task-settlement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@pymodel/pythinker-code": patch
---

A background task that finishes after its agent is closed no longer emits stray task events.
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Adding an OpenAI-compatible provider requires **zero code changes** — just add
| `packages/acp-server` | Agent Client Protocol host over engine v2 | Drives the engine through a `klient` memory-transport facade. |
| `packages/pi-tui` | Vendored TUI library | Upstream fork with local divergences; tests run with `node --test`, not vitest. See its `AGENTS.md`. |
| `packages/protocol` | Shared REST + WS protocol schemas | Envelope, error codes, pagination, WS-control types. |
| `packages/remote-control` | Remote Control tunnel client | Registers this machine with a relay and forwards HTTP/WebSocket traffic to the local server, behind a machine-wide single-instance lock. Consumed by agent-gateway (the `/api/v1/remote-control` toggle) and the CLI (`pythinker web --remote-control`). |

The web bundle: `apps/pythinker-code/dist-web` is the committed, prebuilt bundle of `apps/pythinker-web` (built with `pnpm --filter @pymodel/pythinker-web run build` and copied via `scripts/copy-web-assets.mjs`). `apps/pythinker-code/scripts/check-web-assets.mjs` fails when the bundle is missing **or stale** (it compares a fingerprint of every `apps/pythinker-web` build input against the one recorded at copy time); it runs in pre-push, in the CLI `build`, and on `prepack`. Whenever you touch the web UI, run `pnpm run build:web` and commit the restaged bundle in the same change. `packages/server` and `packages/server-e2e` are empty leftover directories excluded from the workspace — not packages.

Expand Down
8 changes: 7 additions & 1 deletion apps/desktop/scripts/finalize-mac-artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,13 @@ export function finalizeMacArtifacts(options: FinalizeMacArtifactsOptions): void
.sort()
if (dmgs.length === 0) throw new Error(`No DMG artifacts found in ${options.distDir}`)

const manifestName = options.manifestName ?? DEFAULT_MAC_MANIFEST
// The workflow always passes the channel manifest positionally, so an unresolved
// channel output arrives as an empty string rather than a missing argument; `??`
// would keep it and read the distribution directory itself.
const manifestName =
options.manifestName === undefined || options.manifestName === ''
? DEFAULT_MAC_MANIFEST
: options.manifestName
const metadataPath = join(options.distDir, manifestName)
let metadata = readFileSync(metadataPath, 'utf8')
const credentialArgs = buildNotarytoolArguments(options.env)
Expand Down
26 changes: 26 additions & 0 deletions apps/desktop/tests/finalize-mac-artifacts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,32 @@ sha512: old
expect(readFileSync(join(distDir, 'nightly-mac.yml'), 'utf8')).toContain(`sha512: ${checksum}`)
})

it('falls back to the default manifest when the channel argument arrives empty', () => {
const distDir = mkdtempSync(join(tmpdir(), 'pythinker-mac-artifacts-'))
directories.push(distDir)
const filename = 'Pythinker-0.1.3-arm64.dmg'
const dmg = Buffer.from('empty argument dmg fixture')
writeFileSync(join(distDir, filename), dmg)
writeFileSync(join(distDir, 'latest-mac.yml'), `files:
- url: ${filename}
sha512: old
size: 1
path: ${filename}
sha512: old
`)

finalizeMacArtifacts({
distDir,
env: { APPLE_KEYCHAIN_PROFILE: 'pythinker-notary' },
log: () => {},
manifestName: '',
runCommand: () => ({ status: 0, stderr: '', stdout: '{"status":"Accepted"}' }),
})

const checksum = createHash('sha512').update(dmg).digest('base64')
expect(readFileSync(join(distDir, 'latest-mac.yml'), 'utf8')).toContain(`sha512: ${checksum}`)
})

it('prints and rejects a non-accepted notarytool result before stapling', () => {
const distDir = mkdtempSync(join(tmpdir(), 'pythinker-mac-artifacts-'))
directories.push(distDir)
Expand Down
2 changes: 1 addition & 1 deletion apps/pythinker-code/dist-web/.web-bundle-manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"sourceHash": "86bbfea2180a13d6184f7bb2bb2bf4f62f3ff4098cfd522de348482ef887d842",
"sourceHash": "3856336183464397291f1fe4b79cf621f9251cfe1d579884874392027f2c376c",
"sourceFileCount": 493
}
1 change: 1 addition & 0 deletions apps/pythinker-code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"@pymodel/pythinker-code-oauth": "workspace:^",
"@pymodel/pythinker-code-sdk": "workspace:^",
"@pymodel/pythinker-telemetry": "workspace:^",
"@pymodel/remote-control": "workspace:^",
"@pymodel/vis-server": "workspace:^",
"@pymodel/vis-web": "workspace:*",
"@types/qrcode": "^1.5.6",
Expand Down
5 changes: 2 additions & 3 deletions apps/pythinker-code/src/cli/sub/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import type { Command } from 'commander';
import { registerDeprecatedServerCommand } from './deprecated-server';
import { registerRotateTokenCommand } from './rotate-token';
import { buildWebCommand } from './run';
import { isRemoteControlEnabled } from './remote-control';

export function registerWebCommand(program: Command): void {
const web = buildWebCommand(
Expand All @@ -26,10 +25,10 @@ export function registerWebCommand(program: Command): void {
registerRotateTokenCommand(web);
buildWebCommand(
program
.command('rc', { hidden: !isRemoteControlEnabled() })
.command('rc')
.alias('remote')
.description(
'Run the local Pythinker server and open the web UI through Remote Control (experimental).',
'Run the local Pythinker server and open the web UI through Remote Control.',
),
{ forceRemoteControl: true },
);
Expand Down
Loading
Loading