🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

Agent 办公室 QingJ01/magpie-agent-office

DeepSeek Harness
QingJ015 天前有提交已提供中文文档扫描:含敏感能力

把编码智能体的实时状态变成太空站里的小人

30.7/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/30 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add QingJ01/magpie-agent-office
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · ui
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 5 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 172 处,展示前 95 条)
  • 读取本地文件
    bin/agent-office.mjs:21
    const VERSION = JSON.parse(readFileSync(join(here, "package.json"), "utf8")).version
  • 删除本地文件递归
    bin/agent-office.mjs:88
    rmSync(scratch, { recursive: true, force: true })
  • 读取本地文件
    bin/agent-office.mjs:158
    if (!statSync(file).isFile()) return new Response("not found", { status: 404 })
  • 读取本地文件
    bin/agent-office.mjs:159
    return new Response(readFileSync(file), {
  • 发起网络请求
    bin/agent-office.mjs:208
    async fetch(req) {
  • 删除本地文件递归
    bin/agent-office.mjs:220
    rmSync(scratch, { recursive: true, force: true })
  • 执行外部命令来自配置/变量
    bin/agent-office.mjs:232
    try { spawn(cmd, argv2, { stdio: "ignore", detached: true }).on("error", () => {}).unref() } catch {}
  • 删除本地文件递归
    bin/agent-office.mjs:238
    rmSync(scratch, { recursive: true, force: true })
  • 读取本地文件
    agent-office.test.mjs:12
    const read = (f) => readFileSync(join(page, f), "utf8")
  • 读取本地文件
    agent-office.test.mjs:13
    const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"))
  • 删除本地文件递归
    agent-office.test.mjs:40
    afterAll(() => { for (const d of tmps) rmSync(d, { recursive: true, force: true }) })
  • 读取本地文件
    agent-office.test.mjs:58
    expect(readdirSync(page)).toContain(m[1].split("?")[0])
  • 读取本地文件
    agent-office.test.mjs:67
    for (const m of readFileSync(join(dir, "README.md"), "utf8").matchAll(/! [^ ]* ([^)]+) /g)) {
  • 读取本地文件
    agent-office.test.mjs:93
    for (const f of readdirSync(page).filter((f) => f.endsWith(".js") && !["live.js", "scene3d.js", "three.min.js"].includes(f))) {
  • 读取本地文件
    agent-office.test.mjs:107
    const icons = new Set(readdirSync(join(page, "icons")))
  • 写入本地文件
    agent-office.test.mjs:161
    mkdirSync(cl, { recursive: true }); mkdirSync(cx, { recursive: true })
  • 写入本地文件
    agent-office.test.mjs:162
    writeFileSync(join(cl, "c1.jsonl"), F.claudeRunning)
  • 写入本地文件
    agent-office.test.mjs:163
    writeFileSync(join(cx, "rollout-2026-10-28T10-00-00-019a0000-0000-7000-8000-000000000001.jsonl"), F.codexApproval)
  • 写入本地文件
    agent-office.test.mjs:173
    writeFileSync(join(cl, "c1.jsonl"), F.claudeDone)
  • 写入本地文件
    agent-office.test.mjs:181
    mkdirSync(sd, { recursive: true })
  • 写入本地文件
    agent-office.test.mjs:184
    writeFileSync(file, Bun.zstdCompressSync(enc(F.dshApproval)))
  • 发起网络请求
    agent-office.test.mjs:319
    expect(t.request({ model: "m", tools: [1], messages: [{ role: "user", content: "x" }] }, { origin: "remote", agent: "a", session: "s" }, 1)).toBeNull(
  • 删除本地文件递归
    cli.test.mjs:14
    afterAll(() => { for (const d of tmps) rmSync(d, { recursive: true, force: true }) })
  • 写入本地文件
    cli.test.mjs:20
    mkdirSync(project, { recursive: true })
  • 写入本地文件
    cli.test.mjs:22
    writeFileSync(join(project, "s1.jsonl"), [
  • 发起网络请求
    cli.test.mjs:69
    return fetch(server.url + "api/options", { method: "POST", headers: { origin: server.origin, "content-type": "application/json", ...headers }, body: J
  • 发起网络请求
    cli.test.mjs:105
    const ping = await (await fetch(s.url + "api/ping")).json()
  • 发起网络请求
    cli.test.mjs:108
    const page = await fetch(s.url)
  • 发起网络请求
    cli.test.mjs:114
    expect(await (await fetch(s.url + "app.js")).text()).toContain("live.js?t=")
  • 发起网络请求
    cli.test.mjs:115
    const bridge = await (await fetch(s.url + "_magpie/bridge.js")).text()
  • 发起网络请求
    cli.test.mjs:118
    const live = await fetch(s.url + "live.js?t=123")
  • 请求外部主机evil.example
    cli.test.mjs:154
    expect((await fetch(s.origin + "/api/options", { method: "POST", headers: { origin: "https://evil.example", "content-type": "text/plain" }, body: '{"t
  • 读取本地文件
    cli.test.mjs:215
    expect(readFileSync(script, "utf8").split("\n")[0]).toBe("#!/usr/bin/env bun")
  • 删除本地文件递归
    clients.test.mjs:17
    afterAll(() => { for (const d of tmps) rmSync(d, { recursive: true, force: true }) })
  • 写入本地文件
    clients.test.mjs:41
    mkdirSync(join(p, ".."), { recursive: true })
  • 写入本地文件
    clients.test.mjs:42
    writeFileSync(p, Array.isArray(body) ? body.map(j).join("\n") + "\n" : typeof body === "string" ? body : j(body))
  • 写入本地文件
    clients.test.mjs:262
    utimesSync(p, before / 1000, before / 1000)
  • 读取本地文件
    clients.test.mjs:286
    expect(statSync(p).size).toBeGreaterThan(576 * 1024)
  • 删除本地文件
    clients.test.mjs:348
    rmSync(join(h, rel, "usage.json"))
  • 写入本地文件
    clients.test.mjs:405
    const compressed = (events) => writeFileSync(p, Bun.zstdCompressSync(Buffer.from(events.map(j).join("\n") + "\n")))
  • 删除本地文件递归
    cold-scan.test.mjs:9
    afterAll(()=>{for(const root of roots)rmSync(root,{recursive:true,force:true})})
  • 写入本地文件
    cold-scan.test.mjs:27
    writeFileSync(path,line(user("cold image work"))+image.repeat(4))
  • 写入本地文件
    cold-scan.test.mjs:40
    writeFileSync(path,image+tail)
  • 写入本地文件
    cold-scan.test.mjs:47
    appendFileSync(path,more)
  • 写入本地文件
    cold-scan.test.mjs:50
    appendFileSync(path,'"}\n'+line(user("after image")))
  • 读取本地文件
    facing.test.mjs:4
    new Function('globalThis', readFileSync(new URL('./page/scene.js', import.meta.url), 'utf8'))(scope)
  • 读取本地文件
    features.test.mjs:10
    const read = (f) => readFileSync(join(page, f), "utf8")
  • 读取本地文件
    features.test.mjs:197
    for (const f of readdirSync(page).filter((f) => f.endsWith(".js") && f !== "live.js")) expect(read(f)).toBeTruthy()
  • 删除本地文件递归
    incremental-scan.test.mjs:9
    afterAll(()=>{for(const root of roots)rmSync(root,{recursive:true,force:true})})
  • 写入本地文件
    incremental-scan.test.mjs:24
    writeFileSync(path,line(user("old"))+padding.repeat(Math.ceil(100*1024*1024/Buffer.byteLength(padding)))+line(done()))
  • 读取本地文件
    incremental-scan.test.mjs:26
    const size=statSync(path).size
  • 写入本地文件
    incremental-scan.test.mjs:32
    appendFileSync(path,appended)
  • 写入本地文件
    incremental-scan.test.mjs:45
    writeFileSync(path,record.subarray(0,split))
  • 写入本地文件
    incremental-scan.test.mjs:48
    reset();appendFileSync(path,record.subarray(split))
  • 写入本地文件
    incremental-scan.test.mjs:52
    appendFileSync(path,tool)
  • 写入本地文件
    incremental-scan.test.mjs:54
    appendFileSync(path,line({type:"user",timestamp:stamp,message:{role:"user",content:[{type:"tool_result",tool_use_id:"tool",content:"ok"}]}}))
  • 读取本地文件
    incremental-scan.test.mjs:98
    const reader=scanner.files.get(path).reader,identity=statSync(path)
  • 读取本地文件
    incremental-scan.test.mjs:103
    expect(statSync(path).ino).not.toBe(identity.ino)
  • 读取本地文件
    incremental-scan.test.mjs:135
    const original=statSync(path)
  • 读取本地文件
    incremental-scan.test.mjs:139
    expect(statSync(path).ino).not.toBe(original.ino)
  • 读取本地文件
    incremental-scan.test.mjs:142
    const size=statSync(path).size
  • 删除本地文件
    incremental-scan.test.mjs:183
    rmSync(meta)
  • 读取本地文件
    killed.test.mjs:14
    const fixture = (n) => readFileSync(join(dir, "test", "killed", n), "utf8")
  • 读取本地文件
    killed.test.mjs:16
    new Function("globalThis", readFileSync(join(dir, "page", "agents.js"), "utf8"))(scope)
  • 读取本地文件
    killed.test.mjs:17
    new Function("globalThis", readFileSync(join(dir, "page", "model.js"), "utf8"))(scope)
  • 删除本地文件递归
    killed.test.mjs:22
    afterAll(() => { for (const d of tmps) rmSync(d, { recursive: true, force: true }) })
  • 写入本地文件
    killed.test.mjs:38
    mkdirSync(proj, { recursive: true })
  • 写入本地文件
    killed.test.mjs:40
    writeFileSync(f, fixture(file))
  • 写入本地文件
    killed.test.mjs:42
    utimesSync(f, t, t)
  • 写入本地文件
    killed.test.mjs:44
    mkdirSync(join(h, "sessions"), { recursive: true })
  • 写入本地文件
    killed.test.mjs:45
    for (const p of procs) writeFileSync(join(h, "sessions", p.pid + ".json"), JSON.stringify({ pidDomain: process.platform, kind: "interactive", ...p }))
  • 删除本地文件
    killed.test.mjs:103
    rmSync(join(h, "sessions", process.pid + ".json"))
  • 读取本地文件
    lib/scan.mjs:41
    try { names = readdirSync(join(omp, "profiles"), { withFileTypes: true }) } catch { return out }
  • 读取本地文件
    lib/scan.mjs:91
    try { names = readdirSync(root, { withFileTypes: true }) } catch { return }
  • 读取本地文件
    lib/scan.mjs:100
    try { st = statSync(p) } catch { continue }
  • 读取本地文件
    lib/scan.mjs:211
    const raw = readFileSync(path)
  • 读取本地文件
    lib/scan.mjs:232
    try { names = readdirSync(dir) } catch { return null }
  • 读取本地文件
    lib/scan.mjs:239
    try { st = statSync(p) } catch { continue }
  • 读取本地文件
    movement.test.mjs:4
    new Function('globalThis', readFileSync(new URL('./page/scene.js', import.meta.url), 'utf8'))(scope)
  • 读取本地文件
    office.hooks.mjs:38
    const own = JSON.parse(readFileSync(join(here, "package.json"), "utf8"))
  • 写入本地文件
    office.hooks.mjs:115
    mkdirSync(PAGE, { recursive: true })
  • 写入本地文件
    office.hooks.mjs:117
    writeFileSync(tmp, PREFIX + body + ";\n")
  • 写入本地文件
    office.hooks.mjs:118
    renameSync(tmp, LIVE)
  • 发起网络请求
    office.hooks.mjs:149
    const key = track(options).request(body, ctx, Date.now())
  • 读取本地文件
    office.hooks.mjs:189
    try { list = JSON.parse(readFileSync(file, "utf8")) } catch { continue }
  • 删除本地文件递归
    privacy.test.mjs:11
    afterAll(() => { for (const d of tmps) rmSync(d, { recursive: true, force: true }) })
  • 写入本地文件
    privacy.test.mjs:21
    mkdirSync(project, { recursive: true })
  • 写入本地文件
    privacy.test.mjs:22
    writeFileSync(join(project, "secret.jsonl"), [
  • 写入本地文件
    privacy.test.mjs:35
    if (where === "cwd") writeFileSync(join(work, "plugins.json"), doc)
  • 写入本地文件
    privacy.test.mjs:37
    mkdirSync(join(cfg, "magpie"), { recursive: true })
  • 写入本地文件
    privacy.test.mjs:38
    writeFileSync(join(cfg, "magpie", "plugins.json"), doc)
  • 执行外部命令来自配置/变量
    privacy.test.mjs:48
    const r = spawnSync(process.execPath, ["-e", code], { cwd: where === "cwd" ? work : dir, env, encoding: "utf8" })
  • 读取本地文件
    privacy.test.mjs:50
    return readFileSync(join(out, "live.js"), "utf8")
  • 读取本地文件
    scene-extra.test.mjs:9
    new Function('globalThis', readFileSync(new URL('./page/scene.js', import.meta.url), 'utf8'))(scope)
  • 读取本地文件
    sofa.test.mjs:4
    new Function('globalThis', readFileSync(new URL('./page/scene.js', import.meta.url), 'utf8'))(scope)
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
涉及外部主机:evil.example

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
展开完整介绍(139 字)↓

我的 Agent 在干嘛:实时展示 Claude Code、Codex、DeepSeek Harness、Gemini CLI 等 Agent 的工作状态,3D/2D 太空站办公室、悬浮窗与列表。Live agent activity dashboard for magpie.

README

由 DeepSeek 最新模型翻译生成
Agent Office · 我的 Agent 在干嘛 一个住在 magpie 窗口里的实时 Agent 办公室。 直接读取各 Agent 自己的会话记录,把正在思考、执行工具、等待批准或已经完成的工作,变成太空站里的小人。支持等距 3D、俯视 2D、实时列表和可拖动的悬浮小窗。 一个实时活动面板,把编码智能体搬进 magpie:每个会话都变成体素太空站办公室里的一名小工人,数据来自智能体自己的会话文件,而不是靠网络流量猜。 Agent Office in magpie's window 快速开始 · Quick start magpie plugin add QingJ01/magpie-agent-office 安装后打开 插件 › Agent 办公室。默认显示真实会话,不是演示数据;第一次没有会话时会看到空办公室。想预览完整效果,可在 设置 › 示例 Agent 临时打开示例。 - 3D / 2D:等距太空站或俯视图。 - 办公室 / 列表:实时状态、当前步骤、目录、模型和最近活动时间。 - 点击小人或列表行:查看任务、最近提问、工具步骤、回复摘要和续接命令。 - 画中画:可拖动、可缩放的悬浮小窗,✕ 或 Esc 放回。
展开完整文档(README 剩余 1 节)
Agent Office · 我的 Agent 在干嘛

一个住在 magpie 窗口里的实时 Agent 办公室。 直接读取各 Agent 自己的会话记录,把正在思考、执行工具、等待批准或已经完成的工作,变成太空站里的小人。支持等距 3D、俯视 2D、实时列表和可拖动的悬浮小窗。

一个实时活动面板,把编码智能体搬进 magpie:每个会话都变成体素太空站办公室里的一名小工人,数据来自智能体自己的会话文件,而不是靠网络流量猜。

Agent Office in magpie's window

快速开始 · Quick start

magpie plugin add QingJ01/magpie-agent-office

安装后打开 插件 › Agent 办公室。默认显示真实会话,不是演示数据;第一次没有会话时会看到空办公室。想预览完整效果,可在 设置 › 示例 Agent 临时打开示例。

- 3D / 2D:等距太空站或俯视图。
- 办公室 / 列表:实时状态、当前步骤、目录、模型和最近活动时间。
- 点击小人或列表行:查看任务、最近提问、工具步骤、回复摘要和续接命令。
- 画中画:可拖动、可缩放的悬浮小窗,✕ 或 Esc 放回。

支持直接读取会话文件的 Agent:Claude Code、Codex、DeepSeek Harness、Gemini CLI、Qwen Code、Pi、omp、Qoder、WorkBuddy、CodeBuddy。其他 Agent(Cursor、OpenCode、Copilot、Kimi 等)在通过 magpie 的模型工作时也会显示。

它会读取什么: 这些 Agent 写在本机的会话文件,包括提问、回复和工具命令,并在插件自己的目录里生成 page/live.js 供页面显示。设置里关闭「显示提问和回复」后只保留状态与工具名,不再写入提问、回复或命令参数。

仓库带有 magpie-plugin topic,因此也会出现在 插件 › 发现 › 非官方插件 · GitHub。插件市场的收录进展见 magpie-community/plugins。

功能与状态 · 数据来源 · 隐私 · 设置 · 限制 · 开发测试

小人在哪,就在做什么

| 状态 | 位置 | 标志 |
| Thinking · 思考中 | 坐在桌前 | … |
| Running tools · 执行中 | 坐在桌前,敲着键盘,屏幕亮着 | 转圈,已运行多久 |
| Replying · 回复中 | 坐在桌前 | 一行行文字 |
| Waiting for you · 等你回应 | 站在紫色方块里挥手 | ! |
| Done · 已完成 | 在沙发上,20 分钟后睡着 | z |
| Error · 错误 | 坏掉的操控台前 | × |

顶部的数字分别是:多少人需要你(等批准或等回答、出错、卡住),多少人在干活,多少人已完成。下面是真实会话:DeepSeek Harness 正在执行工具,Codex 已完成躺在沙发上,点一下打开第一个会话的面板:

A real session's panel

每个小人朝哪边

座位决定主人朝哪看:坐在书桌前就面朝书桌,显示器立在书桌远端边缘,亮面朝向人,椅背在身后;坐在左墙沙发上朝东,坐在前墙沙发上朝北,背对靠背。头朝镜头时显示正脸,朝东时显示侧脸,背对镜头时显示后脑勺。

动作与待机小动作

已完成的智能体会偶尔伸懒腰、侧头看、晃腿或打瞌睡。各自的节奏不同,走路或工作时这些动作会暂停。新动作遵循系统的「减少动态效果」偏好;名牌保持静止。

沙发会挡住正常步行路线,包括靠背后面的空间。每个座位都有正面入口:穿过过道,从正面入座,再沿同一条路线离开。入座途中改道会先回到过道。路径平滑会检查经过的每个网格单元,目标不可达时绝不会退化成直接穿过家具。

它怎么知道

读每个智能体自己的会话文件,以智能体写入的内容为准,不靠流量猜测。插件的宿主部分(magpie 打开时运行在 magpie 的插件宿主里)每 1.5 秒读一次,只读变化的部分:

| 智能体 | 读取的文件 |
| Claude Code | ~/.claude/projects//.jsonl |
| Codex | ~/.codex/sessions/YYYY/MM/DD/rollout-.jsonl(标题另读 session_index.jsonl) |
| DeepSeek Harness | ~/.dsh/sessions///session.v4.jsonl.zstd |
| Gemini CLI · Qwen Code | ~/.gemini/tmp//chats/session-、~/.qwen/tmp//chats/session- |
| Pi · omp | ~/.pi/agent/sessions//.jsonl、~/.omp/agent/sessions//.jsonl |
| Qoder · WorkBuddy · CodeBuddy | 各自的 projects//.jsonl(Claude Code 的格式) |

这些智能体认的 _HOME / *_CONFIG_DIR 变量,这里同样认。文件内容直接决定状态:工具调用还没有结果就是运行中,请求审批(Codex 的 exec_approval_request、DeepSeek Harness 的 approval/asked、Gemini 的 awaiting_approval)就是等你确认,提问工具就是问了你问题,一轮结束就是完成,中断就是已停止,出错的一轮就是错误。某一轮的文件十分钟没动,显示为卡住。

其他智能体(Cursor、OpenCode、Copilot、Kimi……)工作时通过 magpie 显示:这个模块同时是异步网关钩子,能看到它们的请求。钩子不返回响应体,所以不会改动任何请求。

两者都会在页面旁边写 page/live.js,页面每秒加载一次(插件页面没有网络,但可以加载自己的文件)。标题旁的绿色 live 圆点,在宿主停止写入后变灰。

magpie 认识的全部 60 个智能体都有自己的名字和图标,用的是 magpie 自己展示的文件(page/icons,来自 magpie 的资源,MIT 协议)。

使用方法

悬停只会高亮某个 worker。点击 worker、它的名牌或列表中的某一行,就能打开它的面板——任务、你最近一次问的内容、它当前所处的步骤、它的回答如何开头、它的模型和文件夹,以及 Resume command(显示为选中状态,按 ⌘C / Ctrl+C 即可复制)——面板会一直留在侧边,直到你关闭它(✕ 或 Esc)或点击另一个智能体。

隐私

- 它读取本机上智能体的会话文件,只读,且只读最近两天的。通过网关,它只记录本机发出的请求(magpie 的 origin: local),除非你设置 "remote": true。
- live.js 保存智能体、会话 id、文件夹名和路径、模型、最近一次提示词(200 字符)、最近一次回答的前 280 字符,以及最近工具调用的名称和目标。它绝不保存密钥、请求头或完整对话。设置 "text": false(设置 › Show prompts and replies,关闭)后,它只保留状态和工具名。
- live.js 留在插件文件夹里,绝不发送到任何地方。页面完全不向 magpie 请求数据:它的 permissions 列表是空的。

画中画

画中画(Picture in picture)把办公室抬进页面自己的小窗口,浮在页面其余部分之上:拖动它的标题栏可移动,拖动它的角可改变形状,点击 ✕ 或按 Esc 可放回去。只有需要你的智能体才会在那里保留名牌;悬停其中任意一个即可看到卡片。

The office in its own window, in magpie

magpie 用 allow="" 和 sandbox="allow-scripts" 框住插件的页面,所以浏览器自带的浮动窗口( 的画中画,或 documentPictureInPicture)会被拒绝给其中的页面——这是最先尝试的方案,结果屏幕上什么也没留下。在页面内绘制的窗口则不会。

2D
The list

选项

{ "mode": "office", "dim": "3d", "demo": false, "showDone": true, "hideAfter": "6h", "text": true, "remote": false }

| 键 | |
| mode | office 或 list |
| dim | 3d 或 2d |
| demo | 显示示例智能体(设置 › Sample agents) |
| showDone | 让已完成的智能体留在沙发上 |
| hideAfter | 已完成或失败的智能体何时离开:1h、6h、24h、never |
| text | 保留提示词和回答(false:只保留状态和工具名) |
| remote | 网关部分也记录来自其他电脑的请求和网关密钥 |
| approvalAfterSec | 对于只能通过网关看到的智能体:它的工具运行多久后算作在等你(90) |

前五项你改动后页面会立即保存;改动会重启插件的宿主(magpie 的选项就是这样),所以它会等你停手一会儿再执行。

它无法知道的事

- 智能体不读它的文件,也不用 magpie 的模型。 这里完全没有它的记录。
- 模型逐字输出的进度。 每条消息写一个文件,所以「正在回复」的意思是:会话的文件在动,模型已经开始作答。
- 超过两天的会话,或不在最新 40 条之内的会话:直接略过,让每次读取都便宜。

文件

- lib/readers.mjs — 把每个智能体的会话格式转成阶段、步骤、提示词和回答。不做 I/O。
- lib/scan.mjs — 在每个智能体的文件夹里找文件,只重读有变化的那几个。
- lib/track.mjs — 网关钩子保存的内容,来自各个 API(Anthropic Messages、Chat Completions、Responses、Gemini)的请求和回复。不做 I/O,所以测试可以直接驱动它。
- office.hooks.mjs — 宿主部分:每 1.5 s 扫描一次,读取网关的请求,写出 page/live.js。
- page/agents.js、page/icons/ — magpie 认识的所有智能体,各带自己的图标。
- page/model.js — 状态、计数、词(英文和中文)、智能体标记、恢复命令和示例智能体,不碰 DOM。
- page/scene.js — 办公室,画在 canvas 上,等距 3D 或俯视 2D。
- page/icons.js、page/app.js、page/index.html、page/style.css — 页面。

测试

bun test

已在 magpie 0.1.1318 自己的窗口(magpie web)里验证过,覆盖每个视图:3D、2D、列表,以及它自己的窗口。

许可证

MIT
预览分享卡片长什么样 ↓QingJ01/magpie-agent-office
分享 · DeepSeek Harness Hub
QingJ01/magpie-agent-office

把编码智能体的实时状态变成太空站里的小人

这是你的仓库?认领条目

回到顶部