npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cortico-world-presence

v0.3.2

Published

Cortico World: 在场感(Windows 专用)——能判别你是否离开/回到电脑前。★ 它会持续读前台窗口标题与键鼠空闲、并能截屏(屏幕上有什么截到什么),这些随模型调用发到你部署配置的模型端点;默认不启用。详细隐私说明见 README。 ★ 支持 Coopanion(Coo):已在 Coopanion 0.2.5 上装机验证;出问题可去 GitHub 提 issue,或到 QQ 群里 @筆離嘢(与作者名同名)。

Readme

cortico-world-presence

要求 Cortico 0.2.0 及以上(扩展契约 world 6,cortico.api: 6)。 在 Cortico 0.1.x 上装它不会被加载。这一条是 0.2.0 起的要求 —— 0.1.x 那一版要求旧契约。

Cortico 的「在场感」World:它能判别你是否离开 / 回到电脑前,也知道你正在用哪个窗口,想看的时候能截一张屏。 Windows 专用(传感器与截图都走 Win32,经由系统自带的 PowerShell,零安装)。

★ 隐私提示(从扩展市场装上之前先读这段)

它会给 bot 三样东西:

  1. 你在不在电脑前 —— presence.away / presence.back 就是「你离开了多久 / 你回来了」, 它读的是系统给的「距上次键鼠输入多少毫秒」,不记录你按了什么键、点了什么(没有键盘钩子);
  2. 你在用哪个窗口 —— 前台窗口的进程名与完整标题,持续采样(标题里常有文件名、网页标题、 聊天对象的名字);
  3. 屏幕本身 —— bot 想看的任何时候都能截屏:整屏、任意区域、任意窗口都行, 屏幕上有什么就截到什么(私聊窗口、邮件、密码管理器、视频画面一样截)。

这些东西去哪:

  • 本包自己不联网 —— 没有任何出站请求,我们这边也没有服务器;
  • 窗口标题、事件正文与截图是随模型调用发出去的,实际到达的地方就是你部署里配的那个 模型端点(你选的那个模型服务商,以及它的留存策略);
  • 截图另会按内容哈希存进 <部署>/data/media/,并在被上下文裁剪掉之前每次请求都重发一遍。

换句话说:开了它,等于把屏幕交给 bot 看,而这段内容要经过你选的模型服务商。

enabled 默认 false —— 装上不会自己开始采样。开之前请确认两件:①你能接受屏幕上出现的东西被发出去; ②你信得过那个端点的留存策略。想收紧就靠 enabled、pollIntervalMs,以及不在不该开的时候开着 (它没有「只截某个程序」「模糊标题」这类旋钮,这是刻意的:本包不做隐私开关,是开发者的拍板,不是漏做)。

在 Coopanion(Coo)上使用

已在 Coopanion 0.2.5(Windows x64 便携版)上装机验收:市场里检查与安装成功,重启后导入成功; 启用后传感器 online,presence_windows 的空闲值与前台窗口采样都有效。默认 digest 挡首帧只打底, 不会立刻投事件 —— 想看到东西要先压到 1 分钟或调一次 presence_windows。这一次没有单独测截图。

Coo 的扩展市场默认可能走镜像源(npmmirror),镜像上偶尔还没有新版本 —— 检查时报「registry 没有给出 cortico-world-presence 的 x.y.z 版本」,就把 Coo 的扩展源改成官方 https://registry.npmjs.org 再装。 装完或改过配置要整进程重启 Coo 才生效。

遇到问题:去 GitHub 开 issue —— https://github.com/biliye/cortico-world-presence/issues; 或者到 QQ 群里 @筆離嘢(和作者名同名)。附上 Coo 版本、本包版本和报错截图,再说清是哪一步出的。

怎么装

Windows 专用,零安装 —— 传感器与截图都走系统自带的 PowerShell,不用装任何别的东西。

  1. 装进部署:控制台「扩展 → 扩展市场」里找到它点安装(它在部署的 extensions/ 里跑一次 pnpm add);或手动 cd extensions && corepack pnpm add --ignore-workspace cortico-world-presence。 ★ 若本机默认源是镜像(npmmirror),装的时候显式指官方源 --registry=https://registry.npmjs.org/。
  2. 在部署的 config.json 里写 worlds.presence(至少 enabled: true,其余见下面的配置表), 重启实例。
  3. 重启后挂的是 digest 挡 —— 窗口变化只记账,每 20 分钟折成一条 presence.digest。想看效果先让她 presence_set_mode {mode:"digest", minutes:1} 压到 1 分钟,再在几个窗口之间来回切。

enabled 默认 false:装上去不会自己开始采样。

它给什么

  • 事件(被动):
    • presence.switched —— 前台窗口切到了哪(应用名 + 标题 + 上一个窗口停留多久);
    • presence.activity —— ambient 姿势下的合并批,或 call 姿势下 3 秒内的连续变化;
    • presence.away / presence.back —— 键鼠空闲超过阈值 / 恢复输入,带离开时长(从最后一次键鼠输入 算起,不是从「发现离开」算起);
    • presence.digest —— 压缩挡下每周期一份累计摘要:应用/窗口停留总时长、观测切换次数、最近状态; 原始逐段时间线按需查询,无切换仍计持续停留;
    • presence.down —— 传感器进程起不来或退了。
  • 工具(主动):
    • presence_windows —— 前台、键鼠空闲秒数、屏幕几何(虚拟屏 + 每台显示器)、每个可见窗口的 矩形;默认附活动摘要(压缩挡下这就是「结账」:当场给累计视图、周期重开)。 view:"timeline" 按记录编号分页读取原始时间线,不列当前窗口、不清账、不重开周期;
    • presence_screenshot —— 截图。三种瞄准方式,优先级:x/y/width/height(任意矩形区域)> hwnd(整个窗口)> target(foreground 默认 / full);PNG 或 JPEG 直接附进回执, 模型不吃图时回执里会把话说破。grid:true 会在图上叠一层淡格线(每条线旁标着它自己的桌面坐标); 回执里始终写着「图上 1px = 桌面多少 px」与图左上角对应的桌面点;
    • presence_set_mode —— 切四挡投递姿势(见下);运行态,重启回默认的 digest。

四挡投递姿势(2026-10-13 加的后两挡,并把默认从 ambient 换成了 digest)

| 挡 | 窗口变化 | 离开 | 回来 | 叫醒 | |---|---|---|---|---| | digest(压缩,默认) | 只记账,每周期(默认 20 分钟)投一份累计摘要 | 投 + 记进摘要 | 投 + 记进摘要 | 只有「回来」,且要离开够久 | | ambient | 攒成批、合并投出 | 单独事件,随下轮送达 | 单独事件,随下轮送达 | 不叫醒 | | call | 每次变化当场投(3 秒合并) | 单独事件,随下轮送达 | 当场投 | 窗口变化;「回来」要离开够久 | | off(关闭) | 只留档、不主动投 | 当场投 | 当场投 | 只有「回来」(要够久);切到「本次运行第一次见到的程序」报一行但不叫醒 |

  • 「离开」在任何挡下都不叫醒(2026-10-13 他定的)——他离开时她多半没什么可做的。事件照投, 只是随她下次开口一起到(即 call 挡下窗口变化仍叫醒、只有「离开」这一条不叫醒)。

  • 「回来」要离开够久才叫醒(2026-10-14 他定的):离开超过 backWakeAfterMs(默认 10 分钟) 才当场叫醒,更短的只 piggyback、随她下次开口一起到——免得为「他去倒杯水」打断她。设 0 就 回到「每次回来都叫醒」。ambient 挡一直不叫醒。

  • 两个时长都从「最后一次键鼠输入」算起(2026-10-14 修):presence.away 正文写明最后一次输入在 几点,presence.back 报的是真实离开时长,摘要里的「离开键盘累计」同样。注意事件到达仍然比 真正离开晚 awayAfterMs——那是阈值检测的固有代价,改的是它说的是几点。

  • 压缩挡默认列累计时长、切换次数与最近状态。周期用 presence_set_mode {mode:"digest", minutes:5} 可以临时改;想立刻要一份就调 presence_windows(结账,当场给、周期重开)。精度就是轮询粒度,周期末尾还开着的那个窗口 只能算到结账那一刻;下周期从结账时刻继续累计,不重复算前一周期。

  • 关闭挡是投递静音,不是关掉这个 World:传感器照采、两个工具照用;跟配置里的 enabled:false (整个 World 不启动)是两码事。「没见过」按程序名算、只在本次运行内有效——重启后前几个 窗口会再被当成新的报一次。

  • 离开/回来在任何挡下都投自己的事件名(presence.away / presence.back),不再混进窗口变化的 批里(从前单独一条会被错标成 presence.switched,顺手修掉)。「离开」不叫醒、「回来」要达到 门槛才叫醒(见上两条)。

累计摘要与按需时间线(2026-10-14)

digest 的自动事件和 digest/off 下默认的 presence_windows 结账都给紧凑视图:

  • 应用按进程名(忽略大小写)累计;窗口按应用、句柄和完整标题累计,标题变化另算窗口项。
  • 各列时长前 5 项,其余报项数与合计;展示标题截短,原始时间线保留完整标题。
  • 切换次数是本周期观测到的窗口/标题变化,不用“时段数减一”估算;首次采样、重复采样、结账不算切换。
  • 没切换也有持续时长。前台停留包含键鼠空闲,不等于工作时长;离开键盘另计,与窗口时段可能重叠。 尚未回来也会按结账时刻分段,回来后不会重复算上一周期。前台采样为 null 时停止累计旧窗口。 离开段的起点是最后一次键鼠输入那一刻(不再是「发现离开」那一刻)。

每份摘要附记录编号。查询旧记录不会调用桌面采样、清账或重置计时器:

{"view":"timeline","snapshot":"摘要中的编号","offset":0,"limit":40}

以上参数传给 presence_windows。snapshot 省略取最近一次结账;offset 从 0 起,limit 默认 40、 范围 1–100;回执给下一页参数。原始时间线按起始时间排序,记录编号在新周期产生后仍稳定。 仅保留最近 8 次有效结账,每份最多 400 段,运行态、重启即忘;编号过期明确失败。 账本超限时会报告丢弃段数,累计时长与时间线只覆盖保留段,切换次数仍覆盖整个周期。 off 切到其他挡时不主动发送摘要,但保留这一份时间线供查询。ambient/call 的投递方式维持原状。

坐标与区域

坐标一律是物理像素、虚拟屏坐标(主屏左上为原点,主屏左边的显示器是负坐标)。两个脚本都声明 DPI 感知,所以窗口矩形与区域坐标同一坐标系,可以直接用来框。

  • 框到屏幕外会被夹回虚拟屏内,回执里说明实际抓了哪一块;完全不重叠则报错并给出屏幕范围。
  • 区域长边超过 1600 会被等比压小,回执里会提醒「想看清小字就把框框小一点」,并写明「图上 1px = 桌面多少 px」与图左上角对应的桌面点——小框不走降采样,按原始像素给,这是「读屏幕上的小字」 的唯一办法;
  • grid:true 会在图上叠一层淡格线,每条线落在桌面坐标的整百处、线旁标着那个坐标;被压过的大图 上间距自动翻倍(2560 宽压到 1600 时 100→200 桌面像素),回执里报出实际间距与条数。要按图上的 位置去点什么东西时加它;
  • 区域截的是屏幕上那一块的当前样子(遮挡也算),与 hwnd 的 PrintWindow 不同。
  • 盯同一块看变化:World 记住每块区域上次的 sha256,回执直接给「和上次一样(像素级完全相同)」 或「有变化」。运行态、重启即忘。时钟/视频这类常动的东西会让它永远显示有变化,环境提示词里说了; 图上那个鼠标箭头也算进去(它是我们画的),所以光标挪进框里来过一次,这块就「有变化」—— 真盯着一块看的时候用 cursor:false,那条「和上次一样」才说得出口(见下)。

图上的鼠标(2026-10-07 加的)

抓屏本身拍不到光标——量过:围着光标框一张 PNG,图里没有箭头。所以图上的箭头是我们照着系统的 真光标画上去的(GetCursorInfo 拿位置与位图,DrawIconEx 画在降采样之后的图上)。

几条分寸:

  • 画的是系统真光标那一张位图,所以形状是如实的:箭头=普通地方、I 形=能打字的地方、沙漏=窗口忙。 这比一个固定的箭头图标多一层信息(「这一点上是什么」),代价是形状随系统主题变。
  • 跟着图一起缩:按这块画面被压的比例缩,但最小 16 像素——被压过的大图上它不会小成一个点。
  • 只画在真抓屏的图上。hwnd 那条走 PrintWindow(画面是窗口自己绘的帧,可能被别的窗口盖着、 光标根本不在上面),那种一律不画,并在回执里说清是这条原因。抓屏那条(全屏/区域/前台窗口)照画。
  • 系统把光标藏起来时也不画(全屏视频、某些程序会自己隐藏),如实说。
  • 不在这张图里就不画,并说出图覆盖的是哪一块——不然她会把「没有箭头」读成「光标不在这块」 或者「这个功能坏了」。
  • 回执里始终给出光标的桌面坐标(虚拟屏物理像素),不管画没画。图上有箭头 + 正文里有数字, 两样一起她才既看得见又量得准。
  • 采样在抓屏那一刻之前读一次(帧是瞬时的,越靠近它越准),不是每张图各读一遍。

她可以不要那个箭头(cursor:false,默认画):位置照读照报,可选的只有图上那支箭头, 所以关掉它不会让她丢任何有用的信息。要它的场合是两处:

  • 盯同一块看变化(反复截同一块,回执说「和上次像素级完全相同」还是「有变化」)——她刚用鼠标 点完某处,光标常常正好停在她要盯的那一块里,一个会动的箭头会让「完全相同」永远说不出口;
  • 读那一块的小字——二十个像素的箭头能盖掉一个字(实测:240×120 那一块里,箭头压着的那行字 在关掉之后才读得全)。

为什么不做成部署配置里的开关:这不是「他的偏好」而是「这一次要看什么」——同一张工具在两种用途 之间来回,所以它按包内惯例做成每次调用一个布尔(与 grid 同一个形状),而不是一个在 config 里 改完要重启的档位。少一个旋钮,也少一处「改完得重启才生效」。

截图的成本与临时性

图是真的进上下文(ToolOutcome.blobs),不是只留档:框架把它按内容哈希存进 <部署>/data/media/,同时每次请求都从那个文件读回来、以 data URL 重发一遍,直到这条回执 被上下文裁剪挤出去。持续多久取决于部署的上下文预算与裁剪策略;把观察写成文字不会删除原图。

因此三条经济性设定:

  • 默认只截前台窗口,不再默认全屏——少暴露、少像素;
  • 照片类画面自动转 JPEG(判定:PNG 字节数 ÷ 像素数 > 0.5;实测文字界面 0.10、视频窗口 1.21), 体积差一个数量级;文字界面保持 PNG,字才清楚;
  • 回执里明说图是临时的,并请她把要紧的内容写成文字;第 2 张起还会提一句 presence_windows 更省。想接着看他在干什么,反复查窗口列表比反复截图划算得多。

框架侧目前没有让工具回执照「只用一轮」的机制(ephemeral 只接了事件,没接工具回执), 所以「图一直躺在上下文里」这件事从 World 里解决不了,只能这么压着。值得给 Cortico 提。

配置(worlds.presence)

| 键 | 默认 | 说明 | |---|---|---| | enabled | false | bot 或部署启用 | | pollIntervalMs | 10000 | 轮询间隔;两次轮询之间的瞬时变化看不见。下限 2000,改完要重启 World | | awayAfterMs | 300000 | 键鼠空闲超过这么久算「离开」。热生效 | | backWakeAfterMs | 600000 | 「回来」值得当场叫醒的离开时长;更短的只随她下次开口一起到。0 = 每次回来都叫醒。热生效。要比 awayAfterMs 长才有意义 |

没有密钥。窗口标题与截图会随模型调用发到部署配置的模型端点——这是设计内的事,部署者知情; 不加隐私旋钮是开发者的拍板(2026-09-19)。

验证

pnpm typecheck
pnpm test      # 单元测试用注入的假传感器;另有一条真 PowerShell 的采样用例
pnpm smoke     # 对真桌面:采样 6 秒 + 列窗口 + 真截全屏、一块区域、光标周围那一块(都落盘)

pnpm test 里有一条独立验证:截图前后各另起一个进程、用另一条 API(GetCursorPos)量一次光标, 被测代码报出来的那个点必须落在两次之间。这挡的是「写死的坐标」「恒为 0」「被 DPI 虚拟化过的值」 这三类假绿——它们都过不了这一关。

pnpm smoke 会把光标周围那一块 1:1 的图落盘(presence-smoke-cursor.png),那是「箭头到底画 上没有、位置对不对」唯一便宜的验法:看一眼。像素级的自动判据在这里都不便宜(系统光标形状随主题 变,写死模板就是给以后埋一条假红),所以这一步是有意留给眼睛的。

一条要记住的预算(2026-10-07 撞上的):captureScript 生成的脚本是编码成一行塞在命令行上跑的 (-EncodedCommand,UTF-16 再 base64 ⇒ 源文本的 2.67 倍),而 Windows 的命令行约 32767 字符。 顶过去的表现是 spawn ENAMETOOLONG——一条完全看不出「你多写了几行注释」的报错。所以: 写进那个模板的每个字都按 2.67 倍算钱,解释写在 TypeScript 这一侧;capture.test.ts 里有一条 用例盯着这个数,离上限不足 2048 字节就当场红(比运行时炸好认)。不改成「写临时 .ps1 用 -File 跑」的 理由:脚本里有中文文案(给她的错误说明),无 BOM 的 UTF-8 会被 PowerShell 5.1 按 ANSI 读成乱码。

装进实例后的第三级目击:默认 digest 挡等待 presence.digest,call 挡可观察 presence.switched/activity;让她调 presence_windows 与 presence_screenshot;重点:她拿到截图后能否真的描述出屏幕内容(模型端吃不吃图的实底, 框架侧 multimodal 只保证 PNG 附进了请求)。 另外让她截一张别的窗口(长边超过 1600 的那种)并加 grid:true:回执里该出现「图上 1px = 桌面 多少 px」那句,图上该出现带坐标标注的格线。 光标那一条:她截一张全屏——现象:图上有个系统样式的箭头,回执里那一句写着光标在桌面哪个坐标; 这时你动一下鼠标再让她截一张,箭头应该跟着挪过去了(那一下「跟着挪」就是它真的在读光标的证据)。 关掉它那一条:让她 {"cursor":false} 截同一块——现象:图上没有箭头,而回执里照样写着光标在 哪个坐标,并说清是「你说了这次不要箭头」。

四挡那两条(2026-10-13 加的;默认挡就是 digest):重启后不用切、挂着的就是压缩挡,只是周期是 20 分钟——要看效果先让她 presence_set_mode {mode:"digest", minutes:1} 压到 1 分钟,然后你在几个 窗口之间来回切切的、再切到一个窗口停一会儿——现象:这一分钟里 没有逐条窗口事件,时间线里过一会冒出一条 presence.digest,正文列应用/窗口累计、切换数、最近状态。 整周期停在同一个窗口也应出现持续时长与 0 次切换。按摘要编号读 view:"timeline",逐段顺序应仍可查看。 再让她 presence_windows——回执里有 [压缩结账] 累计摘要,周期从头开始。 切 {mode:"off"} 后再切几个已经见过的窗口——现象:没有窗口事件; 开一个这个实例没开过的程序——现象:时间线里冒出一条 presence.switched,末尾带「本次运行第一次 见到这个程序」;这时按你的 awayAfterMs 离开一会儿再回来——现象:离开那条(presence.away) 不立刻来(正文会让它说清「最后一次键鼠输入在几点」),离开超过「回来叫醒门槛」(默认 10 分钟) 再回来,回来那条(presence.back)才当场冒出来并报真实离开时长;离开不到门槛就回来, 那条只随她下次开口一起到、不打断她。

改动沿革

2026-10-14(发布日):0.1.0 首发 npm 与公开仓库;随后 0.1.1 把「能判别你离开/回到电脑前」与隐私提示 写进 description 与 README 开头 —— 扩展市场是主要入口,而卡片上只有 description 这一行。

2026-10-14:精简常驻 ENV_PROMPT 和三个工具的描述,合并重复的截图/光标说明;纠正离开不叫醒、 无事件不代表无变化、光标为采样时点等表述。两个切挡回执同步修正离开/回来规则,投递与截图逻辑不变。

同日第二轮:累计摘要、历史分页与跨周期计时——presence.digest 投累计视图,presence_windows 默认结账(当场给、周期重开),view:"timeline" 按记录编号分页读原始时间线。

同日第三轮:离开/回来的时长改从最后一次键鼠输入算起(从前从「发现离开」起算,5 分钟的阈值 会吐出「离开了 30 秒」这种自相矛盾的数),并加「短离开回来不叫醒」的门槛 backWakeAfterMs (默认 10 分钟)。