1. 核心背景与场景痛点 (Context & Problem Statement)

1.1 iPad / iOS PWA(主屏幕 Web Clip)运行环境约束

用户将 InPage Agent 通过 Safari「添加到主屏幕」以独立窗口模式(Standalone WebApp)运行,具备近似原生 App 的全屏体验,但带来两个严重挑战:

  1. 无地址栏与刷新控制:用户无法主动按下 Ctrl+F5 或通过页面刷新强制拉取新代码,导致服务端更新(如接口协议调整、系统提示词哈希门禁)后,客户端常驻旧版 JavaScript 内存,引发突发性鉴权失败(如 403 Forbidden)。
  2. WebKit 存储逐出机制(Eviction Risk):iOS WebKit 在设备磁盘紧张或超过 7 天未激活时,可能静默清理未申请持久化的 LocalStorage / IndexedDB 数据,造成工作区内容和配置丢失。

1.2 需求目标

  1. 客户端版本感知与热更迁移机制:支持版本探测、UI 更新提示、以及跨版本数据结构平滑升级(补丁流水线)。
  2. 工作区全量备份与便携式迁移(.inpage.zip):将虚拟文件系统(VFS)原封不动与核心配置表合并打包为 Zip,实现零损耗导入导出。
  3. 会话记录文件系统化(.chat 规范):将 Agent 对话历史转化为 VFS 中的普通文件,天然纳入备份体系,并支持左侧文件树与右侧对话栏的专属交互路由。

2. 模块一:版本管理与数据迁移流水线 (Versioning & Migration Pipeline)

2.1 版本标识设计

在客户端全局定义两个维度的版本标识:

  • APP_VERSION(语义化应用版本,如 "0.2.0"):对应代码功能迭代,用于版本探测。
  • SCHEMA_VERSION(单调递增整数,如 2):对应存储数据结构(LocalStorage / IndexedDB),用于触发迁移补丁。

2.2 服务端版本声明与更新探测

  1. 构建期由 Vite 插件自动生成并在产物根目录释放 version.json:

    {
      "version": "0.2.0",
      "schemaVersion": 2,
      "buildTime": 1789971000000,
      "changelog": "支持会话文件化与全量 Zip 备份"
    }
  2. 客户端运行时:

    • 页面激活(visibilitychange 且为 visible)或每隔 15 分钟后台发起静默 HEAD/GET 探测 /version.json。
    • 若检测到 remote.version !== APP_VERSION,在界面顶栏或浮层显示优雅非阻塞提示:

      “发现新版本 v0.2.0,点击立即重启更新”
    • 用户点击后,调用 window.location.reload() 重新拉取资源。

2.3 数据结构升级补丁流水线 (Migration Engine)

当新版本加载完成后,首先比对存储中的 lastSchemaVersion 与当前代码的 SCHEMA_VERSION:

interface MigrationStep {
  fromVersion: number;
  toVersion: number;
  description: string;
  run: () => Promise<void>;
}

const MIGRATIONS: MigrationStep[] = [
  {
    fromVersion: 1,
    toVersion: 2,
    description: '将存储在 LocalStorage 中的临时配置与旧表结构迁移到 IndexedDB',
    run: async () => {
      // 1. 读取旧版 localStorage key
      // 2. 结构重映射并写入新版 IndexedDB 规范表
      // 3. 安全移除过时键
    },
  },
];
  • 补丁按顺序逐级串行执行,全部成功后写入最新的 SCHEMA_VERSION。
  • 若迁移发生异常,保留原始备份并降级报警,杜绝数据损坏。

3. 模块二:工作区全量导出与导入规范 (.inpage.zip)

3.1 打包结构设计

导出产物命名为 <项目名>-<日期时间>.inpage.zip,内部结构严格规整:

my-workspace-20260921.inpage.zip
├── .inpage/                      # 专有配置与元数据目录(导入时解析为环境状态)
│   ├── manifest.json             # 空间元信息(导出版次、时间、系统标识)
│   ├── settings.json             # 用户偏好(主题、排序模式、思考预算、昵称等)
│   ├── providers.json            # 模型渠道配置(已绑定的各模型端点信息)
│   ├── skills.json               # 已启用与自定义的 Skills 技能列表
│   └── plugins.json              # 插件市场已装插件状态
├── .archive/                     # 用户已归档的文件与目录(完整保留)
├── .output/                      # 工具产物(如 LaTeX 编译的 PDF 等)
└── [VFS 用户文件目录树]           # 虚拟文件空间中的全部文件(原封不动)
    ├── index.html
    ├── src/
    │   ├── main.ts
    │   └── lru.ts
    ├── notes/
    │   └── design.md
    └── chats/ (或根目录)
        └── 2026-09-21-lru开发.chat

3.2 导出流程规范

  1. 锁定空间:触发导出时开启轻量只读标志,防范正在流式写入。
  2. 提取配置:从 LocalStorage 与 IndexedDB 导出 settings、providers、skills、plugins 结构,格式化为 .inpage/*.json。
  3. 抽取 VFS 文件:读取 IndexedDB 中全部文件实体(包含文本与二进制图片/PDF),按相对路径原样添加到 Zip 文件中。
  4. 流式打包下载:使用 JSZip 生成压缩 Blob,触发浏览器保存为 .inpage.zip。

3.3 导入与恢复流程规范

  1. 格式校验:检查 Zip 根目录是否存在 .inpage/manifest.json。
  2. 导入冲突策略:

    • 完全覆盖(Clean Restore):先清空当前 IndexedDB 与 LocalStorage,再完整解压写入(推荐用于换机迁移)。
    • 安全合并(Merge Import):保留已有冲突文件并重命名为 .conflict.*,配置项按并集补全。
  3. 热重载触发:导入成功后通知各组件(文件树、工作台、对话栏)重新拉取数据,无需整页硬刷新。

4. 模块三:会话记录文件系统化 (.chat File Specification)

4.1 会话即文件(Conversation as a File)

以往 Agent 对话多存储在内存数组或专用的独立 IndexedDB store 中,容易脱离版本管理与文件备份。
核心决策:将每一场对话实体化为 VFS 虚拟文件系统中的一个 .chat 文件。

收益:

  1. 零成本参与全量备份:VFS 导出为 Zip 时,所有历史对话自然打包,免去编写专用会话导出逻辑。
  2. 文件系统原生操作:支持对会话进行重命名、拖拽分组到子文件夹(如 chats/work/)、按时间排序、移动与软删除(归档至 .archive)。
  3. Agent 自省可见:Agent 可以使用已有的 list_files / read_file 查阅或引用过去的对话记录。

4.2 文件命名与前端显示解耦

  • 存储层与真实文件名:始终具备 .chat 后缀,如 架构推演.chat、2026-09-21-会话1.chat。
  • 左侧文件树视图(FileTree)显示:

    • 前端渲染时检测 file.name.endsWith('.chat')。
    • 默认隐藏 .chat 扩展名,界面卡片仅显示 架构推演、2026-09-21-会话1。
    • 呈现专属会话气泡图标(区别于普通的 code/text 文件)。
    • 用户右键重命名时,输入的名称若未带 .chat,系统自动补齐 .chat 保存。

4.3 点击路由拦截机制(Dedicated Action Route)

  • 正常文件(如 .html, .ts, .md, .pdf)点击后调用 workspaceView.openFile(file) 在中央主工作台以 Tab 形式打开。
  • .chat 文件专属路由:

    • 阻止中间主工作台打开该文件(不占用代码编辑器 Tab)。
    • 确保右侧 Chat Rail 展开可见。
    • 将会话反序列化并载入 ChatView / AgentRuntime。
    • 用户可直接在右侧查看完整消息流并继续发问追问。

4.4 .chat 内部数据格式标准 (JSON Schema)

{
  "version": 1,
  "sessionId": "chat_1726900000_a8f9",
  "title": "LRU 缓存开发与重构",
  "createdAt": 1726900000000,
  "updatedAt": 1726900500000,
  "activeProviderId": "gateway-default",
  "effort": "medium",
  "messages": [
    {
      "id": "msg-1726900000100",
      "role": "user",
      "content": "请在 src/lru.ts 编写一个 LRU 缓存类",
      "timestamp": 1726900000100
    },
    {
      "id": "msg-1726900002200",
      "role": "assistant",
      "content": "好的,我已经使用 write_file 创建了该模块。",
      "timestamp": 1726900002200,
      "reasoning_content": "分析需求:需要双向链表加哈希表...",
      "tool_calls": [
        {
          "id": "call_123",
          "type": "function",
          "function": {
            "name": "write_file",
            "arguments": "{\"path\":\"src/lru.ts\",\"content\":\"...\"}"
          }
        }
      ],
      "toolDetails": [
        {
          "id": "call_123",
          "type": "function",
          "function": { "name": "write_file", "arguments": "..." },
          "status": "success",
          "result": "成功写入 1240 字节至 src/lru.ts"
        }
      ]
    }
  ]
}

5. 实施路线图 (Implementation Roadmap)

  1. 第一阶段(规范确立与准备,当前):

    • 确立版本迁移、.inpage.zip 归档结构与 .chat 会话文件标准。
    • 沉淀至开发文档与长期知识库。
  2. 第二阶段(会话文件化):

    • 扩充 VFS 允许格式(加入 chat 支持)。
    • 实现 AgentRuntime 的会话即时存档与载入。
    • 文件树点击拦截与 .chat 后缀视觉隐藏。
  3. 第三阶段(全量备份与便携恢复):

    • 集成 jszip,编写导出 .inpage.zip 与导入覆盖/合并流水线。
  4. 第四阶段(PWA 版本探测与补丁流水线):

    • 接入 /version.json 自动探测与“发现新版本”用户交互提示。
    • 编写 schemaVersion 升级补丁流水线。

本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps