Skip to content

Commit 5b2e1b8

Browse files
committed
fix: repair fallout from the legacy migration removal
Regenerate pnpm-lock.yaml so a frozen-lockfile install no longer fails on the deleted @pymodel/migration-legacy dependency, drop both deleted packages from the changeset ignore list and its documentation, correct the desktop guide (arm64 DMG name, tray animation runs during Host startup, signing wording), and restore the two non-migration assertions the cleanup removed: terminal tracking disposal on startup failure and a loud invalid-config error.
1 parent 5c949d7 commit 5b2e1b8

7 files changed

Lines changed: 73 additions & 43 deletions

File tree

‎.agents/skills/gen-changesets/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description: Use when generating changesets in the pythinker-code repository, in
99

1010
- `@pymodel/pythinker-code`: the CLI
1111

12-
All other `@pymodel/*` packages are treated as internal packages, including `@pymodel/pythinker-code-sdk`, `agent-core`, `kosong`, `kaos`, `pythinker-code-oauth`, `pythinker-telemetry`, and `migration-legacy`.
12+
All other `@pymodel/*` packages are treated as internal packages, including `@pymodel/pythinker-code-sdk`, `agent-core`, `kosong`, `kaos`, `pythinker-code-oauth`, and `pythinker-telemetry`.
1313

1414
## Core Rules
1515

‎.changeset/README.md‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,12 @@ All other workspace packages are private internal packages, are not published to
2222
- `@pymodel/pythinker-telemetry`
2323
- `@pymodel/pythinker-web`
2424
- `@pymodel/kosong`
25-
- `@pymodel/migration-legacy`
2625
- `@pymodel/protocol`
2726
- `@pymodel/server`
2827
- `@pymodel/server-e2e`
2928
- `@pymodel/dashboard`
3029
- `@pymodel/dashboard-server`
3130
- `@pymodel/dashboard-web`
32-
- `pythinker-migration-legacy`
3331

3432
Version impact from internal dependencies must be judged manually. The published artifacts for CLI and SDK bundle internal workspace packages into the artifact itself; runtime `dependencies` of published packages must not include any `@pymodel/*` internal workspace packages.
3533

‎.changeset/config.json‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@
1414
"@pymodel/pythinker-telemetry",
1515
"@pymodel/pythinker-web",
1616
"@pymodel/kosong",
17-
"@pymodel/migration-legacy",
1817
"@pymodel/protocol",
1918
"@pymodel/server",
2019
"@pymodel/server-e2e",
2120
"@pymodel/dashboard",
2221
"@pymodel/dashboard-server",
23-
"@pymodel/dashboard-web",
24-
"pythinker-migration-legacy"
22+
"@pymodel/dashboard-web"
2523
],
2624
"snapshot": {
2725
"useCalculatedVersion": true,

‎apps/pythinker-code/test/cli/run-shell.test.ts‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,34 @@ describe('runShell', () => {
495495
});
496496
});
497497

498+
it('surfaces an invalid target config as an error, not silently', async () => {
499+
mocks.loadTuiConfig.mockResolvedValue(tuiConfig());
500+
mocks.harnessGetConfig.mockRejectedValue(
501+
new Error('Invalid configuration in ~/.pythinker-code/config.toml'),
502+
);
503+
504+
// A broken config.toml must fail loudly before the TUI starts — otherwise the
505+
// user never learns their config is broken.
506+
await expect(
507+
runShell(
508+
{
509+
session: undefined,
510+
continue: false,
511+
rewindFiles: undefined,
512+
yolo: false,
513+
auto: false,
514+
plan: false,
515+
model: undefined,
516+
outputFormat: undefined,
517+
prompt: undefined,
518+
skillsDirs: [],
519+
},
520+
'1.2.3-test',
521+
),
522+
).rejects.toThrow('Invalid configuration');
523+
expect(mocks.tuiStart).not.toHaveBeenCalled();
524+
});
525+
498526
it('closes the harness when TUI startup fails', async () => {
499527
mocks.loadTuiConfig.mockResolvedValue(tuiConfig());
500528
mocks.tuiStart.mockRejectedValue(new Error('boom'));

‎apps/pythinker-code/test/tui/pythinker-tui-startup.test.ts‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ interface InitMainTuiDriver extends StartupDriver {
9090
initMainTui(): Promise<boolean>;
9191
}
9292

93+
interface StartFailureDriver extends StartupDriver {
94+
start(): Promise<void>;
95+
startEventLoop(): void;
96+
initMainTui(): Promise<boolean>;
97+
terminalFocusTrackingDispose?: () => void;
98+
}
99+
93100
interface PresentationDriver extends StartupDriver {
94101
readonly presentation: TuiPresentation;
95102
startEventLoop(): void;
@@ -2031,4 +2038,36 @@ describe('footer update status poll', () => {
20312038
rmSync(home, { recursive: true, force: true });
20322039
}
20332040
}, 30_000);
2041+
2042+
it('disposes terminal tracking when startup fails', async () => {
2043+
const harness = makeHarness();
2044+
const driver = makeDriver(harness, makeStartupInput()) as unknown as StartFailureDriver;
2045+
// pi-tui start/stop and focus tracking touch the real TTY — stub the I/O.
2046+
vi.spyOn(driver.state.ui, 'start').mockImplementation(() => {});
2047+
vi.spyOn(driver.state.ui, 'stop').mockImplementation(() => {});
2048+
vi.spyOn(driver.state.terminal, 'write').mockImplementation(() => {});
2049+
vi.spyOn(driver, 'initMainTui').mockRejectedValue(new Error('resume boom'));
2050+
2051+
// startEventLoop() only installs focus tracking once the terminal reports a
2052+
// width, so give it one — otherwise there is nothing to dispose and the
2053+
// assertion below would hold no matter what the teardown does.
2054+
const stdoutColumns = Object.getOwnPropertyDescriptor(process.stdout, 'columns');
2055+
Object.defineProperty(process.stdout, 'columns', { configurable: true, value: 80 });
2056+
try {
2057+
driver.startEventLoop();
2058+
expect(driver.terminalFocusTrackingDispose).toBeDefined();
2059+
2060+
await expect(driver.start()).rejects.toThrow('resume boom');
2061+
2062+
// The focus tracking installed by startEventLoop() must be torn down before
2063+
// the error propagates — not left active after the process exits.
2064+
expect(driver.terminalFocusTrackingDispose).toBeUndefined();
2065+
} finally {
2066+
if (stdoutColumns === undefined) {
2067+
Reflect.deleteProperty(process.stdout, 'columns');
2068+
} else {
2069+
Object.defineProperty(process.stdout, 'columns', stdoutColumns);
2070+
}
2071+
}
2072+
});
20342073
});

‎docs/guides/desktop.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Download the installer for your platform from the
1414

1515
| Platform | File |
1616
| --- | --- |
17-
| macOS | `Pythinker-<version>.dmg` |
17+
| macOS | `Pythinker-<version>-arm64.dmg` |
1818
| Windows | `Pythinker-<version>-x64-Setup.exe` |
1919

2020
- **macOS**: open the DMG and drag **Pythinker** into `Applications`.
@@ -26,7 +26,7 @@ There is no Linux desktop distribution at this time. On Linux, use the
2626

2727
::: tip Unsigned builds
2828
If a release is published without code-signing credentials, macOS Gatekeeper or Windows SmartScreen
29-
shows a warning at first launch. Signed builds do not show this warning.
29+
shows a warning at first launch. A signed build is much less likely to show one.
3030
:::
3131

3232
## First launch
@@ -45,7 +45,8 @@ For the directory layout, see [Data locations](../configuration/data-locations.m
4545

4646
- Closing the window **hides** it. The Host continues to run and your session stays alive.
4747
- The tray icon menu has two items: **Open Pythinker** shows the window again, and **Quit** stops
48-
the Host and closes the application. The tray icon animates while the agent works.
48+
the Host and closes the application. The tray icon animates while the Host starts, and becomes
49+
static when the Host is ready.
4950
- The window stays on the local Host origin. `http` and `https` links open in your system browser.
5051

5152
## Updates

‎pnpm-lock.yaml‎

Lines changed: 0 additions & 34 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)