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
8 changes: 8 additions & 0 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ runs:
key: desktop-tools-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package.json', 'bun.lock', 'apps/desktop/package.json', 'apps/desktop/hutch.config.ts') }}
restore-keys: |
desktop-tools-v1-${{ runner.os }}-${{ runner.arch }}-
- name: 缓存 Turborepo 任务结果
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .turbo/cache
key: turbo-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('bun.lock', 'turbo.json') }}-${{ github.sha }}-${{ github.job }}
restore-keys: |
turbo-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('bun.lock', 'turbo.json') }}-
turbo-v1-${{ runner.os }}-${{ runner.arch }}-
- name: 从根目录安装依赖
shell: bash
env:
Expand Down
19 changes: 18 additions & 1 deletion .github/workflows/release-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
uses: ./.github/workflows/ci.yml

release:
name: 打包、验收并创建 Release 草稿
name: 打包、验收并发布 npm 包
needs: check
runs-on: ubuntu-24.04
timeout-minutes: 15
Expand All @@ -26,19 +26,31 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: 检查 npm 发布凭据
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
if [[ -z "$NPM_TOKEN" ]]; then
echo '::error::请在仓库 Actions Secrets 配置有 @jointarp/module-cli 发布权限的 NPM_TOKEN。'
exit 1
fi
- uses: ./.github/actions/setup
- name: 准备 CLI 兼容性验收运行时
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "22.12.0"
package-manager-cache: false
- name: 校验 tag 与 CLI 版本
id: version
run: |
bun run - <<'JS'
const { appendFileSync } = require('node:fs');
const { version } = require('./packages/module-cli/package.json');
if (process.env.GITHUB_REF_NAME !== `cli-v${version}`) {
throw new Error(`tag 必须为 cli-v${version}`);
}
const npmTag = version.split('+')[0].includes('-') ? 'next' : 'latest';
appendFileSync(process.env.GITHUB_OUTPUT, `npm-tag=${npmTag}\n`);
JS
- run: bun run --filter @jointarp/module-cli pack
- run: bun scripts/release/smoke.ts cli
Expand All @@ -53,3 +65,8 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: bash scripts/release/draft.sh release-assets
- name: 发布已验收的 npm 包
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TAG: ${{ steps.version.outputs.npm-tag }}
run: bun publish "release-assets/tarp-$GITHUB_REF_NAME.tgz" --registry https://registry.npmjs.org --access public --tag "$NPM_TAG"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ release/
.env
.env.*
!.env.example

.turbo/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ bun run dev
| `bun run package` | 打包桌面应用目录 |
| `bun run dist` | 生成桌面分发产物 |

类型检查与构建由 Turborepo 调度,可复用 CLI 和页面构建结果;缓存范围与 Actions 配置见[发布流程](docs/发布流程.md)。完整测试与桌面原生打包仍实际执行。

构建 CLI 后,可以直接用 Bun 校验模组:

```sh
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ GitHub Actions 的版本 tag、跨平台构建、签名配置和 Release 草稿

- `src/main/`:Electrobun 启动与桌面 RPC 入口。`config/` 负责用户配置;`modules/` 负责模组列表与导入;`sessions/` 接入本地房间资源与笔记接口;`game/` 管理本机模型配置、房间模型选择与订阅登录;`tts/` 维护语音服务。房间存档、聊天、状态、开局与 AI 执行位于 `packages/core/`,通用模组加载、校验和计算位于 `packages/module/`。
- `src/renderer/src/native-bridge.ts`:Electrobun 页面桥,连接 oRPC、桌面事件和本地图片服务。
- `src/shared/`:主进程和渲染进程之间的桌面契约。游戏共享契约从 `@tarp/core/shared/*` 导入,浏览器不引用 `node` 入口。
- `src/shared/`:主进程和渲染进程之间的桌面契约。游戏共享契约从 `@jointarp/core/shared/*` 导入,浏览器不引用 `node` 入口。
- `src/renderer/src/features/modules/`:模组库列表、打开模组与文档预览。
- `src/renderer/src/features/settings/`:设置导航、常规设置与外观设置。
- `src/renderer/src/components/`:跨功能复用的界面组件,`ui/` 存放基于 Base UI 或原生元素维护的基础组件。
Expand Down
5 changes: 3 additions & 2 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
"preview": "electrobun dev",
"package": "bun run scripts/desktop.ts package",
"dist": "bun run scripts/desktop.ts dist",
"prepare:desktop": "electrobun prepare"
"prepare:desktop": "electrobun prepare",
"build:renderer": "bun --bun x --no-install vite build"
},
"dependencies": {
"@base-ui/react": "^1.8.0",
"@colyseus/schema": "5.0.34",
"@earendil-works/pi-ai": "1.2.0",
"@earendil-works/pi-coding-agent": "1.2.0",
"@jointarp/core": "workspace:*",
"@jointarp/module": "workspace:*",
"@jointarp/module-cli": "workspace:*",
"@modelcontextprotocol/sdk": "^1.32.1",
Expand All @@ -34,7 +36,6 @@
"@tanstack/react-query": "^5.103.1",
"@tanstack/react-router": "^1.170.17",
"@tanstack/react-virtual": "^3.14.13",
"@tarp/core": "workspace:*",
"class-variance-authority": "^0.7.1",
"cn": "^0.2.6",
"es-toolkit": "^1.52.0",
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/scripts/desktop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ if (process.platform === "darwin") {
}
}
}
await run(["bun", "--bun", "x", "--no-install", "vite", "build"]);
await run(["bun", "../../scripts/tasks.ts", "run", "build:renderer", "--filter=./apps/desktop"]);
if (mode === "dev") {
// Vite 提供页面热更新;Electrobun 监听主进程并重启。
const vite = Bun.spawn(["bun", "--bun", "x", "--no-install", "vite"], {
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/scripts/runtime-smoke.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { strict as assert } from "node:assert";

import { SqliteDatabase } from "@tarp/core/node/storage/sqlite";
import { SqliteDatabase } from "@jointarp/core/node/storage/sqlite";
import { Kysely, SqliteDialect } from "kysely";
import { getQuickJS } from "quickjs-emscripten";

Expand Down
6 changes: 3 additions & 3 deletions apps/desktop/src/main/agent/host-system-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

import { roomResources } from "@tarp/core/node/agent/pi-runtime";
import { roomResources } from "@jointarp/core/node/agent/pi-runtime";
import {
defaultHostSystemPrompt,
hostInputInstructions,
} from "@tarp/core/shared/host-system-prompt";
import { narrativeInstructions } from "@tarp/core/shared/narrative";
} from "@jointarp/core/shared/host-system-prompt";
import { narrativeInstructions } from "@jointarp/core/shared/narrative";

import { readAppConfig, updateAppConfig } from "../config/app-config";
import { readGameDefaults, updateGameDefaults } from "../config/app-settings";
Expand Down
8 changes: 4 additions & 4 deletions apps/desktop/src/main/config/app-settings.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createIdentityId } from "@tarp/core/node/identity";
import { structuredFile, StructuredFileError } from "@tarp/core/node/storage/structured-file";
import { playerSchema } from "@tarp/core/shared/game";
import { createIdentityId } from "@jointarp/core/node/identity";
import { structuredFile, StructuredFileError } from "@jointarp/core/node/storage/structured-file";
import { playerSchema } from "@jointarp/core/shared/game";
import {
gameDefaultsSchema,
patchGameDefaults,
type GameDefaultsPatch,
} from "@tarp/core/shared/game-defaults";
} from "@jointarp/core/shared/game-defaults";
import { z } from "zod";

import { appConfigSchema } from "../../shared/app-config";
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/main/desktop-rpc-context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { GameContext } from "@jointarp/core/node";
import { os, ORPCError } from "@orpc/server";
import type { GameContext } from "@tarp/core/node";

import { AppConfigError } from "./config/app-config";
import type { LocalGameSettings } from "./game/local-settings";
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/main/desktop-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { gameRouter } from "@jointarp/core/node";
import { gameDefaultsPatchSchema } from "@jointarp/core/shared/game-defaults";
import { onError } from "@orpc/server";
import { RPCHandler } from "@orpc/server/message-port";
import { appConfigSchema } from "@shared/app-config";
import { gameRouter } from "@tarp/core/node";
import { gameDefaultsPatchSchema } from "@tarp/core/shared/game-defaults";
import { z } from "zod";

import { readAppConfig, updateAppConfig } from "./config/app-config";
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/main/desktop.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { isAbsolute, join } from "node:path";

import { ChatService, createPiRuntime } from "@jointarp/core/node";
import { narrationGapMs } from "@jointarp/core/shared/narration";
import { modulePreviewHash } from "@jointarp/module-cli/commands";
import { NativeMessagePort, type NativeBridge } from "@shared/native-bridge";
import { ChatService, createPiRuntime } from "@tarp/core/node";
import { narrationGapMs } from "@tarp/core/shared/narration";
import Electrobun, { BrowserView, Utils } from "electrobun/main";

import { readAppConfig, resolveAppConfigLocation } from "./config/app-config";
Expand Down
12 changes: 6 additions & 6 deletions apps/desktop/src/main/game/local-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { join } from "node:path";

import type { AuthContext, Provider } from "@earendil-works/pi-ai";
import { builtinProviders } from "@earendil-works/pi-ai/providers/all";
import { ORPCError } from "@orpc/server";
import { ModelRuntime, InMemoryModelsStore } from "@tarp/core/node/agent/models";
import { createIdentityId } from "@tarp/core/node/identity";
import { structuredFile, StructuredFileError } from "@tarp/core/node/storage/structured-file";
import { ModelRuntime, InMemoryModelsStore } from "@jointarp/core/node/agent/models";
import { createIdentityId } from "@jointarp/core/node/identity";
import { structuredFile, StructuredFileError } from "@jointarp/core/node/storage/structured-file";
import {
playerSchema,
customAiApis,
type AiSettings,
type ThinkingLevel,
type AvailableAiModel,
} from "@tarp/core/shared/game";
import { gameDefaultsSchema, type GameDefaultsPatch } from "@tarp/core/shared/game-defaults";
} from "@jointarp/core/shared/game";
import { gameDefaultsSchema, type GameDefaultsPatch } from "@jointarp/core/shared/game-defaults";
import { ORPCError } from "@orpc/server";
import { z } from "zod";

import {
Expand Down
6 changes: 3 additions & 3 deletions apps/desktop/src/main/game/room-ai-settings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { tmpdir } from "node:os";
import { join } from "node:path";

import { builtinProviders } from "@earendil-works/pi-ai/providers/all";
import { ChatService } from "@jointarp/core/node/game/chat-service";
import { readRoomSettings } from "@jointarp/core/node/sessions/room-settings";
import { createSession } from "@jointarp/core/node/sessions/session-store";
import { waitFor } from "@jointarp/module/testing/async";
import { writeTestFile as writeFile } from "@jointarp/module/testing/files";
import { ChatService } from "@tarp/core/node/game/chat-service";
import { readRoomSettings } from "@tarp/core/node/sessions/room-settings";
import { createSession } from "@tarp/core/node/sessions/session-store";

import { LocalGameSettings } from "./local-settings";
import { RoomAiSettingsStore } from "./room-ai-settings";
Expand Down
12 changes: 6 additions & 6 deletions apps/desktop/src/main/game/room-ai-settings.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ORPCError } from "@orpc/server";
import {
readCompactionSettingsFile,
saveCompactionSettingsFile,
} from "@tarp/core/node/game/compaction-settings";
import { readRoomSettings, updateRoomSettings } from "@tarp/core/node/sessions/room-settings";
import { readRoomState } from "@tarp/core/node/sessions/session-store";
import type { CompactionRole, CompactionSettings } from "@tarp/core/shared/compaction-settings";
import type { AvailableAiModel, RoomAiSettings, ThinkingLevel } from "@tarp/core/shared/game";
} from "@jointarp/core/node/game/compaction-settings";
import { readRoomSettings, updateRoomSettings } from "@jointarp/core/node/sessions/room-settings";
import { readRoomState } from "@jointarp/core/node/sessions/session-store";
import type { CompactionRole, CompactionSettings } from "@jointarp/core/shared/compaction-settings";
import type { AvailableAiModel, RoomAiSettings, ThinkingLevel } from "@jointarp/core/shared/game";
import { ORPCError } from "@orpc/server";

import type { LocalGameSettings } from "./local-settings";

Expand Down
46 changes: 23 additions & 23 deletions apps/desktop/src/main/game/room-state-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,45 @@ import { join } from "node:path";
import { MessageChannel } from "node:worker_threads";

import { Decoder } from "@colyseus/schema";
import type { WorkbenchView } from "@jointarp/module/creation-workbench";
import { writeTestFile as writeFile } from "@jointarp/module/testing/files";
import { createORPCClient } from "@orpc/client";
import { RPCLink } from "@orpc/client/message-port";
import type { ContractRouterClient } from "@orpc/contract";
import { RPCHandler } from "@orpc/server/message-port";
import { ChatService } from "@tarp/core/node/game/chat-service";
import { gameRouter } from "@tarp/core/node/game/game-router";
import { RoomStateEncoder } from "@tarp/core/node/game/room-state-encoder";
import { ChatService } from "@jointarp/core/node/game/chat-service";
import { gameRouter } from "@jointarp/core/node/game/game-router";
import { RoomStateEncoder } from "@jointarp/core/node/game/room-state-encoder";
import {
assertRoomOverlayAdmission,
projectLaunch,
projectEntities,
} from "@tarp/core/node/game/room-state-projection";
import { readCharacters } from "@tarp/core/node/sessions/character-db";
} from "@jointarp/core/node/game/room-state-projection";
import { readCharacters } from "@jointarp/core/node/sessions/character-db";
import {
characterSnapshot,
validateCharacterDraft,
} from "@tarp/core/node/sessions/character-store";
} from "@jointarp/core/node/sessions/character-store";
import {
materializeCharacter,
updateGameDocument,
writeGameDocument,
} from "@tarp/core/node/sessions/game-state";
import { launchState } from "@tarp/core/node/sessions/launch-store";
import { notifyRoomChanged } from "@tarp/core/node/sessions/room-changes";
import { roomDirectoryForDatabase } from "@tarp/core/node/sessions/session-paths";
} from "@jointarp/core/node/sessions/game-state";
import { launchState } from "@jointarp/core/node/sessions/launch-store";
import { notifyRoomChanged } from "@jointarp/core/node/sessions/room-changes";
import { roomDirectoryForDatabase } from "@jointarp/core/node/sessions/session-paths";
import {
createSession,
loadSessionModuleResources,
openSessionDatabase,
gameDirectoryForDatabase,
} from "@tarp/core/node/sessions/session-store";
import { documentRevision } from "@tarp/core/node/sessions/state-version";
import type { gameContract, RoomNotification } from "@tarp/core/shared/game";
import type { LaunchAction } from "@tarp/core/shared/launch";
import { ROOM_PROTOCOL_VERSION } from "@tarp/core/shared/room-state";
import { RoomStateSchema } from "@tarp/core/shared/room-state-schema";
import { createLaunchTestModule } from "@tarp/core/testing/launch-module";
} from "@jointarp/core/node/sessions/session-store";
import { documentRevision } from "@jointarp/core/node/sessions/state-version";
import type { gameContract, RoomNotification } from "@jointarp/core/shared/game";
import type { LaunchAction } from "@jointarp/core/shared/launch";
import { ROOM_PROTOCOL_VERSION } from "@jointarp/core/shared/room-state";
import { RoomStateSchema } from "@jointarp/core/shared/room-state-schema";
import { createLaunchTestModule } from "@jointarp/core/testing/launch-module";
import type { WorkbenchView } from "@jointarp/module/creation-workbench";
import { writeTestFile as writeFile } from "@jointarp/module/testing/files";
import { createORPCClient } from "@orpc/client";
import { RPCLink } from "@orpc/client/message-port";
import type { ContractRouterClient } from "@orpc/contract";
import { RPCHandler } from "@orpc/server/message-port";

import { RoomConnection } from "../../renderer/src/features/sessions/room-connection";
import {
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/main/game/subscription-auth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { randomUUID } from "node:crypto";

import { registerBunOAuthFlows } from "@earendil-works/pi-ai/bun-oauth";
import type { ModelRuntime } from "@tarp/core/node/agent/models";
import type { ModelRuntime } from "@jointarp/core/node/agent/models";

// 桌面主进程会被 Bun 打包,pi 的变量路径动态导入无法随包发布。
registerBunOAuthFlows();
Expand Down
8 changes: 4 additions & 4 deletions apps/desktop/src/main/mcp/playtest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { createServer } from "node:http";
import { join } from "node:path";

import { fauxAssistantMessage, fauxToolCall } from "@earendil-works/pi-ai";
import { ChatService, type Runtime } from "@jointarp/core/node";
import { updateGameDocument } from "@jointarp/core/node/sessions/game-state";
import { createSession, openSessionDatabase } from "@jointarp/core/node/sessions/session-store";
import { gameDefaultsSchema } from "@jointarp/core/shared/game-defaults";
import { waitFor } from "@jointarp/module/testing/async";
import { writeTestFile as writeFile } from "@jointarp/module/testing/files";
import { createTestModule } from "@jointarp/module/testing/test-module";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { ChatService, type Runtime } from "@tarp/core/node";
import { updateGameDocument } from "@tarp/core/node/sessions/game-state";
import { createSession, openSessionDatabase } from "@tarp/core/node/sessions/session-store";
import { gameDefaultsSchema } from "@tarp/core/shared/game-defaults";

import { PlaytestService, playtestCreateSchema } from "./playtest";
import { startPlaytestMcp } from "./server";
Expand Down
24 changes: 12 additions & 12 deletions apps/desktop/src/main/mcp/playtest.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { join, isAbsolute } from "node:path";

import { sameDocumentIdentity } from "@jointarp/module/document-path";
import { emptyFlowRun } from "@jointarp/module/flow";
import type { ChatService } from "@tarp/core/node";
import { readCharacters } from "@tarp/core/node/sessions/character-db";
import { gameDocumentViews } from "@tarp/core/node/sessions/game-state";
import type { ChatService } from "@jointarp/core/node";
import { readCharacters } from "@jointarp/core/node/sessions/character-db";
import { gameDocumentViews } from "@jointarp/core/node/sessions/game-state";
import {
readLaunchConfig,
readLaunchRoom,
saveLaunchProgress,
saveLaunchRoom,
} from "@tarp/core/node/sessions/launch-db";
import { patchRoomSettings, readRoomSettings } from "@tarp/core/node/sessions/room-settings";
} from "@jointarp/core/node/sessions/launch-db";
import { patchRoomSettings, readRoomSettings } from "@jointarp/core/node/sessions/room-settings";
import {
createSession,
deleteSession,
openSessionDatabase,
readRoomState,
roomDirectory,
} from "@tarp/core/node/sessions/session-store";
import { structuredFile } from "@tarp/core/node/storage/structured-file";
import { chatText } from "@tarp/core/shared/agent-message";
import { aiConfigSchema, type Player } from "@tarp/core/shared/game";
import type { GameDefaults } from "@tarp/core/shared/game-defaults";
} from "@jointarp/core/node/sessions/session-store";
import { structuredFile } from "@jointarp/core/node/storage/structured-file";
import { chatText } from "@jointarp/core/shared/agent-message";
import { aiConfigSchema, type Player } from "@jointarp/core/shared/game";
import type { GameDefaults } from "@jointarp/core/shared/game-defaults";
import { sameDocumentIdentity } from "@jointarp/module/document-path";
import { emptyFlowRun } from "@jointarp/module/flow";
import { z } from "zod";

export const playtestCreateSchema = z.strictObject({
Expand Down
Loading
Loading