Compare commits

..

15 Commits

Author SHA1 Message Date
kdletters 36ae9425e9 完善 AGC 独立 Agent 试验验证
支持使用 Fake Provider 验证跨进程 Agent 回合

修正独立 Agent 与排队模型的匹配和子进程超时回收

补充 AGC 到独立 App Server 的真实子进程 smoke
2026-09-10 13:07:09 +08:00
kdletters bd85694ee9 接入 AGC 独立 Agent 试验模式
新增 agent_runtime 配置并通过 stdio App Server 启动独立 Agent

接通后台、交互和 DirectProject 文本回合,保留旧 Codex 回退

对未接入的 function tool 明确失败,避免静默丢失工具调用

补充 AGC 配置回归与实施边界文档
2026-09-10 12:45:54 +08:00
kdletters c709b3d9b2 新增独立 Agent App Server
为 agent-cli 增加 stdio JSON-RPC 2.0 服务入口与运行控制协议

补充 Host 实时流监听和流式取消入口

新增 App Server 子进程闭环测试及协议文档

更新 README、架构、TODO 与共享决策记录
2026-09-10 00:05:02 +08:00
kdletters fc05617ecc 记录 AGC 使用独立 Agent 内核的边界
明确替换 Codex 执行循环而非替换二进制

保留 AGC 工具权限、Runtime 持久化和完成门

规定兼容桥、实验模式与新旧 fixture 对比顺序
2026-09-09 21:28:04 +08:00
kdletters d85557cf6d 制定 AGC 接入独立 Agent 内核计划
明确以新 Kernel/Engine 替换 Codex 执行循环

保留 AGC 工具权限、Runtime 持久化、预览和完成门

先实现兼容桥与可回滚 agent_runtime 实验模式
2026-09-09 21:27:11 +08:00
kdletters ce8425e671 明确 AGC 使用新 Agent 内核的替换目标
将替换对象从 Codex 适配器修正为 Agent Kernel 与 Engine 执行循环

保留 AGC 宿主的工具、权限、持久化、预览和完成门

规划 agent_runtime 实验模式与可回滚接线
2026-09-09 21:09:36 +08:00
kdletters 9eb1abfda5 评估 AGC 与独立 Codex 替换边界
对比 AGC 0.147.0、独立适配器 0.152.1 与本机 Codex 0.153.4

记录协议、隔离、工具桥与 Runtime 职责差异

明确先做 0.153.4 typed adapter 和可切换接线,不直接替换生产路径
2026-09-09 20:51:00 +08:00
kdletters 0c41cb6758 更新 Host 执行拆分计划状态
记录 execution.rs 已承接运行入口与 lease 恢复编排

保留 Engine worker 主体和终态 glue 的后续边界
2026-09-09 20:14:48 +08:00
kdletters 662ecd3e57 补录 Agent Runtime 架构决策
记录独立 Rust workspace、Runtime 控制面与 Host 模块拆分决策

补充执行入口、checkpoint、Codex 和外部桥接的职责边界与验证口径
2026-09-09 20:13:20 +08:00
kdletters c64d98a18f 拆分 Host 执行入口
将 run、run_existing、streaming 与 cancellation 入口移入 execution.rs

保持 AgentHost 公开 API、Runtime/SQLite 合同和 Engine 接口不变

同步 README、架构说明与 TODO,保留跨职责终态 glue 在根模块
2026-09-09 20:12:02 +08:00
kdletters c7d6eade5e 拆分 Host 检查点与 Codex 桥接
将 checkpoint listener 和 runtime trace 投影移入 checkpoint 模块

将 Codex server-request handler 与 durable tool-call helper 移入 codex 模块

保持根路径公开类型、Engine 执行和 Runtime 边界不变
2026-09-09 19:58:16 +08:00
kdletters 3ba935367a 拆分 Host 检查点与事件投影
将 DurableCheckpoints、RuntimeTraceProgress 和 runtime trace 投影移入 checkpoint 模块

保持 Engine 执行、Runtime reducer 和公开 Host API 边界不变

补齐拆分后的 workspace、Clippy、Rustdoc、编码与差异验证
2026-09-09 19:49:29 +08:00
kdletters 69fc3d8ca0 拆分 Agent Host 运行职责
将 durable 取消、失败收口、审批决议和外部结果对账迁入 RuntimeService

把 Host 工具、MCP、Skill 与外部 backend 桥接拆为私有模块并保持公开 API

补充 Runtime 控制测试、依赖反向门禁和架构验收文档
2026-09-09 19:20:54 +08:00
kdletters 202279c6d9 新增独立 Agent Runtime Rust 工作区
新增 Core、Engine、Runtime、SQLite、Provider、MCP、Skill、Codex、CLI 与 DAG crate

补齐 OpenAI endpoint 配置、Provider 实例/协议路由和统一工具权限边界

加入持久化、lease、checkpoint、reconciliation、审批恢复与消息历史回归

加入独立 workspace CI、依赖边界、能力集和 Fake Agent 测试脚本

同步建设计划、TODO、架构、测试与验收文档
2026-09-06 17:44:54 +08:00
kdletters 3e8591040d 忽略所有 Rust target 目录
将 target 忽略规则扩展到仓库任意层级
2026-09-01 15:23:50 +08:00
2638 changed files with 738433 additions and 91005 deletions
+1 -1
View File
@@ -1 +1 @@
{ "containers": [], "config": {} }
{"containers":[],"config":{}}
+11 -23
View File
@@ -7,33 +7,23 @@ import { fileURLToPath } from 'node:url';
const scriptDir = dirname(fileURLToPath(import.meta.url));
const repoRoot = resolve(scriptDir, '..', '..');
const logDir = resolve(repoRoot, '.codex', 'logs');
const hasCodegraphConfig = existsSync(
resolve(repoRoot, '.codegraph', 'config.json'),
);
const hasCodegraphConfig = existsSync(resolve(repoRoot, '.codegraph', 'config.json'));
const npmCommand = process.platform === 'win32' ? 'cmd' : 'npm';
if (!hasCodegraphConfig) {
console.log(
'[codex-hook] 未发现 .codegraph/config.json,跳过 CodeGraph 同步。',
);
console.log('[codex-hook] 未发现 .codegraph/config.json,跳过 CodeGraph 同步。');
process.exit(0);
}
const result = spawnSync(
npmCommand,
process.platform === 'win32'
? ['/d', '/s', '/c', 'npm run codegraph:sync']
: ['run', 'codegraph:sync'],
{
cwd: repoRoot,
shell: false,
encoding: 'utf8',
env: {
...process.env,
NO_COLOR: process.env.NO_COLOR ?? '1',
},
const result = spawnSync(npmCommand, process.platform === 'win32' ? ['/d', '/s', '/c', 'npm run codegraph:sync'] : ['run', 'codegraph:sync'], {
cwd: repoRoot,
shell: false,
encoding: 'utf8',
env: {
...process.env,
NO_COLOR: process.env.NO_COLOR ?? '1',
},
);
});
mkdirSync(logDir, { recursive: true });
if (result.stdout) {
@@ -54,9 +44,7 @@ if (result.signal) {
}
if ((result.status ?? 0) !== 0) {
console.error(
'[codex-hook] CodeGraph 同步失败,请手动运行 npm run codegraph:sync 查看详情。',
);
console.error('[codex-hook] CodeGraph 同步失败,请手动运行 npm run codegraph:sync 查看详情。');
process.exit(result.status ?? 1);
}
@@ -28,11 +28,16 @@
"longDescription": "Plan, prototype, and build browser games with guided workflows for gameplay systems, UI, asset pipelines, and playtesting across 2D and 3D projects.",
"developerName": "OpenAI",
"category": "Coding",
"capabilities": ["Interactive", "Write"],
"capabilities": [
"Interactive",
"Write"
],
"websiteURL": "https://openai.com/",
"privacyPolicyURL": "https://openai.com/policies/privacy-policy/",
"termsOfServiceURL": "https://openai.com/policies/terms-of-use/",
"defaultPrompt": ["Design a browser game and plan the core loop"],
"defaultPrompt": [
"Design a browser game and plan the core loop"
],
"brandColor": "#0F766E",
"composerIcon": "./assets/game-studio.svg",
"logo": "./assets/app-icon.png",
+1 -2
View File
@@ -1,7 +1,6 @@
name: game-studio
version: 0.1.0
description:
Design, prototype, and ship browser games with guided 2D and 3D workflows,
description: Design, prototype, and ship browser games with guided 2D and 3D workflows,
asset pipelines, and playtesting support.
author: OpenAI
kind: standalone
@@ -5,19 +5,19 @@ Use this as the canonical minimal pattern for loading shipped 3D content.
## Vanilla Three.js
```ts
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
const draco = new DRACOLoader();
draco.setDecoderPath('/draco/');
draco.setDecoderPath("/draco/");
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(draco);
gltfLoader.load('/assets/hero.glb', (gltf) => {
gltfLoader.load("/assets/hero.glb", (gltf) => {
const root = gltf.scene;
root.traverse((node) => {
if ('castShadow' in node) {
if ("castShadow" in node) {
node.castShadow = true;
node.receiveShadow = true;
}
@@ -29,10 +29,10 @@ gltfLoader.load('/assets/hero.glb', (gltf) => {
## React Three Fiber
```tsx
import { useGLTF } from '@react-three/drei';
import { useGLTF } from "@react-three/drei";
function HeroModel() {
const gltf = useGLTF('/assets/hero.glb');
const gltf = useGLTF("/assets/hero.glb");
return <primitive object={gltf.scene} />;
}
```
@@ -5,14 +5,12 @@ Use this as the smallest canonical pattern for adding physics without letting it
## Vanilla Three.js
```ts
import RAPIER from '@dimforge/rapier3d-compat';
import RAPIER from "@dimforge/rapier3d-compat";
await RAPIER.init();
const world = new RAPIER.World({ x: 0, y: -9.81, z: 0 });
const body = world.createRigidBody(
RAPIER.RigidBodyDesc.dynamic().setTranslation(0, 2, 0),
);
const body = world.createRigidBody(RAPIER.RigidBodyDesc.dynamic().setTranslation(0, 2, 0));
world.createCollider(RAPIER.ColliderDesc.cuboid(0.5, 0.5, 0.5), body);
renderer.setAnimationLoop(() => {
@@ -26,7 +24,7 @@ renderer.setAnimationLoop(() => {
## React Three Fiber
```tsx
import { Physics, RigidBody } from '@react-three/rapier';
import { Physics, RigidBody } from "@react-three/rapier";
<Physics gravity={[0, -9.81, 0]}>
<RigidBody colliders="cuboid">
@@ -12,7 +12,7 @@ src/
## `src/App.tsx`
```tsx
import { Canvas } from '@react-three/fiber';
import { Canvas } from "@react-three/fiber";
function Spinner() {
return (
@@ -27,7 +27,7 @@ export default function App() {
return (
<div className="app-shell">
<Canvas camera={{ position: [0, 1.5, 4], fov: 60 }}>
<color attach="background" args={['#101418']} />
<color attach="background" args={["#101418"]} />
<ambientLight intensity={0.7} />
<directionalLight position={[4, 6, 3]} intensity={1.2} />
<Spinner />
@@ -12,17 +12,12 @@ src/
## `src/main.ts`
```ts
import * as THREE from 'three';
import * as THREE from "three";
const scene = new THREE.Scene();
scene.background = new THREE.Color('#101418');
scene.background = new THREE.Color("#101418");
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.1,
200,
);
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 200);
camera.position.set(0, 1.5, 4);
const renderer = new THREE.WebGLRenderer({ antialias: true });
@@ -37,11 +32,11 @@ scene.add(light);
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: '#3dd9b8' }),
new THREE.MeshStandardMaterial({ color: "#3dd9b8" }),
);
scene.add(mesh);
window.addEventListener('resize', () => {
window.addEventListener("resize", () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
@@ -1,4 +1,4 @@
interface:
display_name: 'Game Playtest'
short_description: 'Run browser-game playtests and QA'
default_prompt: 'Playtest the browser game, check core interactions and visual state changes, and report concrete issues.'
display_name: "Game Playtest"
short_description: "Run browser-game playtests and QA"
default_prompt: "Playtest the browser game, check core interactions and visual state changes, and report concrete issues."
@@ -1,4 +1,4 @@
interface:
display_name: 'Game Studio'
short_description: 'Route browser-game work to the right path'
default_prompt: 'Help me choose the right browser-game stack and workflow before implementation starts.'
display_name: "Game Studio"
short_description: "Route browser-game work to the right path"
default_prompt: "Help me choose the right browser-game stack and workflow before implementation starts."
@@ -1,4 +1,4 @@
interface:
display_name: 'Game UI Frontend'
short_description: 'Design browser-game HUDs, menus, and overlays'
default_prompt: 'Design a browser-game UI layer that supports the play experience without crowding the playfield.'
display_name: "Game UI Frontend"
short_description: "Design browser-game HUDs, menus, and overlays"
default_prompt: "Design a browser-game UI layer that supports the play experience without crowding the playfield."
@@ -1,4 +1,4 @@
interface:
display_name: 'Phaser 2D Game'
short_description: 'Build 2D browser games with Phaser'
default_prompt: 'Implement this 2D browser game with Phaser, TypeScript, and a clear gameplay architecture.'
display_name: "Phaser 2D Game"
short_description: "Build 2D browser games with Phaser"
default_prompt: "Implement this 2D browser game with Phaser, TypeScript, and a clear gameplay architecture."
@@ -1,4 +1,4 @@
interface:
display_name: 'React Three Fiber Game'
short_description: 'Build React-hosted 3D browser games'
default_prompt: 'Build this 3D browser game with React Three Fiber and keep the 3D runtime aligned with the React app shell.'
display_name: "React Three Fiber Game"
short_description: "Build React-hosted 3D browser games"
default_prompt: "Build this 3D browser game with React Three Fiber and keep the 3D runtime aligned with the React app shell."
@@ -1,4 +1,4 @@
interface:
display_name: 'Sprite Pipeline'
short_description: 'Generate and normalize 2D sprite animations'
default_prompt: 'Create and normalize 2D sprite animation assets for a browser game with consistent scale and anchors.'
display_name: "Sprite Pipeline"
short_description: "Generate and normalize 2D sprite animations"
default_prompt: "Create and normalize 2D sprite animation assets for a browser game with consistent scale and anchors."
@@ -1,4 +1,4 @@
interface:
display_name: 'Three WebGL Game'
short_description: 'Build browser-game runtimes with Three.js'
default_prompt: 'Implement this browser-game runtime with plain Three.js and keep the scene architecture easy to debug.'
display_name: "Three WebGL Game"
short_description: "Build browser-game runtimes with Three.js"
default_prompt: "Implement this browser-game runtime with plain Three.js and keep the scene architecture easy to debug."
@@ -1,4 +1,4 @@
interface:
display_name: 'Web 3D Asset Pipeline'
short_description: 'Prepare and optimize browser-game 3D assets'
default_prompt: 'Prepare these browser-game 3D assets for shipping as predictable runtime-ready GLB or glTF files.'
display_name: "Web 3D Asset Pipeline"
short_description: "Prepare and optimize browser-game 3D assets"
default_prompt: "Prepare these browser-game 3D assets for shipping as predictable runtime-ready GLB or glTF files."
@@ -1,4 +1,4 @@
interface:
display_name: 'Web Game Foundations'
short_description: 'Set browser-game architecture before implementation'
default_prompt: 'Establish the core architecture for this browser game before implementation starts.'
display_name: "Web Game Foundations"
short_description: "Set browser-game architecture before implementation"
default_prompt: "Establish the core architecture for this browser game before implementation starts."
@@ -5,13 +5,7 @@ license: MIT
metadata:
codex:
tags: [BDD, Gherkin, 验收标准, 用户故事, 测试, Genarrative]
related_skills:
[
writing-plans,
test-driven-development,
systematic-debugging,
requesting-code-review,
]
related_skills: [writing-plans, test-driven-development, systematic-debugging, requesting-code-review]
---
# BDD 行为驱动开发流程
@@ -224,14 +218,14 @@ Feature: Work publish permission
## 映射到测试类型
| BDD 场景关注点 | 推荐测试层级 | 示例 |
| ---------------------------- | ----------------- | ------------------------------------ |
| 纯领域规则、状态机、校验 | Rust/TS 单元测试 | reducer、module-\*、schema validator |
| DTO 契约、API 请求响应 | API/contract 测试 | Axum handler、shared-contracts serde |
| 页面渲染、按钮状态、表单校验 | 组件测试 | Vitest + Testing Library |
| 路由、tab、页面阶段切换 | 前端集成测试 | appPageRoutes、FlowShell 行为 |
| 登录态、发布、运行态完整链路 | E2E/smoke | Playwright 或项目 smoke 脚本 |
| 埋点、副作用、后台导出 | 后端集成/API 测试 | tracking event、admin export |
| BDD 场景关注点 | 推荐测试层级 | 示例 |
| --- | --- | --- |
| 纯领域规则、状态机、校验 | Rust/TS 单元测试 | reducer、module-*、schema validator |
| DTO 契约、API 请求响应 | API/contract 测试 | Axum handler、shared-contracts serde |
| 页面渲染、按钮状态、表单校验 | 组件测试 | Vitest + Testing Library |
| 路由、tab、页面阶段切换 | 前端集成测试 | appPageRoutes、FlowShell 行为 |
| 登录态、发布、运行态完整链路 | E2E/smoke | Playwright 或项目 smoke 脚本 |
| 埋点、副作用、后台导出 | 后端集成/API 测试 | tracking event、admin export |
原则:
@@ -261,8 +255,8 @@ describe('帮助与反馈入口', () => {
// Given ...
// When ...
// Then ...
});
});
})
})
```
Rust 测试命名建议:
@@ -282,13 +276,13 @@ fn anonymous_user_cannot_publish_generated_draft() {
### Gherkin/BDD 场景默认落点
| 产物类型 | 推荐路径 | 适用场景 |
| --------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| 实施前分析 / 临时计划 | 当前任务说明或 `.tmp/<task-name>-bdd-scenarios.md` | 某次 Codex 开发任务前,用于澄清行为、拆测试、辅助实现;不作为长期产品依据。 |
| 正式产品验收 / PRD 场景 | 当前 `docs/` 融合文档,必要时新增 `docs/【产品验收】<功能名>BDD场景-YYYY-MM-DD.md` | 产品、测试、开发都需要长期参考的验收标准、用户故事、功能边界。 |
| 技术/API/领域行为场景 | 当前 `docs/` 融合文档,必要时新增 `docs/【技术验收】<功能名>BDD场景-YYYY-MM-DD.md` | 后端 API、领域规则、状态机、SpacetimeDB reducer/table、SSE/异步任务、埋点副作用。 |
| 自动化 Gherkin feature 文件 | `tests/features/*.feature``e2e/features/*.feature` | 项目已接入 Cucumber/Playwright BDD 等 Gherkin runner 时。未接入前不要随意新建测试 runner 目录。 |
| 稳定流程或团队经验 | `docs/project-memory/shared-memory/``.codex/skills/` | 不是某个功能验收,而是长期可复用的团队流程、坑点、执行规范。 |
| 产物类型 | 推荐路径 | 适用场景 |
| --- | --- | --- |
| 实施前分析 / 临时计划 | 当前任务说明或 `.tmp/<task-name>-bdd-scenarios.md` | 某次 Codex 开发任务前,用于澄清行为、拆测试、辅助实现;不作为长期产品依据。 |
| 正式产品验收 / PRD 场景 | 当前 `docs/` 融合文档,必要时新增 `docs/【产品验收】<功能名>BDD场景-YYYY-MM-DD.md` | 产品、测试、开发都需要长期参考的验收标准、用户故事、功能边界。 |
| 技术/API/领域行为场景 | 当前 `docs/` 融合文档,必要时新增 `docs/【技术验收】<功能名>BDD场景-YYYY-MM-DD.md` | 后端 API、领域规则、状态机、SpacetimeDB reducer/table、SSE/异步任务、埋点副作用。 |
| 自动化 Gherkin feature 文件 | `tests/features/*.feature``e2e/features/*.feature` | 项目已接入 Cucumber/Playwright BDD 等 Gherkin runner 时。未接入前不要随意新建测试 runner 目录。 |
| 稳定流程或团队经验 | `docs/project-memory/shared-memory/``.codex/skills/` | 不是某个功能验收,而是长期可复用的团队流程、坑点、执行规范。 |
默认规则:
@@ -319,17 +313,15 @@ e2e/features/invite-code.feature
BDD 文档建议包含:
````markdown
```markdown
# <功能名> BDD 验收场景
## 背景
- 需求来源:
- 相关文档:
- 相关入口/接口:
## 角色与目标
- 角色:
- 目标:
- 非目标:
@@ -344,19 +336,16 @@ BDD 文档建议包含:
当 ...
那么 ...
```
````
## 测试映射
| 场景 | 测试层级 | 目标文件 | 状态 |
| ---- | --------- | -------- | ------- |
| ... | component | ... | planned |
| 场景 | 测试层级 | 目标文件 | 状态 |
| --- | --- | --- | --- |
| ... | component | ... | planned |
## 开放问题
- ...
````
```
注意:上面的 Markdown 模板中如果嵌套代码块,需要在真实文档里调整围栏长度,避免代码块提前闭合。
@@ -395,7 +384,7 @@ BDD 文档建议包含:
npm run check:encoding
npm run typecheck
npm run test -- --run <相关测试文件>
````
```
- [ ] 若涉及后端 Rust/API,按相关 DDD/SpacetimeDB 文档运行对应 cargo/npm/API smoke 验证。
- [ ] 若产生长期有效经验,已同步到 `docs/project-memory/shared-memory/` 或合适的仓库级 skill。
@@ -4,17 +4,7 @@ description: 在 Genarrative/陶泥儿后台新增或修改管理页、后台 BF
license: MIT
metadata:
codex:
tags:
[
Genarrative,
陶泥儿后台,
admin-web,
后台接口,
Excel导出,
Rust,
Axum,
SpacetimeDB,
]
tags: [Genarrative, 陶泥儿后台, admin-web, 后台接口, Excel导出, Rust, Axum, SpacetimeDB]
related_skills: [genarrative-play-type-integration]
---
@@ -216,7 +206,6 @@ npm install
3. `cargo fmt --all` 可能格式化不相关 Rust 文件;提交前用 `git status` 检查并 revert 非本任务文件。
4. patch 工具对 Rust 单文件 lint 可能用 Rust 2015 edition 误报 `async fn is not permitted in Rust 2015`;以 `cargo test/check` 为准。
5. `adminRoutes` 新增 route id 后,`AdminShell.routeIcons` 必须同步,否则 TypeScript 会因 `satisfies Record<AdminRouteId, ...>` 报错。
- 后台页面中的中文和 JSON 预览要避免整文件重写导致编码问题;修改后运行 `npm run check:encoding`
- 后台数据页移动端要保证表格横向滚动,不要让整页布局撑坏。
- 若用户追问“之前不是说要把 npm run dev 修好吗”这类已承诺的 dev 启动问题,不要只解释;先复现 `npm run dev`,再按启动日志修脚本并验证到服务就绪。WSL/Linux 下本地开发应走 `spacetime start --data-dir=server-rs/.spacetimedb/local/data` 这一类数据目录隔离,不再用项目级 `--root-dir`,详见 `references/dev-rust-stack-startup-2026-05-08.md`
@@ -1,12 +1,10 @@
# 本次后台表查询接入的可复用经验
## 需求落点
- 后台“总览”页的表统计仍保留,只把每张表的表名改成可点击跳转到 `#tables?table=<name>`
- 新增独立 `#tables` 页承载表选择、关键词搜索、结构化字段筛选、limit、行详情弹窗(详情内保留字段复制,列头漏斗按钮可按列添加条件;每条条件可勾选启用或停用,停用时保留字段和值;`in` / `notIn` 使用逐项值标签,支持粘贴多行值,逗号不再作为隐式分隔符)
- 新增独立 `#tables` 页承载表选择、关键词搜索、JSON filters、limit、行详情弹窗
## 后端实现要点
- 新增只读接口:
- `GET /admin/api/database/tables`
- `GET /admin/api/database/tables/{table_name}/rows`
@@ -15,20 +13,17 @@
- `search` / `filters` 不进入 SQL 字符串:
- SQL 只负责 `SELECT * FROM {table_name} LIMIT {limit}`
- 返回后在 api-server 内存中过滤
- `filters` 接受两种 JSON 形式:object(列名到等值,如 `{"user_id":"u1"}`)与条件数组(如 `[{"column":"points","op":"gt","value":"5"}]`,运算符含 `eq``ne``gt``gte``lt``lte``contains``notContains``startsWith``endsWith``in``notIn``isEmpty``isNotEmpty`,允许同列多条件,条件间为 AND;非 object 且非数组直接 400,未知运算符或 value 形态不匹配也 400。数组中的 `eq` / `ne` 和其他标量运算符一样必须提供 `value`;显式空值判断使用 `isEmpty` / `isNotEmpty`
- `filters` 接受 JSON object,按列名匹配;非 object 直接 400
- SpacetimeDB HTTP SQL 返回可能是 statement array + rows,解析时要兼容这一层结构。
## 前端实现要点
- `adminRoutes` 必须新增 `tables``AdminShell.routeIcons` 也要同步覆盖。
- `AdminApp` 需要显式渲染 `AdminDatabaseTablesPage`
- 预览表格数据行直接点击(或行自身聚焦后按 Enter / Space)打开详情,行内按钮 / 输入控件的键盘操作不冒泡打开详情;详情按钮不单独占列。详情字段仅提供复制操作,成功、剪贴板失败和空字段复制都使用右下角自动消失的 Toast,JSON 预览与平台亮色 / 暗色主题保持一致,表头保持单行并在空间不足时省略显示。表单和标题区查询按钮共用筛选完整性校验。
- worktree 下可能没有本地 `node_modules/typescript/bin/tsc`,而根目录有依赖;在验证前可以临时把根目录 `node_modules` 软链到 worktree 再执行 `npm run admin-web:typecheck`,验证后删除软链,避免污染 git 状态。
## 验证结果
- `cargo test -p api-server admin_database -- --nocapture` 通过。
- `cargo fmt --manifest-path Cargo.toml -p api-server -p shared-contracts --check` 通过。
- `npm run admin-web:typecheck` 通过。
- `npm run admin-web:build` 通过。
- `npm run check:encoding` 通过。
- `npm run check:encoding` 通过。
@@ -1,7 +1,6 @@
# `npm run dev` / `scripts/dev-rust-stack.sh` 启动修复记录
## 症状
- 多个 worktree 同时本地开发时,SpacetimeDB 数据库名可能相同,早期曾用项目级 CLI root 隔离 CLI 状态来规避冲突。
- 实测后确认:真正需要隔离的是 standalone 的 `data-dir`,不需要把 publish 也绑到项目级 CLI root。
- 早期脚本曾通过把用户级 SpacetimeDB 可执行文件目录同步到 `server-rs/.spacetimedb/local/bin/current` 来满足 standalone 回调需求,但这会把整套可执行文件复制进项目本地目录,维护成本高,也容易和用户级 CLI 版本漂移。
@@ -10,7 +9,6 @@
- `api-server` 首次冷编译时,默认 300 秒超时不够,容易在就绪前被回收。
## 当前方案
1. SpacetimeDB 可执行文件继续使用用户环境里的 `spacetime` 命令
- 启动 standalone 时不再复制 `spacetimedb-cli`、版本目录或 `bin/current`
- `spacetime start` 不再通过工程内 CLI root 寻找可执行文件。
@@ -31,7 +29,6 @@
- `API_SERVER_TIMEOUT_SECONDS` 保持 600,降低首次冷编译误判失败概率。
## 复现 / 验证
- 运行脚本语法检查:`bash -n scripts/dev-rust-stack.sh`
- 运行帮助检查:`bash scripts/dev-rust-stack.sh --help`,确认有 `--spacetime-data-dir`
- 运行 `npm run dev` 后观察日志:
@@ -44,7 +41,6 @@
- api-server 进入健康检查等待并最终可访问 `/healthz`
## 相关文件
- `scripts/dev-rust-stack.sh`
- `server-rs/.spacetimedb/local/data/`
- `server-rs/.cargo/config.toml`
@@ -1,34 +1,28 @@
# 本地 private table SQL 权限修复
场景:
- 后台或 api-server 通过 SpacetimeDB HTTP SQL 读取 `tracking_event` 这类 private table。
- 本地清库、重建 standalone 或重新发布模块后,原 CLI token 失效,SQL 可能报 `no such table ... If the table exists, it may be marked private`
操作步骤:
1. 清空本地 SpacetimeDB 数据目录
- 使用项目脚本停止本地实例后,备份或删除 `server-rs/.spacetimedb/local/data`
- 只清本地开发环境,不要误伤远端或其他 worktree。
2. 启动本地 standalone
- 用项目约定的 `scripts/dev-rust-stack.sh` 或等价命令启动 `spacetime`
- 确认 `/v1/ping` 可访问后再取 identity。
3. 通过 `/v1/identity` 获取新 token 和 identity
- 使用 `POST http://127.0.0.1:3101/v1/identity`
- 只记录 identity,不要在日志中打印 token 明文。
4. 用新 token 登录 CLI
- 运行:`spacetime login --token <token>`
- 这会把 token 写到本地 CLI 配置,后续 HTTP SQL 可读 private table。
5. 重新验证 SQL
- 使用带 token 的 `POST /v1/database/<db>/sql`
- 先尝试 `SELECT ... FROM tracking_event LIMIT 1`
- 若成功,再让 api-server 走同样 token。
@@ -38,7 +32,6 @@
- 输出日志时统一 `[REDACTED]`
排查要点:
- `ORDER BY` 和 private table 是两个独立问题,先分开修。
- 清库后旧 token 很可能不再能看见 private table,不代表表不存在。
-`/v1/identity` 返回的 token 没权限,再检查当前 standalone 是否就是刚启动的本地实例、database 名是否一致、模块是否已重新发布。
@@ -4,14 +4,8 @@ description: 在 Genarrative 中排查或修改登录、access token、refresh c
license: MIT
metadata:
codex:
tags:
[Genarrative, auth, session, cookie, refresh-token, AuthGate, tracking]
related_skills:
[
systematic-debugging,
test-driven-development,
genarrative-profile-features,
]
tags: [Genarrative, auth, session, cookie, refresh-token, AuthGate, tracking]
related_skills: [systematic-debugging, test-driven-development, genarrative-profile-features]
---
# Genarrative 认证会话与登录埋点链路
@@ -4,16 +4,7 @@ description: 在 Genarrative 中修改 npm run dev / dev:spacetime / dev:api-ser
license: MIT
metadata:
codex:
tags:
[
Genarrative,
dev-stack,
端口探测,
Vite,
api-server,
SpacetimeDB,
npm-run-dev,
]
tags: [Genarrative, dev-stack, 端口探测, Vite, api-server, SpacetimeDB, npm-run-dev]
related_skills: [genarrative-admin-backoffice]
---
@@ -1,6 +1,6 @@
interface:
display_name: 'Genarrative External Editor API'
short_description: 'Route async canvas generation safely'
default_prompt: 'Use $genarrative-external-editor-api to discover the hosted integration, prepare a canvas session, and submit and poll asset generation into the canvas and library.'
display_name: "Genarrative External Editor API"
short_description: "Route async canvas generation safely"
default_prompt: "Use $genarrative-external-editor-api to discover the hosted integration, prepare a canvas session, and submit and poll asset generation into the canvas and library."
policy:
allow_implicit_invocation: true

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