-
Notifications
You must be signed in to change notification settings - Fork 6
feat: desktop app with auto-update, telemetry, release pipeline, and site showcase #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
8cb219e
feat(desktop): scaffold the Pythinker desktop app package
elkaix 611ae7d
feat(desktop): supervise the local Pythinker server process
elkaix f0a4447
feat(desktop): add tray-owned window and quit lifecycle
elkaix e3c8971
feat(desktop): add the Electron main process with splash and tray
elkaix a791852
feat(desktop): add the mascot brand assets
elkaix 45c4efd
feat(desktop): stage the server runtime for packaging
elkaix 8cbb9d8
feat(desktop): add the macOS signing and notarization pipeline
elkaix 6e301f9
test(desktop): cover the server supervisor
elkaix b3ba232
test(desktop): cover window lifecycle and packaged runtime checks
elkaix de27b17
test(desktop): cover packaging configuration and release preflight
elkaix 7a2d9c1
docs(desktop): document development, packaging, and release
elkaix 949df66
chore: register the desktop app in the workspace
elkaix 3cbbd55
fix(cli): run on Node 20+ by gating the FFI re-exec on Node 26.4
elkaix 148188d
feat(web): inset the sidebar header on macOS desktop and add the masc…
elkaix 342f832
fix(agent-core): skip invalid sessions during listing instead of failing
elkaix e7b81bd
feat(web): periwinkle accent, desktop translucency, and a live mascot…
elkaix b84506e
fix(web): dedupe streamed transcript copies and keep paragraph breaks
elkaix 5659c33
feat(web): standardize the periwinkle accent and show the mascot on w…
elkaix b5457c7
fix(protocol): add synthetic prompt lifecycle events to the event schema
elkaix 58d17ac
fix(web): keep scoped descendants inside global desktop-platform sele…
elkaix 37b3cd5
fix(protocol): add question and approval lifecycle events to the schema
elkaix 32c82a5
feat(web): desktop sidebar, collapse choreography, and empty-state halo
elkaix 5cbfd00
feat(web): reference typography for the desktop app
elkaix b13ff20
feat(desktop): auto-update, update settings UI, and telemetry
elkaix 821f135
ci: add the desktop macOS release workflow
elkaix b9f8e4d
feat(site): add the Pythinker Desktop showcase section
elkaix 8abe06d
chore: add changesets for the desktop app branch
elkaix a7074c9
Merge branch 'main' into feat/desktop-app
elkaix 2dfd2db
feat(cli): paint the update notice in the status bar in the warning c…
elkaix 8ae5114
fix: address PR review findings
elkaix d897070
fix: address CodeRabbit review findings
elkaix 47aa019
chore: release the SDK event union additions as a major bump
elkaix File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@pymodel/pythinker-code": minor | ||
| --- | ||
|
|
||
| Match the desktop app's sidebar, collapse animation, empty-state visuals, and typography to the desktop design. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@pymodel/pythinker-code": minor | ||
| --- | ||
|
|
||
| Add a Desktop app section to web settings with automatic updates on by default, a manual update check, and a restart-to-update action. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@pymodel/pythinker-code": patch | ||
| --- | ||
|
|
||
| Fix sessions failing to load with an invalid event journal error after questions or approvals were resolved. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@pymodel/pythinker-code": patch | ||
| --- | ||
|
|
||
| Run on Node 20 and newer by only re-executing for FFI support on Node 26.4+. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@pymodel/pythinker-code-sdk": major | ||
| --- | ||
|
|
||
| Add question, approval, and prompt lifecycle events to the SDK session event types. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@pymodel/pythinker-code": patch | ||
| --- | ||
|
|
||
| Skip invalid sessions during listing instead of failing the whole list. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@pymodel/pythinker-code": patch | ||
| --- | ||
|
|
||
| Highlight the update notice in the terminal status bar with the warning color. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@pymodel/pythinker-code": minor | ||
| --- | ||
|
|
||
| Refresh the web UI accent color and show the animated mascot on workflow cards, the activity spinner, and the empty state. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@pymodel/pythinker-code": patch | ||
| --- | ||
|
|
||
| Fix duplicated streamed transcript copies and lost paragraph breaks in the web UI. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| name: Desktop Release | ||
|
|
||
| on: | ||
| push: | ||
| tags: ['desktop-v*'] | ||
| workflow_dispatch: {} | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| concurrency: | ||
| group: desktop-release-${{ github.ref }} | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| mac: | ||
| runs-on: macos-15 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # pinned from v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| persist-credentials: true | ||
|
|
||
| - uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # pinned from v6 | ||
|
|
||
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # pinned from v6 | ||
| with: | ||
| node-version-file: .nvmrc | ||
| cache: pnpm | ||
|
|
||
| - run: pnpm install --frozen-lockfile | ||
|
|
||
| - name: Stamp desktop version for tag builds | ||
| if: startsWith(github.ref, 'refs/tags/desktop-v') | ||
| env: | ||
| TAG_NAME: ${{ github.ref_name }} | ||
| run: | | ||
| export DESKTOP_VERSION="${TAG_NAME#desktop-v}" | ||
| node -e 'const fs = require("node:fs"); const path = "apps/desktop/package.json"; const packageJson = JSON.parse(fs.readFileSync(path, "utf8")); packageJson.version = process.env.DESKTOP_VERSION; fs.writeFileSync(path, `${JSON.stringify(packageJson, null, 2)}\n`);' | ||
|
|
||
| - name: Build workspace | ||
| run: pnpm --workspace-root run build | ||
|
|
||
| - name: Stage desktop runtime | ||
| working-directory: apps/desktop | ||
| run: node --import tsx scripts/stage-runtime.ts | ||
|
|
||
| # On a desktop-v* tag, --publish always creates or updates the draft-or-release | ||
| # for that tag; contents: write makes GITHUB_TOKEN sufficient. | ||
| # Without Developer ID signing secrets, electron-builder publishes an | ||
| # ad-hoc/self-signed app. macOS auto-update will not accept unsigned updates, | ||
| # but this still proves packaging and the feed shape. | ||
| - name: Package and publish desktop release | ||
| working-directory: apps/desktop | ||
| run: pnpm exec electron-builder --mac dmg zip --publish always | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| CSC_LINK: ${{ secrets.MAC_CSC_LINK }} | ||
| CSC_KEY_PASSWORD: ${{ secrets.MAC_CSC_KEY_PASSWORD }} | ||
| APPLE_ID: ${{ secrets.APPLE_ID }} | ||
| APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} | ||
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | ||
|
|
||
| - name: Upload macOS artifacts for manual runs | ||
| if: github.event_name == 'workflow_dispatch' | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pinned from v7 | ||
| with: | ||
| name: desktop-macos | ||
| path: | | ||
| apps/desktop/dist/*.dmg | ||
| apps/desktop/dist/*.zip | ||
| apps/desktop/dist/latest-mac.yml | ||
| if-no-files-found: error |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| # Pythinker Desktop | ||
|
|
||
| The desktop app supervises the existing loopback Web Host and keeps it alive from the system tray when its window is closed. | ||
|
|
||
| ## Development | ||
|
|
||
| Install dependencies, then use the single desktop development command. It builds the Host and client packages, Web frontend, and Electron main process before launching the application: | ||
|
|
||
| ```sh | ||
| pnpm run dev:desktop | ||
| ``` | ||
|
|
||
| Closing the window hides it. Use the tray menu to restore the window or quit the application. Explicit quit waits for the Host process to stop and escalates termination after the bounded Host grace period. | ||
|
|
||
| The desktop app accepts only the readiness URL emitted by `pythinker server run` for `127.0.0.1` or `localhost`. Navigation stays on that origin; HTTP and HTTPS links open in the system browser. | ||
|
|
||
| Native chrome follows the host platform. macOS uses a frameless inset title bar, traffic lights, and sidebar vibrancy; its collapsed sidebar is 90px wide, with centered controls whose top edge aligns with the expanded logo row below the traffic lights. Windows retains its system frame, shadow, resize and Snap behavior, and Windows 11 rounded corners while a hidden title bar places the native caption buttons in the Session header's first row; the Windows sidebar has no traffic-light inset. The empty part of that row remains draggable, its controls remain clickable, and a resident drag band covers the same row when no Session header is visible. Windows acrylic and macOS vibrancy reach only the sidebar, while conversation and details stay opaque. Linux keeps a frameless window and an opaque sidebar fallback. | ||
|
|
||
| ## Packaging | ||
|
|
||
| The local packaging command performs the complete repository build, stages the Host's closed production dependency tree, and creates an unpacked application for the current platform. A separate manual build is not required: | ||
|
|
||
| ```sh | ||
| pnpm run package:desktop | ||
| ``` | ||
|
|
||
| Packaged applications run the staged `@pymodel/pythinker-code` CLI in a separate process through Electron's Node mode. The application therefore retains the supervised-Host lifecycle without shipping a second Node executable. An `afterPack` check rejects the package before signing when the staged CLI entry or Web frontend entry is absent. Both macOS and Windows use the exact tracked `apps/desktop/build/icon.png` source; the repository does not preprocess or commit platform-specific icon variants. | ||
|
|
||
| ### Signed macOS DMG | ||
|
|
||
| The macOS distribution command requires a valid `Developer ID Application` identity whose certificate and private key are both installed in the build user's Keychain. It also requires one complete notarization credential source. A Keychain profile keeps the app-specific password out of the repository and shell history: | ||
|
|
||
| ```sh | ||
| xcrun notarytool store-credentials "pythinker-notary" --apple-id "<Apple ID>" --team-id "<Team ID>" | ||
| ``` | ||
|
|
||
| `notarytool` requests the secret interactively. Build the signed, hardened-runtime, notarized DMG with the stored profile: | ||
|
|
||
| ```sh | ||
| APPLE_KEYCHAIN_PROFILE=pythinker-notary pnpm run dist:mac:desktop | ||
| ``` | ||
|
|
||
| An existing secrets file can supply `MAC_CERT_P12_BASE64`, `MACOS_SIGN_IDENTITY`, `CSC_KEY_PASSWORD`, `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, and `APPLE_TEAM_ID` without importing the certificate into the persistent Keychain: | ||
|
|
||
| ```sh | ||
| node --env-file=/absolute/path/to/macos-signing-secrets.env --import tsx apps/desktop/scripts/release-mac.ts | ||
| ``` | ||
|
|
||
| Electron Builder imports that Base64 PKCS#12 certificate into its temporary Keychain and removes it when the build finishes. The wrapper keeps signing and notarization variables out of the repository-build and runtime-staging subprocesses, then passes them only to Electron Builder. The secrets file and its path are never tracked. | ||
|
|
||
| The release preflight runs before the repository build. It fails if the host is not macOS, the supplied identity is not a `Developer ID Application` identity, signing credentials are incomplete, signing discovery is disabled, or notarization credentials are missing or incomplete. Without the PKCS#12 group, it requires a usable `Developer ID Application` identity and private key in the Keychain. Instead of a Keychain profile, the command accepts the complete Apple ID group (`APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, and `APPLE_TEAM_ID`) or App Store Connect API key group (`APPLE_API_KEY`, `APPLE_API_KEY_ID`, and `APPLE_API_ISSUER`). | ||
|
|
||
| After a successful build, mount the generated DMG and verify the installed application signature, Gatekeeper assessment, and stapled notarization ticket: | ||
|
|
||
| ```sh | ||
| DMG_PATH="$(find apps/desktop/dist -maxdepth 1 -type f -name '*.dmg' -print -quit)" | ||
| MOUNT_POINT="$(mktemp -d)" | ||
| hdiutil attach "$DMG_PATH" -mountpoint "$MOUNT_POINT" -nobrowse -readonly | ||
| APP_PATH="$MOUNT_POINT/Pythinker.app" | ||
| codesign --verify --deep --strict --verbose=2 "$APP_PATH" | ||
| spctl --assess --type execute --verbose=4 "$APP_PATH" | ||
| xcrun stapler validate "$APP_PATH" | ||
| hdiutil detach "$MOUNT_POINT" | ||
| rmdir "$MOUNT_POINT" | ||
| ``` | ||
|
|
||
| ## Known limitations | ||
|
|
||
| The first desktop assembly uses a loopback HTTP Host. The renderer and Host protocol remain unchanged so the application can replace the transport with the IPC carrier reserved by the GUI architecture without changing product features. | ||
|
|
||
| The signed installer path currently targets macOS. Windows and Linux packaging creates unpacked applications; their installer formats and distribution signing remain release work. | ||
|
|
||
| ## Model Experience | ||
|
|
||
| The desktop shell does not add model-visible input. The reused Web profile continues to own its existing Web runtime context. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| { | ||
| "name": "@pymodel/pythinker-desktop", | ||
| "description": "Pythinker desktop application with tray-owned Host lifecycle", | ||
| "version": "0.1.0", | ||
| "private": true, | ||
| "type": "module", | ||
| "main": "dist/main.js", | ||
| "scripts": { | ||
| "build": "tsc -p tsconfig.json && tsdown", | ||
| "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tests/tsconfig.json", | ||
| "dev": "pnpm -C ../pythinker-code run build && tsc -p tsconfig.json && tsdown && electron .", | ||
| "package": "pnpm --workspace-root run build && node --import tsx scripts/stage-runtime.ts && electron-builder --dir", | ||
| "dist": "pnpm --workspace-root run build && node --import tsx scripts/stage-runtime.ts && electron-builder", | ||
| "dist:mac": "node --import tsx scripts/release-mac.ts" | ||
| }, | ||
| "license": "MIT", | ||
| "devDependencies": { | ||
| "@pymodel/pythinker-telemetry": "workspace:*", | ||
| "@types/node": "^26.1.2", | ||
| "electron": "43.4.0", | ||
| "electron-builder": "26.15.3", | ||
| "electron-updater": "^6.8.9", | ||
| "tsdown": "0.22.3", | ||
| "typescript": "6.0.3", | ||
| "vitest": "4.1.9" | ||
| }, | ||
| "build": { | ||
| "appId": "com.pythinker.desktop", | ||
| "productName": "Pythinker", | ||
| "publish": [ | ||
| { | ||
| "provider": "github", | ||
| "owner": "PyModel", | ||
| "repo": "pythinker-code" | ||
| } | ||
| ], | ||
| "afterPack": "./scripts/verify-packaged-runtime.ts", | ||
| "asar": true, | ||
| "files": [ | ||
| "dist/main.js", | ||
| "dist/preload.cjs", | ||
| "package.json" | ||
| ], | ||
| "extraResources": [ | ||
| { | ||
| "from": "resources", | ||
| "to": "desktop-resources" | ||
| }, | ||
| { | ||
| "from": "runtime-host/package.json", | ||
| "to": "host/package.json" | ||
| }, | ||
| { | ||
| "from": "runtime-host/node_modules", | ||
| "to": "host/node_modules" | ||
| } | ||
| ], | ||
| "mac": { | ||
| "category": "public.app-category.developer-tools", | ||
| "hardenedRuntime": true, | ||
| "icon": "build/icon.png", | ||
| "notarize": true, | ||
| "target": [ | ||
| "dir" | ||
| ] | ||
| }, | ||
| "win": { | ||
| "icon": "build/icon.png", | ||
| "target": [ | ||
| "dir" | ||
| ] | ||
| }, | ||
| "linux": { | ||
| "category": "Development", | ||
| "target": [ | ||
| "dir" | ||
| ] | ||
| } | ||
| } | ||
| } | ||
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| <!doctype html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="utf-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
| <style> | ||
| :root, | ||
| body { | ||
| width: 100%; | ||
| height: 100%; | ||
| margin: 0; | ||
| } | ||
|
|
||
| body { | ||
| display: grid; | ||
| place-items: center; | ||
| overflow: hidden; | ||
| background: transparent; | ||
| } | ||
|
|
||
| img { | ||
| width: 192px; | ||
| height: 208px; | ||
| object-fit: contain; | ||
| image-rendering: pixelated; | ||
| } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <img id="mascot" src="idle-00.png" alt="Pythinker"> | ||
| <script> | ||
| const frames = Array.from({ length: 6 }, (_, index) => `idle-${String(index).padStart(2, '0')}.png`) | ||
| const mascot = document.getElementById('mascot') | ||
| let frame = 0 | ||
| setInterval(() => { | ||
| frame = (frame + 1) % frames.length | ||
| mascot.src = frames[frame] | ||
| }, 140) | ||
| </script> | ||
| </body> | ||
| </html> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "name": "@pymodel/pythinker-desktop-runtime", | ||
| "description": "Dependency-only deploy root for the packaged desktop Host", | ||
| "version": "0.0.0", | ||
| "private": true, | ||
| "type": "module", | ||
| "dependencies": { | ||
| "@pymodel/pythinker-code": "workspace:*" | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.