Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ jobs:
node-version: ${{ matrix.node }}
registry-url: https://registry.npmjs.org
package-manager-cache: false
- run: npm ci
- run: npm test
- run: npm pack --dry-run
83 changes: 79 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,27 @@ Multi-app theming CLI and runtime for supported Chromium/Electron desktop applic
[中文文档](./README_zh.md)

```bash
npx --yes --package=@codedrobe/core@0.1.1 codedrobe apps
npx --yes --package=@codedrobe/core@0.1.1 codedrobe detect
npx --yes --package=@codedrobe/core@0.1.1 codedrobe apply --app workbuddy --theme /absolute/theme.codedrobe-theme
npx --yes --package=@codedrobe/core@0.2.0 codedrobe apps
npx --yes --package=@codedrobe/core@0.2.0 codedrobe detect
npx --yes --package=@codedrobe/core@0.2.0 codedrobe apply --app workbuddy --theme /absolute/theme.codedrobe-theme
```

Bun is supported as a CLI runtime:

```bash
bunx --package @codedrobe/core@0.1.1 codedrobe apps
bunx --package @codedrobe/core@0.2.0 codedrobe apps
```

Check for or install the latest global CLI version:

```bash
codedrobe update --check
codedrobe update
codedrobe update --check --json
```

Interactive global installations check at most once every 24 hours and print an update hint only when a newer version is available. JSON output, CI, non-interactive runs, and pinned `npx`/`bunx` invocations stay silent. Set `NO_UPDATE_NOTIFIER=1` or `CODEDROBE_DISABLE_UPDATE_CHECK=1` to disable automatic checks.

Applications can consume the same package as an ES module:

```bash
Expand All @@ -26,4 +36,69 @@ npm install @codedrobe/core
import { getAdapter, launchApp, readThemePackage } from "@codedrobe/core";
```

The package ships TypeScript declarations for the root API and the `@codedrobe/core/adapters` and `@codedrobe/core/theme` subpath exports.

Built-in adapters currently include `codex` and `workbuddy`. Existing applications are never restarted unless `--restart-existing` is explicitly provided.

If an application is installed outside the adapter's default locations, pass its app bundle, installation directory, or executable file explicitly:

```bash
codedrobe detect --app workbuddy --app-path "/custom/WorkBuddy.app"
codedrobe apply --app workbuddy --app-path "/custom/WorkBuddy.app" --theme /absolute/theme.codedrobe-theme
```

The same `appPath` override is available to applications using the exported `launchApp()` API.

Probe an application's current DOM without injecting or removing a theme:

```bash
codedrobe probe --app codex
codedrobe probe --app codex --theme /absolute/theme.codedrobe-theme --json
codedrobe probe --app workbuddy --timeout-ms 10000
```

`probe` never launches or restarts an application. It prints the target address immediately, waits 5 seconds by default, and suggests the matching `codedrobe launch` command when no CDP renderer is available. Use `--timeout-ms` to change the wait from 250ms up to 5 minutes.

CodeDrobe probes each adapter's stable cross-route renderer landmarks before injecting CSS. A theme may add required landmarks, advisory landmarks, and route-specific contexts without adding runtime JavaScript:

```json
{
"targets": {
"workbuddy": {
"css": "workbuddy.css",
"verification": {
"required": [
{ "name": "chat-surface", "any": [".chat-container", ".wb-cb-chat"] }
],
"recommended": [
{ "name": "conversation-list", "any": [".conversation-list"] }
],
"contexts": [
{
"name": "active-chat",
"when": { "any": [".chat-route"] },
"required": [
{ "name": "message-list", "any": [".message-list"] }
]
}
]
}
}
}
}
```

Missing adapter or theme `required` landmarks stop injection and report the scope, active context, name, attempted selectors, and selector parse errors. Missing `recommended` landmarks are returned as warnings without blocking injection. Context checks run only while one of their `when.any` landmarks is visible.

`codedrobe theme pack` and `codedrobe theme inspect` also report non-blocking selector lint warnings for positional selectors, deep direct-child chains, localized text attributes, generated classes, and unusually long selectors. Keep adapter files limited to stable cross-route landmarks; put feature- and theme-specific DOM dependencies in the theme target.

Convert a legacy Codex-only package without copying JavaScript into a skill:

```bash
codedrobe theme convert ./legacy.codex-theme \
--output ./legacy.codedrobe-theme
```

The converter validates the old package, preserves its CSS, metadata, copy, artwork, and base-theme options, and creates a declaration-only package with a single `targets.codex` entry. Existing output files require `--force` before they can be replaced.

The Codex adapter was last verified against macOS app version `26.707.72221` (build `5307`) and the WorkBuddy adapter against macOS `5.2.6`, both on 2026-07-16. WorkBuddy passed the full launch/probe/apply/verify/screenshot/restore flow. Use `codedrobe apps --json` to read this metadata.
113 changes: 106 additions & 7 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ codedrobe apps
无需全局安装:

```bash
npx --yes --package=@codedrobe/core@0.1.1 codedrobe apps
bunx --package @codedrobe/core@0.1.1 codedrobe apps
npx --yes --package=@codedrobe/core@0.2.0 codedrobe apps
bunx --package @codedrobe/core@0.2.0 codedrobe apps
```

在源码仓库中也可以直接通过 Bun 运行:
Expand All @@ -32,6 +32,16 @@ bunx --package @codedrobe/core@0.1.1 codedrobe apps
bun ./bin/codedrobe.mjs apps
```

检查和安装全局 CLI 的新版本:

```bash
codedrobe update --check
codedrobe update
codedrobe update --check --json
```

`codedrobe update` 会根据当前运行环境选择 npm、Bun 或 pnpm,安装 `@codedrobe/core@latest` 的全局版本。普通命令只会在全局安装、交互式终端中检查更新;检查结果缓存 24 小时,网络失败不会影响原命令。`--json`、CI、非交互执行和固定版本的 `npx`/`bunx` 调用不会出现升级提示。可以设置 `NO_UPDATE_NOTIFIER=1` 或 `CODEDROBE_DISABLE_UPDATE_CHECK=1` 关闭自动检查。

Skill 应固定 `codedrobe` 的准确版本,避免 `npx` 自动取得新版本后行为漂移。CodeDrobe Desktop 等软件则把它作为普通依赖,在 Electron 主进程使用导出的 API:

```bash
Expand All @@ -42,6 +52,8 @@ npm install @codedrobe/core
import { getAdapter, launchApp, readThemePackage } from "@codedrobe/core";
```

npm 包内置 TypeScript 类型声明,覆盖根入口以及 `@codedrobe/core/adapters`、`@codedrobe/core/theme` 子路径,不需要另外安装 `@types` 包。

Skill 目录不再复制 JavaScript 运行时,只保留 `SKILL.md`、必要 references 和对 `@codedrobe/core@固定版本` 的调用说明。

本仓库开发时可以链接命令:
Expand All @@ -60,6 +72,28 @@ codedrobe apply \
--theme /absolute/dream-1.0.0.codedrobe-theme
```

如果应用不在适配器的默认安装位置,可以通过 `--app-path` 传入应用目录、macOS `.app` 包或可执行文件:

```bash
codedrobe detect --app workbuddy --app-path "/custom/WorkBuddy.app"
codedrobe apply \
--app workbuddy \
--app-path "/custom/WorkBuddy.app" \
--theme /absolute/dream-1.0.0.codedrobe-theme
```

软件直接使用 `launchApp()` API 时,也可以传入同名的 `appPath` 字段。

只检查当前应用 DOM,不注入或移除主题:

```bash
codedrobe probe --app codex
codedrobe probe --app codex --theme /absolute/theme.codedrobe-theme --json
codedrobe probe --app workbuddy --timeout-ms 10000
```

`probe` 不会启动或重启应用。命令会立即显示正在检查的地址,默认等待 5 秒;找不到 CDP renderer 时会提示对应的 `codedrobe launch` 命令。可以使用 `--timeout-ms` 将等待时间设置为 250 毫秒至 5 分钟。

如果应用已经在未开启 CDP 的状态下运行,命令会停止并要求用户自行关闭应用,或者显式传入:

```bash
Expand Down Expand Up @@ -98,13 +132,46 @@ codedrobe restore --app workbuddy
},
"targets": {
"codex": { "css": "/* Codex CSS */" },
"workbuddy": { "css": "/* WorkBuddy CSS */" }
"workbuddy": {
"css": "/* WorkBuddy CSS */",
"verification": {
"required": [
{
"name": "chat-surface",
"any": [".chat-container", ".wb-cb-chat"]
}
],
"recommended": [
{
"name": "conversation-list",
"any": [".conversation-list"]
}
],
"contexts": [
{
"name": "active-chat",
"when": { "any": [".chat-route"] },
"required": [
{ "name": "message-list", "any": [".message-list"] }
]
}
]
}
}
}
}
```

主题包限制为 30MB,拒绝外部 `url(...)` 与 `@import`。主题包只能包含声明式配置、CSS 和内嵌图片,不能携带或执行 JavaScript。

`targets.<app>.verification` 是可选的主题专属 DOM 依赖:

- `required`:缺失时阻止注入。
- `recommended`:缺失时只返回警告,不阻止注入。
- `contexts`:通过 `when.any` 判断当前页面,只在上下文激活时检查其中的 `required` 和 `recommended`。

Core 会在注入前合并适配器基础探针和主题探针。验证结果会返回探针来源、上下文、名称、全部尝试过的选择器以及无效选择器的解析错误。

开发主题时先维护源清单和独立 CSS 文件:

```json
Expand All @@ -115,7 +182,26 @@ codedrobe restore --app workbuddy
"version": "1.0.0",
"targets": {
"codex": { "css": "codex.css" },
"workbuddy": { "css": "workbuddy.css" }
"workbuddy": {
"css": "workbuddy.css",
"verification": {
"required": [
{ "name": "chat-surface", "any": [".chat-container", ".wb-cb-chat"] }
],
"recommended": [
{ "name": "conversation-list", "any": [".conversation-list"] }
],
"contexts": [
{
"name": "active-chat",
"when": { "any": [".chat-route"] },
"required": [
{ "name": "message-list", "any": [".message-list"] }
]
}
]
}
}
}
}
```
Expand All @@ -127,6 +213,17 @@ codedrobe theme pack ./theme.json --output ./dream-1.0.0.codedrobe-theme
codedrobe theme inspect ./dream-1.0.0.codedrobe-theme
```

打包和检查命令会额外输出非阻断的选择器 lint 警告,包括位置选择器、过深的直接子节点链、依赖本地化文本的属性、生成类名和过长选择器。适配器应只保留跨页面稳定地标;功能页和主题专属 DOM 依赖放在主题 target 中。

旧版 Codex 专属主题可以直接转换,不需要在 Skill 中复制 JavaScript:

```bash
codedrobe theme convert ./legacy.codex-theme \
--output ./legacy.codedrobe-theme
```

转换器会先验证旧主题包,保留 CSS、主题元数据、文案、图片和基础主题选项,再生成只包含 `targets.codex` 的声明式新主题包。输出文件已存在时必须显式传入 `--force` 才会覆盖。

## 适配器职责

应用适配器只描述宿主差异:
Expand All @@ -136,16 +233,18 @@ codedrobe theme inspect ./dream-1.0.0.codedrobe-theme
- 独立默认 CDP 端口。
- CDP 页面目标识别规则。
- 页面根节点、工作区和输入区域的验证探针。
- 每个平台最后一次实机验证的应用版本和日期。

CDP 会话、注入、重载监听、截图、主题包校验和恢复由通用运行时负责。新增应用时注册新适配器,不复制整套启动脚本或注入器。
CDP 会话、注入前预检、主题探针合并、缺失节点报告、重载监听、截图、主题包校验和恢复由通用运行时负责。新增应用时注册新适配器,不复制整套启动脚本或注入器。

## 当前验证状态

- macOS 应用发现:已验证 Codex 与 WorkBuddy。
- `.codedrobe-theme` 双目标打包与读取:已自动化测试。
- WorkBuddy 实际 DOM 选择器和视觉效果:需要在用户允许重启 WorkBuddy 并开启本地 CDP 后完成截图验收。
- Codex 26.707.72221(build 5307)macOS 任务页的基础 DOM 探针:已通过本地 CDP 实机验证。
- WorkBuddy 5.2.6 macOS 欢迎页:已完成 `launch/probe/apply/verify/screenshot/restore` 全流程实机验证,主题探针、视觉截图和恢复均通过。
- Windows 应用发现和启动:已实现适配入口,尚需 Windows 实机验证。

## 与旧项目的关系

`codedrobe-codex-skill` 后续应改为调用 `codedrobe` npm 包的 Codex adapter。旧 `.codex-theme` 可由兼容层转换成只包含 `targets.codex` 的 `.codedrobe-theme`,不应继续把 Codex 专属配置写入通用核心。
`codedrobe-codex-skill` 后续应改为调用 `codedrobe` npm 包的 Codex adapter。旧 `.codex-theme` 使用 `codedrobe theme convert` 转换成只包含 `targets.codex` 的 `.codedrobe-theme`,不应继续把 Codex 专属配置写入通用核心。
45 changes: 42 additions & 3 deletions examples/dream-1.0.0.codedrobe-theme
Original file line number Diff line number Diff line change
@@ -1,18 +1,57 @@
{
"format": "codedrobe-theme",
"schemaVersion": 1,
"exportedAt": "2026-07-16T05:34:55.212Z",
"exportedAt": "2026-07-16T08:29:05.758Z",
"theme": {
"id": "dream",
"displayName": "Dream Multi-App",
"version": "1.0.0"
},
"targets": {
"codex": {
"css": ":root.codedrobe-host-codex {\n --codedrobe-surface: #fff4fa;\n --codedrobe-panel: rgba(255, 255, 255, 0.78);\n --codedrobe-accent: #b65cff;\n --codedrobe-ink: #4a235f;\n}\n\nhtml.codedrobe-host-codex body {\n background: radial-gradient(circle at 80% 10%, #f8dcff, transparent 36%), var(--codedrobe-surface);\n color: var(--codedrobe-ink);\n}\n\nhtml.codedrobe-host-codex aside,\nhtml.codedrobe-host-codex .composer-surface-chrome {\n background-color: var(--codedrobe-panel);\n backdrop-filter: blur(18px);\n}\n"
"css": ":root.codedrobe-host-codex {\n --codedrobe-surface: #fff4fa;\n --codedrobe-panel: rgba(255, 255, 255, 0.78);\n --codedrobe-accent: #b65cff;\n --codedrobe-ink: #4a235f;\n}\n\nhtml.codedrobe-host-codex body {\n background: radial-gradient(circle at 80% 10%, #f8dcff, transparent 36%), var(--codedrobe-surface);\n color: var(--codedrobe-ink);\n}\n\nhtml.codedrobe-host-codex aside,\nhtml.codedrobe-host-codex .composer-surface-chrome {\n background-color: var(--codedrobe-panel);\n backdrop-filter: blur(18px);\n}\n",
"verification": {
"contexts": [
{
"name": "home",
"when": {
"any": [
"[role='main']:has([data-testid='home-icon'])"
]
},
"recommended": [
{
"name": "home-suggestions",
"any": [
".group\\/home-suggestions"
]
}
]
}
]
}
},
"workbuddy": {
"css": ":root.codedrobe-host-workbuddy {\n --codedrobe-surface: #fff4fa;\n --codedrobe-panel: rgba(255, 255, 255, 0.8);\n --codedrobe-accent: #b65cff;\n --codedrobe-ink: #4a235f;\n}\n\nhtml.codedrobe-host-workbuddy body,\nhtml.codedrobe-host-workbuddy .monaco-workbench {\n background-color: var(--codedrobe-surface);\n color: var(--codedrobe-ink);\n}\n\nhtml.codedrobe-host-workbuddy .part.sidebar,\nhtml.codedrobe-host-workbuddy [class*=\"sidebar\"] {\n background-color: var(--codedrobe-panel);\n backdrop-filter: blur(18px);\n}\n\nhtml.codedrobe-host-workbuddy textarea,\nhtml.codedrobe-host-workbuddy [contenteditable=\"true\"] {\n caret-color: var(--codedrobe-accent);\n}\n"
"css": ":root.codedrobe-host-workbuddy {\n --codedrobe-surface: #fff4fa;\n --codedrobe-panel: rgba(255, 255, 255, 0.8);\n --codedrobe-accent: #b65cff;\n --codedrobe-ink: #4a235f;\n}\n\nhtml.codedrobe-host-workbuddy body,\nhtml.codedrobe-host-workbuddy .teams-container,\nhtml.codedrobe-host-workbuddy .teams-main-content {\n background-color: var(--codedrobe-surface);\n color: var(--codedrobe-ink);\n}\n\nhtml.codedrobe-host-workbuddy .conversation-sidebar,\nhtml.codedrobe-host-workbuddy .conversation-list {\n background-color: var(--codedrobe-panel);\n backdrop-filter: blur(18px);\n}\n\nhtml.codedrobe-host-workbuddy [role=\"textbox\"][contenteditable=\"true\"] {\n caret-color: var(--codedrobe-accent);\n}\n",
"verification": {
"required": [
{
"name": "chat-surface",
"any": [
".chat-container",
".wb-cb-chat"
]
}
],
"recommended": [
{
"name": "conversation-list",
"any": [
".conversation-list"
]
}
]
}
}
}
}
34 changes: 32 additions & 2 deletions examples/dream/theme.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,40 @@
"version": "1.0.0",
"targets": {
"codex": {
"css": "codex.css"
"css": "codex.css",
"verification": {
"contexts": [
{
"name": "home",
"when": {
"any": ["[role='main']:has([data-testid='home-icon'])"]
},
"recommended": [
{
"name": "home-suggestions",
"any": [".group\\/home-suggestions"]
}
]
}
]
}
},
"workbuddy": {
"css": "workbuddy.css"
"css": "workbuddy.css",
"verification": {
"required": [
{
"name": "chat-surface",
"any": [".chat-container", ".wb-cb-chat"]
}
],
"recommended": [
{
"name": "conversation-list",
"any": [".conversation-list"]
}
]
}
}
}
}
Loading