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
68 changes: 63 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ Multi-app theming CLI and runtime for supported Chromium/Electron desktop applic
[中文文档](./README_zh.md)

```bash
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
npx --yes --package=@codedrobe/core@0.3.0 codedrobe apps
npx --yes --package=@codedrobe/core@0.3.0 codedrobe detect
npx --yes --package=@codedrobe/core@0.3.0 codedrobe apply --app workbuddy --theme /absolute/theme.codedrobe-theme
```

Bun is supported as a CLI runtime:

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

Check for or install the latest global CLI version:
Expand All @@ -33,13 +33,24 @@ npm install @codedrobe/core
```

```js
import { getAdapter, launchApp, readThemePackage } from "@codedrobe/core";
import { applySkin, getAdapter, readThemePackage, resolveThemeTarget, restoreSkin } from "@codedrobe/core";

const adapter = getAdapter("codex");
const theme = await readThemePackage("/absolute/theme.codedrobe-theme");
const targetTheme = resolveThemeTarget(theme, adapter.id);

await applySkin({ adapter, targetTheme, port: 9335 });
await restoreSkin({ adapter, port: 9335 });
```

Applications should normally use the high-level `applySkin()` and `restoreSkin()` APIs. They coordinate host settings, launch, DOM preflight, renderer injection, verification, and rollback. `watchTheme()` accepts an `AbortSignal`, so an Electron main process can own its lifecycle without relying on process signals.

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.

When a Codex theme changes host appearance settings, a running Codex process must restart before the complete skin can load. Core returns `CODEDROBE_RESTART_REQUIRED` and rolls the settings back unless `--restart-existing` is explicit. Renderer-only changes can still apply live.

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

```bash
Expand All @@ -49,6 +60,27 @@ codedrobe apply --app workbuddy --app-path "/custom/WorkBuddy.app" --theme /abso

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

Capture a read-only DOM and computed-style snapshot for AI-assisted theme authoring:

```bash
codedrobe dom snapshot --app codex --output /absolute/codex-dom.json
codedrobe dom snapshot --app workbuddy --port 9440 --max-nodes 1500 --output /absolute/workbuddy-dom.json
```

The snapshot records the active CodeDrobe theme, element relationships, semantic classes, selected safe attributes, stable selector candidates with match counts, bounding boxes, adapter landmark matches, and theme-relevant computed styles. It deliberately excludes text content, form values, accessible names, query/hash data, links, and media sources. Only visible elements are included by default; use `--include-hidden` when a hidden route or dialog must be styled. The command never launches, restarts, or mutates the application.

Applications can call the same read-only API:

```js
import { getAdapter, snapshotDom } from "@codedrobe/core";

const targets = await snapshotDom({
adapter: getAdapter("workbuddy"),
port: 9336,
maxNodes: 1500,
});
```

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

```bash
Expand Down Expand Up @@ -90,6 +122,28 @@ CodeDrobe probes each adapter's stable cross-route renderer landmarks before inj

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.

A source manifest can declare up to 32 named PNG, JPEG, WebP, or GIF images. Packing embeds them under `assets.images`; the renderer creates scoped Blob URLs and exposes one CSS variable per image:

```json
{
"images": {
"hero": "assets/hero.webp",
"background": "assets/background.jpg",
"logo": "assets/logo.png",
"texture": "assets/texture.png"
}
}
```

```css
.home-hero { background-image: var(--codedrobe-image-hero); }
.app-shell { background-image: var(--codedrobe-image-background); }
.brand::before { background-image: var(--codedrobe-image-logo); }
.panel { background-image: var(--codedrobe-image-texture); }
```

Image IDs map directly to `--codedrobe-image-<id>`. The `hero` image also aliases to `--codedrobe-art` and, for converted Codex themes, `--dream-art`. Legacy `assets.art` packages still resolve as `assets.images.hero`, while new packing and conversion output `assets.images`.

`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:
Expand All @@ -101,4 +155,8 @@ codedrobe theme convert ./legacy.codex-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.

Converted Codex themes select a trusted renderer profile supplied by Core. It restores the legacy DOM classes, decorative layer, copy, and artwork variables expected by existing CSS while stopping any observer, timer, or style node left by the old Skill runtime. Theme packages remain declaration-only and cannot provide JavaScript.

For Codex themes with `baseTheme`, `applySkin()` changes only the three managed appearance keys under `[desktop]` in `~/.codex/config.toml`. Restore merges those keys from `config.before-codedrobe.toml` and preserves unrelated edits. The default backup path remains compatible with the old Skill (`~/Library/Application Support/CodeDrobe/` on macOS and `%LOCALAPPDATA%\CodeDrobe\` on Windows), and `restoreSkin()` can recover host settings even while Codex/CDP is offline.

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.
73 changes: 69 additions & 4 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.2.0 codedrobe apps
bunx --package @codedrobe/core@0.2.0 codedrobe apps
npx --yes --package=@codedrobe/core@0.3.0 codedrobe apps
bunx --package @codedrobe/core@0.3.0 codedrobe apps
```

在源码仓库中也可以直接通过 Bun 运行:
Expand All @@ -49,9 +49,18 @@ npm install @codedrobe/core
```

```js
import { getAdapter, launchApp, readThemePackage } from "@codedrobe/core";
import { applySkin, getAdapter, readThemePackage, resolveThemeTarget, restoreSkin } from "@codedrobe/core";

const adapter = getAdapter("codex");
const theme = await readThemePackage("/absolute/theme.codedrobe-theme");
const targetTheme = resolveThemeTarget(theme, adapter.id);

await applySkin({ adapter, targetTheme, port: 9335 });
await restoreSkin({ adapter, port: 9335 });
```

软件集成应优先使用高层 `applySkin()` / `restoreSkin()` API。它统一处理宿主配置、应用启动、DOM 预检、渲染器注入、注入后验证和失败回滚;`applyTheme()` / `removeTheme()` 只适合明确只操作当前渲染器的底层场景。`watchTheme()` 接受 `AbortSignal`,因此 Electron 主进程可以用自己的生命周期停止监听,不依赖进程信号。

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

Skill 目录不再复制 JavaScript 运行时,只保留 `SKILL.md`、必要 references 和对 `@codedrobe/core@固定版本` 的调用说明。
Expand Down Expand Up @@ -84,6 +93,27 @@ codedrobe apply \

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

为 AI 动态编写主题采集只读 DOM 与 computed style 快照:

```bash
codedrobe dom snapshot --app codex --output /absolute/codex-dom.json
codedrobe dom snapshot --app workbuddy --port 9440 --max-nodes 1500 --output /absolute/workbuddy-dom.json
```

快照包含当前 CodeDrobe 主题、元素父子关系、语义 class、经过限制的安全属性、带匹配数量的稳定选择器候选、元素尺寸、适配器地标命中情况和主题相关 computed style。它不会读取文本内容、输入值、可访问名称、URL 查询和 hash、链接或媒体地址。默认只记录可见节点;确实需要处理隐藏路由或弹窗时再使用 `--include-hidden`。该命令不会启动、重启或修改应用。

应用也可以直接调用同一只读 API:

```js
import { getAdapter, snapshotDom } from "@codedrobe/core";

const targets = await snapshotDom({
adapter: getAdapter("workbuddy"),
port: 9336,
maxNodes: 1500,
});
```

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

```bash
Expand All @@ -103,6 +133,8 @@ codedrobe apply \
--restart-existing
```

Codex 主题修改基础外观配置时也需要重新启动 Codex 才能完整生效。如果 Codex 已经通过 CDP 运行且基础配置发生变化,Core 会返回 `CODEDROBE_RESTART_REQUIRED` 并回滚配置;显式使用 `--restart-existing` 才会由 Core 安全重启。基础配置没有变化时仍可直接热切换 CSS。

持续覆盖页面重载和新窗口:

```bash
Expand Down Expand Up @@ -164,6 +196,30 @@ codedrobe restore --app workbuddy

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

源清单可以声明最多 32 张命名图片。打包时 Core 会把 PNG、JPEG、WebP 或 GIF 写入 `assets.images`,运行时为每张图片创建独立 Blob URL:

```json
{
"images": {
"hero": "assets/hero.webp",
"background": "assets/background.jpg",
"logo": "assets/logo.png",
"texture": "assets/texture.png"
}
}
```

主题 CSS 使用对应的命名变量,因此图片不再局限于 Hero:

```css
.home-hero { background-image: var(--codedrobe-image-hero); }
.app-shell { background-image: var(--codedrobe-image-background); }
.brand::before { background-image: var(--codedrobe-image-logo); }
.panel { background-image: var(--codedrobe-image-texture); }
```

图片 ID 会原样映射为 `--codedrobe-image-<id>`。`hero` 还会自动生成 `--codedrobe-art`,旧 Codex 配置会继续生成 `--dream-art`。旧包中的 `assets.art` 读取时等同于 `assets.images.hero`,新打包和旧主题转换统一输出 `assets.images`。

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

- `required`:缺失时阻止注入。
Expand All @@ -180,6 +236,10 @@ Core 会在注入前合并适配器基础探针和主题探针。验证结果会
"id": "dream",
"displayName": "Dream Multi-App",
"version": "1.0.0",
"images": {
"hero": "assets/hero.webp",
"logo": "assets/logo.png"
},
"targets": {
"codex": { "css": "codex.css" },
"workbuddy": {
Expand Down Expand Up @@ -224,6 +284,10 @@ codedrobe theme convert ./legacy.codex-theme \

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

转换后的旧版 Codex 主题会声明由 Core 提供的受信任渲染配置。Core 会恢复旧 CSS 所依赖的 `.codedrobe-codex-skin`、`.dream-home`、`#codedrobe-codex-skin-chrome`、文案和图片变量,并在接管时停止旧 Skill 遗留的 Observer、定时器和样式节点。主题包本身仍然不能携带 JavaScript。

如果主题包含 `baseTheme`,`applySkin()` 只修改 `~/.codex/config.toml` 中 `[desktop]` 下的 `appearanceTheme`、`appearanceLightCodeThemeId` 和 `appearanceLightChromeTheme`。首次应用会保留 `config.before-codedrobe.toml`;恢复时只合并这三个托管项,保留期间产生的其他配置修改。默认备份路径继续兼容旧 Skill:macOS 为 `~/Library/Application Support/CodeDrobe/config.before-codedrobe.toml`,Windows 为 `%LOCALAPPDATA%\CodeDrobe\config.before-codedrobe.toml`。即使 Codex/CDP 当前没有运行,`restoreSkin()` 仍会恢复宿主配置。

## 适配器职责

应用适配器只描述宿主差异:
Expand All @@ -234,8 +298,9 @@ codedrobe theme convert ./legacy.codex-theme \
- CDP 页面目标识别规则。
- 页面根节点、工作区和输入区域的验证探针。
- 每个平台最后一次实机验证的应用版本和日期。
- 可选的受信任渲染配置与宿主设置处理器;主题只能按 ID 声明使用,不能提供可执行代码。

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

## 当前验证状态

Expand Down
52 changes: 52 additions & 0 deletions examples/doll-sister/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Doll Sister / 玩偶姐姐

An original Codex and WorkBuddy theme inspired by the user-provided composition reference. It uses two named theme images:

- `hero`: the home-page banner and polaroid artwork.
- `texture`: the sidebar, main surface, cards, and composer background.

Build and apply:

```bash
bun ./bin/codedrobe.mjs theme pack examples/doll-sister/theme.json \
--output examples/doll-sister-1.0.0.codedrobe-theme --force
bun ./bin/codedrobe.mjs apply --app codex \
--theme examples/doll-sister-1.0.0.codedrobe-theme --restart-existing
bun ./bin/codedrobe.mjs apply --app workbuddy \
--theme examples/doll-sister-1.0.0.codedrobe-theme
```

## Asset generation

The assets were generated with OpenAI image generation on 2026-07-16. The supplied image was used only as a composition, wardrobe, motif, and palette reference. The generated artwork is original and contains no copied UI, typography, logos, or screenshot framing.

### Hero prompt

```text
Use case: stylized-concept
Asset type: wide desktop-app theme hero background
Primary request: Create an original premium "Doll Sister" visual inspired by the supplied reference image, for use behind a Codex desktop home screen.
Input images: Image 1 is a composition, wardrobe, subject, and palette reference only; do not reproduce its UI, typography, logos, or screenshot framing.
Scene/backdrop: a dreamy blush-pink bedroom studio with translucent curtains, soft cherry blossoms, floating petals, tiny pearlescent sparkles, ribbons, and subtle lavender gingham details.
Subject: one clearly adult East Asian woman with shoulder-length soft brown hair and wispy bangs, wearing a white face mask, cream knit cardigan, white blouse, and lavender plaid bow; seated naturally on the right third of the frame, friendly expressive eyes.
Style/medium: polished editorial photography with gentle dollhouse romanticism, realistic skin and fabric texture, refined rather than childish.
Composition/framing: wide 16:9 landscape; subject concentrated on the right 40 percent; generous clean low-contrast negative space across the left and center for interface text and cards; no important detail in the bottom 18 percent where the composer will sit.
Lighting/mood: luminous diffused morning light, soft bloom, delicate depth, calm and inspiring.
Color palette: ivory, shell pink, dusty rose, pale lavender, muted plum accents.
Constraints: image only; no text, no letters, no UI, no icons, no borders, no watermark; adult proportions; keep the center-left readable under dark plum text; avoid overexposure and preserve gentle contrast.
```

### Texture prompt

```text
Use case: stylized-concept
Asset type: subtle repeating desktop-app background texture
Primary request: Create an original seamless-looking romantic texture inspired by the supplied Doll Sister reference palette, for use behind sidebars, chat surfaces, and cards.
Input images: Image 1 is a color and motif reference only; do not reproduce its UI, person, text, logos, or screenshot.
Scene/backdrop: flat decorative surface combining extremely subtle lavender gingham, faint blush watercolor paper grain, sparse tiny cherry blossom petals, pearl dots, miniature ribbon linework, and delicate stitched borders.
Style/medium: refined Japanese stationery and couture fabric sample, premium and understated, low visual noise.
Composition/framing: square tile-like composition with balanced motifs and no focal center; edges should blend naturally when cropped or repeated.
Lighting/mood: soft matte finish, calm, airy, elegant.
Color palette: warm ivory, shell pink, dusty lavender, muted plum at very low opacity.
Constraints: no person, no text, no letters, no UI, no icons, no watermark; keep contrast low enough for dark text to remain readable; avoid large objects and avoid strong gradients.
```
Binary file added examples/doll-sister/assets/hero.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/doll-sister/assets/texture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading