diff --git a/.agents/skills/README.md b/.agents/skills/README.md new file mode 100644 index 0000000000..4ab76a1245 --- /dev/null +++ b/.agents/skills/README.md @@ -0,0 +1,108 @@ +# Euro-Office task pipeline — skills + +Assisted, portable AI-agent skills covering the full lifecycle of a task — +**fetch/define → plan → implement → audit → prepare a PR** — for the Euro-Office DocumentServer +meta-repo. The skills **propose and show** commands; a **human** runs builds, commits, and PRs. They +work across **Claude Code, Codex, and Cursor**. + +The canonical source lives here in `.agents/skills/`. The skills **do not duplicate** the +environment docs (`AGENTS.md`, `CONTRIBUTING.md`, per-repo `AGENTS.md`/`CLAUDE.md`) — they **link** +them. + +## The skills + +| Skill | Invoke | What it does | Output | +|---|---|---|---| +| `blueprint` | `/blueprint []` | Onboard `gh`/Jira (first run) + fetch + investigate + define a task (GitHub / Jira / manual) | `.ai/tasks//plan.md` | +| `breakdown` | `/breakdown []` | plan.md → atomic ~5-min steps; propose a branch per affected repo | `.ai/tasks//tasks.md` | +| `apply` | `/apply` | Ensure the task branch (interactive — propose/create, you can rename it), apply the next step, show the build/test command; stop | (branch + code edit + `- [x]`) | +| `audit` | `/audit` · `/audit /#` · `/audit ` | Security + code review + emulated quality gate + proposed PR comments — task diff **or** any open PR | task: `.ai/tasks//review.md` · PR: `.ai/reviews/-/review.md` | +| `prepare-pr` | `/prepare-pr` | Prepare (never publish) the PR(s): body + `gh pr create` | `.ai/tasks//pr-.md` | + +Artifacts are gitignored and cross-tool, split by concept: +- **Task workspace** — `.ai/tasks//` holds everything for a task you drive (`plan.md`, + `tasks.md`, `review.md`, `pr-.md`), co-located so each stage feeds the next. `` is a + slug of the ref (`web-apps #54` → `web-apps-54`, `EUOFFICE-5` → `euoffice-5`, manual → slug of the + title); skills infer it from the current branch `feature/`, or ask. +- **Standalone PR reviews** — `.ai/reviews/-/` holds `audit`'s output when reviewing an open + PR. A PR review is **not** a task, so it never lives under `.ai/tasks/`. + +## The flow + +``` +/blueprint -> plan.md (onboards gh/Jira on first run; else manual paste) + | +/breakdown -> tasks.md (+ propose feature/ branches) + | +/apply (repeat) -> ensure branch (interactive) + one step; you run build/test; you commit + | +/audit -> review.md (security / code / quality gate) + | +/prepare-pr -> PR body + `gh pr create` for you to run +``` + +Assisted mode throughout: the agent never runs builds/commits/PRs and never opens issues/PRs — it +proposes and you execute (the one exception: `apply` may create/switch the task branch after you +confirm). Contribution policy lives in `AGENTS.md` (§Commits, §Contribution policy) and +`CONTRIBUTING.md` (§AI-assisted contributions): Conventional Commits + `Assisted-by: AGENT:MODEL`, +**never** `Signed-off-by` (human DCO), AI-use disclosure in the PR, focused PRs, AGPL-3.0. + +## Smart execution (mode / model / effort) + +When a skill starts it **announces a recommended execution profile** — plan mode for planning stages, +a suggested model, and a suggested reasoning effort — plus how to switch (`/plan` or Shift+Tab · +`/model` · `/effort`). You apply it: skills **recommend and remind, they don't enforce** (SKILL.md +frontmatter can't set model/effort/mode, and these are Claude-Code-specific). Skills also remind you +to **lower effort** if you'd raised it. Full table + how-to: `_shared/execution-profiles.md`. + +## Onboarding (once per person) + +The first `/blueprint` run offers to set up the integrations it needs. You can also run the helper +directly at any time: +- Linux / macOS / WSL / Git Bash: `bash scripts/setup-integrations.sh` +- Windows PowerShell: `powershell -File scripts/setup-integrations.ps1` + +It detects your OS, installs `gh`, runs the interactive `gh auth login`, helps set the Jira env vars, +and self-checks. Everything is **per-person** and **never committed** (OSS). The only unavoidable +manual step is the interactive `gh auth login`. Without any of this, the skills still work via +**manual paste**. Per-platform matrix: `_shared/integrations.md`. + +## Portability — how each tool discovers the skills + +| Tool | Mechanism | +|---|---| +| **Codex / generic** | reads `.agents/skills//SKILL.md` directly (canonical) | +| **Claude Code** | `.claude/skills//SKILL.md` — a **real thin adapter** that points here | +| **Cursor** | `.cursor/rules/.mdc` — a thin rule that points here | + +> Why real adapters for Claude Code, not a symlink? Claude Code on Windows over `\\wsl.localhost` +> cannot follow WSL symlinks, and skill discovery does not resolve symlinks anyway (regression +> anthropics/claude-code #38051). So each `.claude/skills//SKILL.md` is a real file that +> redirects to the canonical playbook — a single source of truth is preserved. + +## `_shared/` references (read, don't duplicate) + +- `repo-matrix.md` — what lives in each submodule/repo + code anchors + build/lint per repo +- `task-ref-parsing.md` — GitHub / Jira / manual detection + task-id slug rules +- `integrations.md` — `gh` + Jira setup, cross-platform (Linux/macOS/Windows/WSL) +- `build-commands.md` — pointer to `AGENTS.md` + per-repo lint/test +- `sonar-quality-gate.md` — emulated quality-gate rubric (A–E, PASS/FAIL) +- `agpl-checklist.md` — AGPL-3.0 checks +- `memory-leak-checklist.md` — web-apps memory-leak sweep +- `execution-profiles.md` — recommended mode / model / effort per skill + +Onboarding helper scripts live in `scripts/setup-integrations.{sh,ps1}`. + +## Maintenance — editing or adding a skill + +- **Edit** a skill's behavior: change only `.agents/skills//SKILL.md` (canonical). The Claude + Code adapter and Cursor rule redirect here, so behavior updates with no re-sync. (If you change the + `description`, also update it in the adapter/rule, since that one line is duplicated there.) +- **Add** a skill: create `.agents/skills//SKILL.md`, plus a real adapter at + `.claude/skills//SKILL.md` (frontmatter + pointer) and a Cursor rule at + `.cursor/rules/.mdc`. +- **Frontmatter**: `name`, `description` (trigger-oriented), `user-invokable` (spelled with a **k**), + and `metadata` (e.g. `version`). There is no top-level `version` key, and no `model`/`effort`/ + `permission-mode` key (those are recommendations in the body — see `_shared/execution-profiles.md`). +- Skills load at session start; a **new** Claude Code session is needed to pick up new/renamed skills. + Use `/skills` to list discovered skills and `/doctor` to validate config. diff --git a/.agents/skills/_shared/agpl-checklist.md b/.agents/skills/_shared/agpl-checklist.md new file mode 100644 index 0000000000..7d2fbf015f --- /dev/null +++ b/.agents/skills/_shared/agpl-checklist.md @@ -0,0 +1,24 @@ +# AGPL-3.0 checklist (licensing) + +DocumentServer and its components are **AGPL-3.0**. Every AI-assisted contribution must comply. +Sources: `LICENSE` (root), `CONTRIBUTING.md` §"AI-assisted contributions" (Licensing) and the +[AI Contribution Policy](https://github.com/Euro-Office/.github/blob/main/AI_POLICY.md). + +## Checks + +- [ ] **License header** on every NEW source file, in the format used by neighboring files in the same + repo (copy the existing header; do not invent one). +- [ ] **No incompatible material**: no snippet copied from sources whose license is incompatible with + AGPL-3.0 (proprietary, GPL-incompatible, code with unclear licensing). +- [ ] **Third-party dependencies**: license **compatible** with AGPL-3.0 and **verified against the + real registry** (npm/PyPI/…); no invented or unverified packages (Euro-Office policy). +- [ ] **Copyright/attribution** preserved when adapting permitted third-party code. +- [ ] **Network use (AGPL §13)**: if a network-accessible feature is added, the obligation to make the + corresponding source available is not broken. +- [ ] **No secrets or proprietary data** embedded in the code. + +## Notes + +- The **human** certifies the DCO (`Signed-off-by`); the agent **never** adds it. +- If in doubt about the license of an AI-generated snippet → **flag it in `review.md`** for human + review; do not silence it. diff --git a/.agents/skills/_shared/build-commands.md b/.agents/skills/_shared/build-commands.md new file mode 100644 index 0000000000..35a0c65903 --- /dev/null +++ b/.agents/skills/_shared/build-commands.md @@ -0,0 +1,54 @@ +# Build / lint / test commands (per repo) + +> **POINTER, not duplication.** The server's start/build/verify workflow is authoritative in +> **`AGENTS.md`** (root), §"Build & run a test server (Docker)". **Always derive from there**; this +> sheet only adds what `AGENTS.md` does not cover (per-repo lint/test) and a quick target index. + +## Server: start, in-container build, and verification + +See `AGENTS.md` §"Build & run a test server (Docker)": +- **Start** → "Start the server" subsection (docker under `develop/`; healthcheck at `/healthcheck`). +- **Build** → "Build changes" subsection (in-container targets via `docker compose exec -T eo make `). +- **Verify in a browser** → "Verify in a browser (Playwright MCP)" subsection. + +`AGENTS.md` is the reference; follow whatever it says (e.g. do not use interactive `make`/`make local` +under `develop/`). This sheet **does not** contradict `AGENTS.md`. + +### Quick index of in-container targets (source: `AGENTS.md` + `develop/setup/Makefile`) + +| You change… | Target | +|---|---| +| web-apps (first time / deps) | `make web-apps` | +| web-apps (fast rebuild) | `make web-apps-dev` | +| sdkjs | `make sdkjs` | +| core (all) | `make core` | +| core (x2t only) | `make core/x2t` | +| server docservice | `make server/docservice` (or `server/converter`, `server/metrics`, `server/adminp`) | + +⚠️ The `web-apps*` targets rewrite locale JSON (`translation/merge_and_check.py`). **Do not commit** +that churn unless intended (`audit` and `prepare-pr` watch for it). + +## Lint / test per repo (what `AGENTS.md` does not cover) + +**server** (in the `server/` repo, see `server/package.json`): +```sh +npm run lint:check # eslint . +npm run format:check # prettier . --check +npm run code:check # both (lint + format) +npm run "unit tests" # jest — the name has a space → it must be quoted! +``` +Auto-fix: `lint:fix` / `format:fix` / `code:fix`. Integration: `"integration tests with server instance"`, +`"integration database tests"`. + +**sdkjs**: +```sh +cd sdkjs && python tests/code-style/check.py # code-style +``` +QUnit: HTML tests under `sdkjs/tests/{word,cell,slide,pdf,common,oform,visio}/` (open in a browser). + +**web-apps**: repo eslint/prettier; prioritize the *memory-leak sweep* +(`.agents/skills/_shared/memory-leak-checklist.md`). + +**core**: C++/CMake build via `make core*` (above); see `core/AGENTS.md` for tests. + +> Rule: if a repo's `AGENTS.md`/`CLAUDE.md` defines commands, **those win** over this sheet. diff --git a/.agents/skills/_shared/execution-profiles.md b/.agents/skills/_shared/execution-profiles.md new file mode 100644 index 0000000000..385e6cc7de --- /dev/null +++ b/.agents/skills/_shared/execution-profiles.md @@ -0,0 +1,25 @@ +# Execution profiles (mode / model / effort per skill) + +Each skill runs best in a certain **mode**, **model**, and reasoning **effort**. These are +**recommendations, not enforcement**: Claude Code's `SKILL.md` frontmatter cannot set model/effort/ +mode (verified — those keys are rejected), and the concepts are Claude-Code-specific (Codex/Cursor +ignore them). So each skill **announces** its recommended profile when it starts and **you apply it**: + +- **Mode** — plan mode via `/plan` or Shift+Tab (cycles modes); leave plan mode to run edits. +- **Model** — `/model `. **If you only have one model available, ignore this.** +- **Effort** — `/effort `. If you raised effort earlier and a skill wants + less, **lower it now** (e.g. `/effort medium`) — skills remind you so you don't stay on max by accident. + +## Recommended profiles + +| Skill | Mode | Model | Effort | Why | +|---|---|---|---|---| +| `blueprint` | plan mode | Opus | high | investigate + define; deep reasoning, no code changes | +| `breakdown` | plan mode | Sonnet (Opus if complex) | medium | decompose the plan into atomic steps | +| `apply` | normal | Sonnet | low–medium | apply one small, well-scoped step | +| `audit` | normal (read-only review) | Opus | high (max if security-critical) | catch bugs / security / quality | +| `prepare-pr` | normal | Sonnet (or Haiku) | low | draft the PR body from plan.md | + +Notes: +- Starting points — scale **up** for unusually complex tasks, **down** for trivial ones. +- Only the human switches model/effort/mode; skills recommend and remind, never enforce. diff --git a/.agents/skills/_shared/integrations.md b/.agents/skills/_shared/integrations.md new file mode 100644 index 0000000000..841d7f2c44 --- /dev/null +++ b/.agents/skills/_shared/integrations.md @@ -0,0 +1,118 @@ +# Integrations (personal) — NEVER committed (this is OSS) + +## Contents + +- [Which shell actually runs the fetch?](#which-shell-actually-runs-the-fetch) +- [GitHub — `gh` CLI (primary path)](#github--gh-cli-primary-path): install · authenticate · fetch +- [Jira — direct REST (current solution)](#jira--direct-rest-current-solution): set env vars · fetch +- [Jira — MCP `mcp-atlassian` (professional upgrade, future)](#jira--mcp-mcp-atlassian-professional-upgrade-future) +- [Quick self-check](#quick-self-check) +- [Fallback](#fallback) + +No credential, instance, or config containing secrets may be **committed**. Everything lives in the +**user's shell profile / OS keychain** or in **local** config (never `project` scope). If nothing is +available, fall back to **manual paste**. + +These skills are used by an **international team on Linux, macOS, Windows, and WSL**. The fetch +**commands** below are identical on every platform — only the **install step** and **where you set +env vars / PATH** differ. Pick your platform from the tables. + +**Fastest path (recommended):** run the onboarding helper once — `bash scripts/setup-integrations.sh` +(Linux/macOS/WSL/Git Bash) or `powershell -File scripts/setup-integrations.ps1` (Windows). `blueprint` +also offers this on its first run. It automates the install + auth + env + self-check described below. + +## Which shell actually runs the fetch? (read this first) + +The agent runs `gh`/`curl` in **the shell your AI tool uses**, and `gh` + env vars must be available +**there**: +- Native **Linux / macOS**: your login shell (bash/zsh). +- Native **Windows**: usually **Git Bash** (bundled with the AI tool). It inherits Windows PATH and + Windows user env vars. +- **Windows editing a repo inside WSL** (repo under `\\wsl.localhost\...`): the tool may run **Git + Bash on Windows** even though the code is in WSL. Then `gh` must be installed **for Windows**, not + only in WSL. If you prefer to keep everything in WSL, install `gh` in WSL and have the agent call + `wsl gh …` / `wsl curl …`. + +**Rule of thumb:** run `gh --version` in the same shell the tool uses. If it says *command not +found*, install `gh` for **that** environment (see table). Same idea for `echo "$JIRA_URL"`. + +## GitHub — `gh` CLI (primary path) + +### 1) Install (pick your platform) + +| Platform | Command | +|---|---| +| macOS | `brew install gh` | +| Debian / Ubuntu / **WSL** | `sudo apt install gh` (for the latest, add the official gh apt repo) | +| Fedora / RHEL | `sudo dnf install gh` | +| Arch | `sudo pacman -S github-cli` | +| **Windows** | `winget install --id GitHub.cli` (or `scoop install gh` / `choco install gh`) | + +Official install matrix: . After a Windows install, **reopen** +the tool so Git Bash picks up the new PATH. + +### 2) Authenticate (once, any platform) + +```sh +gh auth login # GitHub.com · HTTPS · account with access to the Euro-Office org (incl. private repos like `internal`) +gh auth status # verify +``` +Non-interactive / CI alternative: export a PAT (repo scope) as `GH_TOKEN` (or `GITHUB_TOKEN`) instead +of `gh auth login`. + +### 3) Fetch (identical on every platform) + +```sh +gh issue view --repo / \ + --json title,body,comments,labels,state,assignees,url +``` +(`` defaults to `Euro-Office`.) For PRs: `gh pr view --repo … --json …`. +No `gh` / not authed / no access to a private repo → **manual paste**. + +## Jira — direct REST (current solution) + +**Server/Data Center** instance → **PAT + `Bearer`**, REST **v2**, description in **wiki-markup** +(not ADF). The skill reads `$JIRA_URL` → **instance-agnostic**. + +### 1) Set the env vars (per platform — never in the repo) + +| Shell / platform | Where | How (reopen the shell afterwards) | +|---|---|---| +| bash — Linux / **WSL** | `~/.bashrc` | `export JIRA_URL="https://"` / `export JIRA_PERSONAL_TOKEN=""` | +| zsh — macOS (default) | `~/.zshrc` | same `export …` lines | +| **Git Bash** — Windows | `~/.bashrc` (= `%USERPROFILE%\.bashrc`) | same `export …` lines | +| Windows (system-wide) | user env vars | `setx JIRA_URL "https://"` then `setx JIRA_PERSONAL_TOKEN ""` (Git Bash inherits them; reopen) | + +Check: `echo "$JIRA_URL"` prints a value (not empty). + +### 2) Fetch (identical on every platform) + +```sh +curl -sf -H "Authorization: Bearer $JIRA_PERSONAL_TOKEN" \ + "$JIRA_URL/rest/api/2/issue/?fields=summary,description,status,issuetype,comment,attachment,labels,priority" +``` +Lightweight wiki-markup → markdown conversion (`h1.`→`#`, `*bold*`, `{code}`→fenced block, `#`/`*` +lists). Without the env vars → **manual paste**. (`curl` ships with macOS/Linux and Git Bash.) + +## Jira — MCP `mcp-atlassian` (professional upgrade, future) + +Only if you want JQL/boards. Docker + **local** registration with env pass-through (no secrets in config): +```sh +claude mcp add jira --scope local \ + -e JIRA_URL -e JIRA_PERSONAL_TOKEN \ + -- docker run -i --rm -e JIRA_URL -e JIRA_PERSONAL_TOKEN +``` +(Verify the image against its real registry before using it — Euro-Office policy: nothing unverified.) +**Never** in `project` scope nor in a committed `.mcp.json` (it would expose/force config on the whole repo). + +## Quick self-check (run in the tool's shell) + +```sh +gh --version && gh auth status # GitHub ready? +echo "${JIRA_URL:-}" # Jira URL present? +``` + +## Fallback + +Preference per source: integration available → if it fails / is absent → **manual paste** (title + +description + screenshots). **Never invent** the content of an issue. diff --git a/.agents/skills/_shared/memory-leak-checklist.md b/.agents/skills/_shared/memory-leak-checklist.md new file mode 100644 index 0000000000..d791b8399e --- /dev/null +++ b/.agents/skills/_shared/memory-leak-checklist.md @@ -0,0 +1,27 @@ +# Memory-leak sweep (web-apps / front-end focus) + +The editors are long-lived SPAs with canvas and real-time collaboration: leaks accumulate as +documents, panels, and views are opened/closed. Sweep the diff with this checklist. Anchors: +`web-apps/apps/*`, `sdkjs/common/` (e.g. `sdkjs/common/CollaborativeEditingBase.js`). + +## Checks (everything created must be released in `destroy`/teardown) + +- [ ] **Event listeners**: every `addEventListener` / `on(...)` / jQuery `.on(...)` has its matching + `removeEventListener` / `off(...)` on teardown. Watch `window`, `document`, `resize`, `scroll`, + `keydown`. +- [ ] **Timers**: every `setInterval`/`setTimeout`/`requestAnimationFrame` is cleared + (`clearInterval`/`clearTimeout`/`cancelAnimationFrame`). +- [ ] **Canvas / contexts**: 2D/WebGL contexts and large buffers released; no `ImageData`/canvas + retained out of use; render caches bounded or cleared. +- [ ] **Collaborative handlers**: subscriptions to co-editing events / websockets / engine callbacks + (`Asc`/sdkjs) unregistered when the document closes or the view changes. +- [ ] **DOM references**: detached nodes not retained by closures; refs set to `null` on destroy. +- [ ] **Observers / pub-sub**: `MutationObserver`/`ResizeObserver`/`IntersectionObserver` disconnected; + internal event buses have their `unsubscribe`. +- [ ] **Cycles**: no object↔DOM cycles that prevent GC; no globals growing without bound. + +## How to verify + +- Open/close the same document N times and watch the heap (DevTools → Memory → snapshots) with no + monotonic growth of detached nodes / listeners. +- Check that every component with `init`/`create` has a **symmetric** `destroy`/`dispose`. diff --git a/.agents/skills/_shared/repo-matrix.md b/.agents/skills/_shared/repo-matrix.md new file mode 100644 index 0000000000..44c2ea2590 --- /dev/null +++ b/.agents/skills/_shared/repo-matrix.md @@ -0,0 +1,47 @@ +# Repo matrix — what lives in each repo and how it is built/verified + +> **Source of truth per repo:** the `AGENTS.md` and `CLAUDE.md` **of each submodule** (read them at +> runtime; some are still under review on GitHub and may be absent today — use this matrix as a +> fallback). Build/lint/test commands → `.agents/skills/_shared/build-commands.md`. + +DocumentServer is the **master meta-repo**: it aggregates every submodule via `.gitmodules`. The +skills live here to have the **full context** and to **break down which repos each task affects**. +No repo is a privileged pilot. + +## Submodules (11) — all under the `Euro-Office` org + +| Submodule | What lives there | Code anchors | Build target (in-container) | Lint / test | +|---|---|---|---|---| +| `core` | C++ conversion/render engine (x2t, fonts, DocxRenderer, doctrenderer, WASM) | `core/OOXML/`, `core/OdfFile/`, `core/X2tConverter/`, `core/DocxRenderer/`, `core/DesktopEditor/`, `core/Common/` | `make core` (subsets: `core/x2t`, `core/allfontsgen`, `core/wasm`, …) | C++/CMake — see `core/AGENTS.md` | +| `core-fonts` | Bundled fonts | `core-fonts/` | (via `core/allfontsgen`) | — | +| `sdkjs` | JavaScript SDK for the editors (word/cell/slide/pdf/visio) | `sdkjs/common/`, `sdkjs/word/`, `sdkjs/cell/`, `sdkjs/slide/`, `sdkjs/pdf/` | `make sdkjs` | `python tests/code-style/check.py`; QUnit in `sdkjs/tests/` | +| `sdkjs-forms` | OForm layer (fillable forms) on top of sdkjs | `sdkjs-forms/` (integrated via `configs/word.json`) | (part of `make sdkjs`) | see `sdkjs-forms/AGENTS.md` | +| `server` | Node.js backend (co-editing, storage, conversion, metrics, auth/JWT) | `server/Common/sources/` (`storage/`, `signing/`, `logger.js`…), `server/DocService/`, `server/FileConverter/` | `make server/docservice` (+ `server/converter`, `server/metrics`, `server/adminp`) | `npm run lint:check` / `format:check` / `code:check` / `"unit tests"` | +| `web-apps` | Editors UI (front-end) | `web-apps/apps/{api,common,documenteditor,spreadsheeteditor,presentationeditor,pdfeditor,visioeditor}` | `make web-apps` (first time) / `make web-apps-dev` (fast) | repo eslint/prettier; *memory-leak sweep* | +| `dictionaries` | Hunspell dictionaries (45+ locales) | `dictionaries//` | — | strict LF + UTF-8 — see `dictionaries/AGENTS.md` | +| `document-formats` | Format definitions/resources | `document-formats/` | — | see `document-formats/AGENTS.md` | +| `document-templates` | Document templates | `document-templates/` | — | — | +| `document-server-package` | Packaging/distribution (DEB/RPM/EXE/TAR) | `document-server-package/` | — (release only) | — | +| `document-server-integration` | Integrations/examples (Nextcloud, WOPI, …) | `document-server-integration/` | — | see its `AGENTS.md` | + +## Org repos that are NOT local submodules + +They can be the target of a task even though they are not in `.gitmodules` (clone them separately if +needed): `DesktopEditors`, `internal`, `issue-taxi`, and others under `github.com/Euro-Office`. Treat +them the same way: read their `AGENTS.md`/`CLAUDE.md`, derive their commands, and propose them as +affected repos. + +## How to determine which repos a task affects + +1. Task keywords → layer: + - UI, toolbar, panel, dialog, editor i18n → **web-apps** (`apps//`) + - Editor logic / JS API / collaboration → **sdkjs** (`common/`, `/`) + - Fillable forms → **sdkjs-forms** + - Format conversion / render / fonts / x2t → **core** + - Co-editing, storage, server-side conversion, auth/JWT, metrics → **server** (`Common/sources/`) + - Spellcheck / dictionaries → **dictionaries** + - Packaging / installers → **document-server-package** + - Integration (Nextcloud, WOPI, examples) → **document-server-integration** +2. Confirm by grepping/reading the anchors (above) before locking the list. +3. A task may touch **several** repos (e.g. a UI feature that needs an API in sdkjs). `blueprint` + lists them all; `breakdown` proposes one `feature/` branch per affected repo. diff --git a/.agents/skills/_shared/sonar-quality-gate.md b/.agents/skills/_shared/sonar-quality-gate.md new file mode 100644 index 0000000000..e98d3cc7c3 --- /dev/null +++ b/.agents/skills/_shared/sonar-quality-gate.md @@ -0,0 +1,46 @@ +# Emulated Quality Gate (SonarQube-style) — rubric + +There is **no SonarQube** in the project. This sheet defines an **emulated** gate that `audit` +applies over the diff. **CodeQL** does run in CI (security) — note **parity** with its findings where +applicable. This gate **does not block**; it is a quality snapshot for the human to decide. + +## Finding categories + +- **Bugs** — reliability defects (incorrect logic, null/undefined, race conditions). +- **Vulnerabilities** — exploitable security flaws. +- **Security Hotspots** — security-sensitive code that needs manual review (not necessarily a flaw). +- **Code Smells** — maintainability (complexity, local duplication, naming, dead code). +- **Duplications** — % of duplicated lines introduced. +- **Coverage** — test coverage of the new/modified code (if measurable). + +## Ratings (A–E) over the NEW/modified code + +| Rating | Reliability (Bugs) | Security (Vulns) | Maintainability (tech debt) | +|---|---|---|---| +| **A** | 0 bugs | 0 vulns | debt ratio ≤ 5% | +| **B** | ≥1 Minor | ≥1 Minor | ≤ 10% | +| **C** | ≥1 Major | ≥1 Major | ≤ 20% | +| **D** | ≥1 Critical | ≥1 Critical | ≤ 50% | +| **E** | ≥1 Blocker | ≥1 Blocker | > 50% | + +Severities: **Blocker > Critical > Major > Minor > Info**. + +## Quality Gate condition (default, on "new code") + +**PASS** if ALL hold; otherwise **FAIL** (informational): +- Reliability = **A** (0 new bugs) +- Security = **A** (0 new vulns) +- Security Hotspots: **100% reviewed** +- Maintainability = **A** (debt ≤ 5%) +- Duplications on new code ≤ **3%** +- Coverage of new code ≥ **80%** (or `n/a` if not measurable — note it, do not count it as a failure) + +## Expected output (block in `review.md`) + +``` +### Quality Gate (emulated) — PASS | FAIL +Reliability: A Security: A Maintainability: B +Bugs: 0 · Vulnerabilities: 0 · Hotspots: 1 (review) · Code Smells: 4 · Duplications: 1.2% · Coverage(new): n/a +CodeQL parity: no known findings | [list] +Top items: 1) … 2) … +``` diff --git a/.agents/skills/_shared/task-ref-parsing.md b/.agents/skills/_shared/task-ref-parsing.md new file mode 100644 index 0000000000..679b536fb5 --- /dev/null +++ b/.agents/skills/_shared/task-ref-parsing.md @@ -0,0 +1,42 @@ +# Task reference resolution (3 modes) + +`blueprint []` accepts the task in three ways. Detect the mode **in this order** and, if +anything is ambiguous or missing, **ask** (do not assume). GitHub is the primary path. + +## Detection order + +1. **GitHub** (primary path) + - URL: `https://github.com///issues/` (or `/pull/`) + - Short ref: `/#`, or ` #` / `#` (owner defaults to `Euro-Office`) + - Examples: `web-apps #54`, `Euro-Office/web-apps#54`, `DocumentServer #38` +2. **Jira** — if GitHub does not match, look for a key with regex `\b[A-Z][A-Z0-9]+-\d+\b` + - Key: `EUOFFICE-5` + - URL: `…/browse/EUOFFICE-5`, or `…?selectedIssue=EUOFFICE-5` +3. **Manual** — if no ref is detectable: interactive intake (title + description + screenshots). + +## task-id (slug) + +| Mode | Example ref | `task-id` | +|---|---|---| +| GitHub | `web-apps #54` | `web-apps-54` | +| GitHub | `DocumentServer #38` | `documentserver-38` | +| Jira | `EUOFFICE-5` | `euoffice-5` | +| Manual | title "Fix crash on paste" | `fix-crash-on-paste` | + +Slug rules: lowercase; spaces/`#`/`/`/`_` → `-`; strip accents and symbols; collapse repeated `-`; +trim to ~50 chars. The GitHub pattern is `-`; Jira is ``. + +## Fetching the content + +Depending on the mode, use `.agents/skills/_shared/integrations.md`: +- GitHub → `gh` CLI (or manual paste if there is no `gh`/auth). +- Jira → REST with `$JIRA_URL`/`$JIRA_PERSONAL_TOKEN` (or the future MCP; or manual paste). +- Manual → the user pastes text + screenshots (images read directly). + +If the integration is unavailable → **fall back to manual paste** (never invent the content of an issue). + +## Inferring the task-id from context (when no `` is passed) + +1. Current branch `feature/` → use that `task-id`. +2. Most recently modified `.ai/tasks//plan.md` → propose that one. +3. If still ambiguous → **ask** which one. diff --git a/.agents/skills/apply/SKILL.md b/.agents/skills/apply/SKILL.md new file mode 100644 index 0000000000..01159e3ea7 --- /dev/null +++ b/.agents/skills/apply/SKILL.md @@ -0,0 +1,76 @@ +--- +name: apply +description: Applies the next unchecked step from the current task's tasks.md — first ensures the target repo is on the task branch (proposes/creates it interactively; you can rename it), then edits the code and shows the build/lint/test command for you to run (no build/commit auto-run), and stops. Use to implement a task one step at a time after breakdown. +user-invokable: true +metadata: + version: 0.1.0 +--- + +# apply — assisted implementation (one step, then stop) + +> **Language rule (non-negotiable):** detect the language the human used when invoking this skill +> and use that language for ALL user-facing output. Default to **English** if unclear. Never output +> in a language that was not used in the invocation or the conversation history. + +Third stage. Inherently interactive: applies exactly **one** step and stops. Before editing it makes +sure the target repo is on the **task branch** (proposing/creating it with your confirmation), then +edits code and **shows** the build/lint/test command for **you** to run. It never runs builds/tests, +never commits/pushes, and never auto-heals in a loop. The only git action it performs is +creating/switching the task branch — and only after you confirm. + +> **Recommended execution:** normal mode. See `.agents/skills/_shared/execution-profiles.md` for +> recommended model and effort. State the profile to the human before starting; if they raised +> effort earlier remind them to lower it (`/effort`). + +## Invocation + +- `/apply` — take the **first `- [ ]`** from `.ai/tasks//tasks.md` for the current task-id. + +## Steps + +1. **Resolve the `task-id`** and read `tasks.md`. Resolve from the current branch `feature/`, + the most recent `tasks.md`, or ask. A **custom branch name is fine** — in that case resolve the + task-id from `tasks.md`, not from the branch. +2. **Pick the first unchecked step** `- [ ]`. If none remain → report completion and suggest `audit`. +3. **Ensure the repo is on the task branch (interactive — propose, confirm, then create/switch):** + a. **Intended branch** = the one recorded for this repo under `tasks.md` "## Branches", else the + default `feature/`. + b. **Current branch**: `git -C rev-parse --abbrev-ref HEAD`. + c. If it already matches (or you confirm the current branch is this task's branch) → continue. + d. Otherwise **propose the branch**: show the default name `feature/` and ask you to + **accept it or type a different name** (you may not like the default). With the confirmed + ``, and only after your OK, run **just** this: + - new: `git -C checkout -b ` + - existing: `git -C switch ` + + If you decline, **stop** without editing. Never create/switch without confirmation; never + commit or push. + e. If `` differs from what `tasks.md` records, **update** the "## Branches" line for this + repo so `audit` and `prepare-pr` use the right branch. +4. **Apply the change** in that repo, **scoped** to this step; respect the repo's `AGENTS.md`/`CLAUDE.md`; + do not touch unrelated files. +5. **Show the verify command(s)** for that repo — do **not** run them — from + `.agents/skills/_shared/build-commands.md` and root `AGENTS.md`. Examples: + - `docker compose exec -T eo make web-apps-dev` + - `npm run "unit tests"` (in `server/`) + - `cd sdkjs && python tests/code-style/check.py` +6. **Wait for you** to run them and report the result. If it fails, help diagnose, but do not auto-run + fixes in a loop. +7. On your confirmation, mark the step `- [x]` in `tasks.md` and **stop** (one step per run). +8. **Remind** you that the commit is yours: Conventional Commits v1.0.0 + an `Assisted-by: AGENT:MODEL` + trailer, and **never** `Signed-off-by` (see root `AGENTS.md` §Commits). + +## Guardrails + +- **Assisted mode:** the only git command `apply` runs is `checkout -b` / `switch` for the task branch, + and only after you confirm. No build/test auto-run, no auto-heal, no commit, no push. +- **One step per invocation**, then stop. +- Watch the `web-apps*` locale JSON churn — do not stage it unless intended + (`.agents/skills/_shared/build-commands.md`). +- Do not modify submodule contents against their own `CLAUDE.md`/`AGENTS.md`. + +## References + +- `.agents/skills/_shared/build-commands.md` · `repo-matrix.md` · `execution-profiles.md` +- Root `AGENTS.md` (§"Build & run a test server (Docker)", §Commits), `CONTRIBUTING.md` +- Prev: `breakdown` · Next: `audit`. diff --git a/.agents/skills/audit/SKILL.md b/.agents/skills/audit/SKILL.md new file mode 100644 index 0000000000..0526cbff52 --- /dev/null +++ b/.agents/skills/audit/SKILL.md @@ -0,0 +1,151 @@ +--- +name: audit +description: Audits a diff — the current task's working changes OR any open PR — into review.md with four blocks: security (/security-review + AGPL checklist + web-apps memory-leak sweep), code quality (/code-review), an emulated SonarQube-style Quality Gate (A–E, PASS/FAIL), and proposed PR comments (drafts for the human to post, never posted autonomously). Task-mode reviews are written to .ai/tasks//review.md; standalone PR reviews to .ai/reviews/-/review.md. Use before preparing a PR, or to review any PR independently. +user-invokable: true +metadata: + version: 0.1.0 +--- + +# audit — security + code + emulated quality gate + +> **Language rule (non-negotiable):** detect the language the human used when invoking this skill +> and use that language for ALL user-facing output. Default to **English** if unclear. Never output +> in a language that was not used in the invocation or the conversation history. + +Independent stage. Audits a diff and writes `review.md` with four blocks — (a) security, (b) code, +(c) an emulated Quality Gate, and (d) proposed PR comments. It **reuses the built-in +`/security-review` and `/code-review`** skills and adds Euro-Office-specific layers. The Quality Gate +is **informational — it does not block**. + +Two modes: + +| Mode | When to use | Output | +|---|---|---| +| **Task mode** (default) | Reviewing your own in-progress changes before a PR | `.ai/tasks//review.md` | +| **PR mode** | Reviewing any open PR (your own or a teammate's) | `.ai/reviews/-/review.md` | + +> **Where the review is written — task vs PR are different concepts.** A task-mode review is one +> artifact of the task workspace, so it lives with the task's other files under `.ai/tasks//`. +> A PR review is **not** a task — it gets its own top-level namespace `.ai/reviews/` so it never +> mixes into `.ai/tasks/`. + +> Named `audit` (not `code-review`) so it can invoke the built-in `/code-review` without shadowing +> or recursing into itself. + +> **Recommended execution:** normal mode. See `.agents/skills/_shared/execution-profiles.md` for +> recommended model and effort (bump to max if security-critical). State the profile to the human +> before starting. + +## Invocation + +``` +/audit # task mode: diff for the current task-id (working tree vs main) +/audit /# # PR mode: review an open PR by ref +/audit # PR mode: review an open PR by URL +``` + +If no argument is given and no task-id can be inferred from the current branch, ask the human +which mode to use. + +## Steps + +### Step 1 — Resolve the target diff + +**Task mode** (no argument): +- Infer `task-id` from the current branch (`feature/`) or ask. +- Diff = uncommitted changes + commits on `feature/` vs `main`. +- Output file: `.ai/tasks//review.md`. + +**PR mode** (argument provided): +- Parse the ref: `/#` or extract from a GitHub PR URL + (pattern: `github.com///pull/`). +- Fetch the diff: + ```sh + gh pr diff --repo / + ``` + No `gh` / not authenticated / no access → ask the human to paste the diff manually. +- Output file: `.ai/reviews/-/review.md` (owner defaults to `Euro-Office`; keep the owner in + the folder only if it is not `Euro-Office`, e.g. `.ai/reviews/--/review.md`). + Paste-back if `.ai/` is not writable. **Never** write a PR review under `.ai/tasks/`. +- Note the PR title, branch, and target branch for context. + +### Step 2 — Block (a) Security + +- Invoke the built-in **`/security-review`** on the diff. +- Run the **AGPL-3.0 checklist** (`.agents/skills/_shared/agpl-checklist.md`). +- Run the **memory-leak sweep** on `web-apps` changes + (`.agents/skills/_shared/memory-leak-checklist.md`). +- Note **parity with CodeQL** (which runs in CI). +- Reminder: verified security issues are reported **privately by email** to the maintainers, + **never** as GitHub issues and **never** autonomously (root `AGENTS.md`). + +### Step 3 — Block (b) Code (correctness + quality) + +- Invoke the built-in **`/code-review`**, respecting the repo's eslint/prettier config. + +### Step 4 — Block (c) Quality Gate (emulated) + +- Apply `.agents/skills/_shared/sonar-quality-gate.md`: classify findings, assign + Reliability/Security/Maintainability ratings **A–E**, compute **PASS/FAIL** + score. + +### Step 5 — Block (d) Proposed PR comments + +Turn the confirmed findings into concrete, copy-pasteable review comments the **human** can post on +the PR. This block is always produced (most useful in PR mode). + +- One entry per comment, anchored to a location: ` :` + a short, actionable + suggestion written in the reviewer's voice (a phrasing the human can paste as-is). +- Only include findings worth a comment — do not restate every Quality-Gate line. +- These are **drafts for the human to post** — the skill never posts them itself (see Guardrails). +- **Language rule applies:** write the comments (and every heading) in the human's language; + default to English if unclear. + +### Step 6 — Write output + +Write the review file (path from Step 1). + +## Output template + +~~~markdown +# Review — + +Scope: +Mode: task | PR () + +## a) Security +- /security-review: +- AGPL-3.0 checklist: +- Memory-leak sweep (web-apps): +- CodeQL parity: +> Security reports go privately by email to the maintainers — never as issues, never autonomous. + +## b) Code (correctness + quality) +- /code-review: + +## c) Quality Gate (emulated) — PASS | FAIL +Reliability: A Security: A Maintainability: B +Bugs: 0 · Vulnerabilities: 0 · Hotspots: 1 (review) · Code Smells: 4 · Duplications: 1.2% · Coverage(new): n/a +CodeQL parity: no known findings | [list] +Top items: 1) … 2) … + +## d) Proposed PR comments +> Drafts for the human to post — the skill never comments on GitHub itself. +> Written in the human's language (default English). +- ` :` — +- ` :` — +~~~ + +## Guardrails + +- **Audit only** — produce `review.md`; do not fix, commit, or publish. +- The Quality Gate is **non-blocking** (a snapshot for the human). +- **Never** post review comments on GitHub autonomously; share findings with the human only. +- **Never** file security reports autonomously; flag AGPL doubts rather than silencing them. +- Assisted mode: findings are for the human to act on. + +## References + +- `.agents/skills/_shared/agpl-checklist.md` · `memory-leak-checklist.md` · `sonar-quality-gate.md` · `execution-profiles.md` +- Built-in skills: `/security-review`, `/code-review` +- Root `AGENTS.md` (§"Contribution policy"), `CONTRIBUTING.md`, `SECURITY.md` +- Prev: `apply` · Next: `prepare-pr` (or standalone for PR reviews). diff --git a/.agents/skills/blueprint/SKILL.md b/.agents/skills/blueprint/SKILL.md new file mode 100644 index 0000000000..6b7acf9326 --- /dev/null +++ b/.agents/skills/blueprint/SKILL.md @@ -0,0 +1,124 @@ +--- +name: blueprint +description: Fetches, investigates, and defines a Euro-Office task (GitHub issue, Jira key, or pasted description + screenshots) into a plan.md with the affected repos, an action plan, and Gherkin acceptance criteria; on first run it also onboards the gh/Jira integrations it needs. Use when starting a new task or when the request is under-specified and needs scoping before any coding. +user-invokable: true +metadata: + version: 0.1.0 +--- + +# blueprint — onboard (first run) + fetch + investigate + define + +> **Language rule (non-negotiable):** detect the language the human used when invoking this skill +> and use that language for ALL user-facing output — questions, options, messages, and the +> `plan.md` summary. Default to **English** if the invocation language is unclear. Never output +> in a language that was not used in the invocation or the conversation history. + +First stage of the Euro-Office pipeline. Turns a task reference (or a pasted description) into a +structured `plan.md`. On its **first run** on a machine it also sets up the integrations it needs +(GitHub `gh` / Jira). **Assisted mode:** it investigates and writes `plan.md`; it does **not** run +builds, commits, or PRs, and never opens issues/PRs. Interactive auth (`gh auth login`) and any +privileged install (`sudo`/`winget`) are the **human's** to run — never do them silently. When +anything is ambiguous, **ask; never assume**. + +> **Recommended execution:** plan mode. See `.agents/skills/_shared/execution-profiles.md` for +> recommended model and effort. State the profile to the human and how to switch +> (`/plan` or Shift+Tab · `/model` · `/effort`) before starting. + +Runs from the **DocumentServer** meta-repo, so it has whole-project context and can decide which +submodules/repos a task actually touches. No repo is privileged. + +## Invocation + +- `/blueprint web-apps #54` +- `/blueprint https://github.com/Euro-Office/web-apps/issues/54` +- `/blueprint EUOFFICE-5` +- `/blueprint https:///browse/EUOFFICE-5` +- `/blueprint` (no ref → **interactive intake**: ask the user to paste a title + description + + screenshots, or give an ID/URL) + +## Steps + +1. **Resolve the reference.** Follow `.agents/skills/_shared/task-ref-parsing.md` (detection order: + GitHub → Jira → manual). Derive the `task-id` slug. +2. **Ensure integrations (first run), then fetch** — per `.agents/skills/_shared/integrations.md`: + a. **Check readiness** in the tool's shell for the source you resolved: `gh auth status` (GitHub) + or `echo "$JIRA_URL"` (Jira). + b. **If the needed integration is missing/unauthed, offer one-time onboarding** — run the + cross-platform helper (`bash scripts/setup-integrations.sh` on Linux/macOS/WSL/Git Bash, or + `powershell -File scripts/setup-integrations.ps1` on Windows), or walk the human through the + matching row of `integrations.md`. The interactive `gh auth login` and any `sudo`/`winget` are + the **human's** to run — propose, never do them silently. + c. **Fetch**: GitHub (primary) → `gh issue view … --json …`; Jira → REST with + `$JIRA_URL`/`$JIRA_PERSONAL_TOKEN`. + d. If the human declines onboarding, is offline, or the mode is manual → use the **pasted** title, + description, and **screenshots** (read images directly). **Never invent** issue content. +3. **Interactive intake when needed.** If there is no ref, required info is missing, or a screenshot + is unclear, **ask focused technical questions** before continuing. Do not guess intent. +4. **Investigate the codebase.** Using `.agents/skills/_shared/repo-matrix.md`, map task keywords to + layers and confirm by reading/grepping the code anchors (`web-apps/apps/*`, `sdkjs/common/`, + `server/Common/sources/`, `core/…`). Read the `AGENTS.md`/`CLAUDE.md` of each involved repo + (root `AGENTS.md` always; per-repo docs when present — they may be absent today). +5. **Determine the affected repos** (may be several) and note the specific files/dirs in scope. +6. **Assess readiness.** Confirm there is: a clear action plan, defined inputs/outputs, and testable + acceptance criteria. Fill gaps by asking, not assuming. For complex/multi-subsystem work, note in + `plan.md` that a discussion ticket should be opened first (per `AGENTS.md` policy) — but **do not + open it**; that is the human's action. +7. **Write** `.ai/tasks//plan.md` (always produced) using the template below. + +## Output — `.ai/tasks//plan.md` + +~~~markdown +# + +- **Source:** · +- **task-id:** +- **Status/type/labels:** + +## Summary +<1–3 sentences: the problem and the intended outcome, in your own words.> + +## Investigation + + +## Affected repos +| Repo | Why | Files/areas in scope | +|---|---|---| +| web-apps | … | `apps//…` | +| sdkjs | … | `common/…` | + +## Action plan +1. (repo) +2. … + +## Inputs / Outputs +- **Inputs:** +- **Outputs:** + +## Acceptance criteria (Gherkin) +Scenario: + Given + When + Then + +## Open questions +- +~~~ + +## Guardrails + +- **Assisted mode:** investigate + write `plan.md` only. Do not build, commit, branch, or open + anything. For integration onboarding, propose/run the helper but leave interactive auth + (`gh auth login`) and privileged installs (`sudo`/`winget`) to the human — never enter tokens or + secrets on their behalf, and never commit secrets. +- **Ask, don't assume** when ambiguous (including unclear screenshots). +- **Never invent** issue content; fall back to manual paste if a source is unreachable. +- **Do not duplicate** `AGENTS.md`/`CLAUDE.md` — read and link them. +- Keep `.ai/` local (it is gitignored); no secrets in `plan.md`. + +## References + +- `.agents/skills/_shared/task-ref-parsing.md` · `integrations.md` · `repo-matrix.md` · `execution-profiles.md` +- Onboarding helper: `scripts/setup-integrations.sh` · `scripts/setup-integrations.ps1` +- Root `AGENTS.md`, `CONTRIBUTING.md`; per-repo `AGENTS.md`/`CLAUDE.md` +- Next stage: `breakdown`. diff --git a/.agents/skills/breakdown/SKILL.md b/.agents/skills/breakdown/SKILL.md new file mode 100644 index 0000000000..c97bf97930 --- /dev/null +++ b/.agents/skills/breakdown/SKILL.md @@ -0,0 +1,72 @@ +--- +name: breakdown +description: Turns a task's plan.md into tasks.md — atomic ~5-minute steps grouped by repo — and proposes (assisted) a feature/ branch per affected repo. Use after blueprint, when you have a plan and need an executable roadmap plus branches. +user-invokable: true +metadata: + version: 0.1.0 +--- + +# breakdown — roadmap + branches + +> **Language rule (non-negotiable):** detect the language the human used when invoking this skill +> and use that language for ALL user-facing output. Default to **English** if unclear. Never output +> in a language that was not used in the invocation or the conversation history. + +Second stage. Reads `plan.md` and produces `tasks.md`: a checklist of **atomic steps** (~5 minutes +each; the count flexes to the real size of the task), grouped by affected repo. It **proposes** the +branch command per repo but **does not run it** — the human confirms and executes. + +> **Recommended execution:** plan mode. See `.agents/skills/_shared/execution-profiles.md` for +> recommended model and effort. State the profile to the human and how to switch +> (`/plan` or Shift+Tab · `/model` · `/effort`) before starting. + +## Invocation + +- `/breakdown` — infer the `task-id` from the current branch `feature/`, else from the + most recent `plan.md`. If ambiguous, **ask** which one. +- `/breakdown euoffice-5` — explicit task-id. + +## Steps + +1. **Resolve the `task-id`** (see `.agents/skills/_shared/task-ref-parsing.md` → "Inferring the + task-id"). Ask if ambiguous. +2. **Read** `.ai/tasks//plan.md`. If missing, tell the user to run `blueprint` first. +3. **Decompose** the action plan into atomic steps: each ~5 minutes, independently verifiable, + ordered by dependency, grouped by repo. Split anything larger; the number of steps is flexible. +4. **Propose branches (assisted).** For each affected repo, show — do not run: + `git -C checkout -b feature/`. Use descriptive branch names per `CONTRIBUTING.md`. + The human confirms/executes. +5. **Write** `.ai/tasks//tasks.md` (template below), one `- [ ]` per atomic step, with the + files touched and a verify hint (from `.agents/skills/_shared/build-commands.md`). + +## Output — `.ai/tasks//tasks.md` + +~~~markdown +# Tasks — + +Plan: `.ai/tasks//plan.md` + +## Branches (assisted — run these yourself) +- web-apps: `git -C web-apps checkout -b feature/` +- sdkjs: `git -C sdkjs checkout -b feature/` + +## Steps +### web-apps +- [ ] — files: `apps//…` — verify: `docker compose exec -T eo make web-apps-dev` +- [ ] — files: … — verify: … + +### sdkjs +- [ ] — files: `common/…` — verify: `docker compose exec -T eo make sdkjs` +~~~ + +## Guardrails + +- **Assisted mode:** propose the branch command; never run git, build, or commit. +- Keep steps **atomic and ordered**; one concern per step. +- Do not modify submodule contents here (that is `apply`); respect each repo's `CLAUDE.md`. + +## References + +- `.agents/skills/_shared/task-ref-parsing.md` · `build-commands.md` · `repo-matrix.md` · `execution-profiles.md` +- Root `AGENTS.md`, `CONTRIBUTING.md` +- Prev: `blueprint` · Next: `apply`. diff --git a/.agents/skills/prepare-pr/SKILL.md b/.agents/skills/prepare-pr/SKILL.md new file mode 100644 index 0000000000..b183607c98 --- /dev/null +++ b/.agents/skills/prepare-pr/SKILL.md @@ -0,0 +1,64 @@ +--- +name: prepare-pr +description: Prepares (never publish) the PR(s) for the current task — drafts each affected repo's PR body from plan.md with the source link and an AI-use disclosure, and shows the gh pr create command for the human to run. Prepare-only; no auditing here. +user-invokable: true +metadata: + version: 0.1.0 +--- + +# prepare-pr — prepare only (never submit) + +> **Language rule (non-negotiable):** detect the language the human used when invoking this skill +> and use that language for ALL user-facing output. Default to **English** if unclear. Never output +> in a language that was not used in the invocation or the conversation history. + +Final stage. **Prepares** the pull request(s) for the human to review and submit. It **never** opens +a PR, posts comments, or submits anything autonomously (root `AGENTS.md` §"Contribution policy"). +No auditing happens here — that lives in the audit stage (`audit`). + +> **Recommended execution:** normal mode. See `.agents/skills/_shared/execution-profiles.md` for +> recommended model and effort. State the profile to the human before starting; remind them to lower +> effort if they had raised it. + +## Invocation + +- `/prepare-pr` — prepare the PR(s) for the current task-id. + +## Steps + +1. **Resolve the `task-id`** and read `.ai/tasks//plan.md` (and `review.md` if present, only + to reference audit status — do not re-audit). +2. **Identify affected repos** and their `feature/` branches (or the branch names recorded in + `tasks.md` "## Branches" if they were customized). +3. **(Optional) Propose history cleanup** to Conventional Commits: show the suggested squash/reword; + the **human** performs it. Ensure each AI-assisted commit has an `Assisted-by: AGENT:MODEL` + trailer. **Never** add `Signed-off-by` — only the human certifies the DCO. +4. **Draft the PR body per repo** into `.ai/tasks//pr-.md`: + - Problem + approach (from `plan.md`), scoped to one concern. + - Link to the source issue/Jira. + - Testing done (note: the human tests on a live instance, per `CONTRIBUTING.md`). + - An **AI-use disclosure** — provide a draft the human rewrites **in their own words** + (PR text must be the contributor's own words; the agent must not ghostwrite it as final). + - If the diff is large, **warn** and suggest splitting into focused PRs. +5. **Show the command** (do not run it): + ```sh + gh pr create --repo Euro-Office/ --base main --head feature/ \ + --title "" --body-file .ai/tasks//pr-.md + ``` + If `gh` is not set up, onboard it first (`scripts/setup-integrations.sh` / `.ps1`, or + `.agents/skills/_shared/integrations.md`), or output the body for **manual paste** into the GitHub UI. +6. **Stop.** The human reviews, finalizes the wording, and runs the command / opens the PR. + +## Guardrails + +- **Prepare-only:** never run `gh pr create`, never open/comment on PRs or issues. +- **AI disclosure and PR text in the human's own words** — the skill drafts, the human owns it. +- **Never** `Signed-off-by`. Focused PRs. Verify dependencies against real registries. Comply AGPL-3.0. +- No auditing here (see `audit`). + +## References + +- `.agents/skills/_shared/integrations.md` (gh) · `agpl-checklist.md` · `execution-profiles.md` +- Onboarding helper (if `gh` missing): `scripts/setup-integrations.sh` · `scripts/setup-integrations.ps1` +- Root `AGENTS.md` (§Commits, §"Contribution policy"), `CONTRIBUTING.md` (§"AI-assisted contributions") +- Prev: `audit`. diff --git a/.claude/skills/apply/SKILL.md b/.claude/skills/apply/SKILL.md new file mode 100644 index 0000000000..cd98c0ad40 --- /dev/null +++ b/.claude/skills/apply/SKILL.md @@ -0,0 +1,18 @@ +--- +name: apply +description: Applies the next unchecked step from the current task's tasks.md — first ensures the target repo is on the task branch (proposes/creates it interactively; you can rename it), then edits the code and shows the build/lint/test command for you to run (no build/commit auto-run), and stops. Use to implement a task one step at a time after breakdown. +user-invokable: true +metadata: + version: 0.1.0 + canonical: .agents/skills/apply/SKILL.md +--- + +# apply — adapter (Claude Code) + +The full, canonical playbook for this skill lives at: + +**`.agents/skills/apply/SKILL.md`** + +Read that file now and follow it exactly — it is the single source of truth (shared with Codex and +Cursor). This stub exists only because Claude Code cannot discover skills through symlinks; do not +act from this stub alone. diff --git a/.claude/skills/audit/SKILL.md b/.claude/skills/audit/SKILL.md new file mode 100644 index 0000000000..ea38f9e765 --- /dev/null +++ b/.claude/skills/audit/SKILL.md @@ -0,0 +1,18 @@ +--- +name: audit +description: Audits a diff — the current task's working changes OR any open PR — into review.md with four blocks: security (/security-review + AGPL checklist + web-apps memory-leak sweep), code quality (/code-review), an emulated SonarQube-style Quality Gate (A–E, PASS/FAIL), and proposed PR comments (drafts for the human to post, never posted autonomously). Task-mode reviews are written to .ai/tasks//review.md; standalone PR reviews to .ai/reviews/-/review.md. Use before preparing a PR, or to review any PR independently. +user-invokable: true +metadata: + version: 0.1.0 + canonical: .agents/skills/audit/SKILL.md +--- + +# audit — adapter (Claude Code) + +The full, canonical playbook for this skill lives at: + +**`.agents/skills/audit/SKILL.md`** + +Read that file now and follow it exactly — it is the single source of truth (shared with Codex and +Cursor). This stub exists only because Claude Code cannot discover skills through symlinks; do not +act from this stub alone. diff --git a/.claude/skills/blueprint/SKILL.md b/.claude/skills/blueprint/SKILL.md new file mode 100644 index 0000000000..c5beaee258 --- /dev/null +++ b/.claude/skills/blueprint/SKILL.md @@ -0,0 +1,18 @@ +--- +name: blueprint +description: Fetches, investigates, and defines a Euro-Office task (GitHub issue, Jira key, or pasted description + screenshots) into a plan.md with the affected repos, an action plan, and Gherkin acceptance criteria; on first run it also onboards the gh/Jira integrations it needs. Use when starting a new task or when the request is under-specified and needs scoping before any coding. +user-invokable: true +metadata: + version: 0.1.0 + canonical: .agents/skills/blueprint/SKILL.md +--- + +# blueprint — adapter (Claude Code) + +The full, canonical playbook for this skill lives at: + +**`.agents/skills/blueprint/SKILL.md`** + +Read that file now and follow it exactly — it is the single source of truth (shared with Codex and +Cursor). This stub exists only because Claude Code cannot discover skills through symlinks; do not +act from this stub alone. diff --git a/.claude/skills/breakdown/SKILL.md b/.claude/skills/breakdown/SKILL.md new file mode 100644 index 0000000000..f37e540195 --- /dev/null +++ b/.claude/skills/breakdown/SKILL.md @@ -0,0 +1,18 @@ +--- +name: breakdown +description: Turns a task's plan.md into tasks.md — atomic ~5-minute steps grouped by repo — and proposes (assisted) a feature/ branch per affected repo. Use after blueprint, when you have a plan and need an executable roadmap plus branches. +user-invokable: true +metadata: + version: 0.1.0 + canonical: .agents/skills/breakdown/SKILL.md +--- + +# breakdown — adapter (Claude Code) + +The full, canonical playbook for this skill lives at: + +**`.agents/skills/breakdown/SKILL.md`** + +Read that file now and follow it exactly — it is the single source of truth (shared with Codex and +Cursor). This stub exists only because Claude Code cannot discover skills through symlinks; do not +act from this stub alone. diff --git a/.claude/skills/prepare-pr/SKILL.md b/.claude/skills/prepare-pr/SKILL.md new file mode 100644 index 0000000000..2df24e3152 --- /dev/null +++ b/.claude/skills/prepare-pr/SKILL.md @@ -0,0 +1,18 @@ +--- +name: prepare-pr +description: Prepares (never publish) the PR(s) for the current task — drafts each affected repo's PR body from plan.md with the source link and an AI-use disclosure, and shows the gh pr create command for the human to run. Prepare-only; no auditing here. +user-invokable: true +metadata: + version: 0.1.0 + canonical: .agents/skills/prepare-pr/SKILL.md +--- + +# prepare-pr — adapter (Claude Code) + +The full, canonical playbook for this skill lives at: + +**`.agents/skills/prepare-pr/SKILL.md`** + +Read that file now and follow it exactly — it is the single source of truth (shared with Codex and +Cursor). This stub exists only because Claude Code cannot discover skills through symlinks; do not +act from this stub alone. diff --git a/.cursor/rules/apply.mdc b/.cursor/rules/apply.mdc new file mode 100644 index 0000000000..ad7b6050a8 --- /dev/null +++ b/.cursor/rules/apply.mdc @@ -0,0 +1,12 @@ +--- +description: Euro-Office pipeline — apply: ensures the target repo is on the task branch (proposes/creates it interactively; you can rename it), then applies the next tasks.md step and shows the build/lint/test command for the human to run (no build/commit auto-run), and stops. Canonical playbook: .agents/skills/apply/SKILL.md. +alwaysApply: false +--- + +# apply (Euro-Office pipeline) — adapter + +Thin adapter for Cursor. The single source of truth is the canonical playbook: + +`.agents/skills/apply/SKILL.md` + +Read and follow that file. Do not duplicate its content here. diff --git a/.cursor/rules/audit.mdc b/.cursor/rules/audit.mdc new file mode 100644 index 0000000000..c60958a0c4 --- /dev/null +++ b/.cursor/rules/audit.mdc @@ -0,0 +1,12 @@ +--- +description: Euro-Office pipeline — audit: reviews a diff (task working changes or any open PR) into review.md — security (/security-review + AGPL + memory-leak sweep), code (/code-review), emulated quality gate A–E, and proposed PR comments (drafts for the human to post). Task-mode → .ai/tasks//review.md; PR-mode → .ai/reviews/-/review.md. Usage: /audit | /audit owner/repo#n | /audit . Canonical playbook: .agents/skills/audit/SKILL.md. +alwaysApply: false +--- + +# audit (Euro-Office pipeline) — adapter + +Thin adapter for Cursor. The single source of truth is the canonical playbook: + +`.agents/skills/audit/SKILL.md` + +Read and follow that file. Do not duplicate its content here. diff --git a/.cursor/rules/blueprint.mdc b/.cursor/rules/blueprint.mdc new file mode 100644 index 0000000000..a42f23325d --- /dev/null +++ b/.cursor/rules/blueprint.mdc @@ -0,0 +1,12 @@ +--- +description: Euro-Office pipeline — blueprint: onboards gh/Jira on first run, then fetches, investigates, and defines a task (GitHub/Jira/manual) into plan.md with affected repos and Gherkin criteria. Canonical playbook: .agents/skills/blueprint/SKILL.md. +alwaysApply: false +--- + +# blueprint (Euro-Office pipeline) — adapter + +Thin adapter for Cursor. The single source of truth is the canonical playbook: + +`.agents/skills/blueprint/SKILL.md` + +Read and follow that file. Do not duplicate its content here. diff --git a/.cursor/rules/breakdown.mdc b/.cursor/rules/breakdown.mdc new file mode 100644 index 0000000000..285a8f4c0e --- /dev/null +++ b/.cursor/rules/breakdown.mdc @@ -0,0 +1,12 @@ +--- +description: Euro-Office pipeline — breakdown: turns plan.md into tasks.md (atomic ~5-min steps) and proposes a feature/ branch per affected repo. Canonical playbook: .agents/skills/breakdown/SKILL.md. +alwaysApply: false +--- + +# breakdown (Euro-Office pipeline) — adapter + +Thin adapter for Cursor. The single source of truth is the canonical playbook: + +`.agents/skills/breakdown/SKILL.md` + +Read and follow that file. Do not duplicate its content here. diff --git a/.cursor/rules/prepare-pr.mdc b/.cursor/rules/prepare-pr.mdc new file mode 100644 index 0000000000..0df1666bbd --- /dev/null +++ b/.cursor/rules/prepare-pr.mdc @@ -0,0 +1,12 @@ +--- +description: Euro-Office pipeline — prepare-pr: prepares (never publish) the PR(s) — drafts each repo's PR body from plan.md with an AI-use disclosure and shows the gh pr create command for the human to run. Canonical playbook: .agents/skills/prepare-pr/SKILL.md. +alwaysApply: false +--- + +# prepare-pr (Euro-Office pipeline) — adapter + +Thin adapter for Cursor. The single source of truth is the canonical playbook: + +`.agents/skills/prepare-pr/SKILL.md` + +Read and follow that file. Do not duplicate its content here. diff --git a/.gitignore b/.gitignore index 7425992c94..897bd33552 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,11 @@ -.vscode/ -build/vagrant/.vagrant -build/deploy -develop/richdocuments -e2e/node_modules/ -e2e/playwright-report/ -e2e/test-results/ -e2e/dist/ +.vscode/ +build/vagrant/.vagrant +build/deploy +develop/richdocuments +e2e/node_modules/ +e2e/playwright-report/ +e2e/test-results/ +e2e/dist/ + +# AI task artifacts (local, cross-tool) — never versioned +.ai/ diff --git a/AGENTS.md b/AGENTS.md index 28f0fb4076..de3f9eb65e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,10 @@ +## AI task pipeline (skills) + +This repo ships an assisted, portable AI-agent skill pipeline — fetch/define → plan → implement → +audit → prepare a PR — under `.agents/skills/` (works in Claude Code, Codex, and Cursor). +New here? Just run `/blueprint ` — it sets up `gh`/Jira on first use. Full docs: +[`.agents/skills/README.md`](.agents/skills/README.md). + ## Build & run a test server (Docker) The dev environment in `develop/` runs a full document server from a prebuilt image. Individual components are rebuilt *inside* the container — never rebuild the docker image to test a change. The repo is bind-mounted at `/develop` in the container, so edits on the host are immediately visible inside. diff --git a/scripts/setup-integrations.ps1 b/scripts/setup-integrations.ps1 new file mode 100644 index 0000000000..dfc44cb893 --- /dev/null +++ b/scripts/setup-integrations.ps1 @@ -0,0 +1,53 @@ +# Euro-Office skills - integrations onboarding (gh + Jira) for Windows. +# Run in PowerShell. Per-person; never commits secrets. Safe to re-run. +# Without any of this, the pipeline still works via manual paste. + +function Info($m){ Write-Host "[setup] $m" -ForegroundColor Cyan } +function Ok($m){ Write-Host "[ok] $m" -ForegroundColor Green } +function Warn($m){ Write-Host "[warn] $m" -ForegroundColor Yellow } + +Info "Platform: Windows (PowerShell)" + +# 1) Ensure gh +if (Get-Command gh -ErrorAction SilentlyContinue) { + Ok ("gh installed: " + (gh --version)[0]) +} else { + Warn "gh not found." + $ans = Read-Host "Install GitHub CLI via winget now? [y/N]" + if ($ans -eq 'y' -or $ans -eq 'Y') { + winget install --id GitHub.cli --accept-source-agreements --accept-package-agreements + Info "Reopen the terminal so gh is on PATH, then re-run this script." + return + } else { + Write-Host " winget install --id GitHub.cli (or: scoop install gh / choco install gh)" + } +} + +# 2) gh auth (interactive - you do it) +if (Get-Command gh -ErrorAction SilentlyContinue) { + gh auth status *> $null + if ($LASTEXITCODE -eq 0) { + Ok "gh authenticated." + } else { + Warn "gh not authenticated. Starting 'gh auth login' (GitHub.com / HTTPS / account with Euro-Office access)..." + gh auth login + } +} + +# 3) Jira env (optional, user-scope so it persists and Git Bash inherits it) +if ($env:JIRA_URL -and $env:JIRA_PERSONAL_TOKEN) { + Ok "Jira env present." +} else { + Warn "Jira env not set (optional - only if you use Jira). Persist as user env vars:" + Write-Host ' setx JIRA_URL "https://"' + Write-Host ' setx JIRA_PERSONAL_TOKEN "" # never commit this' + Write-Host " (reopen the shell afterwards; Git Bash inherits these)" +} + +# 4) Self-check +Write-Host "" +Info "Self-check:" +if (Get-Command gh -ErrorAction SilentlyContinue) { gh auth status } else { Write-Host " gh: not ready (blueprint will use manual paste)" } +if ($env:JIRA_URL) { Write-Host (" JIRA_URL: " + $env:JIRA_URL) } else { Write-Host " JIRA_URL: " } +Write-Host "" +Ok "Done. If gh is authenticated, /blueprint auto-fetches; otherwise it falls back to manual paste." diff --git a/scripts/setup-integrations.sh b/scripts/setup-integrations.sh new file mode 100755 index 0000000000..e529c5bfa4 --- /dev/null +++ b/scripts/setup-integrations.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +# Euro-Office skills - integrations onboarding (gh + Jira). +# Run this in YOUR terminal. Per-person; never commits secrets. Safe to re-run. +# Without any of this, the pipeline still works via manual paste. + +info(){ printf '\033[1;34m[setup]\033[0m %s\n' "$*"; } +ok(){ printf '\033[1;32m[ok]\033[0m %s\n' "$*"; } +warn(){ printf '\033[1;33m[warn]\033[0m %s\n' "$*"; } + +# 1) Detect platform +case "$(uname -s 2>/dev/null || echo unknown)" in + Linux*) if grep -qi microsoft /proc/version 2>/dev/null; then PLAT=wsl; else PLAT=linux; fi ;; + Darwin*) PLAT=macos ;; + MINGW*|MSYS*|CYGWIN*) PLAT=gitbash ;; + *) PLAT=unknown ;; +esac +info "Platform detected: $PLAT" + +install_hint(){ + case "$PLAT" in + macos) echo "brew install gh" ;; + linux|wsl) + if command -v apt-get >/dev/null 2>&1; then echo "sudo apt update && sudo apt install -y gh" + elif command -v dnf >/dev/null 2>&1; then echo "sudo dnf install -y gh" + elif command -v pacman >/dev/null 2>&1; then echo "sudo pacman -S --noconfirm github-cli" + else echo "see https://github.com/cli/cli#installation"; fi ;; + gitbash) echo "winget install --id GitHub.cli (run in PowerShell, or use scripts/setup-integrations.ps1)" ;; + *) echo "see https://github.com/cli/cli#installation" ;; + esac +} + +# 2) Ensure gh +if command -v gh >/dev/null 2>&1; then + ok "gh installed: $(gh --version | head -1)" +else + warn "gh not found. Install with:" + echo " $(install_hint)" + if [ "$PLAT" = "macos" ] || [ "$PLAT" = "linux" ] || [ "$PLAT" = "wsl" ]; then + printf '\033[1;33m[warn]\033[0m Attempt install now? [y/N] '; read -r ans + case "$ans" in + y|Y) + case "$PLAT" in + macos) brew install gh || warn "brew install failed - install gh manually." ;; + linux|wsl) + if command -v apt-get >/dev/null 2>&1; then sudo apt update && sudo apt install -y gh || warn "apt install failed." + elif command -v dnf >/dev/null 2>&1; then sudo dnf install -y gh || warn "dnf install failed." + elif command -v pacman >/dev/null 2>&1; then sudo pacman -S --noconfirm github-cli || warn "pacman install failed." + fi ;; + esac ;; + *) info "Skipping install. Run the command above when ready." ;; + esac + fi +fi + +# 3) gh auth (interactive - you do it) +if command -v gh >/dev/null 2>&1; then + if gh auth status >/dev/null 2>&1; then + ok "gh authenticated." + else + warn "gh not authenticated. Starting 'gh auth login' (GitHub.com / HTTPS / account with Euro-Office access)..." + gh auth login || warn "Auth not completed - run 'gh auth login' yourself later." + fi +fi + +# 4) Jira env (optional) +if [ -n "${JIRA_URL:-}" ] && [ -n "${JIRA_PERSONAL_TOKEN:-}" ]; then + ok "Jira env present (JIRA_URL is set)." +else + warn "Jira env not set (optional - only if you use Jira). Add to your shell profile:" + echo ' export JIRA_URL="https://"' + echo ' export JIRA_PERSONAL_TOKEN="" # never commit this' + echo " (bash: ~/.bashrc - zsh/macOS: ~/.zshrc - Git Bash: ~/.bashrc)" +fi + +# 5) Self-check +echo +info "Self-check:" +if command -v gh >/dev/null 2>&1; then gh auth status 2>&1 | sed 's/^/ /'; else echo " gh: not ready (blueprint will use manual paste)"; fi +echo " JIRA_URL: ${JIRA_URL:-}" +echo +ok "Done. If gh is authenticated, /blueprint auto-fetches; otherwise it falls back to manual paste."