Agent Skills › MrModest/reisenotiz

MrModest/reisenotiz

GitHub

用于为Reisenotiz旅行笔记PWA生成符合品牌规范的界面和资产。提供设计指南、色彩、字体及UI组件,支持输出静态HTML原型或生产代码。

2 skills 70

Install All Skills

npx skills add MrModest/reisenotiz --all -g -y
More Options

List skills in collection

npx skills add MrModest/reisenotiz --list

Skills in Collection (2)

用于为Reisenotiz旅行笔记PWA生成符合品牌规范的界面和资产。提供设计指南、色彩、字体及UI组件,支持输出静态HTML原型或生产代码。
需要设计Reisenotiz品牌的界面或资产 创建视觉原型或静态HTML文件 开发Reisenotiz生产代码并遵循品牌规范
.claude/skills/reisenotiz-design/SKILL.md
npx skills add MrModest/reisenotiz --skill reisenotiz-design -g -y
SKILL.md
Frontmatter
{
    "name": "reisenotiz-design",
    "description": "Use this skill to generate well-branded interfaces and assets for Reisenotiz, a self-hosted offline-first travel notes PWA. Contains essential design guidelines, colors, type, fonts, assets, and UI kit components for prototyping.",
    "user-invocable": true
}

Read the README.md file within this skill, and explore the other available files. If creating visual artifacts (slides, mocks, throwaway prototypes, etc), copy assets out and create static HTML files for the user to view. If working on production code, you can copy assets and read the rules here to become an expert in designing with this brand. If the user invokes this skill without any other guidance, ask them what they want to build or design, ask some questions, and act as an expert designer who outputs HTML artifacts or production code, depending on the need.

提供Automerge React开发指南,涵盖useDocument/useRepo等核心Hook、就地变更语义陷阱、updateText协同编辑及无Mock测试模式。用于编写、调试和审查Automerge相关代码。
编写或调试Automerge代码 询问数据同步或CRDT行为 使用useDocument/useRepo/changeDoc 编写Automerge存储测试 修改sync引擎或store目录文件
.claude/skills/automerge/SKILL.md
npx skills add MrModest/reisenotiz --skill automerge -g -y
SKILL.md
Frontmatter
{
    "name": "automerge",
    "description": "Fresh Automerge knowledge for this project — React hooks (useDocument, useRepo, RepoContext), mutation semantics, updateText for collaborative text, testing patterns, and common gotchas. Use this skill whenever the user is writing, debugging, or reviewing Automerge code, asks how to sync data with Automerge, mentions useDocument\/useRepo\/changeDoc, is working on the sync engine, asks about CRDT behavior, or is writing tests for Automerge-backed stores. Always load this skill when touching apps\/frontend\/src\/store\/automerge\/ or apps\/frontend\/src\/contexts\/sync*."
}

Automerge Knowledge Reference

Read references/automerge-react.md for full detail. Below is the critical-path summary.


Core React Hooks

useDocument<T>(docUrl, options?)

Primary hook. Returns [doc, changeDoc] — reactive snapshot + mutation function.

const [doc, changeDoc] = useDocument<TaskList>(docUrl, { suspense: true });
  • doc is undefined until loaded. With suspense: true, component suspends instead.
  • changeDoc callback receives a mutable draft — mutations inside it are the ONLY valid way to write.

useRepo()

Returns the Repo instance from context. Use to create/find/delete documents imperatively.

const repo = useRepo();
const handle = repo.create<MyType>({ ...initialData });

RepoContext

Wrap your app tree once. All useDocument/useRepo calls inside read from it.

<RepoContext.Provider value={repo}>
  <App />
</RepoContext.Provider>

Mutation Semantics — the #1 gotcha

Automerge tracks operations, not snapshots. You MUST mutate in-place inside changeDoc. Never spread or replace.

// CORRECT — targeted mutation, records the operation
changeDoc((d) => {
  d.tasks[i].done = !d.tasks[i].done;
});

// WRONG — replaces the entire array, destroys merge history
changeDoc((d) => ({
  ...d,
  tasks: d.tasks.map((t, idx) => idx === i ? { ...t, done: !t.done } : t),
}));

Any mutation outside changeDoc is invisible to Automerge and will not sync.


Collaborative Text — updateText

Direct string assignment replaces the whole string (poor merge). Use updateText for any user-editable text:

import { updateText } from "@automerge/react";

changeDoc((d) => {
  updateText(d, ["notes", "body"], e.target.value);
});

updateText diffs the old and new strings and emits minimal splice operations, enabling proper multi-user merge.

Automerge v3+: no Text class — all collaborative strings are plain string. Use updateText or Automerge.splice.


Testing Patterns

See references/automerge-react.md#testing for full patterns.

Key principles:

  • No mocks for Automerge itself — use a real in-memory Repo with new Repo({ network: [] }) (no storage adapter either — IndexedDB unavailable in jsdom).
  • Wrap test components in <RepoContext.Provider value={repo}>.
  • Create documents via repo.create(initialData) before the hook renders, pass the URL to hooks.
  • Multi-peer tests: instantiate two Repo objects, connect via MessageChannelNetworkAdapter.
  • Offline scenarios: disconnect the adapter, mutate, reconnect — verify sync after.
  • Assert on doc snapshots not on internal CRDT state: handle.doc() synchronously after a change.

Critical vitest setup (blockers if missing)

vite-plugin-wasm + vite-plugin-top-level-await — Automerge ships a WASM binary. Without these plugins the module fails to load in jsdom:

// vitest.config.ts
import wasm from 'vite-plugin-wasm'
import topLevelAwait from 'vite-plugin-top-level-await'
export default defineConfig({
  plugins: [wasm(), topLevelAwait(), react()],
  test: { environment: 'jsdom', setupFiles: ['./vitest.setup.ts'] },
})

IS_REACT_ACT_ENVIRONMENT — React 19 requires this so act() flushes effects:

// vitest.setup.ts
globalThis.IS_REACT_ACT_ENVIRONMENT = true

await act() — every mutation must be wrapped; useDocument uses useSyncExternalStore so changes schedule async re-renders:

await act(async () => {
  result.current.addItem({ title: 'foo' })
})
// now result.current reflects updated state

Reading raw doc state — access the document directly from the repo's handle map to assert on CRDT structure independent of hook state:

import { interpretAsDocumentId } from '@automerge/react'
const handle = repo.handles[interpretAsDocumentId(url)]
const doc = handle.doc() // synchronous after change applied

Key Gotchas (quick-reference)

# Gotcha Fix
1 Immutability semantics inverted Always mutate inside changeDoc
2 useDocument returns undefined until loaded Guard with if (!doc) return null or use suspense: true
3 Schema init on two devices = incompatible docs Sync or share initial state before independent writes
4 Text class removed in v3 Use plain string + updateText/Automerge.splice
5 Array spread kills merge Use push, unshift, or indexed assignment
6 Root doc stored in localStorage Losing the key = losing access (docs still in IndexedDB)
7 Full history retained, no GC yet Monitor memory on high-edit-count docs
8 Multiple adapters are independent No prioritization — both receive all changes
9 Fine-grained docs = overhead Consolidate if sync overhead grows
10 Merge is automatic, no conflicts Trust the CRDT; no manual conflict resolution needed
11 Automerge WASM breaks vitest without plugins Add vite-plugin-wasm + vite-plugin-top-level-await to vitest config
12 React 19 act() doesn't flush without flag Set globalThis.IS_REACT_ACT_ENVIRONMENT = true in vitest.setup.ts

Read references/automerge-react.md for extended examples, network adapters, and persistence setup.

Home - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-14 12:06
浙ICP备14020137号-1 $Map of visitor$