Compare commits

..

12 Commits

Author SHA1 Message Date
kdletters 9107d887ed 补充 Cocos 内置编辑器能力说明
在 DirectProject 提示词中加入已核对的 Cocos 场景和资源操作示例

明确先查询真实 UUID 与状态再执行单项修改并回读

更新 Cocos 插件 README 的 Agent 能力与 JavaScript 用法
2026-09-13 00:13:28 +08:00
kdletters 7605250697 修复打开项目时的同步阻塞
将项目目录检查、manifest、revision 和 Planning V2 hydrate 移到 blocking worker

保留同步核心函数供单元测试复用并更新测试调用

同步更新项目打开链路技术方案
2026-09-13 00:04:17 +08:00
kdletters 1be6e6756c 修复 Cocos 内置桥接与客户端项目打开链路
修复 Cocos 内置插件提示词,禁止回退到项目内 MCP 扩展

移除 agc_cocos_execute 对项目写锁的无关依赖

将项目对话读取移到 blocking worker,避免客户端窗口阻塞

为 Windows 开发与发行构建默认启用 Cocos 编辑器执行能力

补充 Cocos Inspector 引导、桥接协议和客户端回归验证
2026-09-12 23:24:45 +08:00
kdletters fd904ea144 修复 DirectProject 写入锁竞争并开启 Cocos 编辑器执行
DirectProject 历史落盘与 Codex 返回记录改用项目写锁有界等待,不再零等待失败拖垮整轮

Codex 返回记录取锁改到阻塞线程池执行,避免占用 runtime worker

agc_write_file 增加取锁/写入/revision 分段计时日志,用于定位长时间持锁

Windows dev 构建默认启用 cocos-editor-execute,使 Agent 具备 agc_cocos_execute

补充 start-tauri-dev 参数单测与历史落盘等待回归用例
2026-09-11 23:25:37 +08:00
kdletters 299877b197 修复 Tauri dev 插件资源自触发重建
build.rs 只在内容变化时落盘插件资源,避免构建产物触发下一轮重建

新增应用目录与 src-tauri 的 .taurignore,把 resources/plugins 排除出 dev 监听
2026-09-11 23:25:31 +08:00
kdletters b67cb18b45 接入 Cocos 项目识别与导入
完善 Cocos Creator 项目识别、导入和 Agent 目录初始化

补充打开项目流程、契约、测试与文档
2026-09-11 19:56:34 +08:00
kdletters 8ba9835d10 合并远端 master 最新修改
保留 AGC 插件系统与 Cocos 适配改动
合并远端项目写锁等待与持锁方诊断修复
同步远端项目锁、配置和测试更新
2026-09-11 11:42:23 +08:00
kdletters 02ff914bd3 修复内置插件跨进程开关与不确定执行阻断
让 Runner 和 CLI 查询持久化开关并即时感知 GUI 状态更新
让隔离 MCP 经现有工具桥获取可用工具,并将开关纳入会话缓存标识
在执行入口复查禁用状态,固定原生函数缓存构建使用的工具快照
修复损坏开关文件保存成功后仍保持关闭的状态
保留插件执行结果不确定的结构化回执和宿主适配器阻断,拒绝并发积压与自动重发
新增跨进程工具目录、热切换、坏文件恢复及不确定执行回归测试并同步文档
2026-09-10 21:37:51 +08:00
kdletters dd36de3aa6 新增 AGC 内置插件模式与插件工作区
- 新增 plugins/ 插件工作区及 agc-cocos-editor 插件包,Cocos 直连模块从宿主源码树迁入插件包
- 新增 server-rs/crates/editor-adapter-api 通用编辑器适配器契约,宿主只保留适配器注册与 RPC 路由
- 新增内置插件登记表与可用开关,状态持久化在 AppData extensions/builtin-plugins.json,状态文件损坏时失败关闭
- 禁用内置插件时先停止进程并拒绝启动,同时从 Runtime 工具目录、工具策略快照、原生函数目录与 DirectProject 工具面移除对应工具
- 插件宿主新增 plugins/ 工作区扫描,内置插件优先于同名 AppData 导入插件,前端只提供可用开关而不提供重命名和卸载入口
- 编辑器操作统一经 host.rpc 路由到插件包自带的 native 适配器,并删除 Cocos 专属 Tauri 命令
- 修正 Windows 打包与开发态 payload 路径,随包映射 plugins 工作区资源
- 同步插件、Cocos 桥接、实施计划文档与 decision log
2026-09-10 20:00:02 +08:00
kdletters 9d2ad69a75 新增 AGC Cocos 直连模块
新增独立 crate server-rs/crates/cocos-editor-bridge:Creator 主进程发现与项目/PID 身份校验、named pipe 命令协议、可选 Windows DLL 注入,默认 feature 全部关闭。
新增 Creator 主进程内 payload:在 \\.\pipe\genarrative-cocos-editor-{pid} 上串行提供 ping/status/execute,execute 只接受有界 JavaScript 函数体,结果不确定时返回 ExecutionUncertain 并禁止自动重放。
AGC 新增 cocos_editor 模块与 prepare_cocos_editor_injection、inject_cocos_editor、ping_cocos_editor、status_cocos_editor、execute_cocos_editor_code 五条命令,注入只加载随包资源目录中的 DLL。
AGC 新增 cocos-editor、cocos-editor-execute、cocos-editor-injection 三层 feature 与资源映射,Windows 构建把 bridge DLL 暂存到 resources/cocos-editor-bridge,并改为按 Cargo profile 目录查找产物 DLL。
Runtime 新增 cocos.editor.execute:同步工具策略快照、并行账本、隔离 Agent 拒绝表、工具描述与动作审计,审计只记录代码长度与 SHA-256。
DirectProject 的 agc_tools 新增 agc_cocos_execute,只接收 code,复用项目写锁和当前项目权限,结果不确定时阻断后续调用。
共享契约新增 cocos.editor.execute(confirm 权限),当前分支命令契约从 64 条更新为 65 条。
新增技术方案文档与决策记录,并在文档索引登记;resources/cocos-editor-bridge 仅提交占位与 .gitignore,生成的 DLL 不入库。
移植到 codex/agc-agent-plugins 的适配:命令契约长度、Tauri 未调用命令 allowlist 与 Windows 资源清单校验随当前分支基线同步更新。
2026-09-10 16:50:49 +08:00
kdletters 7df526868c 合并远端 master 到 codex/agc-agent-plugins
合并远端 master 的 AGC 启动、进程复用与项目写锁回收修复
合并远端 master 的开发脚本、运维文档与项目记忆更新
保留本分支的通用插件宿主、插件宿主服务与 AGC Plugin SDK 改动
2026-09-10 16:33:42 +08:00
kdletters 3c1711c7df 新增 AGC 通用插件宿主与 SDK
统一 Agent Plugin、Skill、MCP 的来源索引和启停状态
新增通用进程宿主、JSON-RPC、能力注册、权限审计与面板挂载
新增 AGC Plugin SDK 与标准 plugin.json 解析支持
保留 EditorAdapter 扩展点,不内置具体编辑器适配器
补充运行时设置界面、项目上下文同步和定向测试
同步更新插件方案、DirectProject、workspace 与项目记忆文档
2026-09-10 13:37:27 +08:00
212 changed files with 10570 additions and 13292 deletions
-31
View File
@@ -232,37 +232,6 @@ jobs:
done
done
- name: Prepare standalone Rust crate dependencies
shell: bash
run: |
set -euo pipefail
# agent-runtime-core / agent-runtime-orchestration 被 server-rs/Cargo.toml 的
# exclude 排除,不参与上面的 workspace 锁文件,因此上面那次锁定 fetch 覆盖不到它们;
# 而 check:native-shells 会经 agent-runtime-*:check 用 `cargo test --manifest-path`
# 单独跑这两个 crate。不在这里预热的话,这两条测试会在测试阶段自己
# `Updating crates.io index`crates.io 一抖动整条 native shell 作业就红
# (见 #327 / PR #316 run 1950)。
# 两个 crate 都没有提交 Cargo.lock,所以这里只能做不带锁标志的 fetch:
# 加锁标志会因为缺少锁文件直接失败。生成的 Cargo.lock 落在两个 crate 目录内,
# 已被各自的 .gitignore 忽略,只留在容器里;随后的测试阶段因此能用锁定版本
# 解析,不再触碰 registry index。
for manifest_path in \
server-rs/crates/agent-runtime-core/Cargo.toml \
server-rs/crates/agent-runtime-orchestration/Cargo.toml; do
for attempt in $(seq 1 5); do
if cargo fetch \
--target x86_64-unknown-linux-gnu \
--manifest-path "${manifest_path}"; then
break
fi
if [[ "${attempt}" -eq 5 ]]; then
echo "standalone crate dependency fetch failed after 5 attempts: ${manifest_path}" >&2
exit 1
fi
sleep $((attempt * 2))
done
done
- name: Run native shell gates
run: npm run check:native-shells
+2
View File
@@ -40,6 +40,8 @@ temp*build*/
/apps/ai-game-creator-shell/src-tauri/resources/codex/win-x64/codex-path/
/apps/ai-game-creator-shell/src-tauri/resources/codex/win-x64/codex-resources/
/apps/ai-game-creator-shell/src-tauri/resources/codex/win-x64/codex-package.json
/apps/ai-game-creator-shell/src-tauri/resources/plugins/
/plugins/agc-cocos-editor/native/payload/
/apps/ai-game-creator-shell/logs/
/apps/ai-game-creator-shell/.llm-drafts/
/apps/ai-game-creator-shell/game-creator.config.local.json
+4
View File
@@ -0,0 +1,4 @@
# resources/plugins 由 build.rs 从 plugins/ 复制生成,属于构建产物。
# 它在 dev 监听范围内,重新生成会让 Tauri dev 误判为源码改动而触发
# “构建 -> 监听 -> 再构建”的自触发循环。
resources/plugins/
@@ -4,6 +4,11 @@ import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import {
defaultEditorFeatures,
withDefaultCargoFeatures,
} from './cargo-features.mjs';
const appRoot = fileURLToPath(new URL('..', import.meta.url));
const defaultReleaseTarget = 'x86_64-pc-windows-msvc';
const releaseTarget =
@@ -159,10 +164,30 @@ export async function prepareReleaseVersion() {
return nextVersion;
}
export function runTauriBuild(args = []) {
export function buildTauriBuildArguments(
args = [],
target = releaseTarget,
platform = process.platform,
) {
const noBundle = args.includes('--no-bundle');
const hasTarget = args.includes('--target');
const targetArgs = noBundle || hasTarget ? [] : ['--target', releaseTarget];
const targetIndex = args.indexOf('--target');
const explicitTarget =
targetIndex >= 0
? args[targetIndex + 1]
: args
.find((value) => value.startsWith('--target='))
?.slice('--target='.length);
const targetArgs = noBundle || explicitTarget ? [] : ['--target', target];
const features = defaultEditorFeatures(
explicitTarget || (noBundle ? platform : target),
);
return [
'build',
...withDefaultCargoFeatures([...targetArgs, ...args], features),
];
}
export function runTauriBuild(args = []) {
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
const result = spawnSync(
npmCommand,
@@ -172,9 +197,7 @@ export function runTauriBuild(args = []) {
'exec',
'tauri',
'--',
'build',
...targetArgs,
...args,
...buildTauriBuildArguments(args),
],
{ cwd: appRoot, stdio: 'inherit', shell: process.platform === 'win32' },
);
@@ -0,0 +1,24 @@
/** 默认桌面能力;显式 feature 参数优先,不把应用参数当 Cargo 参数。 */
export function withDefaultCargoFeatures(argv, features) {
const separator = argv.indexOf('--');
const cargoArgs = separator < 0 ? argv : argv.slice(0, separator);
if (
!features.length ||
cargoArgs.some(
(value) =>
value === '--features' ||
value === '-f' ||
value.startsWith('--features=') ||
/^-f.+/u.test(value),
)
) {
return argv;
}
return [`--features=${features.join(',')}`, ...argv];
}
export function defaultEditorFeatures(target) {
return target === 'win32' || target.includes('windows')
? ['cocos-editor-execute']
: [];
}
@@ -0,0 +1,49 @@
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { buildTauriBuildArguments } from './build-release.mjs';
import { withDefaultCargoFeatures } from './cargo-features.mjs';
test('Windows release includes the same editor feature as development', () => {
assert.deepEqual(
buildTauriBuildArguments([], 'x86_64-pc-windows-msvc', 'win32'),
[
'build',
'--features=cocos-editor-execute',
'--target',
'x86_64-pc-windows-msvc',
],
);
assert.deepEqual(
buildTauriBuildArguments(
['--no-bundle'],
'x86_64-pc-windows-msvc',
'linux',
),
['build', '--no-bundle'],
);
assert.deepEqual(
buildTauriBuildArguments(['--target=aarch64-apple-darwin']),
['build', '--target=aarch64-apple-darwin'],
);
});
test('explicit Cargo features override defaults in every supported spelling', () => {
for (const args of [
['--features', 'custom'],
['--features=custom'],
['-f', 'custom'],
['-fcustom'],
]) {
assert.deepEqual(
withDefaultCargoFeatures(args, ['cocos-editor-execute']),
args,
);
}
assert.deepEqual(
withDefaultCargoFeatures(
['--', '--features=app'],
['cocos-editor-execute'],
),
['--features=cocos-editor-execute', '--', '--features=app'],
);
});
@@ -114,10 +114,19 @@ const allowedUncalledTauriCommands = [
'open_game_creator_launcher_window',
'open_game_creator_workspace_window',
'read_direct_project_conversation',
'reset_design_agent_session',
'stop_local_game_preview_if_matches',
'start_game_creator_external_mcp',
'stop_game_creator_external_mcp',
'list_agc_plugins',
'list_agc_extensions',
'refresh_agc_plugins',
'start_agc_plugin',
'stop_agc_plugin',
'reload_agc_plugin',
'call_agc_plugin',
'read_agc_plugin_panel',
'set_agc_plugin_project_path',
'set_agc_plugin_enabled',
];
const sourceExtensions = new Set([
'.json',
@@ -1286,10 +1295,7 @@ if (tauriConfig.identifier !== 'world.genarrative.ai-game-creator') {
throw new Error('AI game creator shell identifier drifted');
}
const expectedBundledDesignAgentResources = {
'design-agent': 'design-agent',
};
const expectedBundledCodexResources = {
const expectedBundledWindowsResources = {
'resources/codex/win-x64/bin/codex.exe': 'codex/win-x64/bin/codex.exe',
'resources/codex/win-x64/bin/codex-code-mode-host.exe':
'codex/win-x64/bin/codex-code-mode-host.exe',
@@ -1303,34 +1309,18 @@ const expectedBundledCodexResources = {
'codex/win-x64/codex-package.json',
'resources/codex/win-x64/NOTICE.md': 'codex/win-x64/NOTICE.md',
'resources/codex/win-x64/manifest.json': 'codex/win-x64/manifest.json',
'resources/plugins': 'plugins',
};
assert.deepEqual(
tauriConfig.bundle?.resources,
expectedBundledDesignAgentResources,
'AI game creator shell base Tauri config must bundle the design-agent resource pack',
);
for (const key of Object.keys(tauriConfig.bundle?.resources ?? {})) {
if (String(key).includes('codex')) {
throw new Error(
'AI game creator shell base Tauri config must not require Windows-only Codex resources',
);
}
if (tauriConfig.bundle?.resources !== undefined) {
throw new Error(
'AI game creator shell base Tauri config must not require Windows-only Codex resources',
);
}
assert.deepEqual(
windowsTauriConfig.bundle?.resources,
expectedBundledCodexResources,
'AI game creator shell Windows Tauri config must bundle the complete pinned Codex resource set',
expectedBundledWindowsResources,
'AI game creator shell Windows Tauri config must bundle the complete pinned Codex resource set and Cocos bridge payload directory',
);
if (
Object.prototype.hasOwnProperty.call(
windowsTauriConfig.bundle?.resources ?? {},
'design-agent',
)
) {
throw new Error(
'design-agent resource pack must not be mixed into the Windows Codex sidecar bundle',
);
}
if (windowsTauriConfig.bundle?.useLocalToolsDir !== true) {
throw new Error(
'AI game creator shell Windows Tauri config must cache bundling tools in the project target directory',
@@ -436,6 +436,10 @@ function spawnChild(command, args, options, spawnImpl = spawn) {
const child = spawnImpl(command, args, {
...options,
shell: useShell,
// npm.cmd and the Windows shell otherwise create a visible console for
// every service in the dev stack. Their stdout/stderr is already inherited
// by the launcher, so no separate terminal window is useful.
windowsHide: process.platform === 'win32' ? true : options.windowsHide,
// POSIX 下让每个长驻服务拥有独立进程组,退出时可以连同 npm、
// Node、Cargo 及其子进程一起清理,避免残留订阅任务持续刷日志。
detached: isPosix,
@@ -1,6 +1,7 @@
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { withDefaultCargoFeatures } from './cargo-features.mjs';
import {
readAgcDevEndpoint,
resolveAgcDevEndpoint,
@@ -20,10 +21,6 @@ import {
const appRoot = fileURLToPath(new URL('..', import.meta.url));
const repoRoot = resolve(appRoot, '../..');
const tauriCliPath = resolve(repoRoot, 'node_modules/@tauri-apps/cli/tauri.js');
const AGC_DESIGN_DEBUG_ENV = 'GENARRATIVE_AGC_DESIGN_DEBUG';
const AGC_DESIGN_DEBUG_VITE_ENV = 'VITE_GENARRATIVE_AGC_DESIGN_DEBUG';
const designDebugEnabled =
process.env[AGC_DESIGN_DEBUG_ENV]?.trim() === '0' ? '0' : '1';
function buildTauriArguments(argv, devUrl = readAgcDevEndpoint().url) {
const args = [...argv];
@@ -47,6 +44,24 @@ function buildTauriArguments(argv, devUrl = readAgcDevEndpoint().url) {
];
}
// `agc_cocos_execute` 与 Cocos 编辑器适配器只在 `cocos-editor-execute` feature 下
// 注册。开发构建默认在 Windows 打开它,否则 Agent 的工具清单里根本没有该工具,
// 只能退化成改写脚本。可用 AGC_DEV_CARGO_FEATURES(逗号分隔)覆盖,传空串即关闭。
function readDevCargoFeatures(env = process.env) {
const override = env.AGC_DEV_CARGO_FEATURES;
if (override !== undefined) {
return override
.split(',')
.map((value) => value.trim())
.filter(Boolean);
}
return process.platform === 'win32' ? ['cocos-editor-execute'] : [];
}
function withDevCargoFeatures(argv, features = readDevCargoFeatures()) {
return withDefaultCargoFeatures(argv, features);
}
function spawnTauriCli(argv, { env = process.env } = {}) {
return spawnChild(process.execPath, [tauriCliPath, ...argv], {
cwd: appRoot,
@@ -110,13 +125,12 @@ async function runTauriDev(
shutdownRequested.then(() => false),
]);
if (!prepared || shutdownSignal) return 1;
const tauriArguments = buildTauriArguments(argv, endpoint.url);
const tauriArguments = buildTauriArguments(
withDevCargoFeatures(argv),
endpoint.url,
);
child = spawnCli(tauriArguments, {
env: {
...withAgcDevEndpointEnv(endpoint),
[AGC_DESIGN_DEBUG_ENV]: designDebugEnabled,
[AGC_DESIGN_DEBUG_VITE_ENV]: designDebugEnabled,
},
env: withAgcDevEndpointEnv(endpoint),
});
const childResult = waitForCli(child);
const outcome = await Promise.race([
@@ -165,13 +179,7 @@ async function prepareFrontendDev(endpoint, { onChild, signal }) {
const frontend = spawnChild(
process.platform === 'win32' ? 'npm.cmd' : 'npm',
['run', 'agc:serve'],
{
cwd: repoRoot,
env: {
...withAgcDevEndpointEnv(endpoint),
[AGC_DESIGN_DEBUG_VITE_ENV]: designDebugEnabled,
},
},
{ cwd: repoRoot, env: withAgcDevEndpointEnv(endpoint) },
);
onChild(frontend);
console.log(
@@ -207,6 +215,7 @@ export {
isDirectModuleExecution,
runTauriDev,
spawnTauriCli,
withDevCargoFeatures,
};
if (isDirectModuleExecution()) {
@@ -0,0 +1,4 @@
# resources/plugins 由 build.rs 从 plugins/ 复制生成,属于构建产物。
# 它在 dev 监听范围内,重新生成会让 Tauri dev 误判为源码改动而触发
# “构建 -> 监听 -> 再构建”的自触发循环。
resources/plugins/
+25
View File
@@ -733,6 +733,20 @@ dependencies = [
"error-code",
]
[[package]]
name = "cocos-editor-bridge"
version = "0.1.0"
dependencies = [
"cc",
"editor-adapter-api",
"reqwest 0.12.28",
"serde",
"serde_json",
"sha2",
"tungstenite",
"windows-sys 0.61.2",
]
[[package]]
name = "combine"
version = "4.6.7"
@@ -1205,6 +1219,14 @@ version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "editor-adapter-api"
version = "0.1.0"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "either"
version = "1.16.0"
@@ -1709,6 +1731,8 @@ dependencies = [
"axum",
"base64 0.22.1",
"chromiumoxide",
"cocos-editor-bridge",
"editor-adapter-api",
"futures",
"getrandom 0.3.4",
"http",
@@ -4281,6 +4305,7 @@ dependencies = [
"cookie",
"cookie_store",
"encoding_rs",
"futures-channel",
"futures-core",
"futures-util",
"h2",
@@ -6,6 +6,9 @@ publish = false
[features]
default = []
cocos-editor = ["cocos-editor-bridge/process-discovery"]
cocos-editor-execute = ["cocos-editor", "cocos-editor-bridge/windows-bootstrap"]
cocos-editor-injection = ["cocos-editor-execute", "cocos-editor-bridge/windows-injection"]
[build-dependencies]
serde = { version = "1", features = ["derive"] }
@@ -19,6 +22,8 @@ ts-rs = "12.0.1"
typed_floats = { version = "1.0.7", features = ["serde"] }
nalgebra = { version = "0.35.0", features = ["serde-serialize"] }
agent-runtime-core = { path = "../../../server-rs/crates/agent-runtime-core" }
cocos-editor-bridge = { path = "../../../plugins/agc-cocos-editor/native/cocos-editor-bridge", default-features = false }
editor-adapter-api = { path = "../../../server-rs/crates/editor-adapter-api" }
base64 = "0.22"
axum = "0.8"
chromiumoxide = "0.9.1"
@@ -74,14 +79,6 @@ codegen-units = 256
lto = "off"
incremental = true
# Runner 启动阶段会对当前 Debug 可执行文件计算 SHA-256。仅优化密码学依赖,
# 保持业务代码的 Debug 编译速度,同时避免整份 Debug 构建因未优化 hash 热点而阻塞启动。
[profile.dev.package.sha2]
opt-level = 3
[profile.dev.package.digest]
opt-level = 3
[profile.test]
opt-level = 0
debug = 1
@@ -182,6 +182,8 @@ fn main() {
);
let manifest_path = manifest_dir.join("prompts/runtime/manifest.json");
stage_bundled_codex_cli(&manifest_dir);
stage_plugin_workspace(&manifest_dir);
stage_cocos_editor_payload(&manifest_dir);
let compiled = runtime_prompt_bundle::compile_manifest(&manifest_path)
.unwrap_or_else(|error| panic!("Prompt Bundle 编译失败:{error}"));
validate_seed_task_catalog(&compiled);
@@ -203,3 +205,146 @@ fn main() {
}
tauri_build::build()
}
#[cfg(windows)]
fn stage_cocos_editor_payload(manifest_dir: &std::path::Path) {
if std::env::var_os("CARGO_FEATURE_COCOS_EDITOR_INJECTION").is_none() {
return;
}
let out_dir = std::path::PathBuf::from(std::env::var_os("OUT_DIR").expect("OUT_DIR"));
let profile_dir = out_dir
.ancestors()
.find(|path| path.file_name().is_some_and(|name| name == "build"))
.and_then(|build_dir| build_dir.parent())
.expect("AGC Cargo profile directory not found");
let candidates = [
profile_dir.join("deps/cocos_editor_bridge.dll"),
profile_dir.join("cocos_editor_bridge.dll"),
];
let source = candidates
.iter()
.find(|path| path.is_file())
.unwrap_or_else(|| {
panic!(
"Cocos bridge native payload 未构建:{}",
candidates
.iter()
.map(|p| p.display().to_string())
.collect::<Vec<_>>()
.join("")
)
});
for destination in [
// 插件工作区里的 payload 是开发态与打包态的唯一真源。
manifest_dir
.join("../../../plugins/agc-cocos-editor/native/payload/cocos-editor-bridge.dll"),
// 随包资源目录与 tauri.windows.conf.json 的 `resources/plugins` 映射保持一致。
manifest_dir
.join("resources/plugins/agc-cocos-editor/native/payload/cocos-editor-bridge.dll"),
] {
std::fs::create_dir_all(destination.parent().expect("payload resource parent"))
.expect("创建 Cocos bridge payload 目录失败");
std::fs::copy(source, &destination).expect("复制 Cocos bridge native payload 失败");
}
println!("cargo:rerun-if-changed={}", source.display());
}
#[cfg(not(windows))]
fn stage_cocos_editor_payload(_manifest_dir: &std::path::Path) {}
/// 把 `plugins/` 工作区里的插件包随包映射到应用资源目录。
///
/// 只复制插件运行需要的清单、入口、面板和 native payload,不复制 native 源码、
/// Cargo target 目录或 node_modules。
#[cfg(windows)]
fn stage_plugin_workspace(manifest_dir: &std::path::Path) {
let repo_root = manifest_dir
.parent()
.and_then(|app_root| app_root.parent())
.and_then(|apps_dir| apps_dir.parent())
.expect("AGC 应用必须位于仓库 apps 目录下")
.to_path_buf();
let workspace = repo_root.join("plugins");
let destination_root = manifest_dir.join("resources/plugins");
std::fs::create_dir_all(&destination_root).expect("创建插件资源目录失败");
let entries = match std::fs::read_dir(&workspace) {
Ok(entries) => entries,
Err(_) => return,
};
for entry in entries.flatten() {
let plugin_root = entry.path();
if !plugin_root.is_dir() || !plugin_root.join("plugin.json").is_file() {
continue;
}
let name = entry.file_name();
let destination = destination_root.join(&name);
copy_plugin_file(
&plugin_root.join("plugin.json"),
&destination.join("plugin.json"),
);
for relative in [
std::path::PathBuf::from("src"),
std::path::PathBuf::from("panels"),
std::path::PathBuf::from("native/payload"),
] {
copy_plugin_tree(&plugin_root.join(&relative), &destination.join(&relative));
}
println!("cargo:rerun-if-changed={}", plugin_root.display());
}
}
#[cfg(windows)]
fn stage_plugin_file(source: &std::path::Path, destination: &std::path::Path) {
let Ok(bytes) = std::fs::read(source) else {
return;
};
if std::fs::read(destination).is_ok_and(|existing| existing == bytes) {
return;
}
if let Some(parent) = destination.parent() {
std::fs::create_dir_all(parent).expect("创建插件资源目录失败");
}
std::fs::write(destination, bytes).expect("复制插件资源失败");
}
#[cfg(windows)]
fn copy_plugin_tree(source: &std::path::Path, destination: &std::path::Path) {
let entries = match std::fs::read_dir(source) {
Ok(entries) => entries,
Err(_) => return,
};
for entry in entries.flatten() {
let target = destination.join(entry.file_name());
let path = entry.path();
if path.is_dir() {
let name = entry.file_name();
let name = name.to_string_lossy();
if matches!(name.as_ref(), "target" | "node_modules" | ".git") {
continue;
}
std::fs::create_dir_all(&target).expect("创建插件资源目录失败");
copy_plugin_tree(&path, &target);
} else {
// 测试文件不随包分发。
let name = entry.file_name();
let name = name.to_string_lossy();
if name.contains(".test.") {
continue;
}
stage_plugin_file(&path, &target);
}
}
}
#[cfg(windows)]
fn copy_plugin_file(source: &std::path::Path, destination: &std::path::Path) {
if !source.is_file() {
return;
}
std::fs::create_dir_all(destination.parent().expect("插件资源父目录"))
.expect("创建插件资源目录失败");
std::fs::copy(source, destination).expect("复制插件资源失败");
}
#[cfg(not(windows))]
fn stage_plugin_workspace(_manifest_dir: &std::path::Path) {}
@@ -1 +0,0 @@
当前阶段:系统架构。明确系统清单、职责边界、依赖和数据归属。
@@ -1,6 +0,0 @@
共享过程文件(如需维护,请使用这些相对路径):
- project/analysis.md
- project/决策台账.md
- project/dialog.md
不要把正式产物写在工作区根目录,也不要等审批失败后再迁移。
阶段审批工具:当你判断本阶段必需产物已完成时,必须提交阶段审批。用户批准后 Runtime 自动进入下一阶段;你不能自行切换阶段。
@@ -1 +0,0 @@
当前阶段:概念设计。明确游戏是什么、不是什么,并形成概念设计产物。
@@ -1,4 +0,0 @@
顾问阶段不需要继续自主推动项目或主动安排下一步;遵照用户的具体指示行动。
根据用户指示回答问题、读取相关文档、修改工作区文件,并说明改动可能影响的已有产物。
涉及方向性变化或多个可行方案时,先向用户说明影响并等待用户决定;不要替用户做决定。
顾问阶段没有下一层,也不需要提交阶段审批。
@@ -1 +0,0 @@
当前阶段:项目顾问。五个策划阶段已经完成,后续由用户指示驱动协作。
@@ -1,44 +0,0 @@
概念阶段定稿时,还必须创建或更新 `project/速览卡.md`。Runtime 只检查该文件是否存在,不检查内容。请使用下面的固定结构,不要加入审批操作说明或独立的决定状态段落:
# 速览卡:《游戏名》
## 1. 游戏名称
## 2. 游戏分类
## 3. 美术风格
- 视觉类型:
- 风格关键词:
- 色彩与氛围:
- MVP 美术边界:
## 4. 一句话描述
## 5. 游戏支柱
| 支柱 | 玩家感受 | 实现机制 |
|---|---|---|
## 6. 核心循环
## 7. 目标用户
- 核心用户:
- 游戏偏好:
- 单次游玩时长:
- 参考游戏与参考点:
## 8. 平台事实
## 9. 最小 MVP 系统
| 系统 | 最小功能 | 为什么必须有 | 验证方法 |
|---|---|---|---|
## 10. 给创作者的关键提示
- 先做:
- 暂时不做:
- 这样验证:
- 达标再扩展:
### 待原型验证项
- 问题:
- 原型:
- 观察:
@@ -1 +0,0 @@
当前阶段:系统文档。逐个完成已确定系统的内部规则、接口和验证标准。
@@ -1 +0,0 @@
当前阶段:技术文档。完成数据与配表、技术实现、美术圣经和总册。
@@ -1 +0,0 @@
当前阶段:顶层设计。明确玩家持续游玩的循环、资源流、节奏和系统范围。
File diff suppressed because one or more lines are too long
@@ -1,384 +0,0 @@
{
"version": 1,
"resources": [
{
"path": "skills/concept.md",
"id": "skills.concept",
"summary": "概念阶段写作规则。",
"category": "skills",
"title": "概念设计分册",
"inject_phases": [
"concept"
]
},
{
"path": "skills/top_design.md",
"id": "skills.top_design",
"summary": "顶层设计阶段写作规则。",
"category": "skills",
"title": "顶层设计分册",
"inject_phases": [
"top_design"
]
},
{
"path": "skills/architecture.md",
"id": "skills.architecture",
"summary": "系统架构阶段写作规则。",
"category": "skills",
"title": "系统架构分册",
"inject_phases": [
"architecture"
]
},
{
"path": "skills/systems.md",
"id": "skills.systems",
"summary": "系统文档阶段写作规则。",
"category": "skills",
"title": "系统文档分册",
"inject_phases": [
"systems"
]
},
{
"path": "skills/tdd.md",
"id": "skills.tdd",
"summary": "技术文档阶段写作规则。",
"category": "skills",
"title": "技术文档分册",
"inject_phases": [
"tdd"
]
},
{
"id": "templates.analysis",
"category": "templates",
"title": "analysis",
"summary": "策划文档结构模板。",
"path": "templates/analysis.md"
},
{
"id": "templates.architecture",
"category": "templates",
"title": "architecture",
"summary": "策划文档结构模板。",
"path": "templates/architecture.md"
},
{
"id": "templates.concept_design",
"category": "templates",
"title": "concept-design",
"summary": "策划文档结构模板。",
"path": "templates/concept-design.md"
},
{
"id": "templates.stardew_analysis",
"category": "templates",
"title": "stardew-analysis",
"summary": "策划文档结构模板。",
"path": "templates/stardew-analysis.md"
},
{
"id": "templates.tdd_art_bible",
"category": "templates",
"title": "tdd-art-bible",
"summary": "策划文档结构模板。",
"path": "templates/tdd-art-bible.md"
},
{
"id": "templates.tdd_data",
"category": "templates",
"title": "tdd-data",
"summary": "策划文档结构模板。",
"path": "templates/tdd-data.md"
},
{
"id": "templates.tdd_master",
"category": "templates",
"title": "tdd-master",
"summary": "策划文档结构模板。",
"path": "templates/tdd-master.md"
},
{
"id": "templates.tdd_tech",
"category": "templates",
"title": "tdd-tech",
"summary": "策划文档结构模板。",
"path": "templates/tdd-tech.md"
},
{
"id": "templates.top_design",
"category": "templates",
"title": "top-design",
"summary": "策划文档结构模板。",
"path": "templates/top-design.md"
},
{
"id": "exemplars.decision_log",
"category": "exemplars",
"title": "decision-log",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/decision-log.md"
},
{
"id": "exemplars.fast_gdd",
"category": "exemplars",
"title": "fast-gdd",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/fast-gdd.md"
},
{
"id": "exemplars.overview_card",
"category": "exemplars",
"title": "overview-card",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/overview-card.md"
},
{
"id": "exemplars.stardew_architecture",
"category": "exemplars",
"title": "stardew-architecture",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/stardew-architecture.md"
},
{
"id": "exemplars.stardew_concept",
"category": "exemplars",
"title": "stardew-concept",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/stardew-concept.md"
},
{
"id": "exemplars.stardew_s06_combat",
"category": "exemplars",
"title": "stardew-s06-combat",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/stardew-s06-combat.md"
},
{
"id": "exemplars.stardew_tdd_art_bible",
"category": "exemplars",
"title": "stardew-tdd-art-bible",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/stardew-tdd-art-bible.md"
},
{
"id": "exemplars.stardew_tdd_data",
"category": "exemplars",
"title": "stardew-tdd-data",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/stardew-tdd-data.md"
},
{
"id": "exemplars.stardew_tdd_master",
"category": "exemplars",
"title": "stardew-tdd-master",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/stardew-tdd-master.md"
},
{
"id": "exemplars.stardew_tdd_tech",
"category": "exemplars",
"title": "stardew-tdd-tech",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/stardew-tdd-tech.md"
},
{
"id": "exemplars.stardew_top_design",
"category": "exemplars",
"title": "stardew-top-design",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/stardew-top-design.md"
},
{
"id": "exemplars.tdd_art_bible_SKILL",
"category": "exemplars",
"title": "tdd-art-bible-SKILL",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/tdd-art-bible-SKILL.md"
},
{
"id": "exemplars.tdd_data_SKILL",
"category": "exemplars",
"title": "tdd-data-SKILL",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/tdd-data-SKILL.md"
},
{
"id": "exemplars.tdd_tech_SKILL",
"category": "exemplars",
"title": "tdd-tech-SKILL",
"summary": "策划文档范例或需求附件。",
"path": "exemplars/tdd-tech-SKILL.md"
},
{
"id": "system_types.核心玩法编排.skill",
"category": "system_types",
"title": "01_核心玩法编排 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/01_核心玩法编排/SKILL.md"
},
{
"id": "system_types.核心玩法编排.template",
"category": "system_types",
"title": "01_核心玩法编排 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/01_核心玩法编排/模板.md"
},
{
"id": "system_types.时间与日程.skill",
"category": "system_types",
"title": "02_时间与日程 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/02_时间与日程/SKILL.md"
},
{
"id": "system_types.时间与日程.template",
"category": "system_types",
"title": "02_时间与日程 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/02_时间与日程/模板.md"
},
{
"id": "system_types.生产种植经营.skill",
"category": "system_types",
"title": "03_生产种植经营 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/03_生产种植经营/SKILL.md"
},
{
"id": "system_types.生产种植经营.template",
"category": "system_types",
"title": "03_生产种植经营 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/03_生产种植经营/模板.md"
},
{
"id": "system_types.地图与探索.skill",
"category": "system_types",
"title": "04_地图与探索 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/04_地图与探索/SKILL.md"
},
{
"id": "system_types.地图与探索.template",
"category": "system_types",
"title": "04_地图与探索 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/04_地图与探索/模板.md"
},
{
"id": "system_types.采集与支线活动.skill",
"category": "system_types",
"title": "05_采集与支线活动 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/05_采集与支线活动/SKILL.md"
},
{
"id": "system_types.采集与支线活动.template",
"category": "system_types",
"title": "05_采集与支线活动 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/05_采集与支线活动/模板.md"
},
{
"id": "system_types.战斗与敌人.skill",
"category": "system_types",
"title": "06_战斗与敌人 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/06_战斗与敌人/SKILL.md"
},
{
"id": "system_types.战斗与敌人.template",
"category": "system_types",
"title": "06_战斗与敌人 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/06_战斗与敌人/模板.md"
},
{
"id": "system_types.物品背包与制作.skill",
"category": "system_types",
"title": "07_物品背包与制作 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/07_物品背包与制作/SKILL.md"
},
{
"id": "system_types.物品背包与制作.template",
"category": "system_types",
"title": "07_物品背包与制作 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/07_物品背包与制作/模板.md"
},
{
"id": "system_types.成长与技能.skill",
"category": "system_types",
"title": "08_成长与技能 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/08_成长与技能/SKILL.md"
},
{
"id": "system_types.成长与技能.template",
"category": "system_types",
"title": "08_成长与技能 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/08_成长与技能/模板.md"
},
{
"id": "system_types.NPC关系与任务.skill",
"category": "system_types",
"title": "09_NPC关系与任务 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/09_NPC关系与任务/SKILL.md"
},
{
"id": "system_types.NPC关系与任务.template",
"category": "system_types",
"title": "09_NPC关系与任务 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/09_NPC关系与任务/模板.md"
},
{
"id": "system_types.经济与商店.skill",
"category": "system_types",
"title": "10_经济与商店 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/10_经济与商店/SKILL.md"
},
{
"id": "system_types.经济与商店.template",
"category": "system_types",
"title": "10_经济与商店 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/10_经济与商店/模板.md"
},
{
"id": "system_types.事件与节日.skill",
"category": "system_types",
"title": "11_事件与节日 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/11_事件与节日/SKILL.md"
},
{
"id": "system_types.事件与节日.template",
"category": "system_types",
"title": "11_事件与节日 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/11_事件与节日/模板.md"
},
{
"id": "system_types.UI与文本呈现.skill",
"category": "system_types",
"title": "12_UI与文本呈现 skill",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/12_UI与文本呈现/SKILL.md"
},
{
"id": "system_types.UI与文本呈现.template",
"category": "system_types",
"title": "12_UI与文本呈现 template",
"summary": "系统类型写法规则或模板。",
"path": "modules/system-types/12_UI与文本呈现/模板.md"
}
]
}
@@ -1,66 +0,0 @@
# 决策台账:《星露谷物语》金样项目
版本:v3 | 规则:台账放活队列——design 只放结论、分析只放论证、决定与开放问题住这里。编号连续不复用;被推翻的行标 overturned 挂新行,不删行。
状态六态:`confirmed`(用户亲口/亲选)/ `auto_decided`(技术类代决,必带理由+推翻条件,用户一键可翻)/ `default_pending`(默认建议兜底,用户未点头)/ `prototype_pending`(待原型验证)/ `pending_user`(等用户拍板)/ `overturned`(被推翻,挂旧行编号)。
> 编号口径:D-01~D-13 与 exemplars/stardew-analysis.md 台账节选一致(D-04~D-06、D-08~D-10、D-12 原为"就地小权衡,直接登记未开条目",此处按登记口径展开);D-14 起为技术文档期新增,与 stardew-tdd-tech.md 开放问题回执互引。
## 当前待办(活队列)
### 等用户拍板(pending_user
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-14 | 体力与战斗共享单池 | TDD | user | 风险资源统一制造取舍(概念张力一);**暂按共享实现,改单拆只需改 S02 成本入口** | 战斗参与率实测过低(玩家回避矿井) | pending_user(暂按共享实现) |
| D-15 | 背包格子制 vs 重量制 | TDD | user | 格子制直觉、重量制焦虑感与 T5"休闲不打卡"冲突;暂按格子制实现、存档预留 capacity_type 字段 | 格子管理成为主要负面反馈 | pending_user(B 级阻断存档结构,暂按格子制) |
### 待原型验证(prototype_pending
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-13b | 战斗判定窗口手感(前摇帧数/无敌帧 450ms 基准) | 系统 | user | 数值可定、手感不可纸面验证 | 原型显示节奏拖慢/玩家困惑 | prototype_pending(规则本体见 D-13 confirmed |
### 默认建议兜底(default_pending
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-19 | 天气权重表具体数值(晴/雨/风暴按季节) | TDD | agent | 概念层只定"雨免浇水"定性;数值推内容期填 | 前 5 日出现连续 3 日雨/全无雨 | default_pending(默认值已进数据表,带 designer_note |
## 已采用决定
### 用户确认(confirmed
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-01 | 定调:牧场物语系参照、治愈慢节奏 | 概念 | user | 用户原始需求 | — | confirmed |
| D-02 | 单人体验,无多人 | 概念 | user | 概念层非目标 | — | confirmed |
| D-03 | 战斗保持伴生风险,不做装备驱动主轴 | 概念 | user | 概念期问题一 | 矿井流失率过半且归因战斗 | confirmed |
| D-07 | 日目标自设,季节与社区提供低频牵引 | 顶层 | user | 顶层期问题一 | 新手周流失归因无方向 | confirmed |
| D-11 | 采集/钓鱼/战斗统一"活动结果"接口 | 架构 | user | 架构期问题一 | 第三活动类型出现结构性差异 | confirmed |
| D-13 | 战斗采用节奏/指令判定 | 系统 | user | S06 问题一 | 原型显示节奏拖慢/玩家困惑 | confirmed(手感部分拆 D-13b prototype_pending |
### 技术代决(auto_decided——带理由与推翻条件,用户一键可翻)
| 编号 | 决定 | 层 | 谁 | 依据(理由) | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-04 | 时间片制:700ms=10 游戏分钟 | 概念 | agent | 原作实证节拍;一天≈14 分钟真实时间贴合 T5"休闲" | 内测一天体感过短/过长 | auto_decided |
| D-05 | 分区域切换(区域独立场景,非连续地图) | 概念 | agent | 概念层"不是什么:无边界开放世界";区域小网络全部步行可达 | 场景切换成为移动负担反馈 | auto_decided |
| D-06 | 28 日/季、四季/年 | 顶层 | agent | 季节窗口制造"本季计划"节奏(支柱二) | 换季频率在测试中被无视 | auto_decided |
| D-09 | 商店营业时段走条件表 | 架构 | agent | 与配方/区域解锁共用 check(condition_id) 单一入口 | 条件表规模膨胀难维护 | auto_decided |
| D-10 | 出货箱日终统一结算 | 架构 | agent | 收入集中进日终面板,强化"一天一结算"叙事;商店现卖保留即时通道 | 玩家普遍绕开出货箱 | auto_decided |
| D-12 | 工具升级期间该工具不可用 | 系统 | agent | 升级=时间成本换效率(顶层张力二);备用旧工具暂不做(开放问题) | 升级期挫败感集中爆发 | auto_decided |
| D-16 | 矿井逐层生成本期不做(P2 | TDD | agent | GDD 已标"不做无限地牢";首期按布局池 8~12 模板拼装 | 内测要求深度爬塔玩法 | auto_decided |
| D-17 | 换装首期 5 层(基础体/裤/衣/发型/饰件),非 19 层 | TDD | agent | 外观自定义非首期卖点;层结构预留到 19 层 | 外观系统成核心诉求 | auto_decided |
| D-18 | 作物品质三档:普通/银/金 | TDD | agent | 经济分层需要(即时变现 vs 等待升值的取舍) | 银金档无人区分、一律普通出售 | auto_decided |
### 已推翻(overturned——旧行保留,挂新行)
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-08 | 作物品质两档:普通/银 | TDD | agent | 早期小权衡:两档最简 | — | **overturned → D-18**(经济分层不足,改三档;铱档留 P1) |
## 队列纪律(给 agent 的使用说明)
- 新决定入队:拿下一号(当前最大 D-19,下一号 D-20);就现代决可登记不开条目,但状态必须写 auto_decided 并带理由+推翻条件。
- 用户翻案:旧行标 overturned 挂新行,受影响文档节重写(本台账只记录,不代改)。
- 概念层变更定稿后:速览卡"决定状态与原型验证项"字段随本文件最新版同步(prompt 级纪律)。

Some files were not shown because too many files have changed in this diff Show More