modified
.claude/skills/drawio-fancy-diagram/generator/examples/sidekicks_packages.py +7 -5 | @@ -1,7 +1,7 @@ | ||
| 1 | 1 | """The description of docs/diagrams/packages.{drawio,svg} (Sidekicks, ADR 0003, 0004, 0006 and 0007). |
| 2 | 2 | |
| 3 | 3 | python3 .claude/skills/drawio-fancy-diagram/generator/examples/sidekicks_packages.py docs/diagrams |
| 4 | - rsvg-convert -w 1440 -h 800 -o docs/diagrams/packages.png docs/diagrams/packages.svg | |
| 4 | + rsvg-convert -w 1690 -h 800 -o docs/diagrams/packages.png docs/diagrams/packages.svg | |
| 5 | 5 | |
| 6 | 6 | Blue boxes exist; grey boxes are planned (their milestone is written in them). |
| 7 | 7 | """ |
| @@ -12,11 +12,11 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), ".." | ||
| 12 | 12 | from flowgen import Diagram |
| 13 | 13 | |
| 14 | 14 | OUT = sys.argv[1] if len(sys.argv) > 1 else "docs/diagrams" |
| 15 | -W, COLUMNS = 230, (30, 310, 590, 870, 1150) | |
| 15 | +W, COLUMNS = 230, (30, 310, 590, 870, 1150, 1430) | |
| 16 | 16 | CENTERS = [x + W // 2 for x in COLUMNS] |
| 17 | 17 | |
| 18 | 18 | d = Diagram("packages", "Sidekicks — packages and dependencies", |
| 19 | - "arrows are imports · all packages exist (M4) · only main.go imports Wails", width=1410, height=800) | |
| 19 | + "arrows are imports · all packages exist (v0.1) · only main.go imports Wails", width=1690, height=800) | |
| 20 | 20 | |
| 21 | 21 | # Row 1: the entry points. |
| 22 | 22 | d.box(COLUMNS[0], 100, W, 115, "user", "💻", "frontend/", ["Svelte 5 · panels · chat · @ /", "files · xterm.js · bindings"]) |
| @@ -24,6 +24,8 @@ d.box(COLUMNS[2], 100, W, 115, "decider", "🔀", "internal/app", ["Agent · Cha | ||
| 24 | 24 | d.box(COLUMNS[4], 100, W, 115, "hook", "⚙️", "main.go (root)", ["flags · Wails app · window", "events · file dialog"]) |
| 25 | 25 | d.edge([(COLUMNS[0] + W, 157), (COLUMNS[2], 157)], "bindings · events", at=(450, 157), lw=130, both=True) |
| 26 | 26 | d.edge([(COLUMNS[4], 157), (COLUMNS[2] + W, 157)], "creates", at=(1010, 157), lw=70) |
| 27 | +d.box(COLUMNS[5], 100, W, 115, "agent", "🧰", "internal/shellpath", ["PATH of the user's shell", "for apps opened from the Finder"]) | |
| 28 | +d.edge([(COLUMNS[4] + W, 157), (COLUMNS[5], 157)]) | |
| 27 | 29 | |
| 28 | 30 | # Row 2: what internal/app uses. |
| 29 | 31 | d.box(COLUMNS[0], 300, W, 110, "agent", "💬", "internal/channels", ["channels · direct · routing @", "unseen context · queue · perms"]) |
| @@ -31,7 +33,7 @@ d.box(COLUMNS[1], 300, W, 110, "agent", "🤖", "internal/agents", ["lazy start | ||
| 31 | 33 | d.box(COLUMNS[2], 300, W, 110, "agent", "📋", "internal/config", ["load · validate · locate", "default · save · watch"]) |
| 32 | 34 | d.box(COLUMNS[3], 300, W, 110, "agent", "🧰", "internal/prefs", ["last opened file", "recent files (JSON)"]) |
| 33 | 35 | d.box(COLUMNS[4], 300, W, 110, "agent", "🧰", "internal/workspace", ["files · watch · terminals", "local (pty) · docker exec"]) |
| 34 | -for cx in CENTERS: | |
| 36 | +for cx in CENTERS[:5]: | |
| 35 | 37 | d.edge([(705, 215), (705, 255), (cx, 255), (cx, 300)]) |
| 36 | 38 | d.edge([(COLUMNS[0] + W, 355), (COLUMNS[1], 355)]) |
| 37 | 39 | d.edge([(COLUMNS[1] + W, 355), (COLUMNS[2], 355)]) |
| @@ -56,5 +58,5 @@ d.edge([(CENTERS[4], 410), (CENTERS[4], 490)]) | ||
| 56 | 58 | d.edge([(CENTERS[0], 595), (CENTERS[0], 670)]) |
| 57 | 59 | d.edge([(CENTERS[1], 595), (CENTERS[1], 670)], "stdio", at=(CENTERS[1] + 45, 632), lw=50) |
| 58 | 60 | d.edge([(CENTERS[2], 595), (CENTERS[2], 670)]) |
| 59 | -d.text(705, 765, "channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store.", 12.5, italic=True) | |
| 61 | +d.text(845, 765, "channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store.", 12.5, italic=True) | |
| 60 | 62 | d.write(OUT) |
| @@ -1,7 +1,7 @@ | |||
| 1 | """The description of docs/diagrams/packages.{drawio,svg} (Sidekicks, ADR 0003, 0004, 0006 and 0007). | 1 | """The description of docs/diagrams/packages.{drawio,svg} (Sidekicks, ADR 0003, 0004, 0006 and 0007). |
| 2 | 2 | ||
| 3 | python3 .claude/skills/drawio-fancy-diagram/generator/examples/sidekicks_packages.py docs/diagrams | 3 | python3 .claude/skills/drawio-fancy-diagram/generator/examples/sidekicks_packages.py docs/diagrams |
| 4 | - rsvg-convert -w 1440 -h 800 -o docs/diagrams/packages.png docs/diagrams/packages.svg | 4 | + rsvg-convert -w 1690 -h 800 -o docs/diagrams/packages.png docs/diagrams/packages.svg |
| 5 | 5 | ||
| 6 | Blue boxes exist; grey boxes are planned (their milestone is written in them). | 6 | Blue boxes exist; grey boxes are planned (their milestone is written in them). |
| 7 | """ | 7 | """ |
| @@ -12,11 +12,11 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), ".." | |||
| 12 | from flowgen import Diagram | 12 | from flowgen import Diagram |
| 13 | 13 | ||
| 14 | OUT = sys.argv[1] if len(sys.argv) > 1 else "docs/diagrams" | 14 | OUT = sys.argv[1] if len(sys.argv) > 1 else "docs/diagrams" |
| 15 | -W, COLUMNS = 230, (30, 310, 590, 870, 1150) | 15 | +W, COLUMNS = 230, (30, 310, 590, 870, 1150, 1430) |
| 16 | CENTERS = [x + W // 2 for x in COLUMNS] | 16 | CENTERS = [x + W // 2 for x in COLUMNS] |
| 17 | 17 | ||
| 18 | d = Diagram("packages", "Sidekicks — packages and dependencies", | 18 | d = Diagram("packages", "Sidekicks — packages and dependencies", |
| 19 | - "arrows are imports · all packages exist (M4) · only main.go imports Wails", width=1410, height=800) | 19 | + "arrows are imports · all packages exist (v0.1) · only main.go imports Wails", width=1690, height=800) |
| 20 | 20 | ||
| 21 | # Row 1: the entry points. | 21 | # Row 1: the entry points. |
| 22 | d.box(COLUMNS[0], 100, W, 115, "user", "💻", "frontend/", ["Svelte 5 · panels · chat · @ /", "files · xterm.js · bindings"]) | 22 | d.box(COLUMNS[0], 100, W, 115, "user", "💻", "frontend/", ["Svelte 5 · panels · chat · @ /", "files · xterm.js · bindings"]) |
| @@ -24,6 +24,8 @@ d.box(COLUMNS[2], 100, W, 115, "decider", "🔀", "internal/app", ["Agent · Cha | |||
| 24 | d.box(COLUMNS[4], 100, W, 115, "hook", "⚙️", "main.go (root)", ["flags · Wails app · window", "events · file dialog"]) | 24 | d.box(COLUMNS[4], 100, W, 115, "hook", "⚙️", "main.go (root)", ["flags · Wails app · window", "events · file dialog"]) |
| 25 | d.edge([(COLUMNS[0] + W, 157), (COLUMNS[2], 157)], "bindings · events", at=(450, 157), lw=130, both=True) | 25 | d.edge([(COLUMNS[0] + W, 157), (COLUMNS[2], 157)], "bindings · events", at=(450, 157), lw=130, both=True) |
| 26 | d.edge([(COLUMNS[4], 157), (COLUMNS[2] + W, 157)], "creates", at=(1010, 157), lw=70) | 26 | d.edge([(COLUMNS[4], 157), (COLUMNS[2] + W, 157)], "creates", at=(1010, 157), lw=70) |
| 27 | +d.box(COLUMNS[5], 100, W, 115, "agent", "🧰", "internal/shellpath", ["PATH of the user's shell", "for apps opened from the Finder"]) | ||
| 28 | +d.edge([(COLUMNS[4] + W, 157), (COLUMNS[5], 157)]) | ||
| 27 | 29 | ||
| 28 | # Row 2: what internal/app uses. | 30 | # Row 2: what internal/app uses. |
| 29 | d.box(COLUMNS[0], 300, W, 110, "agent", "💬", "internal/channels", ["channels · direct · routing @", "unseen context · queue · perms"]) | 31 | d.box(COLUMNS[0], 300, W, 110, "agent", "💬", "internal/channels", ["channels · direct · routing @", "unseen context · queue · perms"]) |
| @@ -31,7 +33,7 @@ d.box(COLUMNS[1], 300, W, 110, "agent", "🤖", "internal/agents", ["lazy start | |||
| 31 | d.box(COLUMNS[2], 300, W, 110, "agent", "📋", "internal/config", ["load · validate · locate", "default · save · watch"]) | 33 | d.box(COLUMNS[2], 300, W, 110, "agent", "📋", "internal/config", ["load · validate · locate", "default · save · watch"]) |
| 32 | d.box(COLUMNS[3], 300, W, 110, "agent", "🧰", "internal/prefs", ["last opened file", "recent files (JSON)"]) | 34 | d.box(COLUMNS[3], 300, W, 110, "agent", "🧰", "internal/prefs", ["last opened file", "recent files (JSON)"]) |
| 33 | d.box(COLUMNS[4], 300, W, 110, "agent", "🧰", "internal/workspace", ["files · watch · terminals", "local (pty) · docker exec"]) | 35 | d.box(COLUMNS[4], 300, W, 110, "agent", "🧰", "internal/workspace", ["files · watch · terminals", "local (pty) · docker exec"]) |
| 34 | -for cx in CENTERS: | 36 | +for cx in CENTERS[:5]: |
| 35 | d.edge([(705, 215), (705, 255), (cx, 255), (cx, 300)]) | 37 | d.edge([(705, 215), (705, 255), (cx, 255), (cx, 300)]) |
| 36 | d.edge([(COLUMNS[0] + W, 355), (COLUMNS[1], 355)]) | 38 | d.edge([(COLUMNS[0] + W, 355), (COLUMNS[1], 355)]) |
| 37 | d.edge([(COLUMNS[1] + W, 355), (COLUMNS[2], 355)]) | 39 | d.edge([(COLUMNS[1] + W, 355), (COLUMNS[2], 355)]) |
| @@ -56,5 +58,5 @@ d.edge([(CENTERS[4], 410), (CENTERS[4], 490)]) | |||
| 56 | d.edge([(CENTERS[0], 595), (CENTERS[0], 670)]) | 58 | d.edge([(CENTERS[0], 595), (CENTERS[0], 670)]) |
| 57 | d.edge([(CENTERS[1], 595), (CENTERS[1], 670)], "stdio", at=(CENTERS[1] + 45, 632), lw=50) | 59 | d.edge([(CENTERS[1], 595), (CENTERS[1], 670)], "stdio", at=(CENTERS[1] + 45, 632), lw=50) |
| 58 | d.edge([(CENTERS[2], 595), (CENTERS[2], 670)]) | 60 | d.edge([(CENTERS[2], 595), (CENTERS[2], 670)]) |
| 59 | -d.text(705, 765, "channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store.", 12.5, italic=True) | 61 | +d.text(845, 765, "channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store.", 12.5, italic=True) |
| 60 | d.write(OUT) | 62 | d.write(OUT) |
modified
.github/workflows/ci.yml +1 -1 | @@ -8,7 +8,7 @@ | ||
| 8 | 8 | # needs GTK >= 4.10 (GtkFileDialog), which older Ubuntu releases lack. |
| 9 | 9 | # Rickub runs it as an ordinary GitHub Actions workflow, on every push and |
| 10 | 10 | # every merge request. No workflow_dispatch: Rickub's dispatch API fires every |
| 11 | -# dispatchable workflow of a ref (see mini-me's release.yml). | |
| 11 | +# dispatchable workflow of a ref, and release.yml must stay the only one. | |
| 12 | 12 | name: CI |
| 13 | 13 | |
| 14 | 14 | on: |
| @@ -8,7 +8,7 @@ | |||
| 8 | # needs GTK >= 4.10 (GtkFileDialog), which older Ubuntu releases lack. | 8 | # needs GTK >= 4.10 (GtkFileDialog), which older Ubuntu releases lack. |
| 9 | # Rickub runs it as an ordinary GitHub Actions workflow, on every push and | 9 | # Rickub runs it as an ordinary GitHub Actions workflow, on every push and |
| 10 | # every merge request. No workflow_dispatch: Rickub's dispatch API fires every | 10 | # every merge request. No workflow_dispatch: Rickub's dispatch API fires every |
| 11 | -# dispatchable workflow of a ref (see mini-me's release.yml). | 11 | +# dispatchable workflow of a ref, and release.yml must stay the only one. |
| 12 | name: CI | 12 | name: CI |
| 13 | 13 | ||
| 14 | on: | 14 | on: |
added
.github/workflows/release.yml +70 -0 | new file mode 100644 | ||
| @@ -0,0 +1,70 @@ | ||
| 1 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | +# | |
| 3 | +# Release: when a tag v<version> is pushed (scripts/tag-release.sh), creates | |
| 4 | +# the release on Rickub with its notes, and nothing else. The packages are | |
| 5 | +# built on the maintainer's Mac (scripts/build-release.sh) and attached to the | |
| 6 | +# release by hand: Rickub has Linux x86-64 runners only. See RELEASING.md. | |
| 7 | +# | |
| 8 | +# The job token needs `contents: write` to create a release; | |
| 9 | +# softprops/action-gh-release talks to Rickub's GitHub-compatible API behind | |
| 10 | +# $GITHUB_API_URL (as in rickub/cli's release.yml). | |
| 11 | +name: Release | |
| 12 | + | |
| 13 | +on: | |
| 14 | + push: | |
| 15 | + tags: | |
| 16 | + - "v*" | |
| 17 | + | |
| 18 | +permissions: | |
| 19 | + contents: write | |
| 20 | + | |
| 21 | +jobs: | |
| 22 | + release: | |
| 23 | + runs-on: ubuntu-latest | |
| 24 | + steps: | |
| 25 | + - name: Checkout | |
| 26 | + uses: actions/checkout@v4 | |
| 27 | + | |
| 28 | + - name: The tag is the version of build/config.yml | |
| 29 | + id: version | |
| 30 | + run: | | |
| 31 | + set -eu | |
| 32 | + version="$(scripts/package.sh version)" | |
| 33 | + if [ "v$version" != "$GITHUB_REF_NAME" ]; then | |
| 34 | + echo "::error::The tag is $GITHUB_REF_NAME but build/config.yml says $version." | |
| 35 | + exit 1 | |
| 36 | + fi | |
| 37 | + echo "version=$version" >> "$GITHUB_OUTPUT" | |
| 38 | + | |
| 39 | + - name: Release notes | |
| 40 | + id: notes | |
| 41 | + env: | |
| 42 | + VERSION: ${{ steps.version.outputs.version }} | |
| 43 | + run: | | |
| 44 | + set -eu | |
| 45 | + base="${RICKUB_GITHUB_SERVER_URL:-https://rickub.com}/${GITHUB_REPOSITORY}" | |
| 46 | + { | |
| 47 | + echo "## Sidekicks $VERSION" | |
| 48 | + echo | |
| 49 | + echo "Commit \`$GITHUB_SHA\`." | |
| 50 | + echo | |
| 51 | + echo "Install: [English]($base/blob/$GITHUB_REF_NAME/docs/en/how-to/install-sidekicks.md) · [Français]($base/blob/$GITHUB_REF_NAME/docs/fr/how-to/installer-sidekicks.md)" | |
| 52 | + echo | |
| 53 | + echo "| File | System |" | |
| 54 | + echo "| --- | --- |" | |
| 55 | + for name in $(scripts/package.sh names macos universal); do echo "| \`$name\` | macOS 13 or later (Apple Silicon and Intel) |"; done | |
| 56 | + for name in $(scripts/package.sh names windows amd64); do echo "| \`$name\` | Windows x86-64 |"; done | |
| 57 | + for name in $(scripts/package.sh names linux amd64); do echo "| \`$name\` | Linux x86-64 |"; done | |
| 58 | + echo "| \`SHA256SUMS\` | checksums: \`sha256sum -c SHA256SUMS --ignore-missing\` (\`shasum -a 256 -c\` on macOS) |" | |
| 59 | + } > "$RUNNER_TEMP/release-notes.md" | |
| 60 | + cat "$RUNNER_TEMP/release-notes.md" | |
| 61 | + echo "path=$RUNNER_TEMP/release-notes.md" >> "$GITHUB_OUTPUT" | |
| 62 | + | |
| 63 | + - name: Create the release | |
| 64 | + uses: softprops/action-gh-release@v2 | |
| 65 | + with: | |
| 66 | + tag_name: ${{ github.ref_name }} | |
| 67 | + name: Sidekicks ${{ github.ref_name }} | |
| 68 | + body_path: ${{ steps.notes.outputs.path }} | |
| 69 | + draft: false | |
| 70 | + prerelease: false | |
| new file mode 100644 | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | +# | ||
| 3 | +# Release: when a tag v<version> is pushed (scripts/tag-release.sh), creates | ||
| 4 | +# the release on Rickub with its notes, and nothing else. The packages are | ||
| 5 | +# built on the maintainer's Mac (scripts/build-release.sh) and attached to the | ||
| 6 | +# release by hand: Rickub has Linux x86-64 runners only. See RELEASING.md. | ||
| 7 | +# | ||
| 8 | +# The job token needs `contents: write` to create a release; | ||
| 9 | +# softprops/action-gh-release talks to Rickub's GitHub-compatible API behind | ||
| 10 | +# $GITHUB_API_URL (as in rickub/cli's release.yml). | ||
| 11 | +name: Release | ||
| 12 | + | ||
| 13 | +on: | ||
| 14 | + push: | ||
| 15 | + tags: | ||
| 16 | + - "v*" | ||
| 17 | + | ||
| 18 | +permissions: | ||
| 19 | + contents: write | ||
| 20 | + | ||
| 21 | +jobs: | ||
| 22 | + release: | ||
| 23 | + runs-on: ubuntu-latest | ||
| 24 | + steps: | ||
| 25 | + - name: Checkout | ||
| 26 | + uses: actions/checkout@v4 | ||
| 27 | + | ||
| 28 | + - name: The tag is the version of build/config.yml | ||
| 29 | + id: version | ||
| 30 | + run: | | ||
| 31 | + set -eu | ||
| 32 | + version="$(scripts/package.sh version)" | ||
| 33 | + if [ "v$version" != "$GITHUB_REF_NAME" ]; then | ||
| 34 | + echo "::error::The tag is $GITHUB_REF_NAME but build/config.yml says $version." | ||
| 35 | + exit 1 | ||
| 36 | + fi | ||
| 37 | + echo "version=$version" >> "$GITHUB_OUTPUT" | ||
| 38 | + | ||
| 39 | + - name: Release notes | ||
| 40 | + id: notes | ||
| 41 | + env: | ||
| 42 | + VERSION: ${{ steps.version.outputs.version }} | ||
| 43 | + run: | | ||
| 44 | + set -eu | ||
| 45 | + base="${RICKUB_GITHUB_SERVER_URL:-https://rickub.com}/${GITHUB_REPOSITORY}" | ||
| 46 | + { | ||
| 47 | + echo "## Sidekicks $VERSION" | ||
| 48 | + echo | ||
| 49 | + echo "Commit \`$GITHUB_SHA\`." | ||
| 50 | + echo | ||
| 51 | + echo "Install: [English]($base/blob/$GITHUB_REF_NAME/docs/en/how-to/install-sidekicks.md) · [Français]($base/blob/$GITHUB_REF_NAME/docs/fr/how-to/installer-sidekicks.md)" | ||
| 52 | + echo | ||
| 53 | + echo "| File | System |" | ||
| 54 | + echo "| --- | --- |" | ||
| 55 | + for name in $(scripts/package.sh names macos universal); do echo "| \`$name\` | macOS 13 or later (Apple Silicon and Intel) |"; done | ||
| 56 | + for name in $(scripts/package.sh names windows amd64); do echo "| \`$name\` | Windows x86-64 |"; done | ||
| 57 | + for name in $(scripts/package.sh names linux amd64); do echo "| \`$name\` | Linux x86-64 |"; done | ||
| 58 | + echo "| \`SHA256SUMS\` | checksums: \`sha256sum -c SHA256SUMS --ignore-missing\` (\`shasum -a 256 -c\` on macOS) |" | ||
| 59 | + } > "$RUNNER_TEMP/release-notes.md" | ||
| 60 | + cat "$RUNNER_TEMP/release-notes.md" | ||
| 61 | + echo "path=$RUNNER_TEMP/release-notes.md" >> "$GITHUB_OUTPUT" | ||
| 62 | + | ||
| 63 | + - name: Create the release | ||
| 64 | + uses: softprops/action-gh-release@v2 | ||
| 65 | + with: | ||
| 66 | + tag_name: ${{ github.ref_name }} | ||
| 67 | + name: Sidekicks ${{ github.ref_name }} | ||
| 68 | + body_path: ${{ steps.notes.outputs.path }} | ||
| 69 | + draft: false | ||
| 70 | + prerelease: false | ||
modified
.gitignore +7 -0 | @@ -8,6 +8,13 @@ bin/ | ||
| 8 | 8 | frontend/dist |
| 9 | 9 | frontend/node_modules |
| 10 | 10 | build/linux/appimage/build |
| 11 | +build/linux/sidekicks.desktop | |
| 12 | +# Created by `wails3 task common:update:build-assets`; Sidekicks has no iOS build | |
| 13 | +build/ios/ | |
| 14 | +build/linux/appimage/sidekicks | |
| 15 | +build/linux/appimage/sidekicks.png | |
| 16 | +# Release packages (make package-*) | |
| 17 | +dist/ | |
| 11 | 18 | build/windows/nsis/MicrosoftEdgeWebview2Setup.exe |
| 12 | 19 | # pnpm content-addressable store (created next to the repository when it sits on another file system) |
| 13 | 20 | .pnpm-store/ |
| @@ -8,6 +8,13 @@ bin/ | |||
| 8 | frontend/dist | 8 | frontend/dist |
| 9 | frontend/node_modules | 9 | frontend/node_modules |
| 10 | build/linux/appimage/build | 10 | build/linux/appimage/build |
| 11 | +build/linux/sidekicks.desktop | ||
| 12 | +# Created by `wails3 task common:update:build-assets`; Sidekicks has no iOS build | ||
| 13 | +build/ios/ | ||
| 14 | +build/linux/appimage/sidekicks | ||
| 15 | +build/linux/appimage/sidekicks.png | ||
| 16 | +# Release packages (make package-*) | ||
| 17 | +dist/ | ||
| 11 | build/windows/nsis/MicrosoftEdgeWebview2Setup.exe | 18 | build/windows/nsis/MicrosoftEdgeWebview2Setup.exe |
| 12 | # pnpm content-addressable store (created next to the repository when it sits on another file system) | 19 | # pnpm content-addressable store (created next to the repository when it sits on another file system) |
| 13 | .pnpm-store/ | 20 | .pnpm-store/ |
added
.memory/handoffs/2026-10-30-logo-and-ci.md +26 -0 | new file mode 100644 | ||
| @@ -0,0 +1,26 @@ | ||
| 1 | +# Handoff — 2026-10-30 — Logo, English wireframes, CI green | |
| 2 | + | |
| 3 | +## State | |
| 4 | + | |
| 5 | +- CI (`.github/workflows/ci.yml`) is green on Rickub. | |
| 6 | +- Logo "Orbite" chosen by the owner: sources in `docs/design/logo/` and `build/appicon.svg`; app icons regenerated (PNG, icns, ico, and `Assets.car` regenerated by the owner on the Mac); the welcome screen shows it (`frontend/src/lib/layout/Logo.svelte`, `--logo-*` tokens in `style.css`); README shows it (light/dark `<picture>`). | |
| 7 | +- `docs/design/` wireframes are in English (`wireframes.py` → SVG/PNG/drawio). | |
| 8 | +- `make check` passes. Nothing committed: the owner commits. | |
| 9 | + | |
| 10 | +## In flight | |
| 11 | + | |
| 12 | +Nothing. | |
| 13 | + | |
| 14 | +## Next steps | |
| 15 | + | |
| 16 | +1. Milestone "v0.1 · Première release" (#33–#37) and #38 (qlty kit), when the owner says so. | |
| 17 | +2. Optional: `build/darwin/dmg-file-icon.*` still carry the Wails icon. | |
| 18 | + | |
| 19 | +## Open questions / blockers | |
| 20 | + | |
| 21 | +None. | |
| 22 | + | |
| 23 | +## Watch out for | |
| 24 | + | |
| 25 | +- Regenerating icons: `rsvg-convert` then `wails3 generate icons …` (docs/design/README.md, Logo); `Assets.car` only on macOS. | |
| 26 | +- To change a wireframe, edit `docs/design/wireframes.py`, never the generated SVG/drawio. | |
| new file mode 100644 | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | +# Handoff — 2026-10-30 — Logo, English wireframes, CI green | ||
| 2 | + | ||
| 3 | +## State | ||
| 4 | + | ||
| 5 | +- CI (`.github/workflows/ci.yml`) is green on Rickub. | ||
| 6 | +- Logo "Orbite" chosen by the owner: sources in `docs/design/logo/` and `build/appicon.svg`; app icons regenerated (PNG, icns, ico, and `Assets.car` regenerated by the owner on the Mac); the welcome screen shows it (`frontend/src/lib/layout/Logo.svelte`, `--logo-*` tokens in `style.css`); README shows it (light/dark `<picture>`). | ||
| 7 | +- `docs/design/` wireframes are in English (`wireframes.py` → SVG/PNG/drawio). | ||
| 8 | +- `make check` passes. Nothing committed: the owner commits. | ||
| 9 | + | ||
| 10 | +## In flight | ||
| 11 | + | ||
| 12 | +Nothing. | ||
| 13 | + | ||
| 14 | +## Next steps | ||
| 15 | + | ||
| 16 | +1. Milestone "v0.1 · Première release" (#33–#37) and #38 (qlty kit), when the owner says so. | ||
| 17 | +2. Optional: `build/darwin/dmg-file-icon.*` still carry the Wails icon. | ||
| 18 | + | ||
| 19 | +## Open questions / blockers | ||
| 20 | + | ||
| 21 | +None. | ||
| 22 | + | ||
| 23 | +## Watch out for | ||
| 24 | + | ||
| 25 | +- Regenerating icons: `rsvg-convert` then `wails3 generate icons …` (docs/design/README.md, Logo); `Assets.car` only on macOS. | ||
| 26 | +- To change a wireframe, edit `docs/design/wireframes.py`, never the generated SVG/drawio. | ||
added
.memory/handoffs/2026-10-30-v0.1-release.md +28 -0 | new file mode 100644 | ||
| @@ -0,0 +1,28 @@ | ||
| 1 | +# Handoff — 2026-10-30 — v0.1 · Première release | |
| 2 | + | |
| 3 | +## State | |
| 4 | + | |
| 5 | +Everything of milestone v0.1 is implemented on `feature/1st-release` (not committed: the owner commits). `make check` is green. Tickets #33, #35, #36, #37 have their tasks closed and a comment, but stay open until the owner validates on the Mac; #34 has the guide and waits for the owner's run and report. | |
| 6 | + | |
| 7 | +## In flight | |
| 8 | + | |
| 9 | +Nothing half-done in the code. | |
| 10 | + | |
| 11 | +## Next steps | |
| 12 | + | |
| 13 | +1. Owner, on the Mac: `make check`, `make dev`, then the v0.1 checks of `docs/en/how-to/run-the-end-to-end-scenarios.md` (section 7) and the six scenarios; post the report on #34. | |
| 14 | +2. Owner, on the Mac: `make package-macos`, install the .dmg, check the Gatekeeper procedure and that an app opened from the Finder finds `mm` (shell PATH). | |
| 15 | +3. Release v0.1.0 as in RELEASING.md: `make release-build` on the Mac (needs Docker running, `brew install makensis zip`), `make release-tag` (from an up-to-date `main`), check that the tag push created the release on Rickub, attach the files of dist/ by hand. | |
| 16 | +4. Close #33–#37 and the milestone once validated; then #38 / #40. | |
| 17 | + | |
| 18 | +## Open questions / blockers | |
| 19 | + | |
| 20 | +- The release workflow (tag push → softprops creates the release) has not run on Rickub yet. | |
| 21 | +- Linux amd64 packages are built in Docker with emulation on Apple Silicon: slow, not tried on the Mac yet. | |
| 22 | + | |
| 23 | +## Watch out for | |
| 24 | + | |
| 25 | +- `wails3 task common:update:build-assets` recreates `build/ios/` (ignored) and rewrites Info.plist etc.; `wails3 task linux:*` regenerates `build/darwin/icons.icns` on Linux (same source PNG) — `Assets.car` is only rebuilt on macOS. | |
| 26 | +- Packaging Linux needs `GOARCH` set (nfpm `${GOARCH}`), done by `scripts/package.sh`; AppImage needs `file`; the desktop entry must not contain whitespace-only lines (appimagetool rejects it). | |
| 27 | +- Vitest leaves CSS empty: `?raw` of style.css works only because `test.css.include` lists it. | |
| 28 | +- `/etc/sandbox-persistent.sh` adds `~/go/bin` to PATH idempotently (a non-idempotent line broke `TestInstallTestConfigWritesAValidConfiguration`, whose script re-sources it). | |
| new file mode 100644 | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | +# Handoff — 2026-10-30 — v0.1 · Première release | ||
| 2 | + | ||
| 3 | +## State | ||
| 4 | + | ||
| 5 | +Everything of milestone v0.1 is implemented on `feature/1st-release` (not committed: the owner commits). `make check` is green. Tickets #33, #35, #36, #37 have their tasks closed and a comment, but stay open until the owner validates on the Mac; #34 has the guide and waits for the owner's run and report. | ||
| 6 | + | ||
| 7 | +## In flight | ||
| 8 | + | ||
| 9 | +Nothing half-done in the code. | ||
| 10 | + | ||
| 11 | +## Next steps | ||
| 12 | + | ||
| 13 | +1. Owner, on the Mac: `make check`, `make dev`, then the v0.1 checks of `docs/en/how-to/run-the-end-to-end-scenarios.md` (section 7) and the six scenarios; post the report on #34. | ||
| 14 | +2. Owner, on the Mac: `make package-macos`, install the .dmg, check the Gatekeeper procedure and that an app opened from the Finder finds `mm` (shell PATH). | ||
| 15 | +3. Release v0.1.0 as in RELEASING.md: `make release-build` on the Mac (needs Docker running, `brew install makensis zip`), `make release-tag` (from an up-to-date `main`), check that the tag push created the release on Rickub, attach the files of dist/ by hand. | ||
| 16 | +4. Close #33–#37 and the milestone once validated; then #38 / #40. | ||
| 17 | + | ||
| 18 | +## Open questions / blockers | ||
| 19 | + | ||
| 20 | +- The release workflow (tag push → softprops creates the release) has not run on Rickub yet. | ||
| 21 | +- Linux amd64 packages are built in Docker with emulation on Apple Silicon: slow, not tried on the Mac yet. | ||
| 22 | + | ||
| 23 | +## Watch out for | ||
| 24 | + | ||
| 25 | +- `wails3 task common:update:build-assets` recreates `build/ios/` (ignored) and rewrites Info.plist etc.; `wails3 task linux:*` regenerates `build/darwin/icons.icns` on Linux (same source PNG) — `Assets.car` is only rebuilt on macOS. | ||
| 26 | +- Packaging Linux needs `GOARCH` set (nfpm `${GOARCH}`), done by `scripts/package.sh`; AppImage needs `file`; the desktop entry must not contain whitespace-only lines (appimagetool rejects it). | ||
| 27 | +- Vitest leaves CSS empty: `?raw` of style.css works only because `test.css.include` lists it. | ||
| 28 | +- `/etc/sandbox-persistent.sh` adds `~/go/bin` to PATH idempotently (a non-idempotent line broke `TestInstallTestConfigWritesAValidConfiguration`, whose script re-sources it). | ||
modified
.memory/history.md +28 -0 | @@ -160,3 +160,31 @@ | ||
| 160 | 160 | - **CI follow-up**: `node: command not found` — Rickub's runner runs JavaScript actions inside the job container; `nodejs` added to the first (bash-only) step. |
| 161 | 161 | - **CI follow-up 2**: `actions/setup-go` on Rickub ignored `go-version-file` and found no Go. setup-go and setup-node removed: Go installed from go.dev (version from go.mod, dpkg arch), node and npm from Ubuntu 26.04 (node 22.22); only actions/checkout kept. |
| 162 | 162 | - **CI follow-up 3**: lint, Go tests, svelte-check and vitest pass on Rickub; the shell tests failed for want of `jq` (scripts/agents.sh) — jq added to the apt packages. |
| 163 | + | |
| 164 | +## 2026-10-30 — Logo | |
| 165 | + | |
| 166 | +- **Goal**: owner asked for logo proposals while the CI ran; five concepts drawn on a private design canvas (Duo, Orbite, La bande, Le compagnon, S en deux voix); owner chose **02 · Orbite** (centre dot = the user, teal and coral dots in orbit = the agents). | |
| 167 | +- **Changes**: `docs/design/logo/` (mark light/dark, favicon without the ring, app icon copy); `build/appicon.svg` (new source: 1024 canvas, 824 ink tile, macOS grid) → `build/appicon.png`, `build/darwin/icons.icns`, `build/windows/icon.ico` regenerated with `wails3 generate icons`; `build/appicon.icon` glyph replaced (`Assets/sidekicks-mark.svg`, ink automatic-gradient fill, Wails default glyph removed); README shows the mark (light/dark `<picture>`); `docs/design/README.md` Logo section with the regeneration commands. | |
| 168 | +- **Not done here**: `build/darwin/Assets.car` is still the Wails one — it can only be rebuilt on macOS (`-iconcomposerinput appicon.icon -macassetdir darwin`); `dmg-file-icon.*` untouched. | |
| 169 | +- **Follow-up**: owner regenerated `build/darwin/Assets.car` on the Mac. The welcome screen (no channel open, i.e. at launch) now shows the mark above "Sidekicks": `frontend/src/lib/layout/Logo.svelte` (inline SVG, `$props.id()` for the mask id), colours from new `--logo-*` tokens in `style.css` (light and dark). svelte-check, vitest and licence headers pass. | |
| 170 | +- **Follow-up 2**: owner wants the graphics in `docs/design/` in English. `wireframes.py` texts translated (window, messages, notes, titles; the sample `AGENTS.md` stays a French-typography style guide), the six SVG/PNG and `wireframes.drawio` regenerated, `docs/design/README.md` screen names and language sentence updated. | |
| 171 | + | |
| 172 | +## 2026-10-30 — Session closed | |
| 173 | + | |
| 174 | +- **CI**: owner confirms the run is green on Rickub after the `jq` fix (container ubuntu:26.04, Go from go.dev, node/npm/jq from apt). | |
| 175 | +- **Logo work** (above) checked locally: `make check` passes (golangci-lint, Go tests, svelte-check, vitest 63, agents.sh 15, licence headers). | |
| 176 | + | |
| 177 | +## 2026-10-30 — v0.1 · Première release (implementation) | |
| 178 | + | |
| 179 | +- **Goal**: milestone v0.1 (#33 onboarding, #34 end-to-end scenarios, #35 keyboard and accessibility, #36 macOS packaging) plus, asked mid-way, Linux and Windows packages and a workflow that builds them and attaches them to a release. Owner's choices: assistant for local + Docker + sbx; scenarios as a step-by-step guide + report; no Apple Developer account (unsigned .dmg + Gatekeeper procedure); command palette included; #40 not in the milestone; "tout d'un coup". | |
| 180 | +- **Changes**: Go — `internal/app/newagent.go` (`AgentForm`, `entryOf`, `splitArguments`, `ConfigService.AddAgent`, `ChooseFolder`, `Options.PickFolder`), `config.RuntimeEntry`, `unescapeLongCharacters` (yaml.v3 wrote 🤖 as `"\U0001F916"`), default config comment, `internal/shellpath` (interactive login shell with markers, merge, Apply; called in main.go before locating the config). Frontend — `lib/agentform.ts`, `lib/agent/AddAgentForm.svelte`, welcome screen (wireframe 6) in `ConversationPanel`, "+ Add an agent" in AgentsPanel, `lib/errors.ts` + `chat/ErrorText.svelte` used by ActionError/AgentsPanel/MessageView/AgentView/TerminalView (ActionError hides an error already shown on the agent row), `lib/shortcuts.ts`, `layout/CommandPalette.svelte`, Shell keydown (terminal keeps Ctrl outside macOS), `lib/contrast.ts` + test (style.css read via `?raw`, `test.css.include` in vite.config.ts), light theme colours darkened for AA, `:focus-visible`. Packaging — version 0.1.0 + `update:build-assets`, `build/linux/desktop` used instead of the generated one, nfpm licence/homepage/maintainer/icons, `scripts/package.sh` + test, `make package-*`, `.github/workflows/release.yml`, `.gitignore` (dist/, build/ios/, generated desktop). Diagram: `internal/shellpath` column. | |
| 181 | +- **Decisions**: errors stay technical in Go and are explained in the interface (unknown ones shown as they are); Rickub has Linux x86-64 runners only → CI builds Linux amd64 + Windows (CGO off cross-build), macOS on the Mac; tag must equal `v`+`build/config.yml` version. | |
| 182 | +- **Tests**: Go (entryOf, splitArguments, AddAgent, ChooseFolder, AppendAgent runtime/emoji, shellpath), vitest 85 (agentform, errors, shortcuts, contrast), shell (package names). `make check` green. Headless checks under Xvfb: welcome, assistant end to end (agent written, folder created, conversation opens), error sentence, palette, ⌘N/⌘L; AppImage launches; deb/rpm metadata checked; Windows installer built. | |
| 183 | +- **Quality**: golangci-lint 0 issues (qlty unavailable, #38). | |
| 184 | +- **Docs** (EN/FR): tutorial your-first-agent / premier-agent; how-to install-sidekicks, add-an-agent, publish-a-release, run-the-end-to-end-scenarios (+ report); reference keyboard-shortcuts, configuration (what the assistant writes), commands (package targets, package.sh, workflows, CI description fixed); explanation architecture (shell PATH, errors); indexes; root README (status, install, layout). | |
| 185 | +- **Follow-up (owner tested the assistant: works)**: copy a whole agent answer — `answerText` in `frontend/src/lib/conversation.ts` (text parts as Markdown, thoughts/tools/plans left out, tested), a "⧉ Copy" button next to the agent's name, shown on hover/focus once the answer is done (`MessageView.svelte`, key `message.copy`). Tutorial first-conversation (EN/FR) mentions it. Not seen on screen in the sandbox (no real agent there). | |
| 186 | +- **Follow-up**: `make package-macos` on the Mac warned `ld: object file … built for newer 'macOS' version (13.0) than being linked (12.0)`: the Go toolchain targets macOS 13 while Wails' darwin Taskfile asked for 12.0. Minimum set to 13.0 (Taskfile CGO flags + MACOSX_DEPLOYMENT_TARGET, LSMinimumSystemVersion 13.0.0 in both plists); install docs say macOS 13+; publish docs warn that `update:build-assets` resets the plists to 12.0.0. | |
| 187 | +- **Follow-up (owner pointed at rickub/cli)**: its `RELEASING.md` and `release.yml` show what works on Rickub's CI: `workflow_dispatch` (the only dispatchable workflow; the web UI targets one), `permissions: contents: write` (the token is read-only otherwise), `softprops/action-gh-release@v2` through the `/gh` shim behind `$GITHUB_API_URL` (creates the tag at `target_commitish`), artifacts uploaded first (fallback when publishing fails with 403/422). `.github/workflows/release.yml` rewritten on that model: version from `build/config.yml`, tag-exists check, `dry_run`, notes with checksums. Docs publish-a-release and commands reference (EN/FR) follow. Rickub's release page has no upload button: how the macOS packages reach a release is open. | |
| 188 | +- **Follow-up (macOS packages into the release)**: Rickub's CLI cannot upload release files (no `release` command; `rickub api` sends JSON only; the public API has no asset endpoint); the release web page accepts files by hand (owner checked). Owner chose the branch route: `scripts/push-macos-packages.sh` (on the Mac, after `make package-macos`: the .dmg and .zip as one parentless commit `built-from: <HEAD>`, built with plumbing — hash-object, mktree, commit-tree — force-pushed to `macos-packages`), `scripts/fetch-macos-packages.sh` (CI: writes them into dist/ for the version of build/config.yml, fails listing the branch content otherwise, prints built-from). Release workflow: step "macOS packages" before the checksums, input `without_macos`, warning when built-from ≠ released commit, notes say where the macOS packages come from. Test `scripts/macos-packages_test.sh` (bare remote + Mac clone + CI clone, 9 checks) in `make test-scripts`. Docs publish-a-release (steps reordered: version → Mac packages → workflow), commands reference, run-the-tests (EN/FR). | |
| 189 | +- **Follow-up**: root `RELEASING.md` / `RELEASING.fr.md` (owner asked for a document at the root): how a release is built (table), five-step checklist (version → Mac packages → dry run → publish → after), troubleshooting table, manual builds; linked from README and the publish-a-release guides. | |
| 190 | +- **Follow-up (owner: "c'est trop compliqué")**: release procedure simplified to the owner's plan — build everything on the Mac, tag with a script, the tag push creates the release, the files are attached by hand. `scripts/build-release.sh` (`make release-build`: macOS native, Windows cross-built, Linux `scripts/package.sh linux` in a Docker container from `scripts/linux-packages.Dockerfile` per `LINUX_ARCHES` (default amd64), `SKIP`, then `dist/SHA256SUMS`), `scripts/tag-release.sh` (`make release-tag`: clean tree, on main, equal to origin/main, tag free; warns when dist/ misses a package; annotated tag pushed; `--no-push`; test `tag-release_test.sh`, 11 checks), `.github/workflows/release.yml` now `on: push: tags: v*` → checks tag = config version, creates the release with notes (file table) via softprops, no files, `contents: write`. The `macos-packages` branch scripts and their test were removed; CI no longer builds packages. `scripts/package.sh` removes `bin/sidekicks` before a Linux or macOS build (a binary of the other OS in the shared bin/ made go build fail: "not an object file"). The Docker image needs `ibus-gtk4` (the AppImage GTK plugin copies `/usr/lib/<arch>/gtk-4.0`). RELEASING.md/.fr.md, publish-a-release (EN/FR) and the commands reference rewritten. | |
| @@ -160,3 +160,31 @@ | |||
| 160 | - **CI follow-up**: `node: command not found` — Rickub's runner runs JavaScript actions inside the job container; `nodejs` added to the first (bash-only) step. | 160 | - **CI follow-up**: `node: command not found` — Rickub's runner runs JavaScript actions inside the job container; `nodejs` added to the first (bash-only) step. |
| 161 | - **CI follow-up 2**: `actions/setup-go` on Rickub ignored `go-version-file` and found no Go. setup-go and setup-node removed: Go installed from go.dev (version from go.mod, dpkg arch), node and npm from Ubuntu 26.04 (node 22.22); only actions/checkout kept. | 161 | - **CI follow-up 2**: `actions/setup-go` on Rickub ignored `go-version-file` and found no Go. setup-go and setup-node removed: Go installed from go.dev (version from go.mod, dpkg arch), node and npm from Ubuntu 26.04 (node 22.22); only actions/checkout kept. |
| 162 | - **CI follow-up 3**: lint, Go tests, svelte-check and vitest pass on Rickub; the shell tests failed for want of `jq` (scripts/agents.sh) — jq added to the apt packages. | 162 | - **CI follow-up 3**: lint, Go tests, svelte-check and vitest pass on Rickub; the shell tests failed for want of `jq` (scripts/agents.sh) — jq added to the apt packages. |
| 163 | + | ||
| 164 | +## 2026-10-30 — Logo | ||
| 165 | + | ||
| 166 | +- **Goal**: owner asked for logo proposals while the CI ran; five concepts drawn on a private design canvas (Duo, Orbite, La bande, Le compagnon, S en deux voix); owner chose **02 · Orbite** (centre dot = the user, teal and coral dots in orbit = the agents). | ||
| 167 | +- **Changes**: `docs/design/logo/` (mark light/dark, favicon without the ring, app icon copy); `build/appicon.svg` (new source: 1024 canvas, 824 ink tile, macOS grid) → `build/appicon.png`, `build/darwin/icons.icns`, `build/windows/icon.ico` regenerated with `wails3 generate icons`; `build/appicon.icon` glyph replaced (`Assets/sidekicks-mark.svg`, ink automatic-gradient fill, Wails default glyph removed); README shows the mark (light/dark `<picture>`); `docs/design/README.md` Logo section with the regeneration commands. | ||
| 168 | +- **Not done here**: `build/darwin/Assets.car` is still the Wails one — it can only be rebuilt on macOS (`-iconcomposerinput appicon.icon -macassetdir darwin`); `dmg-file-icon.*` untouched. | ||
| 169 | +- **Follow-up**: owner regenerated `build/darwin/Assets.car` on the Mac. The welcome screen (no channel open, i.e. at launch) now shows the mark above "Sidekicks": `frontend/src/lib/layout/Logo.svelte` (inline SVG, `$props.id()` for the mask id), colours from new `--logo-*` tokens in `style.css` (light and dark). svelte-check, vitest and licence headers pass. | ||
| 170 | +- **Follow-up 2**: owner wants the graphics in `docs/design/` in English. `wireframes.py` texts translated (window, messages, notes, titles; the sample `AGENTS.md` stays a French-typography style guide), the six SVG/PNG and `wireframes.drawio` regenerated, `docs/design/README.md` screen names and language sentence updated. | ||
| 171 | + | ||
| 172 | +## 2026-10-30 — Session closed | ||
| 173 | + | ||
| 174 | +- **CI**: owner confirms the run is green on Rickub after the `jq` fix (container ubuntu:26.04, Go from go.dev, node/npm/jq from apt). | ||
| 175 | +- **Logo work** (above) checked locally: `make check` passes (golangci-lint, Go tests, svelte-check, vitest 63, agents.sh 15, licence headers). | ||
| 176 | + | ||
| 177 | +## 2026-10-30 — v0.1 · Première release (implementation) | ||
| 178 | + | ||
| 179 | +- **Goal**: milestone v0.1 (#33 onboarding, #34 end-to-end scenarios, #35 keyboard and accessibility, #36 macOS packaging) plus, asked mid-way, Linux and Windows packages and a workflow that builds them and attaches them to a release. Owner's choices: assistant for local + Docker + sbx; scenarios as a step-by-step guide + report; no Apple Developer account (unsigned .dmg + Gatekeeper procedure); command palette included; #40 not in the milestone; "tout d'un coup". | ||
| 180 | +- **Changes**: Go — `internal/app/newagent.go` (`AgentForm`, `entryOf`, `splitArguments`, `ConfigService.AddAgent`, `ChooseFolder`, `Options.PickFolder`), `config.RuntimeEntry`, `unescapeLongCharacters` (yaml.v3 wrote 🤖 as `"\U0001F916"`), default config comment, `internal/shellpath` (interactive login shell with markers, merge, Apply; called in main.go before locating the config). Frontend — `lib/agentform.ts`, `lib/agent/AddAgentForm.svelte`, welcome screen (wireframe 6) in `ConversationPanel`, "+ Add an agent" in AgentsPanel, `lib/errors.ts` + `chat/ErrorText.svelte` used by ActionError/AgentsPanel/MessageView/AgentView/TerminalView (ActionError hides an error already shown on the agent row), `lib/shortcuts.ts`, `layout/CommandPalette.svelte`, Shell keydown (terminal keeps Ctrl outside macOS), `lib/contrast.ts` + test (style.css read via `?raw`, `test.css.include` in vite.config.ts), light theme colours darkened for AA, `:focus-visible`. Packaging — version 0.1.0 + `update:build-assets`, `build/linux/desktop` used instead of the generated one, nfpm licence/homepage/maintainer/icons, `scripts/package.sh` + test, `make package-*`, `.github/workflows/release.yml`, `.gitignore` (dist/, build/ios/, generated desktop). Diagram: `internal/shellpath` column. | ||
| 181 | +- **Decisions**: errors stay technical in Go and are explained in the interface (unknown ones shown as they are); Rickub has Linux x86-64 runners only → CI builds Linux amd64 + Windows (CGO off cross-build), macOS on the Mac; tag must equal `v`+`build/config.yml` version. | ||
| 182 | +- **Tests**: Go (entryOf, splitArguments, AddAgent, ChooseFolder, AppendAgent runtime/emoji, shellpath), vitest 85 (agentform, errors, shortcuts, contrast), shell (package names). `make check` green. Headless checks under Xvfb: welcome, assistant end to end (agent written, folder created, conversation opens), error sentence, palette, ⌘N/⌘L; AppImage launches; deb/rpm metadata checked; Windows installer built. | ||
| 183 | +- **Quality**: golangci-lint 0 issues (qlty unavailable, #38). | ||
| 184 | +- **Docs** (EN/FR): tutorial your-first-agent / premier-agent; how-to install-sidekicks, add-an-agent, publish-a-release, run-the-end-to-end-scenarios (+ report); reference keyboard-shortcuts, configuration (what the assistant writes), commands (package targets, package.sh, workflows, CI description fixed); explanation architecture (shell PATH, errors); indexes; root README (status, install, layout). | ||
| 185 | +- **Follow-up (owner tested the assistant: works)**: copy a whole agent answer — `answerText` in `frontend/src/lib/conversation.ts` (text parts as Markdown, thoughts/tools/plans left out, tested), a "⧉ Copy" button next to the agent's name, shown on hover/focus once the answer is done (`MessageView.svelte`, key `message.copy`). Tutorial first-conversation (EN/FR) mentions it. Not seen on screen in the sandbox (no real agent there). | ||
| 186 | +- **Follow-up**: `make package-macos` on the Mac warned `ld: object file … built for newer 'macOS' version (13.0) than being linked (12.0)`: the Go toolchain targets macOS 13 while Wails' darwin Taskfile asked for 12.0. Minimum set to 13.0 (Taskfile CGO flags + MACOSX_DEPLOYMENT_TARGET, LSMinimumSystemVersion 13.0.0 in both plists); install docs say macOS 13+; publish docs warn that `update:build-assets` resets the plists to 12.0.0. | ||
| 187 | +- **Follow-up (owner pointed at rickub/cli)**: its `RELEASING.md` and `release.yml` show what works on Rickub's CI: `workflow_dispatch` (the only dispatchable workflow; the web UI targets one), `permissions: contents: write` (the token is read-only otherwise), `softprops/action-gh-release@v2` through the `/gh` shim behind `$GITHUB_API_URL` (creates the tag at `target_commitish`), artifacts uploaded first (fallback when publishing fails with 403/422). `.github/workflows/release.yml` rewritten on that model: version from `build/config.yml`, tag-exists check, `dry_run`, notes with checksums. Docs publish-a-release and commands reference (EN/FR) follow. Rickub's release page has no upload button: how the macOS packages reach a release is open. | ||
| 188 | +- **Follow-up (macOS packages into the release)**: Rickub's CLI cannot upload release files (no `release` command; `rickub api` sends JSON only; the public API has no asset endpoint); the release web page accepts files by hand (owner checked). Owner chose the branch route: `scripts/push-macos-packages.sh` (on the Mac, after `make package-macos`: the .dmg and .zip as one parentless commit `built-from: <HEAD>`, built with plumbing — hash-object, mktree, commit-tree — force-pushed to `macos-packages`), `scripts/fetch-macos-packages.sh` (CI: writes them into dist/ for the version of build/config.yml, fails listing the branch content otherwise, prints built-from). Release workflow: step "macOS packages" before the checksums, input `without_macos`, warning when built-from ≠ released commit, notes say where the macOS packages come from. Test `scripts/macos-packages_test.sh` (bare remote + Mac clone + CI clone, 9 checks) in `make test-scripts`. Docs publish-a-release (steps reordered: version → Mac packages → workflow), commands reference, run-the-tests (EN/FR). | ||
| 189 | +- **Follow-up**: root `RELEASING.md` / `RELEASING.fr.md` (owner asked for a document at the root): how a release is built (table), five-step checklist (version → Mac packages → dry run → publish → after), troubleshooting table, manual builds; linked from README and the publish-a-release guides. | ||
| 190 | +- **Follow-up (owner: "c'est trop compliqué")**: release procedure simplified to the owner's plan — build everything on the Mac, tag with a script, the tag push creates the release, the files are attached by hand. `scripts/build-release.sh` (`make release-build`: macOS native, Windows cross-built, Linux `scripts/package.sh linux` in a Docker container from `scripts/linux-packages.Dockerfile` per `LINUX_ARCHES` (default amd64), `SKIP`, then `dist/SHA256SUMS`), `scripts/tag-release.sh` (`make release-tag`: clean tree, on main, equal to origin/main, tag free; warns when dist/ misses a package; annotated tag pushed; `--no-push`; test `tag-release_test.sh`, 11 checks), `.github/workflows/release.yml` now `on: push: tags: v*` → checks tag = config version, creates the release with notes (file table) via softprops, no files, `contents: write`. The `macos-packages` branch scripts and their test were removed; CI no longer builds packages. `scripts/package.sh` removes `bin/sidekicks` before a Linux or macOS build (a binary of the other OS in the shared bin/ made go build fail: "not an object file"). The Docker image needs `ibus-gtk4` (the AppImage GTK plugin copies `/usr/lib/<arch>/gtk-4.0`). RELEASING.md/.fr.md, publish-a-release (EN/FR) and the commands reference rewritten. | ||
modified
.memory/summary.md +11 -6 | @@ -4,15 +4,18 @@ | ||
| 4 | 4 | |
| 5 | 5 | A desktop application (Go + Wails) to talk with AI agents in channels, for non-technical ("citizen") users. Agent-agnostic: every agent is reached over the Agent Client Protocol (ACP, JSON-RPC on stdio). Full brief: `.tickets/issues/0001-draft.yaml`; backlog of 36 issues, 9 epics, 6 milestones in `.tickets/` (IssueSpec format, see `.claude/skills/issuespec`). |
| 6 | 6 | |
| 7 | -## State (2026-10-30, M4 closed) | |
| 7 | +## State (2026-10-30, v0.1 in progress) | |
| 8 | 8 | |
| 9 | -Milestones **Initialize**, **M1**, **M2**, **M3** and **M4 · Workspace des agents** are closed (M4 validated on the Mac, branch `feature/m4-agents-workspace`; #32 in the backlog). Workspaces: local, Docker container and sbx sandbox (`workspace.Remote`, verified on `milo-sbx`). Test agents are started with mm directly, with the optional `afterStop` unloading their model. Agent view in the centre (📂 on an agent row): Files (lazy tree, hidden files toggle, CodeMirror editor with conflict detection, create, delete to trash), Terminal (xterm.js + pty, local or docker exec), Log. M3 recap: Channels persisted in Pebble (one DB per config file), direct conversations = channels with one member, `@` mentions with popup + invitation, sequential multi-agent answers with unseen-context injection, `/` and `/agent:command` popup (commands cached in the store), resume after restart by context re-injection (mm has no session/load), channel CRUD in the Channels panel, unread badges. Since M2: streaming Markdown (Shiki, DOMPurify), tool calls with diffs, permission cards in plain words, stuck-agent banner, Stop, message queue, context gauge; Settings editor (CodeMirror, live validation by Go, schema completion, save/revert); open another config file + recent list + last-opened at startup. The interface is in **English by default**, French with `ui: language: fr` (ADR 0005). Next: v0.1 · Première release (#33–#37), #38 qlty kit. | |
| 9 | +**v0.1 · Première release** (#33–#37) is implemented on branch `feature/1st-release`, waiting for the owner's validation on the Mac (end-to-end scenarios guide, section 7 for v0.1 checks): welcome screen + "Add an agent" assistant (`ConfigService.AddAgent`/`ChooseFolder`, local/container/sbx), human error messages (`frontend/src/lib/errors.ts` + `ErrorText`), shortcuts + ⌘K palette (`lib/shortcuts.ts`, `CommandPalette.svelte`), WCAG contrast test, `:focus-visible`, `internal/shellpath` (shell PATH at startup), version 0.1.0, packages for macOS/Linux/Windows (`scripts/package.sh`, `make package-*`, `dist/`), release workflow (`.github/workflows/release.yml`). Logo "Orbite" (`docs/design/logo/`, `build/appicon.svg`). | |
| 10 | + | |
| 11 | + | |
| 12 | +Milestones **Initialize**, **M1**, **M2**, **M3** and **M4 · Workspace des agents** are closed (M4 validated on the Mac, branch `feature/m4-agents-workspace`; #32 in the backlog). Workspaces: local, Docker container and sbx sandbox (`workspace.Remote`, verified on `milo-sbx`). Test agents are started with mm directly, with the optional `afterStop` unloading their model. Agent view in the centre (📂 on an agent row): Files (lazy tree, hidden files toggle, CodeMirror editor with conflict detection, create, delete to trash), Terminal (xterm.js + pty, local or docker exec), Log. M3 recap: Channels persisted in Pebble (one DB per config file), direct conversations = channels with one member, `@` mentions with popup + invitation, sequential multi-agent answers with unseen-context injection, `/` and `/agent:command` popup (commands cached in the store), resume after restart by context re-injection (mm has no session/load), channel CRUD in the Channels panel, unread badges. Since M2: streaming Markdown (Shiki, DOMPurify), tool calls with diffs, permission cards in plain words, stuck-agent banner, Stop, message queue, context gauge; Settings editor (CodeMirror, live validation by Go, schema completion, save/revert); open another config file + recent list + last-opened at startup. The interface is in **English by default**, French with `ui: language: fr` (ADR 0005). Next after v0.1: #38 qlty kit, #40 sbx create/remove hook, #32. | |
| 10 | 13 | |
| 11 | 14 | What exists: |
| 12 | 15 | |
| 13 | -- `main.go` (root, only Wails importer; registers 11 typed events; injects the native file dialog; its emitter ignores events sent before the Wails app exists) · `internal/app` (Core, AgentService, ChannelService, ConfigService; opens the history per config file) · `internal/channels` (routing, sessions, context, queue, permissions) · `internal/store` (Pebble) · `internal/workspace` (Local, Container, Terminals; contract tests local + alpine container) · `internal/agents` · `internal/acp` (sessions, readable AgentError, stdin→TERM→KILL) · `internal/config` (+ `WatchWithReady`) · `internal/prefs` · `internal/events` · `schema`. | |
| 16 | +- `main.go` (root, only Wails importer; registers 11 typed events; injects the native file dialog; its emitter ignores events sent before the Wails app exists) · `internal/app` (Core, AgentService, ChannelService, ConfigService; opens the history per config file) · `internal/channels` (routing, sessions, context, queue, permissions) · `internal/store` (Pebble) · `internal/workspace` (Local, Container, Terminals; contract tests local + alpine container) · `internal/agents` · `internal/acp` (sessions, readable AgentError, stdin→TERM→KILL) · `internal/config` (+ `WatchWithReady`, `AppendAgent` keeps comments and unescapes emoji) · `internal/prefs` · `internal/events` · `internal/shellpath` · `schema`. | |
| 14 | 17 | - `frontend/`: shell + panel registry, `state.svelte.ts` (`appState`, one ordered frame batcher for message events), `lib/chat/*` (Markdown, MessageView, ToolCallCard, PermissionCard, Composer), `lib/settings/ConfigEditor.svelte`, `lib/i18n` (en/fr catalogue, `t()`), pure modules with vitest (`markdown`, `conversation`, `composer`, `suggestions`, `tools`, `yamlSchema`, `events`, `theme`, `panels/registry`). State is keyed by channel id; a `$derived` must never call `conversationOf` (it writes state → `state_unsafe_mutation` freezes the UI). |
| 15 | -- Tooling: `Makefile`, golangci-lint (`tools/go.mod`), CI, `scripts/agents.sh`, `scripts/install-test-config.sh`, `scripts/check-license-headers.sh`. | |
| 18 | +- Tooling: `Makefile`, golangci-lint (`tools/go.mod`), CI (`.github/workflows/ci.yml`, job in a `ubuntu:26.04` container, green on Rickub), `scripts/agents.sh`, `scripts/install-test-config.sh`, `scripts/check-license-headers.sh`, `scripts/package.sh` (+ `package_test.sh`), `scripts/build-release.sh`, `scripts/tag-release.sh` (+ `tag-release_test.sh`), `scripts/linux-packages.Dockerfile`, release workflow (tag push → release) `.github/workflows/release.yml`. | |
| 16 | 19 | |
| 17 | 20 | ## Decisions in force |
| 18 | 21 | |
| @@ -37,10 +40,11 @@ What exists: | ||
| 37 | 40 | | Everything the CI runs | `make check` (lint + tests; needs `wails3`, `pnpm`, GTK/WebKit dev packages on Linux) | |
| 38 | 41 | | Tests only | `make test` (Go + vitest + shell) · real agents: `make test-real` | |
| 39 | 42 | | Run | `SIDEKICKS_CONFIG="$PWD/examples/test-agents.yaml" make dev` · build `make build` · macOS app `make package` | |
| 43 | +| Release | `make release-build` (Mac: all packages → dist/, Linux in Docker) · `make release-tag` · single systems: `make package-linux` / `package-windows` / `package-macos`; see RELEASING.md | | |
| 40 | 44 | | Bindings | `make bindings` after changing a service/event; CI runs `make bindings-check` | |
| 41 | 45 | | Test agents | `scripts/agents.sh run alice` · `ps` · `unload --all` (`MM_BIN`, llmman on 127.0.0.1 or host.docker.internal:17434) | |
| 42 | 46 | | Headless UI check (sandbox) | `Xvfb :97`, `GDK_BACKEND=x11 WEBKIT_DISABLE_DMABUF_RENDERER=1 dbus-launch bin/sidekicks --config …`, `xdotool`, `import -window root` | |
| 43 | -| Wireframes / package diagram | `python3 docs/design/wireframes.py` · `python3 .claude/skills/drawio-fancy-diagram/generator/examples/sidekicks_packages.py docs/diagrams` + `rsvg-convert -w 1200 -h 800` | | |
| 47 | +| Wireframes / package diagram | `python3 docs/design/wireframes.py` · `python3 .claude/skills/drawio-fancy-diagram/generator/examples/sidekicks_packages.py docs/diagrams` + `rsvg-convert -w 1690 -h 800` | | |
| 44 | 48 | |
| 45 | 49 | ## Facts about the test agents (mm v1.0.3) |
| 46 | 50 | |
| @@ -54,6 +58,7 @@ What exists: | ||
| 54 | 58 | |
| 55 | 59 | - How to exec a shell / read files inside an `sbx` sandbox (issue #28). |
| 56 | 60 | - Quality gate: `qlty` is not in this sandbox → no qlty measurement yet (issue #38: build a sandbox kit with qlty). golangci-lint (go tool) is the stopgap. |
| 57 | -- Whether the CI workflow runs as-is on rickub. | |
| 58 | 61 | - On the shared Mac⇄Linux folder, the `mkdir` lock of `scripts/agents.sh` is not exclusive: two agents starting at the same instant could exceed the slot limit in the sandbox. Not seen; on the Mac's own disk mkdir is atomic. |
| 62 | +- Release procedure (RELEASING.md): `make release-build` on the Mac (everything into dist/, Linux in Docker), `make release-tag` (pushes `v<version>`), the tag push makes `.github/workflows/release.yml` create the release (notes only, softprops), files attached by hand on the release page. The workflow has not run on Rickub yet; `make release-build` has not run on the Mac yet (Linux arm64 in Docker checked in the sandbox). | |
| 63 | +- `make package-macos` (universal .dmg) and the Windows installer have not been run on their systems; the folder dialog of the assistant (`ChooseFolder`) not tried on the Mac. | |
| 59 | 64 | - Whether `.claude/skills/*` (kit files) should be committed with the project is the owner's call. |
| @@ -4,15 +4,18 @@ | |||
| 4 | 4 | ||
| 5 | A desktop application (Go + Wails) to talk with AI agents in channels, for non-technical ("citizen") users. Agent-agnostic: every agent is reached over the Agent Client Protocol (ACP, JSON-RPC on stdio). Full brief: `.tickets/issues/0001-draft.yaml`; backlog of 36 issues, 9 epics, 6 milestones in `.tickets/` (IssueSpec format, see `.claude/skills/issuespec`). | 5 | A desktop application (Go + Wails) to talk with AI agents in channels, for non-technical ("citizen") users. Agent-agnostic: every agent is reached over the Agent Client Protocol (ACP, JSON-RPC on stdio). Full brief: `.tickets/issues/0001-draft.yaml`; backlog of 36 issues, 9 epics, 6 milestones in `.tickets/` (IssueSpec format, see `.claude/skills/issuespec`). |
| 6 | 6 | ||
| 7 | -## State (2026-10-30, M4 closed) | 7 | +## State (2026-10-30, v0.1 in progress) |
| 8 | 8 | ||
| 9 | -Milestones **Initialize**, **M1**, **M2**, **M3** and **M4 · Workspace des agents** are closed (M4 validated on the Mac, branch `feature/m4-agents-workspace`; #32 in the backlog). Workspaces: local, Docker container and sbx sandbox (`workspace.Remote`, verified on `milo-sbx`). Test agents are started with mm directly, with the optional `afterStop` unloading their model. Agent view in the centre (📂 on an agent row): Files (lazy tree, hidden files toggle, CodeMirror editor with conflict detection, create, delete to trash), Terminal (xterm.js + pty, local or docker exec), Log. M3 recap: Channels persisted in Pebble (one DB per config file), direct conversations = channels with one member, `@` mentions with popup + invitation, sequential multi-agent answers with unseen-context injection, `/` and `/agent:command` popup (commands cached in the store), resume after restart by context re-injection (mm has no session/load), channel CRUD in the Channels panel, unread badges. Since M2: streaming Markdown (Shiki, DOMPurify), tool calls with diffs, permission cards in plain words, stuck-agent banner, Stop, message queue, context gauge; Settings editor (CodeMirror, live validation by Go, schema completion, save/revert); open another config file + recent list + last-opened at startup. The interface is in **English by default**, French with `ui: language: fr` (ADR 0005). Next: v0.1 · Première release (#33–#37), #38 qlty kit. | 9 | +**v0.1 · Première release** (#33–#37) is implemented on branch `feature/1st-release`, waiting for the owner's validation on the Mac (end-to-end scenarios guide, section 7 for v0.1 checks): welcome screen + "Add an agent" assistant (`ConfigService.AddAgent`/`ChooseFolder`, local/container/sbx), human error messages (`frontend/src/lib/errors.ts` + `ErrorText`), shortcuts + ⌘K palette (`lib/shortcuts.ts`, `CommandPalette.svelte`), WCAG contrast test, `:focus-visible`, `internal/shellpath` (shell PATH at startup), version 0.1.0, packages for macOS/Linux/Windows (`scripts/package.sh`, `make package-*`, `dist/`), release workflow (`.github/workflows/release.yml`). Logo "Orbite" (`docs/design/logo/`, `build/appicon.svg`). |
| 10 | + | ||
| 11 | + | ||
| 12 | +Milestones **Initialize**, **M1**, **M2**, **M3** and **M4 · Workspace des agents** are closed (M4 validated on the Mac, branch `feature/m4-agents-workspace`; #32 in the backlog). Workspaces: local, Docker container and sbx sandbox (`workspace.Remote`, verified on `milo-sbx`). Test agents are started with mm directly, with the optional `afterStop` unloading their model. Agent view in the centre (📂 on an agent row): Files (lazy tree, hidden files toggle, CodeMirror editor with conflict detection, create, delete to trash), Terminal (xterm.js + pty, local or docker exec), Log. M3 recap: Channels persisted in Pebble (one DB per config file), direct conversations = channels with one member, `@` mentions with popup + invitation, sequential multi-agent answers with unseen-context injection, `/` and `/agent:command` popup (commands cached in the store), resume after restart by context re-injection (mm has no session/load), channel CRUD in the Channels panel, unread badges. Since M2: streaming Markdown (Shiki, DOMPurify), tool calls with diffs, permission cards in plain words, stuck-agent banner, Stop, message queue, context gauge; Settings editor (CodeMirror, live validation by Go, schema completion, save/revert); open another config file + recent list + last-opened at startup. The interface is in **English by default**, French with `ui: language: fr` (ADR 0005). Next after v0.1: #38 qlty kit, #40 sbx create/remove hook, #32. | ||
| 10 | 13 | ||
| 11 | What exists: | 14 | What exists: |
| 12 | 15 | ||
| 13 | -- `main.go` (root, only Wails importer; registers 11 typed events; injects the native file dialog; its emitter ignores events sent before the Wails app exists) · `internal/app` (Core, AgentService, ChannelService, ConfigService; opens the history per config file) · `internal/channels` (routing, sessions, context, queue, permissions) · `internal/store` (Pebble) · `internal/workspace` (Local, Container, Terminals; contract tests local + alpine container) · `internal/agents` · `internal/acp` (sessions, readable AgentError, stdin→TERM→KILL) · `internal/config` (+ `WatchWithReady`) · `internal/prefs` · `internal/events` · `schema`. | 16 | +- `main.go` (root, only Wails importer; registers 11 typed events; injects the native file dialog; its emitter ignores events sent before the Wails app exists) · `internal/app` (Core, AgentService, ChannelService, ConfigService; opens the history per config file) · `internal/channels` (routing, sessions, context, queue, permissions) · `internal/store` (Pebble) · `internal/workspace` (Local, Container, Terminals; contract tests local + alpine container) · `internal/agents` · `internal/acp` (sessions, readable AgentError, stdin→TERM→KILL) · `internal/config` (+ `WatchWithReady`, `AppendAgent` keeps comments and unescapes emoji) · `internal/prefs` · `internal/events` · `internal/shellpath` · `schema`. |
| 14 | - `frontend/`: shell + panel registry, `state.svelte.ts` (`appState`, one ordered frame batcher for message events), `lib/chat/*` (Markdown, MessageView, ToolCallCard, PermissionCard, Composer), `lib/settings/ConfigEditor.svelte`, `lib/i18n` (en/fr catalogue, `t()`), pure modules with vitest (`markdown`, `conversation`, `composer`, `suggestions`, `tools`, `yamlSchema`, `events`, `theme`, `panels/registry`). State is keyed by channel id; a `$derived` must never call `conversationOf` (it writes state → `state_unsafe_mutation` freezes the UI). | 17 | - `frontend/`: shell + panel registry, `state.svelte.ts` (`appState`, one ordered frame batcher for message events), `lib/chat/*` (Markdown, MessageView, ToolCallCard, PermissionCard, Composer), `lib/settings/ConfigEditor.svelte`, `lib/i18n` (en/fr catalogue, `t()`), pure modules with vitest (`markdown`, `conversation`, `composer`, `suggestions`, `tools`, `yamlSchema`, `events`, `theme`, `panels/registry`). State is keyed by channel id; a `$derived` must never call `conversationOf` (it writes state → `state_unsafe_mutation` freezes the UI). |
| 15 | -- Tooling: `Makefile`, golangci-lint (`tools/go.mod`), CI, `scripts/agents.sh`, `scripts/install-test-config.sh`, `scripts/check-license-headers.sh`. | 18 | +- Tooling: `Makefile`, golangci-lint (`tools/go.mod`), CI (`.github/workflows/ci.yml`, job in a `ubuntu:26.04` container, green on Rickub), `scripts/agents.sh`, `scripts/install-test-config.sh`, `scripts/check-license-headers.sh`, `scripts/package.sh` (+ `package_test.sh`), `scripts/build-release.sh`, `scripts/tag-release.sh` (+ `tag-release_test.sh`), `scripts/linux-packages.Dockerfile`, release workflow (tag push → release) `.github/workflows/release.yml`. |
| 16 | 19 | ||
| 17 | ## Decisions in force | 20 | ## Decisions in force |
| 18 | 21 | ||
| @@ -37,10 +40,11 @@ What exists: | |||
| 37 | | Everything the CI runs | `make check` (lint + tests; needs `wails3`, `pnpm`, GTK/WebKit dev packages on Linux) | | 40 | | Everything the CI runs | `make check` (lint + tests; needs `wails3`, `pnpm`, GTK/WebKit dev packages on Linux) | |
| 38 | | Tests only | `make test` (Go + vitest + shell) · real agents: `make test-real` | | 41 | | Tests only | `make test` (Go + vitest + shell) · real agents: `make test-real` | |
| 39 | | Run | `SIDEKICKS_CONFIG="$PWD/examples/test-agents.yaml" make dev` · build `make build` · macOS app `make package` | | 42 | | Run | `SIDEKICKS_CONFIG="$PWD/examples/test-agents.yaml" make dev` · build `make build` · macOS app `make package` | |
| 43 | +| Release | `make release-build` (Mac: all packages → dist/, Linux in Docker) · `make release-tag` · single systems: `make package-linux` / `package-windows` / `package-macos`; see RELEASING.md | | ||
| 40 | | Bindings | `make bindings` after changing a service/event; CI runs `make bindings-check` | | 44 | | Bindings | `make bindings` after changing a service/event; CI runs `make bindings-check` | |
| 41 | | Test agents | `scripts/agents.sh run alice` · `ps` · `unload --all` (`MM_BIN`, llmman on 127.0.0.1 or host.docker.internal:17434) | | 45 | | Test agents | `scripts/agents.sh run alice` · `ps` · `unload --all` (`MM_BIN`, llmman on 127.0.0.1 or host.docker.internal:17434) | |
| 42 | | Headless UI check (sandbox) | `Xvfb :97`, `GDK_BACKEND=x11 WEBKIT_DISABLE_DMABUF_RENDERER=1 dbus-launch bin/sidekicks --config …`, `xdotool`, `import -window root` | | 46 | | Headless UI check (sandbox) | `Xvfb :97`, `GDK_BACKEND=x11 WEBKIT_DISABLE_DMABUF_RENDERER=1 dbus-launch bin/sidekicks --config …`, `xdotool`, `import -window root` | |
| 43 | -| Wireframes / package diagram | `python3 docs/design/wireframes.py` · `python3 .claude/skills/drawio-fancy-diagram/generator/examples/sidekicks_packages.py docs/diagrams` + `rsvg-convert -w 1200 -h 800` | | 47 | +| Wireframes / package diagram | `python3 docs/design/wireframes.py` · `python3 .claude/skills/drawio-fancy-diagram/generator/examples/sidekicks_packages.py docs/diagrams` + `rsvg-convert -w 1690 -h 800` | |
| 44 | 48 | ||
| 45 | ## Facts about the test agents (mm v1.0.3) | 49 | ## Facts about the test agents (mm v1.0.3) |
| 46 | 50 | ||
| @@ -54,6 +58,7 @@ What exists: | |||
| 54 | 58 | ||
| 55 | - How to exec a shell / read files inside an `sbx` sandbox (issue #28). | 59 | - How to exec a shell / read files inside an `sbx` sandbox (issue #28). |
| 56 | - Quality gate: `qlty` is not in this sandbox → no qlty measurement yet (issue #38: build a sandbox kit with qlty). golangci-lint (go tool) is the stopgap. | 60 | - Quality gate: `qlty` is not in this sandbox → no qlty measurement yet (issue #38: build a sandbox kit with qlty). golangci-lint (go tool) is the stopgap. |
| 57 | -- Whether the CI workflow runs as-is on rickub. | ||
| 58 | - On the shared Mac⇄Linux folder, the `mkdir` lock of `scripts/agents.sh` is not exclusive: two agents starting at the same instant could exceed the slot limit in the sandbox. Not seen; on the Mac's own disk mkdir is atomic. | 61 | - On the shared Mac⇄Linux folder, the `mkdir` lock of `scripts/agents.sh` is not exclusive: two agents starting at the same instant could exceed the slot limit in the sandbox. Not seen; on the Mac's own disk mkdir is atomic. |
| 62 | +- Release procedure (RELEASING.md): `make release-build` on the Mac (everything into dist/, Linux in Docker), `make release-tag` (pushes `v<version>`), the tag push makes `.github/workflows/release.yml` create the release (notes only, softprops), files attached by hand on the release page. The workflow has not run on Rickub yet; `make release-build` has not run on the Mac yet (Linux arm64 in Docker checked in the sandbox). | ||
| 63 | +- `make package-macos` (universal .dmg) and the Windows installer have not been run on their systems; the folder dialog of the assistant (`ChooseFolder`) not tried on the Mac. | ||
| 59 | - Whether `.claude/skills/*` (kit files) should be committed with the project is the owner's call. | 64 | - Whether `.claude/skills/*` (kit files) should be committed with the project is the owner's call. |
modified
.tickets/issues/0033-premier-lancement-et-onboarding-du-citizen-user.yaml +29 -6 | @@ -6,7 +6,7 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-29T07:20:31.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:31.000Z | |
| 9 | +updatedAt: 2026-10-30T07:39:01.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - "kind::feature" |
| 12 | 12 | - "area::ui" |
| @@ -32,34 +32,57 @@ body: | | ||
| 32 | 32 | tasks: |
| 33 | 33 | - id: 1 |
| 34 | 34 | title: "États vides" |
| 35 | - state: open | |
| 35 | + state: closed | |
| 36 | 36 | priority: high |
| 37 | 37 | author: |
| 38 | 38 | name: k33g |
| 39 | 39 | email: ph.charriere@gmail.com |
| 40 | 40 | createdAt: 2026-10-29T07:20:31.000Z |
| 41 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 42 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 41 | 43 | - id: 2 |
| 42 | 44 | title: "Assistant premier agent" |
| 43 | - state: open | |
| 45 | + state: closed | |
| 44 | 46 | priority: high |
| 45 | 47 | author: |
| 46 | 48 | name: k33g |
| 47 | 49 | email: ph.charriere@gmail.com |
| 48 | 50 | createdAt: 2026-10-29T07:20:31.000Z |
| 51 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 52 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 49 | 53 | - id: 3 |
| 50 | 54 | title: "Revue de tous les messages d'erreur" |
| 51 | - state: open | |
| 55 | + state: closed | |
| 52 | 56 | priority: medium |
| 53 | 57 | author: |
| 54 | 58 | name: k33g |
| 55 | 59 | email: ph.charriere@gmail.com |
| 56 | 60 | createdAt: 2026-10-29T07:20:31.000Z |
| 61 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 62 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 57 | 63 | - id: 4 |
| 58 | 64 | title: "Channel d'accueil" |
| 59 | - state: open | |
| 65 | + state: closed | |
| 60 | 66 | priority: medium |
| 61 | 67 | author: |
| 62 | 68 | name: k33g |
| 63 | 69 | email: ph.charriere@gmail.com |
| 64 | 70 | createdAt: 2026-10-29T07:20:31.000Z |
| 65 | -comments: [] | |
| 71 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 72 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 73 | +comments: | |
| 74 | + - id: 1 | |
| 75 | + author: | |
| 76 | + name: k33g | |
| 77 | + email: ph.charriere@gmail.com | |
| 78 | + createdAt: 2026-10-30T07:39:01.000Z | |
| 79 | + body: | | |
| 80 | + Livré sur la branche `feature/1st-release` (à valider sur le Mac, section 7 de [Dérouler les scénarios de bout en bout](docs/fr/how-to/derouler-les-scenarios-de-bout-en-bout.md)). | |
| 81 | + | |
| 82 | + - **États vides** : l'écran d'accueil reprend la maquette 6 (logo, trois étapes, « Ajouter mon premier agent », « Ouvrir une configuration… », chemin du fichier) ; le panneau Agents a un bouton « + Ajouter un agent ». | |
| 83 | + - **Assistant** : `ConfigService.AddAgent` (internal/app/newagent.go) écrit l'agent dans le YAML en gardant les commentaires (`config.AppendAgent`, emoji lisibles), crée son dossier, refuse sans rien écrire un résultat invalide ; local, conteneur Docker ou sandbox sbx ; `ChooseFolder` ouvre le sélecteur de dossier. La conversation directe s'ouvre une fois la configuration rechargée. | |
| 84 | + - **Messages d'erreur** : `frontend/src/lib/errors.ts` traduit les erreurs courantes (programme introuvable ou non exécutable, Docker arrêté, conteneur ou sandbox absents, limite d'agents, serveur de modèles injoignable, agent muet ou arrêté, protocole…) en phrases qui disent quoi faire, détails techniques repliés. | |
| 85 | + - **Channel d'accueil** : `#general` est déjà créé par la configuration par défaut ; inchangé. | |
| 86 | + - En plus : `internal/shellpath` donne à l'application le PATH du shell (app ouverte depuis le Finder). | |
| 87 | + | |
| 88 | + Docs : tutoriel « Votre premier agent, sans écrire de configuration », guide « Ajouter un agent », référence configuration (ce qu'écrit l'assistant), explication architecture (EN/FR). | |
| @@ -6,7 +6,7 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-29T07:20:31.000Z | 8 | createdAt: 2026-10-29T07:20:31.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:31.000Z | 9 | +updatedAt: 2026-10-30T07:39:01.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - "kind::feature" | 11 | - "kind::feature" |
| 12 | - "area::ui" | 12 | - "area::ui" |
| @@ -32,34 +32,57 @@ body: | | |||
| 32 | tasks: | 32 | tasks: |
| 33 | - id: 1 | 33 | - id: 1 |
| 34 | title: "États vides" | 34 | title: "États vides" |
| 35 | - state: open | 35 | + state: closed |
| 36 | priority: high | 36 | priority: high |
| 37 | author: | 37 | author: |
| 38 | name: k33g | 38 | name: k33g |
| 39 | email: ph.charriere@gmail.com | 39 | email: ph.charriere@gmail.com |
| 40 | createdAt: 2026-10-29T07:20:31.000Z | 40 | createdAt: 2026-10-29T07:20:31.000Z |
| 41 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 42 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 41 | - id: 2 | 43 | - id: 2 |
| 42 | title: "Assistant premier agent" | 44 | title: "Assistant premier agent" |
| 43 | - state: open | 45 | + state: closed |
| 44 | priority: high | 46 | priority: high |
| 45 | author: | 47 | author: |
| 46 | name: k33g | 48 | name: k33g |
| 47 | email: ph.charriere@gmail.com | 49 | email: ph.charriere@gmail.com |
| 48 | createdAt: 2026-10-29T07:20:31.000Z | 50 | createdAt: 2026-10-29T07:20:31.000Z |
| 51 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 52 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 49 | - id: 3 | 53 | - id: 3 |
| 50 | title: "Revue de tous les messages d'erreur" | 54 | title: "Revue de tous les messages d'erreur" |
| 51 | - state: open | 55 | + state: closed |
| 52 | priority: medium | 56 | priority: medium |
| 53 | author: | 57 | author: |
| 54 | name: k33g | 58 | name: k33g |
| 55 | email: ph.charriere@gmail.com | 59 | email: ph.charriere@gmail.com |
| 56 | createdAt: 2026-10-29T07:20:31.000Z | 60 | createdAt: 2026-10-29T07:20:31.000Z |
| 61 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 62 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 57 | - id: 4 | 63 | - id: 4 |
| 58 | title: "Channel d'accueil" | 64 | title: "Channel d'accueil" |
| 59 | - state: open | 65 | + state: closed |
| 60 | priority: medium | 66 | priority: medium |
| 61 | author: | 67 | author: |
| 62 | name: k33g | 68 | name: k33g |
| 63 | email: ph.charriere@gmail.com | 69 | email: ph.charriere@gmail.com |
| 64 | createdAt: 2026-10-29T07:20:31.000Z | 70 | createdAt: 2026-10-29T07:20:31.000Z |
| 65 | -comments: [] | 71 | + updatedAt: 2026-10-30T07:39:01.000Z |
| 72 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 73 | +comments: | ||
| 74 | + - id: 1 | ||
| 75 | + author: | ||
| 76 | + name: k33g | ||
| 77 | + email: ph.charriere@gmail.com | ||
| 78 | + createdAt: 2026-10-30T07:39:01.000Z | ||
| 79 | + body: | | ||
| 80 | + Livré sur la branche `feature/1st-release` (à valider sur le Mac, section 7 de [Dérouler les scénarios de bout en bout](docs/fr/how-to/derouler-les-scenarios-de-bout-en-bout.md)). | ||
| 81 | + | ||
| 82 | + - **États vides** : l'écran d'accueil reprend la maquette 6 (logo, trois étapes, « Ajouter mon premier agent », « Ouvrir une configuration… », chemin du fichier) ; le panneau Agents a un bouton « + Ajouter un agent ». | ||
| 83 | + - **Assistant** : `ConfigService.AddAgent` (internal/app/newagent.go) écrit l'agent dans le YAML en gardant les commentaires (`config.AppendAgent`, emoji lisibles), crée son dossier, refuse sans rien écrire un résultat invalide ; local, conteneur Docker ou sandbox sbx ; `ChooseFolder` ouvre le sélecteur de dossier. La conversation directe s'ouvre une fois la configuration rechargée. | ||
| 84 | + - **Messages d'erreur** : `frontend/src/lib/errors.ts` traduit les erreurs courantes (programme introuvable ou non exécutable, Docker arrêté, conteneur ou sandbox absents, limite d'agents, serveur de modèles injoignable, agent muet ou arrêté, protocole…) en phrases qui disent quoi faire, détails techniques repliés. | ||
| 85 | + - **Channel d'accueil** : `#general` est déjà créé par la configuration par défaut ; inchangé. | ||
| 86 | + - En plus : `internal/shellpath` donne à l'application le PATH du shell (app ouverte depuis le Finder). | ||
| 87 | + | ||
| 88 | + Docs : tutoriel « Votre premier agent, sans écrire de configuration », guide « Ajouter un agent », référence configuration (ce qu'écrit l'assistant), explication architecture (EN/FR). | ||
modified
.tickets/issues/0034-scenarios-de-test-de-bout-en-bout-avec-les-agent.yaml +11 -2 | @@ -6,7 +6,7 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-29T07:20:32.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:32.000Z | |
| 9 | +updatedAt: 2026-10-30T07:39:01.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - "kind::chore" |
| 12 | 12 | - "area::quality" |
| @@ -67,4 +67,13 @@ tasks: | ||
| 67 | 67 | name: k33g |
| 68 | 68 | email: ph.charriere@gmail.com |
| 69 | 69 | createdAt: 2026-10-29T07:20:32.000Z |
| 70 | -comments: [] | |
| 70 | +comments: | |
| 71 | + - id: 1 | |
| 72 | + author: | |
| 73 | + name: k33g | |
| 74 | + email: ph.charriere@gmail.com | |
| 75 | + createdAt: 2026-10-30T07:39:01.000Z | |
| 76 | + body: | | |
| 77 | + Le guide pas à pas est prêt (EN/FR) : [Dérouler les scénarios de bout en bout](docs/fr/how-to/derouler-les-scenarios-de-bout-en-bout.md) — les six scénarios du ticket, déchargement des modèles entre chacun (`scripts/agents.sh unload --all`), les vérifications de la v0.1 (section 7) et un modèle de rapport à coller ici. | |
| 78 | + | |
| 79 | + Reste à faire sur le Mac : dérouler les scénarios et poster le rapport (tâche 4). | |
| @@ -6,7 +6,7 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-29T07:20:32.000Z | 8 | createdAt: 2026-10-29T07:20:32.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:32.000Z | 9 | +updatedAt: 2026-10-30T07:39:01.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - "kind::chore" | 11 | - "kind::chore" |
| 12 | - "area::quality" | 12 | - "area::quality" |
| @@ -67,4 +67,13 @@ tasks: | |||
| 67 | name: k33g | 67 | name: k33g |
| 68 | email: ph.charriere@gmail.com | 68 | email: ph.charriere@gmail.com |
| 69 | createdAt: 2026-10-29T07:20:32.000Z | 69 | createdAt: 2026-10-29T07:20:32.000Z |
| 70 | -comments: [] | 70 | +comments: |
| 71 | + - id: 1 | ||
| 72 | + author: | ||
| 73 | + name: k33g | ||
| 74 | + email: ph.charriere@gmail.com | ||
| 75 | + createdAt: 2026-10-30T07:39:01.000Z | ||
| 76 | + body: | | ||
| 77 | + Le guide pas à pas est prêt (EN/FR) : [Dérouler les scénarios de bout en bout](docs/fr/how-to/derouler-les-scenarios-de-bout-en-bout.md) — les six scénarios du ticket, déchargement des modèles entre chacun (`scripts/agents.sh unload --all`), les vérifications de la v0.1 (section 7) et un modèle de rapport à coller ici. | ||
| 78 | + | ||
| 79 | + Reste à faire sur le Mac : dérouler les scénarios et poster le rapport (tâche 4). | ||
modified
.tickets/issues/0035-raccourcis-clavier-et-accessibilite.yaml +24 -5 | @@ -6,7 +6,7 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-29T07:20:33.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:33.000Z | |
| 9 | +updatedAt: 2026-10-30T07:39:01.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - "kind::feature" |
| 12 | 12 | - "area::ui" |
| @@ -26,26 +26,45 @@ body: | | ||
| 26 | 26 | tasks: |
| 27 | 27 | - id: 1 |
| 28 | 28 | title: "Raccourcis principaux" |
| 29 | - state: open | |
| 29 | + state: closed | |
| 30 | 30 | priority: medium |
| 31 | 31 | author: |
| 32 | 32 | name: k33g |
| 33 | 33 | email: ph.charriere@gmail.com |
| 34 | 34 | createdAt: 2026-10-29T07:20:33.000Z |
| 35 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 36 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 35 | 37 | - id: 2 |
| 36 | 38 | title: "Palette de commandes" |
| 37 | - state: open | |
| 39 | + state: closed | |
| 38 | 40 | priority: low |
| 39 | 41 | author: |
| 40 | 42 | name: k33g |
| 41 | 43 | email: ph.charriere@gmail.com |
| 42 | 44 | createdAt: 2026-10-29T07:20:33.000Z |
| 45 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 46 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 43 | 47 | - id: 3 |
| 44 | 48 | title: "Audit contrastes et navigation clavier" |
| 45 | - state: open | |
| 49 | + state: closed | |
| 46 | 50 | priority: medium |
| 47 | 51 | author: |
| 48 | 52 | name: k33g |
| 49 | 53 | email: ph.charriere@gmail.com |
| 50 | 54 | createdAt: 2026-10-29T07:20:33.000Z |
| 51 | -comments: [] | |
| 55 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 56 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 57 | +comments: | |
| 58 | + - id: 1 | |
| 59 | + author: | |
| 60 | + name: k33g | |
| 61 | + email: ph.charriere@gmail.com | |
| 62 | + createdAt: 2026-10-30T07:39:01.000Z | |
| 63 | + body: | | |
| 64 | + Livré sur la branche `feature/1st-release` (à valider sur le Mac, vérifications 7.5 et 7.6 du guide des scénarios). | |
| 65 | + | |
| 66 | + - **Raccourcis** (`frontend/src/lib/shortcuts.ts`, ⌘ sous macOS, Ctrl ailleurs) : ⌘K palette, ⌘N nouveau channel, ⇧⌘N ajouter un agent, ⌘L zone de message, ⌘B dock gauche, ⌘, Settings, ⌘J journal. Sous Linux/Windows, le terminal garde ses Ctrl. | |
| 67 | + - **Palette de commandes** (`CommandPalette.svelte`) : channels, conversations et fichiers des agents, actions ; recherche floue, ↑↓ Entrée Échap, rôles ARIA combobox/listbox. | |
| 68 | + - **Audit** : test de contraste WCAG AA (`lib/contrast.test.ts`) sur les couleurs du thème lues dans `style.css` ; quatre couleurs du thème clair assombries pour passer 4.5:1 ; `:focus-visible` partout. | |
| 69 | + | |
| 70 | + Docs : référence « Raccourcis clavier » (EN/FR). | |
| @@ -6,7 +6,7 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-29T07:20:33.000Z | 8 | createdAt: 2026-10-29T07:20:33.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:33.000Z | 9 | +updatedAt: 2026-10-30T07:39:01.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - "kind::feature" | 11 | - "kind::feature" |
| 12 | - "area::ui" | 12 | - "area::ui" |
| @@ -26,26 +26,45 @@ body: | | |||
| 26 | tasks: | 26 | tasks: |
| 27 | - id: 1 | 27 | - id: 1 |
| 28 | title: "Raccourcis principaux" | 28 | title: "Raccourcis principaux" |
| 29 | - state: open | 29 | + state: closed |
| 30 | priority: medium | 30 | priority: medium |
| 31 | author: | 31 | author: |
| 32 | name: k33g | 32 | name: k33g |
| 33 | email: ph.charriere@gmail.com | 33 | email: ph.charriere@gmail.com |
| 34 | createdAt: 2026-10-29T07:20:33.000Z | 34 | createdAt: 2026-10-29T07:20:33.000Z |
| 35 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 36 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 35 | - id: 2 | 37 | - id: 2 |
| 36 | title: "Palette de commandes" | 38 | title: "Palette de commandes" |
| 37 | - state: open | 39 | + state: closed |
| 38 | priority: low | 40 | priority: low |
| 39 | author: | 41 | author: |
| 40 | name: k33g | 42 | name: k33g |
| 41 | email: ph.charriere@gmail.com | 43 | email: ph.charriere@gmail.com |
| 42 | createdAt: 2026-10-29T07:20:33.000Z | 44 | createdAt: 2026-10-29T07:20:33.000Z |
| 45 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 46 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 43 | - id: 3 | 47 | - id: 3 |
| 44 | title: "Audit contrastes et navigation clavier" | 48 | title: "Audit contrastes et navigation clavier" |
| 45 | - state: open | 49 | + state: closed |
| 46 | priority: medium | 50 | priority: medium |
| 47 | author: | 51 | author: |
| 48 | name: k33g | 52 | name: k33g |
| 49 | email: ph.charriere@gmail.com | 53 | email: ph.charriere@gmail.com |
| 50 | createdAt: 2026-10-29T07:20:33.000Z | 54 | createdAt: 2026-10-29T07:20:33.000Z |
| 51 | -comments: [] | 55 | + updatedAt: 2026-10-30T07:39:01.000Z |
| 56 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 57 | +comments: | ||
| 58 | + - id: 1 | ||
| 59 | + author: | ||
| 60 | + name: k33g | ||
| 61 | + email: ph.charriere@gmail.com | ||
| 62 | + createdAt: 2026-10-30T07:39:01.000Z | ||
| 63 | + body: | | ||
| 64 | + Livré sur la branche `feature/1st-release` (à valider sur le Mac, vérifications 7.5 et 7.6 du guide des scénarios). | ||
| 65 | + | ||
| 66 | + - **Raccourcis** (`frontend/src/lib/shortcuts.ts`, ⌘ sous macOS, Ctrl ailleurs) : ⌘K palette, ⌘N nouveau channel, ⇧⌘N ajouter un agent, ⌘L zone de message, ⌘B dock gauche, ⌘, Settings, ⌘J journal. Sous Linux/Windows, le terminal garde ses Ctrl. | ||
| 67 | + - **Palette de commandes** (`CommandPalette.svelte`) : channels, conversations et fichiers des agents, actions ; recherche floue, ↑↓ Entrée Échap, rôles ARIA combobox/listbox. | ||
| 68 | + - **Audit** : test de contraste WCAG AA (`lib/contrast.test.ts`) sur les couleurs du thème lues dans `style.css` ; quatre couleurs du thème clair assombries pour passer 4.5:1 ; `:focus-visible` partout. | ||
| 69 | + | ||
| 70 | + Docs : référence « Raccourcis clavier » (EN/FR). | ||
modified
.tickets/issues/0036-packaging-et-distribution-macos.yaml +30 -6 | @@ -6,7 +6,7 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-29T07:20:34.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:34.000Z | |
| 9 | +updatedAt: 2026-10-30T07:39:01.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - "kind::chore" |
| 12 | 12 | - "area::infra" |
| @@ -29,34 +29,58 @@ body: | | ||
| 29 | 29 | tasks: |
| 30 | 30 | - id: 1 |
| 31 | 31 | title: "Build universel macOS" |
| 32 | - state: open | |
| 32 | + state: closed | |
| 33 | 33 | priority: high |
| 34 | 34 | author: |
| 35 | 35 | name: k33g |
| 36 | 36 | email: ph.charriere@gmail.com |
| 37 | 37 | createdAt: 2026-10-29T07:20:34.000Z |
| 38 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 39 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 38 | 40 | - id: 2 |
| 39 | 41 | title: "Icône et métadonnées" |
| 40 | - state: open | |
| 42 | + state: closed | |
| 41 | 43 | priority: medium |
| 42 | 44 | author: |
| 43 | 45 | name: k33g |
| 44 | 46 | email: ph.charriere@gmail.com |
| 45 | 47 | createdAt: 2026-10-29T07:20:34.000Z |
| 48 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 49 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 46 | 50 | - id: 3 |
| 47 | 51 | title: "Signature et notarisation (si possible)" |
| 48 | - state: open | |
| 52 | + state: closed | |
| 49 | 53 | priority: medium |
| 50 | 54 | author: |
| 51 | 55 | name: k33g |
| 52 | 56 | email: ph.charriere@gmail.com |
| 53 | 57 | createdAt: 2026-10-29T07:20:34.000Z |
| 58 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 59 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 54 | 60 | - id: 4 |
| 55 | 61 | title: "Vérification des prérequis au démarrage" |
| 56 | - state: open | |
| 62 | + state: closed | |
| 57 | 63 | priority: medium |
| 58 | 64 | author: |
| 59 | 65 | name: k33g |
| 60 | 66 | email: ph.charriere@gmail.com |
| 61 | 67 | createdAt: 2026-10-29T07:20:34.000Z |
| 62 | -comments: [] | |
| 68 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 69 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 70 | +comments: | |
| 71 | + - id: 1 | |
| 72 | + author: | |
| 73 | + name: k33g | |
| 74 | + email: ph.charriere@gmail.com | |
| 75 | + createdAt: 2026-10-30T07:39:01.000Z | |
| 76 | + body: | | |
| 77 | + Livré sur la branche `feature/1st-release`, avec l'élargissement demandé (Linux, Windows et workflow de release). | |
| 78 | + | |
| 79 | + - **Version 0.1.0** dans `build/config.yml`, métadonnées régénérées (Info.plist, ressources Windows, nfpm) ; icône Orbite. | |
| 80 | + - **macOS** : `make package-macos` → `.dmg` et `.zip` universels (arm64 + amd64, signés ad hoc). Pas de compte Apple Developer : pas de notarisation ; procédure Gatekeeper documentée (« Ouvrir quand même », ou `xattr`). | |
| 81 | + - **Linux** : `make package-linux` → `.deb`, `.rpm`, `.AppImage`, `.tar.gz` (vérifiés en arm64 dans la sandbox ; l'AppImage démarre). Licence, page d'accueil et entrée de bureau corrigées. | |
| 82 | + - **Windows** : `make package-windows` → installateur NSIS (avec WebView2) et `.zip`, compilés depuis Linux. Limite : pas d'onglet Terminal sous Windows. | |
| 83 | + - **Workflow** `.github/workflows/release.yml` : à la publication d'une release, vérifie tag = version, `make check`, construit Linux amd64 et Windows, `SHA256SUMS`, attache le tout à la release. Les runners de Rickub sont Linux x86-64 seulement : les paquets macOS se construisent sur le Mac et s'attachent à la main. | |
| 84 | + - **Prérequis au démarrage** : le PATH du shell est lu au lancement (`internal/shellpath`), les avertissements « programme introuvable » sont calculés avec lui, et l'erreur au démarrage d'un agent dit quoi faire. | |
| 85 | + | |
| 86 | + Docs : « Installer Sidekicks », « Publier une release », référence commandes (`package-*`, `scripts/package.sh`, workflows) (EN/FR). | |
| @@ -6,7 +6,7 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-29T07:20:34.000Z | 8 | createdAt: 2026-10-29T07:20:34.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:34.000Z | 9 | +updatedAt: 2026-10-30T07:39:01.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - "kind::chore" | 11 | - "kind::chore" |
| 12 | - "area::infra" | 12 | - "area::infra" |
| @@ -29,34 +29,58 @@ body: | | |||
| 29 | tasks: | 29 | tasks: |
| 30 | - id: 1 | 30 | - id: 1 |
| 31 | title: "Build universel macOS" | 31 | title: "Build universel macOS" |
| 32 | - state: open | 32 | + state: closed |
| 33 | priority: high | 33 | priority: high |
| 34 | author: | 34 | author: |
| 35 | name: k33g | 35 | name: k33g |
| 36 | email: ph.charriere@gmail.com | 36 | email: ph.charriere@gmail.com |
| 37 | createdAt: 2026-10-29T07:20:34.000Z | 37 | createdAt: 2026-10-29T07:20:34.000Z |
| 38 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 39 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 38 | - id: 2 | 40 | - id: 2 |
| 39 | title: "Icône et métadonnées" | 41 | title: "Icône et métadonnées" |
| 40 | - state: open | 42 | + state: closed |
| 41 | priority: medium | 43 | priority: medium |
| 42 | author: | 44 | author: |
| 43 | name: k33g | 45 | name: k33g |
| 44 | email: ph.charriere@gmail.com | 46 | email: ph.charriere@gmail.com |
| 45 | createdAt: 2026-10-29T07:20:34.000Z | 47 | createdAt: 2026-10-29T07:20:34.000Z |
| 48 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 49 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 46 | - id: 3 | 50 | - id: 3 |
| 47 | title: "Signature et notarisation (si possible)" | 51 | title: "Signature et notarisation (si possible)" |
| 48 | - state: open | 52 | + state: closed |
| 49 | priority: medium | 53 | priority: medium |
| 50 | author: | 54 | author: |
| 51 | name: k33g | 55 | name: k33g |
| 52 | email: ph.charriere@gmail.com | 56 | email: ph.charriere@gmail.com |
| 53 | createdAt: 2026-10-29T07:20:34.000Z | 57 | createdAt: 2026-10-29T07:20:34.000Z |
| 58 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 59 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 54 | - id: 4 | 60 | - id: 4 |
| 55 | title: "Vérification des prérequis au démarrage" | 61 | title: "Vérification des prérequis au démarrage" |
| 56 | - state: open | 62 | + state: closed |
| 57 | priority: medium | 63 | priority: medium |
| 58 | author: | 64 | author: |
| 59 | name: k33g | 65 | name: k33g |
| 60 | email: ph.charriere@gmail.com | 66 | email: ph.charriere@gmail.com |
| 61 | createdAt: 2026-10-29T07:20:34.000Z | 67 | createdAt: 2026-10-29T07:20:34.000Z |
| 62 | -comments: [] | 68 | + updatedAt: 2026-10-30T07:39:01.000Z |
| 69 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 70 | +comments: | ||
| 71 | + - id: 1 | ||
| 72 | + author: | ||
| 73 | + name: k33g | ||
| 74 | + email: ph.charriere@gmail.com | ||
| 75 | + createdAt: 2026-10-30T07:39:01.000Z | ||
| 76 | + body: | | ||
| 77 | + Livré sur la branche `feature/1st-release`, avec l'élargissement demandé (Linux, Windows et workflow de release). | ||
| 78 | + | ||
| 79 | + - **Version 0.1.0** dans `build/config.yml`, métadonnées régénérées (Info.plist, ressources Windows, nfpm) ; icône Orbite. | ||
| 80 | + - **macOS** : `make package-macos` → `.dmg` et `.zip` universels (arm64 + amd64, signés ad hoc). Pas de compte Apple Developer : pas de notarisation ; procédure Gatekeeper documentée (« Ouvrir quand même », ou `xattr`). | ||
| 81 | + - **Linux** : `make package-linux` → `.deb`, `.rpm`, `.AppImage`, `.tar.gz` (vérifiés en arm64 dans la sandbox ; l'AppImage démarre). Licence, page d'accueil et entrée de bureau corrigées. | ||
| 82 | + - **Windows** : `make package-windows` → installateur NSIS (avec WebView2) et `.zip`, compilés depuis Linux. Limite : pas d'onglet Terminal sous Windows. | ||
| 83 | + - **Workflow** `.github/workflows/release.yml` : à la publication d'une release, vérifie tag = version, `make check`, construit Linux amd64 et Windows, `SHA256SUMS`, attache le tout à la release. Les runners de Rickub sont Linux x86-64 seulement : les paquets macOS se construisent sur le Mac et s'attachent à la main. | ||
| 84 | + - **Prérequis au démarrage** : le PATH du shell est lu au lancement (`internal/shellpath`), les avertissements « programme introuvable » sont calculés avec lui, et l'erreur au démarrage d'un agent dit quoi faire. | ||
| 85 | + | ||
| 86 | + Docs : « Installer Sidekicks », « Publier une release », référence commandes (`package-*`, `scripts/package.sh`, workflows) (EN/FR). | ||
modified
.tickets/issues/0037-documentation-utilisateur-et-developpeur.yaml +26 -6 | @@ -6,7 +6,7 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-29T07:20:35.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:35.000Z | |
| 9 | +updatedAt: 2026-10-30T07:39:01.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - "kind::chore" |
| 12 | 12 | - "documentation" |
| @@ -33,34 +33,54 @@ body: | | ||
| 33 | 33 | tasks: |
| 34 | 34 | - id: 1 |
| 35 | 35 | title: "Tutoriel première conversation" |
| 36 | - state: open | |
| 36 | + state: closed | |
| 37 | 37 | priority: high |
| 38 | 38 | author: |
| 39 | 39 | name: k33g |
| 40 | 40 | email: ph.charriere@gmail.com |
| 41 | 41 | createdAt: 2026-10-29T07:20:35.000Z |
| 42 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 43 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 42 | 44 | - id: 2 |
| 43 | 45 | title: "Guides pratiques" |
| 44 | - state: open | |
| 46 | + state: closed | |
| 45 | 47 | priority: medium |
| 46 | 48 | author: |
| 47 | 49 | name: k33g |
| 48 | 50 | email: ph.charriere@gmail.com |
| 49 | 51 | createdAt: 2026-10-29T07:20:35.000Z |
| 52 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 53 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 50 | 54 | - id: 3 |
| 51 | 55 | title: "Référence de la configuration" |
| 52 | - state: open | |
| 56 | + state: closed | |
| 53 | 57 | priority: high |
| 54 | 58 | author: |
| 55 | 59 | name: k33g |
| 56 | 60 | email: ph.charriere@gmail.com |
| 57 | 61 | createdAt: 2026-10-29T07:20:35.000Z |
| 62 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 63 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 58 | 64 | - id: 4 |
| 59 | 65 | title: "Explications et architecture" |
| 60 | - state: open | |
| 66 | + state: closed | |
| 61 | 67 | priority: medium |
| 62 | 68 | author: |
| 63 | 69 | name: k33g |
| 64 | 70 | email: ph.charriere@gmail.com |
| 65 | 71 | createdAt: 2026-10-29T07:20:35.000Z |
| 66 | -comments: [] | |
| 72 | + updatedAt: 2026-10-30T07:39:01.000Z | |
| 73 | + closedAt: 2026-10-30T07:39:01.000Z | |
| 74 | +comments: | |
| 75 | + - id: 1 | |
| 76 | + author: | |
| 77 | + name: k33g | |
| 78 | + email: ph.charriere@gmail.com | |
| 79 | + createdAt: 2026-10-30T07:39:01.000Z | |
| 80 | + body: | | |
| 81 | + Livré sur la branche `feature/1st-release`. Contenu minimal du ticket, en anglais et en français : | |
| 82 | + | |
| 83 | + - **Tutoriel** : « Votre première conversation avec un agent » existait ; ajout de « Votre premier agent, sans écrire de configuration » (application installée + assistant). | |
| 84 | + - **Guides** : « Ajouter un agent » (nouveau), « Lancer un agent dans une sandbox sbx » et « Gérer les channels et leurs agents » (existants), plus « Installer Sidekicks », « Publier une release », « Dérouler les scénarios de bout en bout ». | |
| 85 | + - **Référence** : configuration (section « Ce qu'écrit l'assistant »), « Raccourcis clavier » (nouvelle), commandes (packaging, workflows). | |
| 86 | + - **Explications** : « Pourquoi ACP » et « Architecture » (existantes) ; architecture complétée (PATH du shell, erreurs en phrases claires) ; schéma des packages avec `internal/shellpath`. | |
| @@ -6,7 +6,7 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-29T07:20:35.000Z | 8 | createdAt: 2026-10-29T07:20:35.000Z |
| 9 | -updatedAt: 2026-10-29T07:20:35.000Z | 9 | +updatedAt: 2026-10-30T07:39:01.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - "kind::chore" | 11 | - "kind::chore" |
| 12 | - "documentation" | 12 | - "documentation" |
| @@ -33,34 +33,54 @@ body: | | |||
| 33 | tasks: | 33 | tasks: |
| 34 | - id: 1 | 34 | - id: 1 |
| 35 | title: "Tutoriel première conversation" | 35 | title: "Tutoriel première conversation" |
| 36 | - state: open | 36 | + state: closed |
| 37 | priority: high | 37 | priority: high |
| 38 | author: | 38 | author: |
| 39 | name: k33g | 39 | name: k33g |
| 40 | email: ph.charriere@gmail.com | 40 | email: ph.charriere@gmail.com |
| 41 | createdAt: 2026-10-29T07:20:35.000Z | 41 | createdAt: 2026-10-29T07:20:35.000Z |
| 42 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 43 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 42 | - id: 2 | 44 | - id: 2 |
| 43 | title: "Guides pratiques" | 45 | title: "Guides pratiques" |
| 44 | - state: open | 46 | + state: closed |
| 45 | priority: medium | 47 | priority: medium |
| 46 | author: | 48 | author: |
| 47 | name: k33g | 49 | name: k33g |
| 48 | email: ph.charriere@gmail.com | 50 | email: ph.charriere@gmail.com |
| 49 | createdAt: 2026-10-29T07:20:35.000Z | 51 | createdAt: 2026-10-29T07:20:35.000Z |
| 52 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 53 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 50 | - id: 3 | 54 | - id: 3 |
| 51 | title: "Référence de la configuration" | 55 | title: "Référence de la configuration" |
| 52 | - state: open | 56 | + state: closed |
| 53 | priority: high | 57 | priority: high |
| 54 | author: | 58 | author: |
| 55 | name: k33g | 59 | name: k33g |
| 56 | email: ph.charriere@gmail.com | 60 | email: ph.charriere@gmail.com |
| 57 | createdAt: 2026-10-29T07:20:35.000Z | 61 | createdAt: 2026-10-29T07:20:35.000Z |
| 62 | + updatedAt: 2026-10-30T07:39:01.000Z | ||
| 63 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 58 | - id: 4 | 64 | - id: 4 |
| 59 | title: "Explications et architecture" | 65 | title: "Explications et architecture" |
| 60 | - state: open | 66 | + state: closed |
| 61 | priority: medium | 67 | priority: medium |
| 62 | author: | 68 | author: |
| 63 | name: k33g | 69 | name: k33g |
| 64 | email: ph.charriere@gmail.com | 70 | email: ph.charriere@gmail.com |
| 65 | createdAt: 2026-10-29T07:20:35.000Z | 71 | createdAt: 2026-10-29T07:20:35.000Z |
| 66 | -comments: [] | 72 | + updatedAt: 2026-10-30T07:39:01.000Z |
| 73 | + closedAt: 2026-10-30T07:39:01.000Z | ||
| 74 | +comments: | ||
| 75 | + - id: 1 | ||
| 76 | + author: | ||
| 77 | + name: k33g | ||
| 78 | + email: ph.charriere@gmail.com | ||
| 79 | + createdAt: 2026-10-30T07:39:01.000Z | ||
| 80 | + body: | | ||
| 81 | + Livré sur la branche `feature/1st-release`. Contenu minimal du ticket, en anglais et en français : | ||
| 82 | + | ||
| 83 | + - **Tutoriel** : « Votre première conversation avec un agent » existait ; ajout de « Votre premier agent, sans écrire de configuration » (application installée + assistant). | ||
| 84 | + - **Guides** : « Ajouter un agent » (nouveau), « Lancer un agent dans une sandbox sbx » et « Gérer les channels et leurs agents » (existants), plus « Installer Sidekicks », « Publier une release », « Dérouler les scénarios de bout en bout ». | ||
| 85 | + - **Référence** : configuration (section « Ce qu'écrit l'assistant »), « Raccourcis clavier » (nouvelle), commandes (packaging, workflows). | ||
| 86 | + - **Explications** : « Pourquoi ACP » et « Architecture » (existantes) ; architecture complétée (PATH du shell, erreurs en phrases claires) ; schéma des packages avec `internal/shellpath`. | ||
modified
Makefile +18 -1 | @@ -6,7 +6,7 @@ | ||
| 6 | 6 | GOLANGCI_LINT := go tool -modfile=tools/go.mod golangci-lint |
| 7 | 7 | PNPM := pnpm --dir frontend |
| 8 | 8 | |
| 9 | -.PHONY: help install bindings frontend dev build package install-test-config \ | |
| 9 | +.PHONY: help install bindings frontend dev build package package-linux package-windows package-macos release-build release-tag install-test-config \ | |
| 10 | 10 | check test test-go test-frontend test-scripts test-real \ |
| 11 | 11 | lint lint-go lint-frontend lint-headers bindings-check |
| 12 | 12 | |
| @@ -37,6 +37,21 @@ build: ## Build the application into bin/ | ||
| 37 | 37 | package: ## Package the application (macOS: bin/sidekicks.app) |
| 38 | 38 | @wails3 package |
| 39 | 39 | |
| 40 | +package-linux: ## Release packages for Linux (deb, rpm, AppImage, tar.gz) into dist/ | |
| 41 | + @scripts/package.sh linux | |
| 42 | + | |
| 43 | +package-windows: ## Release packages for Windows amd64 (installer, zip) into dist/, cross-built | |
| 44 | + @scripts/package.sh windows | |
| 45 | + | |
| 46 | +package-macos: ## Release packages for macOS (universal dmg, zip) into dist/; on macOS only | |
| 47 | + @scripts/package.sh macos | |
| 48 | + | |
| 49 | +release-build: ## On the Mac: every release package (macOS, Windows, Linux in Docker) and SHA256SUMS into dist/ | |
| 50 | + @scripts/build-release.sh | |
| 51 | + | |
| 52 | +release-tag: ## Tag v<version> on main and push it: the Release workflow creates the release | |
| 53 | + @scripts/tag-release.sh | |
| 54 | + | |
| 40 | 55 | install-test-config: ## Write the test agents configuration at the default location (absolute paths) |
| 41 | 56 | @scripts/install-test-config.sh |
| 42 | 57 | |
| @@ -56,6 +71,8 @@ test-frontend: ## Frontend unit tests (vitest) | ||
| 56 | 71 | test-scripts: ## Tests of the shell tooling |
| 57 | 72 | @scripts/agents_test.sh |
| 58 | 73 | @scripts/check-license-headers_test.sh |
| 74 | + @scripts/package_test.sh | |
| 75 | + @scripts/tag-release_test.sh | |
| 59 | 76 | |
| 60 | 77 | test-real: ## Tests against the real mm agents (needs mm and llmman; 2 agents at most) |
| 61 | 78 | @go test -tags realagents -count=1 ./... |
| @@ -6,7 +6,7 @@ | |||
| 6 | GOLANGCI_LINT := go tool -modfile=tools/go.mod golangci-lint | 6 | GOLANGCI_LINT := go tool -modfile=tools/go.mod golangci-lint |
| 7 | PNPM := pnpm --dir frontend | 7 | PNPM := pnpm --dir frontend |
| 8 | 8 | ||
| 9 | -.PHONY: help install bindings frontend dev build package install-test-config \ | 9 | +.PHONY: help install bindings frontend dev build package package-linux package-windows package-macos release-build release-tag install-test-config \ |
| 10 | check test test-go test-frontend test-scripts test-real \ | 10 | check test test-go test-frontend test-scripts test-real \ |
| 11 | lint lint-go lint-frontend lint-headers bindings-check | 11 | lint lint-go lint-frontend lint-headers bindings-check |
| 12 | 12 | ||
| @@ -37,6 +37,21 @@ build: ## Build the application into bin/ | |||
| 37 | package: ## Package the application (macOS: bin/sidekicks.app) | 37 | package: ## Package the application (macOS: bin/sidekicks.app) |
| 38 | @wails3 package | 38 | @wails3 package |
| 39 | 39 | ||
| 40 | +package-linux: ## Release packages for Linux (deb, rpm, AppImage, tar.gz) into dist/ | ||
| 41 | + @scripts/package.sh linux | ||
| 42 | + | ||
| 43 | +package-windows: ## Release packages for Windows amd64 (installer, zip) into dist/, cross-built | ||
| 44 | + @scripts/package.sh windows | ||
| 45 | + | ||
| 46 | +package-macos: ## Release packages for macOS (universal dmg, zip) into dist/; on macOS only | ||
| 47 | + @scripts/package.sh macos | ||
| 48 | + | ||
| 49 | +release-build: ## On the Mac: every release package (macOS, Windows, Linux in Docker) and SHA256SUMS into dist/ | ||
| 50 | + @scripts/build-release.sh | ||
| 51 | + | ||
| 52 | +release-tag: ## Tag v<version> on main and push it: the Release workflow creates the release | ||
| 53 | + @scripts/tag-release.sh | ||
| 54 | + | ||
| 40 | install-test-config: ## Write the test agents configuration at the default location (absolute paths) | 55 | install-test-config: ## Write the test agents configuration at the default location (absolute paths) |
| 41 | @scripts/install-test-config.sh | 56 | @scripts/install-test-config.sh |
| 42 | 57 | ||
| @@ -56,6 +71,8 @@ test-frontend: ## Frontend unit tests (vitest) | |||
| 56 | test-scripts: ## Tests of the shell tooling | 71 | test-scripts: ## Tests of the shell tooling |
| 57 | @scripts/agents_test.sh | 72 | @scripts/agents_test.sh |
| 58 | @scripts/check-license-headers_test.sh | 73 | @scripts/check-license-headers_test.sh |
| 74 | + @scripts/package_test.sh | ||
| 75 | + @scripts/tag-release_test.sh | ||
| 59 | 76 | ||
| 60 | test-real: ## Tests against the real mm agents (needs mm and llmman; 2 agents at most) | 77 | test-real: ## Tests against the real mm agents (needs mm and llmman; 2 agents at most) |
| 61 | @go test -tags realagents -count=1 ./... | 78 | @go test -tags realagents -count=1 ./... |
modified
README.md +14 -3 | @@ -1,10 +1,19 @@ | ||
| 1 | +<p align="center"> | |
| 2 | + <picture> | |
| 3 | + <source media="(prefers-color-scheme: dark)" srcset="docs/design/logo/sidekicks-mark-dark.svg"> | |
| 4 | + <img src="docs/design/logo/sidekicks-mark.svg" alt="Sidekicks logo: a centre dot with two small dots in orbit" width="120"> | |
| 5 | + </picture> | |
| 6 | +</p> | |
| 7 | + | |
| 1 | 8 | # Sidekicks |
| 2 | 9 | |
| 3 | 10 | A desktop application to talk with AI agents in channels, for people who are not developers. Agents are reached through the [Agent Client Protocol](https://agentclientprotocol.com) (ACP), so any ACP agent can join. Built with Go and [Wails v3](https://wails.io), interface in Svelte 5. |
| 4 | 11 | |
| 5 | -> **Status — milestone M4 (Agents' workspace)**: channels kept from one launch to the next, several agents per channel with `@` mentions, agent commands with `/`, direct conversations, and each agent's folder with an editor and a terminal (local or Docker container); answers stream as Markdown with coloured code, tool calls ask permission in plain words, and the configuration is edited from the window. Backlog and roadmap: `.tickets/` (IssueSpec). | |
| 12 | +> **Status — version 0.1, the first release**: packages for macOS, Linux and Windows; an assistant adds agents (on this computer, in Docker or in an sbx sandbox) without writing YAML; channels kept from one launch to the next, several agents per channel with `@` mentions, agent commands with `/`, direct conversations, each agent's folder with an editor and a terminal; answers stream as Markdown with coloured code, tool calls ask permission in plain words, errors say what to do, and a command palette (⌘K) and shortcuts drive it from the keyboard. Backlog and roadmap: `.tickets/` (IssueSpec). | |
| 13 | + | |
| 14 | +**Install**: download the package for your system from the [releases](https://rickub.com/bots-garden/sidekicks/releases), then follow [How to install Sidekicks](docs/en/how-to/install-sidekicks.md). | |
| 6 | 15 | |
| 7 | -Documentation: [English](docs/en/README.md) · [Français](docs/fr/README.md) · [decisions (ADR)](docs/adr/) · [wireframes](docs/design/README.md) | |
| 16 | +Documentation: [English](docs/en/README.md) · [Français](docs/fr/README.md) · [decisions (ADR)](docs/adr/) · [wireframes](docs/design/README.md) · [releasing](RELEASING.md) | |
| 8 | 17 | |
| 9 | 18 | ## Develop |
| 10 | 19 | |
| @@ -15,6 +24,7 @@ make install # frontend dependencies (macOS and Linux binaries side by sid | ||
| 15 | 24 | make dev # run the application with hot reload |
| 16 | 25 | make check # lint + every test, as the CI does |
| 17 | 26 | make package # macOS: bin/sidekicks.app |
| 27 | +make package-linux # release packages into dist/ (also package-windows, package-macos) | |
| 18 | 28 | make help # every target |
| 19 | 29 | ``` |
| 20 | 30 | |
| @@ -40,9 +50,10 @@ Details: [How to develop the application](docs/en/how-to/develop-the-application | ||
| 40 | 50 | | `internal/acp` | ACP v1 client over stdio (wraps `coder/acp-go-sdk`) | |
| 41 | 51 | | `internal/config` | Configuration file: load, validate, locate, create, save, watch | |
| 42 | 52 | | `internal/events` | Events sent from Go to the interface | |
| 53 | +| `internal/shellpath` | The `PATH` of the user's shell, for an application opened from the Finder | | |
| 43 | 54 | | `schema` | JSON Schema of the configuration file | |
| 44 | 55 | | `frontend` | Svelte 5 interface: panels, shell, state | |
| 45 | -| `scripts` | Test-agent tooling (`agents.sh`), licence header check | | |
| 56 | +| `scripts` | Test-agent tooling (`agents.sh`), licence header check, release packages (`package.sh`) | | |
| 46 | 57 | | `agents`, `examples` | The four test agents and a configuration using them | |
| 47 | 58 | | `spikes` | Throwaway prototypes of milestone Initialize | |
| 48 | 59 | |
| @@ -1,10 +1,19 @@ | |||
| 1 | +<p align="center"> | ||
| 2 | + <picture> | ||
| 3 | + <source media="(prefers-color-scheme: dark)" srcset="docs/design/logo/sidekicks-mark-dark.svg"> | ||
| 4 | + <img src="docs/design/logo/sidekicks-mark.svg" alt="Sidekicks logo: a centre dot with two small dots in orbit" width="120"> | ||
| 5 | + </picture> | ||
| 6 | +</p> | ||
| 7 | + | ||
| 1 | # Sidekicks | 8 | # Sidekicks |
| 2 | 9 | ||
| 3 | A desktop application to talk with AI agents in channels, for people who are not developers. Agents are reached through the [Agent Client Protocol](https://agentclientprotocol.com) (ACP), so any ACP agent can join. Built with Go and [Wails v3](https://wails.io), interface in Svelte 5. | 10 | A desktop application to talk with AI agents in channels, for people who are not developers. Agents are reached through the [Agent Client Protocol](https://agentclientprotocol.com) (ACP), so any ACP agent can join. Built with Go and [Wails v3](https://wails.io), interface in Svelte 5. |
| 4 | 11 | ||
| 5 | -> **Status — milestone M4 (Agents' workspace)**: channels kept from one launch to the next, several agents per channel with `@` mentions, agent commands with `/`, direct conversations, and each agent's folder with an editor and a terminal (local or Docker container); answers stream as Markdown with coloured code, tool calls ask permission in plain words, and the configuration is edited from the window. Backlog and roadmap: `.tickets/` (IssueSpec). | 12 | +> **Status — version 0.1, the first release**: packages for macOS, Linux and Windows; an assistant adds agents (on this computer, in Docker or in an sbx sandbox) without writing YAML; channels kept from one launch to the next, several agents per channel with `@` mentions, agent commands with `/`, direct conversations, each agent's folder with an editor and a terminal; answers stream as Markdown with coloured code, tool calls ask permission in plain words, errors say what to do, and a command palette (⌘K) and shortcuts drive it from the keyboard. Backlog and roadmap: `.tickets/` (IssueSpec). |
| 13 | + | ||
| 14 | +**Install**: download the package for your system from the [releases](https://rickub.com/bots-garden/sidekicks/releases), then follow [How to install Sidekicks](docs/en/how-to/install-sidekicks.md). | ||
| 6 | 15 | ||
| 7 | -Documentation: [English](docs/en/README.md) · [Français](docs/fr/README.md) · [decisions (ADR)](docs/adr/) · [wireframes](docs/design/README.md) | 16 | +Documentation: [English](docs/en/README.md) · [Français](docs/fr/README.md) · [decisions (ADR)](docs/adr/) · [wireframes](docs/design/README.md) · [releasing](RELEASING.md) |
| 8 | 17 | ||
| 9 | ## Develop | 18 | ## Develop |
| 10 | 19 | ||
| @@ -15,6 +24,7 @@ make install # frontend dependencies (macOS and Linux binaries side by sid | |||
| 15 | make dev # run the application with hot reload | 24 | make dev # run the application with hot reload |
| 16 | make check # lint + every test, as the CI does | 25 | make check # lint + every test, as the CI does |
| 17 | make package # macOS: bin/sidekicks.app | 26 | make package # macOS: bin/sidekicks.app |
| 27 | +make package-linux # release packages into dist/ (also package-windows, package-macos) | ||
| 18 | make help # every target | 28 | make help # every target |
| 19 | ``` | 29 | ``` |
| 20 | 30 | ||
| @@ -40,9 +50,10 @@ Details: [How to develop the application](docs/en/how-to/develop-the-application | |||
| 40 | | `internal/acp` | ACP v1 client over stdio (wraps `coder/acp-go-sdk`) | | 50 | | `internal/acp` | ACP v1 client over stdio (wraps `coder/acp-go-sdk`) | |
| 41 | | `internal/config` | Configuration file: load, validate, locate, create, save, watch | | 51 | | `internal/config` | Configuration file: load, validate, locate, create, save, watch | |
| 42 | | `internal/events` | Events sent from Go to the interface | | 52 | | `internal/events` | Events sent from Go to the interface | |
| 53 | +| `internal/shellpath` | The `PATH` of the user's shell, for an application opened from the Finder | | ||
| 43 | | `schema` | JSON Schema of the configuration file | | 54 | | `schema` | JSON Schema of the configuration file | |
| 44 | | `frontend` | Svelte 5 interface: panels, shell, state | | 55 | | `frontend` | Svelte 5 interface: panels, shell, state | |
| 45 | -| `scripts` | Test-agent tooling (`agents.sh`), licence header check | | 56 | +| `scripts` | Test-agent tooling (`agents.sh`), licence header check, release packages (`package.sh`) | |
| 46 | | `agents`, `examples` | The four test agents and a configuration using them | | 57 | | `agents`, `examples` | The four test agents and a configuration using them | |
| 47 | | `spikes` | Throwaway prototypes of milestone Initialize | | 58 | | `spikes` | Throwaway prototypes of milestone Initialize | |
| 48 | 59 | ||
added
RELEASING.fr.md +59 -0 | new file mode 100644 | ||
| @@ -0,0 +1,59 @@ | ||
| 1 | +# Publier une version de Sidekicks | |
| 2 | + | |
| 3 | +[English](RELEASING.md) | |
| 4 | + | |
| 5 | +Trois étapes, sur le Mac : tout construire, tagger, attacher les fichiers. | |
| 6 | + | |
| 7 | +| Étape | Commande | Résultat | | |
| 8 | +| --- | --- | --- | | |
| 9 | +| 1. Construire | `make release-build` | `dist/` : les paquets macOS, Windows et Linux, et `SHA256SUMS` | | |
| 10 | +| 2. Tagger | `make release-tag` | le tag `v<version>` est poussé ; le workflow **Release** crée la release sur Rickub, avec ses notes | | |
| 11 | +| 3. Attacher | à la main, sur la page de la release | tous les fichiers de `dist/` attachés à la release | | |
| 12 | + | |
| 13 | +La version est `info.version` dans `build/config.yml` ; le tag est `v` + cette version. | |
| 14 | + | |
| 15 | +## Avant : fixer la version | |
| 16 | + | |
| 17 | +1. Dans `build/config.yml`, réglez `info.version` (par exemple `"0.2.0"`). | |
| 18 | +2. `wails3 task common:update:build-assets`, puis remettez `LSMinimumSystemVersion` à `13.0.0` dans `build/darwin/Info.plist` et `build/darwin/Info.dev.plist` (la commande le remet à `12.0.0`). | |
| 19 | +3. `make check`, commitez, fusionnez dans `main`, puis `git checkout main && git pull`. | |
| 20 | + | |
| 21 | +## 1. Construire | |
| 22 | + | |
| 23 | +```bash | |
| 24 | +make release-build | |
| 25 | +``` | |
| 26 | + | |
| 27 | +Il construit, dans `dist/` : | |
| 28 | + | |
| 29 | +| Fichiers | Comment | | |
| 30 | +| --- | --- | | |
| 31 | +| `Sidekicks-<v>-macos-universal.dmg`, `.zip` | en natif (outils en ligne de commande de Xcode) | | |
| 32 | +| `Sidekicks-<v>-windows-amd64-installer.exe`, `sidekicks_<v>_windows_amd64.zip` | compilés depuis le Mac (demande `brew install makensis zip`) | | |
| 33 | +| `sidekicks_<v>_linux_amd64.deb`, `.rpm`, `.tar.gz`, `Sidekicks-<v>-x86_64.AppImage` | dans un conteneur Docker (Docker doit tourner ; amd64 est émulé sur Apple Silicon, c'est donc un peu long) | | |
| 34 | +| `SHA256SUMS` | sur tous les fichiers ci-dessus | | |
| 35 | + | |
| 36 | +`LINUX_ARCHES="amd64 arm64" make release-build` ajoute les paquets Linux arm64 ; `SKIP="linux"` (ou `macos`, `windows`) laisse un système de côté. | |
| 37 | + | |
| 38 | +## 2. Tagger | |
| 39 | + | |
| 40 | +```bash | |
| 41 | +make release-tag | |
| 42 | +``` | |
| 43 | + | |
| 44 | +Il refuse si la copie de travail a des modifications, si vous n'êtes pas sur `main`, si `main` diffère de `origin/main`, ou si le tag existe ; il avertit s'il manque un paquet dans `dist/`. Puis il crée le tag annoté `v<version>` et le pousse. Le push lance `.github/workflows/release.yml`, qui vérifie que le tag correspond à `build/config.yml` et crée la release avec des notes qui listent les fichiers attendus. | |
| 45 | + | |
| 46 | +## 3. Attacher | |
| 47 | + | |
| 48 | +Ouvrez la release sur Rickub (**Releases → v<version>**) et attachez tous les fichiers de `dist/`, `SHA256SUMS` compris. | |
| 49 | + | |
| 50 | +## En cas de problème | |
| 51 | + | |
| 52 | +| Symptôme | Que faire | | |
| 53 | +| --- | --- | | |
| 54 | +| `makensis is missing` / `Docker is not running` | `brew install makensis zip` / lancez Docker Desktop — ou laissez ce système de côté avec `SKIP`. | | |
| 55 | +| `the tag v… already exists` | Cette version a déjà été publiée : augmentez `info.version`. | | |
| 56 | +| Le workflow a échoué : « The tag is … but build/config.yml says … » | Supprimez le tag (`git push origin :refs/tags/v…` et `git tag -d v…`), corrigez `info.version`, recommencez. | | |
| 57 | +| Le workflow a tourné mais aucune release n'est apparue | Le journal du job dit pourquoi (un `403` veut dire que le jeton n'a pas pu écrire : `permissions: contents: write` doit rester dans `release.yml`). Créez la release à la main sur Rickub depuis le tag ; les notes sont dans le journal du job. | | |
| 58 | + | |
| 59 | +Détails : [Publier une release](docs/fr/how-to/publier-une-release.md) · [référence des commandes](docs/fr/reference/commandes.md). | |
| new file mode 100644 | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | +# Publier une version de Sidekicks | ||
| 2 | + | ||
| 3 | +[English](RELEASING.md) | ||
| 4 | + | ||
| 5 | +Trois étapes, sur le Mac : tout construire, tagger, attacher les fichiers. | ||
| 6 | + | ||
| 7 | +| Étape | Commande | Résultat | | ||
| 8 | +| --- | --- | --- | | ||
| 9 | +| 1. Construire | `make release-build` | `dist/` : les paquets macOS, Windows et Linux, et `SHA256SUMS` | | ||
| 10 | +| 2. Tagger | `make release-tag` | le tag `v<version>` est poussé ; le workflow **Release** crée la release sur Rickub, avec ses notes | | ||
| 11 | +| 3. Attacher | à la main, sur la page de la release | tous les fichiers de `dist/` attachés à la release | | ||
| 12 | + | ||
| 13 | +La version est `info.version` dans `build/config.yml` ; le tag est `v` + cette version. | ||
| 14 | + | ||
| 15 | +## Avant : fixer la version | ||
| 16 | + | ||
| 17 | +1. Dans `build/config.yml`, réglez `info.version` (par exemple `"0.2.0"`). | ||
| 18 | +2. `wails3 task common:update:build-assets`, puis remettez `LSMinimumSystemVersion` à `13.0.0` dans `build/darwin/Info.plist` et `build/darwin/Info.dev.plist` (la commande le remet à `12.0.0`). | ||
| 19 | +3. `make check`, commitez, fusionnez dans `main`, puis `git checkout main && git pull`. | ||
| 20 | + | ||
| 21 | +## 1. Construire | ||
| 22 | + | ||
| 23 | +```bash | ||
| 24 | +make release-build | ||
| 25 | +``` | ||
| 26 | + | ||
| 27 | +Il construit, dans `dist/` : | ||
| 28 | + | ||
| 29 | +| Fichiers | Comment | | ||
| 30 | +| --- | --- | | ||
| 31 | +| `Sidekicks-<v>-macos-universal.dmg`, `.zip` | en natif (outils en ligne de commande de Xcode) | | ||
| 32 | +| `Sidekicks-<v>-windows-amd64-installer.exe`, `sidekicks_<v>_windows_amd64.zip` | compilés depuis le Mac (demande `brew install makensis zip`) | | ||
| 33 | +| `sidekicks_<v>_linux_amd64.deb`, `.rpm`, `.tar.gz`, `Sidekicks-<v>-x86_64.AppImage` | dans un conteneur Docker (Docker doit tourner ; amd64 est émulé sur Apple Silicon, c'est donc un peu long) | | ||
| 34 | +| `SHA256SUMS` | sur tous les fichiers ci-dessus | | ||
| 35 | + | ||
| 36 | +`LINUX_ARCHES="amd64 arm64" make release-build` ajoute les paquets Linux arm64 ; `SKIP="linux"` (ou `macos`, `windows`) laisse un système de côté. | ||
| 37 | + | ||
| 38 | +## 2. Tagger | ||
| 39 | + | ||
| 40 | +```bash | ||
| 41 | +make release-tag | ||
| 42 | +``` | ||
| 43 | + | ||
| 44 | +Il refuse si la copie de travail a des modifications, si vous n'êtes pas sur `main`, si `main` diffère de `origin/main`, ou si le tag existe ; il avertit s'il manque un paquet dans `dist/`. Puis il crée le tag annoté `v<version>` et le pousse. Le push lance `.github/workflows/release.yml`, qui vérifie que le tag correspond à `build/config.yml` et crée la release avec des notes qui listent les fichiers attendus. | ||
| 45 | + | ||
| 46 | +## 3. Attacher | ||
| 47 | + | ||
| 48 | +Ouvrez la release sur Rickub (**Releases → v<version>**) et attachez tous les fichiers de `dist/`, `SHA256SUMS` compris. | ||
| 49 | + | ||
| 50 | +## En cas de problème | ||
| 51 | + | ||
| 52 | +| Symptôme | Que faire | | ||
| 53 | +| --- | --- | | ||
| 54 | +| `makensis is missing` / `Docker is not running` | `brew install makensis zip` / lancez Docker Desktop — ou laissez ce système de côté avec `SKIP`. | | ||
| 55 | +| `the tag v… already exists` | Cette version a déjà été publiée : augmentez `info.version`. | | ||
| 56 | +| Le workflow a échoué : « The tag is … but build/config.yml says … » | Supprimez le tag (`git push origin :refs/tags/v…` et `git tag -d v…`), corrigez `info.version`, recommencez. | | ||
| 57 | +| Le workflow a tourné mais aucune release n'est apparue | Le journal du job dit pourquoi (un `403` veut dire que le jeton n'a pas pu écrire : `permissions: contents: write` doit rester dans `release.yml`). Créez la release à la main sur Rickub depuis le tag ; les notes sont dans le journal du job. | | ||
| 58 | + | ||
| 59 | +Détails : [Publier une release](docs/fr/how-to/publier-une-release.md) · [référence des commandes](docs/fr/reference/commandes.md). | ||
added
RELEASING.md +59 -0 | new file mode 100644 | ||
| @@ -0,0 +1,59 @@ | ||
| 1 | +# Releasing Sidekicks | |
| 2 | + | |
| 3 | +[Français](RELEASING.fr.md) | |
| 4 | + | |
| 5 | +Three steps, on the Mac: build everything, tag, attach the files. | |
| 6 | + | |
| 7 | +| Step | Command | Result | | |
| 8 | +| --- | --- | --- | | |
| 9 | +| 1. Build | `make release-build` | `dist/`: the macOS, Windows and Linux packages, and `SHA256SUMS` | | |
| 10 | +| 2. Tag | `make release-tag` | the tag `v<version>` is pushed; the **Release** workflow creates the release on Rickub, with its notes | | |
| 11 | +| 3. Attach | by hand, on the release page | every file of `dist/` attached to the release | | |
| 12 | + | |
| 13 | +The version is `info.version` in `build/config.yml`; the tag is `v` + that version. | |
| 14 | + | |
| 15 | +## Before: set the version | |
| 16 | + | |
| 17 | +1. In `build/config.yml`, set `info.version` (e.g. `"0.2.0"`). | |
| 18 | +2. `wails3 task common:update:build-assets`, then put `LSMinimumSystemVersion` back to `13.0.0` in `build/darwin/Info.plist` and `build/darwin/Info.dev.plist` (the command resets it to `12.0.0`). | |
| 19 | +3. `make check`, commit, merge into `main`, and `git checkout main && git pull`. | |
| 20 | + | |
| 21 | +## 1. Build | |
| 22 | + | |
| 23 | +```bash | |
| 24 | +make release-build | |
| 25 | +``` | |
| 26 | + | |
| 27 | +It builds, into `dist/`: | |
| 28 | + | |
| 29 | +| Files | How | | |
| 30 | +| --- | --- | | |
| 31 | +| `Sidekicks-<v>-macos-universal.dmg`, `.zip` | natively (Xcode command line tools) | | |
| 32 | +| `Sidekicks-<v>-windows-amd64-installer.exe`, `sidekicks_<v>_windows_amd64.zip` | cross-built (needs `brew install makensis zip`) | | |
| 33 | +| `sidekicks_<v>_linux_amd64.deb`, `.rpm`, `.tar.gz`, `Sidekicks-<v>-x86_64.AppImage` | in a Docker container (needs Docker running; amd64 is emulated on Apple Silicon, so it takes a while) | | |
| 34 | +| `SHA256SUMS` | over all the files above | | |
| 35 | + | |
| 36 | +`LINUX_ARCHES="amd64 arm64" make release-build` adds the Linux arm64 packages; `SKIP="linux"` (or `macos`, `windows`) leaves a system out. | |
| 37 | + | |
| 38 | +## 2. Tag | |
| 39 | + | |
| 40 | +```bash | |
| 41 | +make release-tag | |
| 42 | +``` | |
| 43 | + | |
| 44 | +It refuses when the working tree has changes, when you are not on `main`, when `main` differs from `origin/main`, or when the tag exists; it warns when `dist/` misses a package. Then it creates the annotated tag `v<version>` and pushes it. The push starts `.github/workflows/release.yml`, which checks that the tag matches `build/config.yml` and creates the release with notes listing the files to expect. | |
| 45 | + | |
| 46 | +## 3. Attach | |
| 47 | + | |
| 48 | +Open the release on Rickub (**Releases → v<version>**), and attach every file of `dist/`, `SHA256SUMS` included. | |
| 49 | + | |
| 50 | +## When something goes wrong | |
| 51 | + | |
| 52 | +| Symptom | What to do | | |
| 53 | +| --- | --- | | |
| 54 | +| `makensis is missing` / `Docker is not running` | `brew install makensis zip` / start Docker Desktop — or leave that system out with `SKIP`. | | |
| 55 | +| `the tag v… already exists` | That version was released already: raise `info.version`. | | |
| 56 | +| The workflow failed: "The tag is … but build/config.yml says …" | Delete the tag (`git push origin :refs/tags/v…` and `git tag -d v…`), fix `info.version`, start again. | | |
| 57 | +| The workflow ran but no release appeared | The job's log tells why (a `403` means the token could not write: `permissions: contents: write` must stay in `release.yml`). Create the release by hand on Rickub from the tag; the notes are in the job's log. | | |
| 58 | + | |
| 59 | +Details: [How to publish a release](docs/en/how-to/publish-a-release.md) · [commands reference](docs/en/reference/commands.md). | |
| new file mode 100644 | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | +# Releasing Sidekicks | ||
| 2 | + | ||
| 3 | +[Français](RELEASING.fr.md) | ||
| 4 | + | ||
| 5 | +Three steps, on the Mac: build everything, tag, attach the files. | ||
| 6 | + | ||
| 7 | +| Step | Command | Result | | ||
| 8 | +| --- | --- | --- | | ||
| 9 | +| 1. Build | `make release-build` | `dist/`: the macOS, Windows and Linux packages, and `SHA256SUMS` | | ||
| 10 | +| 2. Tag | `make release-tag` | the tag `v<version>` is pushed; the **Release** workflow creates the release on Rickub, with its notes | | ||
| 11 | +| 3. Attach | by hand, on the release page | every file of `dist/` attached to the release | | ||
| 12 | + | ||
| 13 | +The version is `info.version` in `build/config.yml`; the tag is `v` + that version. | ||
| 14 | + | ||
| 15 | +## Before: set the version | ||
| 16 | + | ||
| 17 | +1. In `build/config.yml`, set `info.version` (e.g. `"0.2.0"`). | ||
| 18 | +2. `wails3 task common:update:build-assets`, then put `LSMinimumSystemVersion` back to `13.0.0` in `build/darwin/Info.plist` and `build/darwin/Info.dev.plist` (the command resets it to `12.0.0`). | ||
| 19 | +3. `make check`, commit, merge into `main`, and `git checkout main && git pull`. | ||
| 20 | + | ||
| 21 | +## 1. Build | ||
| 22 | + | ||
| 23 | +```bash | ||
| 24 | +make release-build | ||
| 25 | +``` | ||
| 26 | + | ||
| 27 | +It builds, into `dist/`: | ||
| 28 | + | ||
| 29 | +| Files | How | | ||
| 30 | +| --- | --- | | ||
| 31 | +| `Sidekicks-<v>-macos-universal.dmg`, `.zip` | natively (Xcode command line tools) | | ||
| 32 | +| `Sidekicks-<v>-windows-amd64-installer.exe`, `sidekicks_<v>_windows_amd64.zip` | cross-built (needs `brew install makensis zip`) | | ||
| 33 | +| `sidekicks_<v>_linux_amd64.deb`, `.rpm`, `.tar.gz`, `Sidekicks-<v>-x86_64.AppImage` | in a Docker container (needs Docker running; amd64 is emulated on Apple Silicon, so it takes a while) | | ||
| 34 | +| `SHA256SUMS` | over all the files above | | ||
| 35 | + | ||
| 36 | +`LINUX_ARCHES="amd64 arm64" make release-build` adds the Linux arm64 packages; `SKIP="linux"` (or `macos`, `windows`) leaves a system out. | ||
| 37 | + | ||
| 38 | +## 2. Tag | ||
| 39 | + | ||
| 40 | +```bash | ||
| 41 | +make release-tag | ||
| 42 | +``` | ||
| 43 | + | ||
| 44 | +It refuses when the working tree has changes, when you are not on `main`, when `main` differs from `origin/main`, or when the tag exists; it warns when `dist/` misses a package. Then it creates the annotated tag `v<version>` and pushes it. The push starts `.github/workflows/release.yml`, which checks that the tag matches `build/config.yml` and creates the release with notes listing the files to expect. | ||
| 45 | + | ||
| 46 | +## 3. Attach | ||
| 47 | + | ||
| 48 | +Open the release on Rickub (**Releases → v<version>**), and attach every file of `dist/`, `SHA256SUMS` included. | ||
| 49 | + | ||
| 50 | +## When something goes wrong | ||
| 51 | + | ||
| 52 | +| Symptom | What to do | | ||
| 53 | +| --- | --- | | ||
| 54 | +| `makensis is missing` / `Docker is not running` | `brew install makensis zip` / start Docker Desktop — or leave that system out with `SKIP`. | | ||
| 55 | +| `the tag v… already exists` | That version was released already: raise `info.version`. | | ||
| 56 | +| The workflow failed: "The tag is … but build/config.yml says …" | Delete the tag (`git push origin :refs/tags/v…` and `git tag -d v…`), fix `info.version`, start again. | | ||
| 57 | +| The workflow ran but no release appeared | The job's log tells why (a `403` means the token could not write: `permissions: contents: write` must stay in `release.yml`). Create the release by hand on Rickub from the tag; the notes are in the job's log. | | ||
| 58 | + | ||
| 59 | +Details: [How to publish a release](docs/en/how-to/publish-a-release.md) · [commands reference](docs/en/reference/commands.md). | ||
added
agents/butterfly/agent.yaml +85 -0 | new file mode 100644 | ||
| @@ -0,0 +1,85 @@ | ||
| 1 | +# butterfly — answers questions, no tools. | |
| 2 | +# | |
| 3 | +# Written by `mm init`. Every value says why it has that value; change | |
| 4 | +# them as you watch the agent work (guides/agent-settings-for-small-models.md). | |
| 5 | +# | |
| 6 | +# model family: qwen | |
| 7 | +# usage: assistant | |
| 8 | +# machine: small — a laptop, models up to about 8B | |
| 9 | +# model facts: read from llmman: native window 40960 tokens; reasoning switch enable_thinking (default on) | |
| 10 | +# | |
| 11 | +# Where the numbers come from (the tag before their comment): | |
| 12 | +# [card] from the model card or the GGUF, not measured — re-read the new card | |
| 13 | +# [guide] the settings guide's row for this machine | |
| 14 | +# [rule] a rule of thumb, not specific to this model | |
| 15 | +# | |
| 16 | +# mm -config <this file> or mm -tui <this file> | |
| 17 | + | |
| 18 | +provider: llmman | |
| 19 | +# The model. Chosen for it (family qwen): sampling (temperature, top_p, top_k, | |
| 20 | +# max_tokens) and sampling.chat_template_kwargs (enable_thinking). Change the | |
| 21 | +# model and redo them together — running mm init again is the quick way. | |
| 22 | +model: "hf.co/Menlo/Lucy-gguf:Q4_K_M" | |
| 23 | +# No baseUrl: llmman's defaults apply. For the record: | |
| 24 | +# baseUrl: "http://127.0.0.1:17434/v1" | |
| 25 | +# fallback: "http://host.docker.internal:17434/v1" # tried when baseUrl does not answer | |
| 26 | + | |
| 27 | +# 0 = mm asks the server for the window it serves (the model's native window | |
| 28 | +# is 40960 tokens; the server may serve less) | |
| 29 | +contextWindow: 0 | |
| 30 | +# usage assistant's default: tools run without asking | |
| 31 | +yolo: true | |
| 32 | +# usage assistant | |
| 33 | +bashTool: false | |
| 34 | +editTools: false | |
| 35 | +planTool: false | |
| 36 | +askUserTool: true | |
| 37 | +# no skills: add a skills/ folder and set skillsDir to use some (see | |
| 38 | +# docs/en/how-to/add-a-skill.md) | |
| 39 | +skillsDir: no-skills | |
| 40 | +# usage assistant | |
| 41 | +maxTurns: 5 | |
| 42 | +# [guide] settings guide, row "Small model (≤ 8B), short tasks" | |
| 43 | +maxOutput: 8000 | |
| 44 | +firstTokenTimeout: 3m | |
| 45 | +watchdogTimeout: 20s | |
| 46 | + | |
| 47 | +sampling: | |
| 48 | + # [card] family qwen: Qwen model cards (thinking 0.6 / 0.95 / 20, | |
| 49 | + # non-thinking 0.7 / 0.8 / 20); precise 0.0 measured with Qwen3.5 4B, | |
| 50 | + # thinking off (demos/docs-search, memory-search, plans) | |
| 51 | + temperature: 0.7 | |
| 52 | + top_p: 0.8 | |
| 53 | + top_k: 20 | |
| 54 | + # [rule] room for an answer or a whole file in one tool call | |
| 55 | + max_tokens: 4096 | |
| 56 | + # one tool call per reply: small models run a check before the change it | |
| 57 | + # checks has landed otherwise | |
| 58 | + parallel_tool_calls: false | |
| 59 | + chat_template_kwargs: | |
| 60 | + # reasoning off: short, direct answers; the template's default is on (read | |
| 61 | + # from the chat template) | |
| 62 | + enable_thinking: false | |
| 63 | + | |
| 64 | +context: | |
| 65 | + # compress the history before the window is full (settings guide, every row) | |
| 66 | + enabled: true | |
| 67 | + # mm's default: 75 % of the window the server serves, a quarter left for the | |
| 68 | + # next question and its tool outputs | |
| 69 | + threshold: 75 | |
| 70 | + | |
| 71 | +agentsMd: | |
| 72 | + # An AGENTS.md in the project directory is added to the system prompt. | |
| 73 | + enabled: true | |
| 74 | + | |
| 75 | +acp: | |
| 76 | + name: butterfly | |
| 77 | + title: "Butterfly (assistant)" | |
| 78 | + | |
| 79 | +system: | | |
| 80 | + Your name is Blue Butterfly. You are a helpful assistant. Answer clearly and briefly, in the user's | |
| 81 | + language. Say when you do not know; never invent facts, names or | |
| 82 | + figures. | |
| 83 | + | |
| 84 | +# Next: skills (docs/en/how-to/add-a-skill.md), MCP servers (docs/en/tutorials/mcp-getting-started.md), | |
| 85 | +# hooks (docs/en/how-to/guard-the-agent-with-hooks.md), sessions (docs/en/how-to/keep-sessions.md). | |
| new file mode 100644 | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | +# butterfly — answers questions, no tools. | ||
| 2 | +# | ||
| 3 | +# Written by `mm init`. Every value says why it has that value; change | ||
| 4 | +# them as you watch the agent work (guides/agent-settings-for-small-models.md). | ||
| 5 | +# | ||
| 6 | +# model family: qwen | ||
| 7 | +# usage: assistant | ||
| 8 | +# machine: small — a laptop, models up to about 8B | ||
| 9 | +# model facts: read from llmman: native window 40960 tokens; reasoning switch enable_thinking (default on) | ||
| 10 | +# | ||
| 11 | +# Where the numbers come from (the tag before their comment): | ||
| 12 | +# [card] from the model card or the GGUF, not measured — re-read the new card | ||
| 13 | +# [guide] the settings guide's row for this machine | ||
| 14 | +# [rule] a rule of thumb, not specific to this model | ||
| 15 | +# | ||
| 16 | +# mm -config <this file> or mm -tui <this file> | ||
| 17 | + | ||
| 18 | +provider: llmman | ||
| 19 | +# The model. Chosen for it (family qwen): sampling (temperature, top_p, top_k, | ||
| 20 | +# max_tokens) and sampling.chat_template_kwargs (enable_thinking). Change the | ||
| 21 | +# model and redo them together — running mm init again is the quick way. | ||
| 22 | +model: "hf.co/Menlo/Lucy-gguf:Q4_K_M" | ||
| 23 | +# No baseUrl: llmman's defaults apply. For the record: | ||
| 24 | +# baseUrl: "http://127.0.0.1:17434/v1" | ||
| 25 | +# fallback: "http://host.docker.internal:17434/v1" # tried when baseUrl does not answer | ||
| 26 | + | ||
| 27 | +# 0 = mm asks the server for the window it serves (the model's native window | ||
| 28 | +# is 40960 tokens; the server may serve less) | ||
| 29 | +contextWindow: 0 | ||
| 30 | +# usage assistant's default: tools run without asking | ||
| 31 | +yolo: true | ||
| 32 | +# usage assistant | ||
| 33 | +bashTool: false | ||
| 34 | +editTools: false | ||
| 35 | +planTool: false | ||
| 36 | +askUserTool: true | ||
| 37 | +# no skills: add a skills/ folder and set skillsDir to use some (see | ||
| 38 | +# docs/en/how-to/add-a-skill.md) | ||
| 39 | +skillsDir: no-skills | ||
| 40 | +# usage assistant | ||
| 41 | +maxTurns: 5 | ||
| 42 | +# [guide] settings guide, row "Small model (≤ 8B), short tasks" | ||
| 43 | +maxOutput: 8000 | ||
| 44 | +firstTokenTimeout: 3m | ||
| 45 | +watchdogTimeout: 20s | ||
| 46 | + | ||
| 47 | +sampling: | ||
| 48 | + # [card] family qwen: Qwen model cards (thinking 0.6 / 0.95 / 20, | ||
| 49 | + # non-thinking 0.7 / 0.8 / 20); precise 0.0 measured with Qwen3.5 4B, | ||
| 50 | + # thinking off (demos/docs-search, memory-search, plans) | ||
| 51 | + temperature: 0.7 | ||
| 52 | + top_p: 0.8 | ||
| 53 | + top_k: 20 | ||
| 54 | + # [rule] room for an answer or a whole file in one tool call | ||
| 55 | + max_tokens: 4096 | ||
| 56 | + # one tool call per reply: small models run a check before the change it | ||
| 57 | + # checks has landed otherwise | ||
| 58 | + parallel_tool_calls: false | ||
| 59 | + chat_template_kwargs: | ||
| 60 | + # reasoning off: short, direct answers; the template's default is on (read | ||
| 61 | + # from the chat template) | ||
| 62 | + enable_thinking: false | ||
| 63 | + | ||
| 64 | +context: | ||
| 65 | + # compress the history before the window is full (settings guide, every row) | ||
| 66 | + enabled: true | ||
| 67 | + # mm's default: 75 % of the window the server serves, a quarter left for the | ||
| 68 | + # next question and its tool outputs | ||
| 69 | + threshold: 75 | ||
| 70 | + | ||
| 71 | +agentsMd: | ||
| 72 | + # An AGENTS.md in the project directory is added to the system prompt. | ||
| 73 | + enabled: true | ||
| 74 | + | ||
| 75 | +acp: | ||
| 76 | + name: butterfly | ||
| 77 | + title: "Butterfly (assistant)" | ||
| 78 | + | ||
| 79 | +system: | | ||
| 80 | + Your name is Blue Butterfly. You are a helpful assistant. Answer clearly and briefly, in the user's | ||
| 81 | + language. Say when you do not know; never invent facts, names or | ||
| 82 | + figures. | ||
| 83 | + | ||
| 84 | +# Next: skills (docs/en/how-to/add-a-skill.md), MCP servers (docs/en/tutorials/mcp-getting-started.md), | ||
| 85 | +# hooks (docs/en/how-to/guard-the-agent-with-hooks.md), sessions (docs/en/how-to/keep-sessions.md). | ||
added
build/appicon.icon/Assets/sidekicks-mark.svg +12 -0 | new file mode 100644 | ||
| @@ -0,0 +1,12 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 100 100"> | |
| 3 | + <mask id="cut"> | |
| 4 | + <rect width="100" height="100" fill="#fff"/> | |
| 5 | + <circle cx="76" cy="28" r="12" fill="#000"/> | |
| 6 | + <circle cx="18" cy="39" r="10" fill="#000"/> | |
| 7 | + </mask> | |
| 8 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#4A5078" stroke-width="4" mask="url(#cut)"/> | |
| 9 | + <circle cx="50" cy="50" r="15" fill="#FFFFFF"/> | |
| 10 | + <circle cx="76" cy="28" r="9" fill="#2FD1C5"/> | |
| 11 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | |
| 12 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 100 100"> | ||
| 3 | + <mask id="cut"> | ||
| 4 | + <rect width="100" height="100" fill="#fff"/> | ||
| 5 | + <circle cx="76" cy="28" r="12" fill="#000"/> | ||
| 6 | + <circle cx="18" cy="39" r="10" fill="#000"/> | ||
| 7 | + </mask> | ||
| 8 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#4A5078" stroke-width="4" mask="url(#cut)"/> | ||
| 9 | + <circle cx="50" cy="50" r="15" fill="#FFFFFF"/> | ||
| 10 | + <circle cx="76" cy="28" r="9" fill="#2FD1C5"/> | ||
| 11 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | ||
| 12 | +</svg> | ||
deleted
build/appicon.icon/Assets/wails_icon_vector.svg +0 -9 | deleted file mode 100644 | ||
| @@ -1,9 +0,0 @@ | ||
| 1 | -<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
| 2 | -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | |
| 3 | -<svg width="100%" height="100%" viewBox="0 0 583 533" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> | |
| 4 | - <g transform="matrix(1,0,0,1,-246,-251)"> | |
| 5 | - <g id="Ebene1"> | |
| 6 | - <path d="M246,251L265,784L401,784L506,450L507,450L505,784L641,784L829,251L682,251L596,567L595,567L596,251L478,251L378,568L391,251L246,251Z"/> | |
| 7 | - </g> | |
| 8 | - </g> | |
| 9 | -</svg> | |
| deleted file mode 100644 | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | -<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
| 2 | -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||
| 3 | -<svg width="100%" height="100%" viewBox="0 0 583 533" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> | ||
| 4 | - <g transform="matrix(1,0,0,1,-246,-251)"> | ||
| 5 | - <g id="Ebene1"> | ||
| 6 | - <path d="M246,251L265,784L401,784L506,450L507,450L505,784L641,784L829,251L682,251L596,567L595,567L596,251L478,251L378,568L391,251L246,251Z"/> | ||
| 7 | - </g> | ||
| 8 | - </g> | ||
| 9 | -</svg> | ||
modified
build/appicon.icon/icon.json +19 -33 | @@ -1,51 +1,37 @@ | ||
| 1 | 1 | { |
| 2 | - "fill" : { | |
| 3 | - "automatic-gradient" : "extended-gray:1.00000,1.00000" | |
| 2 | + "fill": { | |
| 3 | + "automatic-gradient": "srgb:0.11765,0.13333,0.25098,1.00000" | |
| 4 | 4 | }, |
| 5 | - "groups" : [ | |
| 5 | + "groups": [ | |
| 6 | 6 | { |
| 7 | - "layers" : [ | |
| 7 | + "layers": [ | |
| 8 | 8 | { |
| 9 | - "fill-specializations" : [ | |
| 10 | - { | |
| 11 | - "appearance" : "dark", | |
| 12 | - "value" : { | |
| 13 | - "solid" : "srgb:0.92143,0.92145,0.92144,1.00000" | |
| 14 | - } | |
| 15 | - }, | |
| 16 | - { | |
| 17 | - "appearance" : "tinted", | |
| 18 | - "value" : { | |
| 19 | - "solid" : "srgb:0.83742,0.83744,0.83743,1.00000" | |
| 20 | - } | |
| 21 | - } | |
| 22 | - ], | |
| 23 | - "image-name" : "wails_icon_vector.svg", | |
| 24 | - "name" : "wails_icon_vector", | |
| 25 | - "position" : { | |
| 26 | - "scale" : 0.85, | |
| 27 | - "translation-in-points" : [ | |
| 9 | + "image-name": "sidekicks-mark.svg", | |
| 10 | + "name": "sidekicks-mark", | |
| 11 | + "position": { | |
| 12 | + "scale": 0.8, | |
| 13 | + "translation-in-points": [ | |
| 28 | 14 | 0.0, |
| 29 | 15 | 0.0 |
| 30 | 16 | ] |
| 31 | 17 | } |
| 32 | 18 | } |
| 33 | 19 | ], |
| 34 | - "shadow" : { | |
| 35 | - "kind" : "neutral", | |
| 36 | - "opacity" : 0.5 | |
| 20 | + "shadow": { | |
| 21 | + "kind": "neutral", | |
| 22 | + "opacity": 0.5 | |
| 37 | 23 | }, |
| 38 | - "specular" : true, | |
| 39 | - "translucency" : { | |
| 40 | - "enabled" : true, | |
| 41 | - "value" : 0.5 | |
| 24 | + "specular": true, | |
| 25 | + "translucency": { | |
| 26 | + "enabled": true, | |
| 27 | + "value": 0.5 | |
| 42 | 28 | } |
| 43 | 29 | } |
| 44 | 30 | ], |
| 45 | - "supported-platforms" : { | |
| 46 | - "circles" : [ | |
| 31 | + "supported-platforms": { | |
| 32 | + "circles": [ | |
| 47 | 33 | "watchOS" |
| 48 | 34 | ], |
| 49 | - "squares" : "shared" | |
| 35 | + "squares": "shared" | |
| 50 | 36 | } |
| 51 | 37 | } |
| @@ -1,51 +1,37 @@ | |||
| 1 | { | 1 | { |
| 2 | - "fill" : { | 2 | + "fill": { |
| 3 | - "automatic-gradient" : "extended-gray:1.00000,1.00000" | 3 | + "automatic-gradient": "srgb:0.11765,0.13333,0.25098,1.00000" |
| 4 | }, | 4 | }, |
| 5 | - "groups" : [ | 5 | + "groups": [ |
| 6 | { | 6 | { |
| 7 | - "layers" : [ | 7 | + "layers": [ |
| 8 | { | 8 | { |
| 9 | - "fill-specializations" : [ | 9 | + "image-name": "sidekicks-mark.svg", |
| 10 | - { | 10 | + "name": "sidekicks-mark", |
| 11 | - "appearance" : "dark", | 11 | + "position": { |
| 12 | - "value" : { | 12 | + "scale": 0.8, |
| 13 | - "solid" : "srgb:0.92143,0.92145,0.92144,1.00000" | 13 | + "translation-in-points": [ |
| 14 | - } | ||
| 15 | - }, | ||
| 16 | - { | ||
| 17 | - "appearance" : "tinted", | ||
| 18 | - "value" : { | ||
| 19 | - "solid" : "srgb:0.83742,0.83744,0.83743,1.00000" | ||
| 20 | - } | ||
| 21 | - } | ||
| 22 | - ], | ||
| 23 | - "image-name" : "wails_icon_vector.svg", | ||
| 24 | - "name" : "wails_icon_vector", | ||
| 25 | - "position" : { | ||
| 26 | - "scale" : 0.85, | ||
| 27 | - "translation-in-points" : [ | ||
| 28 | 0.0, | 14 | 0.0, |
| 29 | 0.0 | 15 | 0.0 |
| 30 | ] | 16 | ] |
| 31 | } | 17 | } |
| 32 | } | 18 | } |
| 33 | ], | 19 | ], |
| 34 | - "shadow" : { | 20 | + "shadow": { |
| 35 | - "kind" : "neutral", | 21 | + "kind": "neutral", |
| 36 | - "opacity" : 0.5 | 22 | + "opacity": 0.5 |
| 37 | }, | 23 | }, |
| 38 | - "specular" : true, | 24 | + "specular": true, |
| 39 | - "translucency" : { | 25 | + "translucency": { |
| 40 | - "enabled" : true, | 26 | + "enabled": true, |
| 41 | - "value" : 0.5 | 27 | + "value": 0.5 |
| 42 | } | 28 | } |
| 43 | } | 29 | } |
| 44 | ], | 30 | ], |
| 45 | - "supported-platforms" : { | 31 | + "supported-platforms": { |
| 46 | - "circles" : [ | 32 | + "circles": [ |
| 47 | "watchOS" | 33 | "watchOS" |
| 48 | ], | 34 | ], |
| 49 | - "squares" : "shared" | 35 | + "squares": "shared" |
| 50 | } | 36 | } |
| 51 | } | 37 | } |
modified
build/appicon.png +0 -0 | Binary files a/build/appicon.png and b/build/appicon.png differ |
| Binary files a/build/appicon.png and b/build/appicon.png differ | Binary files a/build/appicon.png and b/build/appicon.png differ |
added
build/appicon.svg +15 -0 | new file mode 100644 | ||
| @@ -0,0 +1,15 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024"> | |
| 3 | + <rect x="100" y="100" width="824" height="824" rx="185" fill="#1E2240"/> | |
| 4 | + <svg x="212" y="212" width="600" height="600" viewBox="0 0 100 100"> | |
| 5 | + <mask id="cut"> | |
| 6 | + <rect width="100" height="100" fill="#fff"/> | |
| 7 | + <circle cx="76" cy="28" r="12" fill="#000"/> | |
| 8 | + <circle cx="18" cy="39" r="10" fill="#000"/> | |
| 9 | + </mask> | |
| 10 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#4A5078" stroke-width="4" mask="url(#cut)"/> | |
| 11 | + <circle cx="50" cy="50" r="15" fill="#FFFFFF"/> | |
| 12 | + <circle cx="76" cy="28" r="9" fill="#2FD1C5"/> | |
| 13 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | |
| 14 | + </svg> | |
| 15 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024"> | ||
| 3 | + <rect x="100" y="100" width="824" height="824" rx="185" fill="#1E2240"/> | ||
| 4 | + <svg x="212" y="212" width="600" height="600" viewBox="0 0 100 100"> | ||
| 5 | + <mask id="cut"> | ||
| 6 | + <rect width="100" height="100" fill="#fff"/> | ||
| 7 | + <circle cx="76" cy="28" r="12" fill="#000"/> | ||
| 8 | + <circle cx="18" cy="39" r="10" fill="#000"/> | ||
| 9 | + </mask> | ||
| 10 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#4A5078" stroke-width="4" mask="url(#cut)"/> | ||
| 11 | + <circle cx="50" cy="50" r="15" fill="#FFFFFF"/> | ||
| 12 | + <circle cx="76" cy="28" r="9" fill="#2FD1C5"/> | ||
| 13 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | ||
| 14 | + </svg> | ||
| 15 | +</svg> | ||
modified
build/config.yml +1 -1 | @@ -11,7 +11,7 @@ info: | ||
| 11 | 11 | description: "Converse with AI agents in channels" # The application description |
| 12 | 12 | copyright: "© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0" # Copyright text |
| 13 | 13 | comments: "Sidekicks" # Comments |
| 14 | - version: "0.0.1" # The application version | |
| 14 | + version: "0.1.0" # The application version | |
| 15 | 15 | # cfBundleIconName: "appicon" # The macOS icon name in Assets.car icon bundles (optional) |
| 16 | 16 | # # Should match the name of your .icon file without the extension |
| 17 | 17 | # # If not set and Assets.car exists, defaults to "appicon" |
| @@ -11,7 +11,7 @@ info: | |||
| 11 | description: "Converse with AI agents in channels" # The application description | 11 | description: "Converse with AI agents in channels" # The application description |
| 12 | copyright: "© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0" # Copyright text | 12 | copyright: "© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0" # Copyright text |
| 13 | comments: "Sidekicks" # Comments | 13 | comments: "Sidekicks" # Comments |
| 14 | - version: "0.0.1" # The application version | 14 | + version: "0.1.0" # The application version |
| 15 | # cfBundleIconName: "appicon" # The macOS icon name in Assets.car icon bundles (optional) | 15 | # cfBundleIconName: "appicon" # The macOS icon name in Assets.car icon bundles (optional) |
| 16 | # # Should match the name of your .icon file without the extension | 16 | # # Should match the name of your .icon file without the extension |
| 17 | # # If not set and Assets.car exists, defaults to "appicon" | 17 | # # If not set and Assets.car exists, defaults to "appicon" |
modified
build/darwin/Assets.car +0 -0 | Binary files a/build/darwin/Assets.car and b/build/darwin/Assets.car differ |
| Binary files a/build/darwin/Assets.car and b/build/darwin/Assets.car differ | Binary files a/build/darwin/Assets.car and b/build/darwin/Assets.car differ |
modified
build/darwin/Info.dev.plist +32 -31 | @@ -1,34 +1,35 @@ | ||
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 1 | 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 2 | 3 | <plist version="1.0"> |
| 3 | - <dict> | |
| 4 | - <key>CFBundlePackageType</key> | |
| 5 | - <string>APPL</string> | |
| 6 | - <key>CFBundleName</key> | |
| 7 | - <string>Sidekicks</string> | |
| 8 | - <key>CFBundleExecutable</key> | |
| 9 | - <string>sidekicks</string> | |
| 10 | - <key>CFBundleIdentifier</key> | |
| 11 | - <string>com.k33g.sidekicks</string> | |
| 12 | - <key>CFBundleVersion</key> | |
| 13 | - <string>0.0.1</string> | |
| 14 | - <key>CFBundleGetInfoString</key> | |
| 15 | - <string>This is a comment</string> | |
| 16 | - <key>CFBundleShortVersionString</key> | |
| 17 | - <string>0.0.1</string> | |
| 18 | - <key>CFBundleIconFile</key> | |
| 19 | - <string>icons</string> | |
| 20 | - <key>CFBundleIconName</key> | |
| 21 | - <string>appicon</string> | |
| 22 | - <key>LSMinimumSystemVersion</key> | |
| 23 | - <string>12.0.0</string> | |
| 24 | - <key>NSHighResolutionCapable</key> | |
| 25 | - <string>true</string> | |
| 26 | - <key>NSHumanReadableCopyright</key> | |
| 27 | - <string>© 2026 Philippe Charrière</string> | |
| 28 | - <key>NSAppTransportSecurity</key> | |
| 29 | - <dict> | |
| 30 | - <key>NSAllowsLocalNetworking</key> | |
| 31 | - <true/> | |
| 32 | - </dict> | |
| 33 | - </dict> | |
| 4 | + <dict> | |
| 5 | + <key>CFBundleExecutable</key> | |
| 6 | + <string>sidekicks</string> | |
| 7 | + <key>CFBundleGetInfoString</key> | |
| 8 | + <string>Sidekicks</string> | |
| 9 | + <key>CFBundleIconFile</key> | |
| 10 | + <string>icons</string> | |
| 11 | + <key>CFBundleIconName</key> | |
| 12 | + <string>appicon</string> | |
| 13 | + <key>CFBundleIdentifier</key> | |
| 14 | + <string>com.k33g.sidekicks</string> | |
| 15 | + <key>CFBundleName</key> | |
| 16 | + <string>Sidekicks</string> | |
| 17 | + <key>CFBundlePackageType</key> | |
| 18 | + <string>APPL</string> | |
| 19 | + <key>CFBundleShortVersionString</key> | |
| 20 | + <string>0.1.0</string> | |
| 21 | + <key>CFBundleVersion</key> | |
| 22 | + <string>0.1.0</string> | |
| 23 | + <key>LSMinimumSystemVersion</key> | |
| 24 | + <string>13.0.0</string> | |
| 25 | + <key>NSAppTransportSecurity</key> | |
| 26 | + <dict> | |
| 27 | + <key>NSAllowsLocalNetworking</key> | |
| 28 | + <true/> | |
| 29 | + </dict> | |
| 30 | + <key>NSHighResolutionCapable</key> | |
| 31 | + <string>true</string> | |
| 32 | + <key>NSHumanReadableCopyright</key> | |
| 33 | + <string>© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0</string> | |
| 34 | + </dict> | |
| 34 | 35 | </plist> |
| \ No newline at end of file | ||
| @@ -1,34 +1,35 @@ | |||
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 1 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 2 | <plist version="1.0"> | 3 | <plist version="1.0"> |
| 3 | - <dict> | 4 | + <dict> |
| 4 | - <key>CFBundlePackageType</key> | 5 | + <key>CFBundleExecutable</key> |
| 5 | - <string>APPL</string> | 6 | + <string>sidekicks</string> |
| 6 | - <key>CFBundleName</key> | 7 | + <key>CFBundleGetInfoString</key> |
| 7 | - <string>Sidekicks</string> | 8 | + <string>Sidekicks</string> |
| 8 | - <key>CFBundleExecutable</key> | 9 | + <key>CFBundleIconFile</key> |
| 9 | - <string>sidekicks</string> | 10 | + <string>icons</string> |
| 10 | - <key>CFBundleIdentifier</key> | 11 | + <key>CFBundleIconName</key> |
| 11 | - <string>com.k33g.sidekicks</string> | 12 | + <string>appicon</string> |
| 12 | - <key>CFBundleVersion</key> | 13 | + <key>CFBundleIdentifier</key> |
| 13 | - <string>0.0.1</string> | 14 | + <string>com.k33g.sidekicks</string> |
| 14 | - <key>CFBundleGetInfoString</key> | 15 | + <key>CFBundleName</key> |
| 15 | - <string>This is a comment</string> | 16 | + <string>Sidekicks</string> |
| 16 | - <key>CFBundleShortVersionString</key> | 17 | + <key>CFBundlePackageType</key> |
| 17 | - <string>0.0.1</string> | 18 | + <string>APPL</string> |
| 18 | - <key>CFBundleIconFile</key> | 19 | + <key>CFBundleShortVersionString</key> |
| 19 | - <string>icons</string> | 20 | + <string>0.1.0</string> |
| 20 | - <key>CFBundleIconName</key> | 21 | + <key>CFBundleVersion</key> |
| 21 | - <string>appicon</string> | 22 | + <string>0.1.0</string> |
| 22 | - <key>LSMinimumSystemVersion</key> | 23 | + <key>LSMinimumSystemVersion</key> |
| 23 | - <string>12.0.0</string> | 24 | + <string>13.0.0</string> |
| 24 | - <key>NSHighResolutionCapable</key> | 25 | + <key>NSAppTransportSecurity</key> |
| 25 | - <string>true</string> | 26 | + <dict> |
| 26 | - <key>NSHumanReadableCopyright</key> | 27 | + <key>NSAllowsLocalNetworking</key> |
| 27 | - <string>© 2026 Philippe Charrière</string> | 28 | + <true/> |
| 28 | - <key>NSAppTransportSecurity</key> | 29 | + </dict> |
| 29 | - <dict> | 30 | + <key>NSHighResolutionCapable</key> |
| 30 | - <key>NSAllowsLocalNetworking</key> | 31 | + <string>true</string> |
| 31 | - <true/> | 32 | + <key>NSHumanReadableCopyright</key> |
| 32 | - </dict> | 33 | + <string>© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0</string> |
| 33 | - </dict> | 34 | + </dict> |
| 34 | </plist> | 35 | </plist> |
| \ No newline at end of file | \ No newline at end of file | ||
modified
build/darwin/Info.plist +27 -26 | @@ -1,29 +1,30 @@ | ||
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 1 | 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 2 | 3 | <plist version="1.0"> |
| 3 | - <dict> | |
| 4 | - <key>CFBundlePackageType</key> | |
| 5 | - <string>APPL</string> | |
| 6 | - <key>CFBundleName</key> | |
| 7 | - <string>Sidekicks</string> | |
| 8 | - <key>CFBundleExecutable</key> | |
| 9 | - <string>sidekicks</string> | |
| 10 | - <key>CFBundleIdentifier</key> | |
| 11 | - <string>com.k33g.sidekicks</string> | |
| 12 | - <key>CFBundleVersion</key> | |
| 13 | - <string>0.0.1</string> | |
| 14 | - <key>CFBundleGetInfoString</key> | |
| 15 | - <string>This is a comment</string> | |
| 16 | - <key>CFBundleShortVersionString</key> | |
| 17 | - <string>0.0.1</string> | |
| 18 | - <key>CFBundleIconFile</key> | |
| 19 | - <string>icons</string> | |
| 20 | - <key>CFBundleIconName</key> | |
| 21 | - <string>appicon</string> | |
| 22 | - <key>LSMinimumSystemVersion</key> | |
| 23 | - <string>12.0.0</string> | |
| 24 | - <key>NSHighResolutionCapable</key> | |
| 25 | - <string>true</string> | |
| 26 | - <key>NSHumanReadableCopyright</key> | |
| 27 | - <string>© 2026 Philippe Charrière</string> | |
| 28 | - </dict> | |
| 4 | + <dict> | |
| 5 | + <key>CFBundleExecutable</key> | |
| 6 | + <string>sidekicks</string> | |
| 7 | + <key>CFBundleGetInfoString</key> | |
| 8 | + <string>Sidekicks</string> | |
| 9 | + <key>CFBundleIconFile</key> | |
| 10 | + <string>icons</string> | |
| 11 | + <key>CFBundleIconName</key> | |
| 12 | + <string>appicon</string> | |
| 13 | + <key>CFBundleIdentifier</key> | |
| 14 | + <string>com.k33g.sidekicks</string> | |
| 15 | + <key>CFBundleName</key> | |
| 16 | + <string>Sidekicks</string> | |
| 17 | + <key>CFBundlePackageType</key> | |
| 18 | + <string>APPL</string> | |
| 19 | + <key>CFBundleShortVersionString</key> | |
| 20 | + <string>0.1.0</string> | |
| 21 | + <key>CFBundleVersion</key> | |
| 22 | + <string>0.1.0</string> | |
| 23 | + <key>LSMinimumSystemVersion</key> | |
| 24 | + <string>13.0.0</string> | |
| 25 | + <key>NSHighResolutionCapable</key> | |
| 26 | + <string>true</string> | |
| 27 | + <key>NSHumanReadableCopyright</key> | |
| 28 | + <string>© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0</string> | |
| 29 | + </dict> | |
| 29 | 30 | </plist> |
| \ No newline at end of file | ||
| @@ -1,29 +1,30 @@ | |||
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 1 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 2 | <plist version="1.0"> | 3 | <plist version="1.0"> |
| 3 | - <dict> | 4 | + <dict> |
| 4 | - <key>CFBundlePackageType</key> | 5 | + <key>CFBundleExecutable</key> |
| 5 | - <string>APPL</string> | 6 | + <string>sidekicks</string> |
| 6 | - <key>CFBundleName</key> | 7 | + <key>CFBundleGetInfoString</key> |
| 7 | - <string>Sidekicks</string> | 8 | + <string>Sidekicks</string> |
| 8 | - <key>CFBundleExecutable</key> | 9 | + <key>CFBundleIconFile</key> |
| 9 | - <string>sidekicks</string> | 10 | + <string>icons</string> |
| 10 | - <key>CFBundleIdentifier</key> | 11 | + <key>CFBundleIconName</key> |
| 11 | - <string>com.k33g.sidekicks</string> | 12 | + <string>appicon</string> |
| 12 | - <key>CFBundleVersion</key> | 13 | + <key>CFBundleIdentifier</key> |
| 13 | - <string>0.0.1</string> | 14 | + <string>com.k33g.sidekicks</string> |
| 14 | - <key>CFBundleGetInfoString</key> | 15 | + <key>CFBundleName</key> |
| 15 | - <string>This is a comment</string> | 16 | + <string>Sidekicks</string> |
| 16 | - <key>CFBundleShortVersionString</key> | 17 | + <key>CFBundlePackageType</key> |
| 17 | - <string>0.0.1</string> | 18 | + <string>APPL</string> |
| 18 | - <key>CFBundleIconFile</key> | 19 | + <key>CFBundleShortVersionString</key> |
| 19 | - <string>icons</string> | 20 | + <string>0.1.0</string> |
| 20 | - <key>CFBundleIconName</key> | 21 | + <key>CFBundleVersion</key> |
| 21 | - <string>appicon</string> | 22 | + <string>0.1.0</string> |
| 22 | - <key>LSMinimumSystemVersion</key> | 23 | + <key>LSMinimumSystemVersion</key> |
| 23 | - <string>12.0.0</string> | 24 | + <string>13.0.0</string> |
| 24 | - <key>NSHighResolutionCapable</key> | 25 | + <key>NSHighResolutionCapable</key> |
| 25 | - <string>true</string> | 26 | + <string>true</string> |
| 26 | - <key>NSHumanReadableCopyright</key> | 27 | + <key>NSHumanReadableCopyright</key> |
| 27 | - <string>© 2026 Philippe Charrière</string> | 28 | + <string>© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0</string> |
| 28 | - </dict> | 29 | + </dict> |
| 29 | </plist> | 30 | </plist> |
| \ No newline at end of file | \ No newline at end of file | ||
modified
build/darwin/Taskfile.yml +3 -3 | @@ -51,9 +51,9 @@ tasks: | ||
| 51 | 51 | GOOS: darwin |
| 52 | 52 | CGO_ENABLED: 1 |
| 53 | 53 | GOARCH: '{{.ARCH | default ARCH}}' |
| 54 | - CGO_CFLAGS: "-mmacosx-version-min=12.0" | |
| 55 | - CGO_LDFLAGS: "-mmacosx-version-min=12.0" | |
| 56 | - MACOSX_DEPLOYMENT_TARGET: "12.0" | |
| 54 | + CGO_CFLAGS: "-mmacosx-version-min=13.0" | |
| 55 | + CGO_LDFLAGS: "-mmacosx-version-min=13.0" | |
| 56 | + MACOSX_DEPLOYMENT_TARGET: "13.0" | |
| 57 | 57 | |
| 58 | 58 | build:docker: |
| 59 | 59 | summary: Cross-compiles for macOS using Docker (for Linux/Windows hosts) |
| @@ -51,9 +51,9 @@ tasks: | |||
| 51 | GOOS: darwin | 51 | GOOS: darwin |
| 52 | CGO_ENABLED: 1 | 52 | CGO_ENABLED: 1 |
| 53 | GOARCH: '{{.ARCH | default ARCH}}' | 53 | GOARCH: '{{.ARCH | default ARCH}}' |
| 54 | - CGO_CFLAGS: "-mmacosx-version-min=12.0" | 54 | + CGO_CFLAGS: "-mmacosx-version-min=13.0" |
| 55 | - CGO_LDFLAGS: "-mmacosx-version-min=12.0" | 55 | + CGO_LDFLAGS: "-mmacosx-version-min=13.0" |
| 56 | - MACOSX_DEPLOYMENT_TARGET: "12.0" | 56 | + MACOSX_DEPLOYMENT_TARGET: "13.0" |
| 57 | 57 | ||
| 58 | build:docker: | 58 | build:docker: |
| 59 | summary: Cross-compiles for macOS using Docker (for Linux/Windows hosts) | 59 | summary: Cross-compiles for macOS using Docker (for Linux/Windows hosts) |
modified
build/darwin/icons.icns +0 -0 | Binary files a/build/darwin/icons.icns and b/build/darwin/icons.icns differ |
| Binary files a/build/darwin/icons.icns and b/build/darwin/icons.icns differ | Binary files a/build/darwin/icons.icns and b/build/darwin/icons.icns differ |
modified
build/linux/Taskfile.yml +3 -1 | @@ -170,7 +170,9 @@ tasks: | ||
| 170 | 170 | dir: build |
| 171 | 171 | cmds: |
| 172 | 172 | - mkdir -p {{.ROOT_DIR}}/build/linux/appimage |
| 173 | - - wails3 generate .desktop -name "{{.APP_NAME}}" -exec "{{.EXEC}}" -icon "{{.ICON}}" -outputfile "{{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop" -categories "{{.CATEGORIES}}" | |
| 173 | + # Sidekicks keeps its own desktop entry (build/linux/desktop): the | |
| 174 | + # generated one names the application in lowercase, as a development tool. | |
| 175 | + - cp "{{.ROOT_DIR}}/build/linux/desktop" "{{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop" | |
| 174 | 176 | vars: |
| 175 | 177 | APP_NAME: '{{.APP_NAME}}' |
| 176 | 178 | EXEC: '{{.APP_NAME}}' |
| @@ -170,7 +170,9 @@ tasks: | |||
| 170 | dir: build | 170 | dir: build |
| 171 | cmds: | 171 | cmds: |
| 172 | - mkdir -p {{.ROOT_DIR}}/build/linux/appimage | 172 | - mkdir -p {{.ROOT_DIR}}/build/linux/appimage |
| 173 | - - wails3 generate .desktop -name "{{.APP_NAME}}" -exec "{{.EXEC}}" -icon "{{.ICON}}" -outputfile "{{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop" -categories "{{.CATEGORIES}}" | 173 | + # Sidekicks keeps its own desktop entry (build/linux/desktop): the |
| 174 | + # generated one names the application in lowercase, as a development tool. | ||
| 175 | + - cp "{{.ROOT_DIR}}/build/linux/desktop" "{{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop" | ||
| 174 | vars: | 176 | vars: |
| 175 | APP_NAME: '{{.APP_NAME}}' | 177 | APP_NAME: '{{.APP_NAME}}' |
| 176 | EXEC: '{{.APP_NAME}}' | 178 | EXEC: '{{.APP_NAME}}' |
modified
build/linux/desktop +1 -4 | @@ -2,12 +2,9 @@ | ||
| 2 | 2 | Version=1.0 |
| 3 | 3 | Name=Sidekicks |
| 4 | 4 | Comment=Converse with AI agents in channels |
| 5 | -# The Exec line includes %u to pass the URL to the application | |
| 6 | -Exec=/usr/local/bin/sidekicks %u | |
| 5 | +Exec=sidekicks | |
| 7 | 6 | Terminal=false |
| 8 | 7 | Type=Application |
| 9 | 8 | Icon=sidekicks |
| 10 | 9 | Categories=Utility; |
| 11 | 10 | StartupWMClass=sidekicks |
| 12 | - | |
| 13 | - | |
| @@ -2,12 +2,9 @@ | |||
| 2 | Version=1.0 | 2 | Version=1.0 |
| 3 | Name=Sidekicks | 3 | Name=Sidekicks |
| 4 | Comment=Converse with AI agents in channels | 4 | Comment=Converse with AI agents in channels |
| 5 | -# The Exec line includes %u to pass the URL to the application | 5 | +Exec=sidekicks |
| 6 | -Exec=/usr/local/bin/sidekicks %u | ||
| 7 | Terminal=false | 6 | Terminal=false |
| 8 | Type=Application | 7 | Type=Application |
| 9 | Icon=sidekicks | 8 | Icon=sidekicks |
| 10 | Categories=Utility; | 9 | Categories=Utility; |
| 11 | StartupWMClass=sidekicks | 10 | StartupWMClass=sidekicks |
| 12 | - | ||
| 13 | - | ||
modified
build/linux/nfpm/nfpm.yaml +7 -5 | @@ -6,21 +6,23 @@ | ||
| 6 | 6 | name: "sidekicks" |
| 7 | 7 | arch: ${GOARCH} |
| 8 | 8 | platform: "linux" |
| 9 | -version: "0.0.1" | |
| 9 | +version: "0.1.0" | |
| 10 | 10 | section: "default" |
| 11 | 11 | priority: "extra" |
| 12 | -maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}> | |
| 12 | +maintainer: "Philippe Charrière" | |
| 13 | 13 | description: "Converse with AI agents in channels" |
| 14 | 14 | vendor: "Philippe Charrière" |
| 15 | -homepage: "https://wails.io" | |
| 16 | -license: "MIT" | |
| 15 | +homepage: "https://git.rickub.com/bots-garden/sidekicks" | |
| 16 | +license: "LicenseRef-Sidekicks-Source-Available-1.0" | |
| 17 | 17 | release: "1" |
| 18 | 18 | |
| 19 | 19 | contents: |
| 20 | 20 | - src: "./bin/sidekicks" |
| 21 | 21 | dst: "/usr/local/bin/sidekicks" |
| 22 | + - src: "./build/appicon.svg" | |
| 23 | + dst: "/usr/share/icons/hicolor/scalable/apps/sidekicks.svg" | |
| 22 | 24 | - src: "./build/appicon.png" |
| 23 | - dst: "/usr/share/icons/hicolor/128x128/apps/sidekicks.png" | |
| 25 | + dst: "/usr/share/pixmaps/sidekicks.png" | |
| 24 | 26 | - src: "./build/linux/sidekicks.desktop" |
| 25 | 27 | dst: "/usr/share/applications/sidekicks.desktop" |
| 26 | 28 | |
| @@ -6,21 +6,23 @@ | |||
| 6 | name: "sidekicks" | 6 | name: "sidekicks" |
| 7 | arch: ${GOARCH} | 7 | arch: ${GOARCH} |
| 8 | platform: "linux" | 8 | platform: "linux" |
| 9 | -version: "0.0.1" | 9 | +version: "0.1.0" |
| 10 | section: "default" | 10 | section: "default" |
| 11 | priority: "extra" | 11 | priority: "extra" |
| 12 | -maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}> | 12 | +maintainer: "Philippe Charrière" |
| 13 | description: "Converse with AI agents in channels" | 13 | description: "Converse with AI agents in channels" |
| 14 | vendor: "Philippe Charrière" | 14 | vendor: "Philippe Charrière" |
| 15 | -homepage: "https://wails.io" | 15 | +homepage: "https://git.rickub.com/bots-garden/sidekicks" |
| 16 | -license: "MIT" | 16 | +license: "LicenseRef-Sidekicks-Source-Available-1.0" |
| 17 | release: "1" | 17 | release: "1" |
| 18 | 18 | ||
| 19 | contents: | 19 | contents: |
| 20 | - src: "./bin/sidekicks" | 20 | - src: "./bin/sidekicks" |
| 21 | dst: "/usr/local/bin/sidekicks" | 21 | dst: "/usr/local/bin/sidekicks" |
| 22 | + - src: "./build/appicon.svg" | ||
| 23 | + dst: "/usr/share/icons/hicolor/scalable/apps/sidekicks.svg" | ||
| 22 | - src: "./build/appicon.png" | 24 | - src: "./build/appicon.png" |
| 23 | - dst: "/usr/share/icons/hicolor/128x128/apps/sidekicks.png" | 25 | + dst: "/usr/share/pixmaps/sidekicks.png" |
| 24 | - src: "./build/linux/sidekicks.desktop" | 26 | - src: "./build/linux/sidekicks.desktop" |
| 25 | dst: "/usr/share/applications/sidekicks.desktop" | 27 | dst: "/usr/share/applications/sidekicks.desktop" |
| 26 | 28 | ||
modified
build/windows/icon.ico +0 -0 | Binary files a/build/windows/icon.ico and b/build/windows/icon.ico differ |
| Binary files a/build/windows/icon.ico and b/build/windows/icon.ico differ | Binary files a/build/windows/icon.ico and b/build/windows/icon.ico differ |
modified
build/windows/info.json +4 -4 | @@ -1,15 +1,15 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "fixed": { |
| 3 | - "file_version": "0.0.1" | |
| 3 | + "file_version": "0.1.0" | |
| 4 | 4 | }, |
| 5 | 5 | "info": { |
| 6 | 6 | "0409": { |
| 7 | - "ProductVersion": "0.0.1", | |
| 7 | + "ProductVersion": "0.1.0", | |
| 8 | 8 | "CompanyName": "Philippe Charrière", |
| 9 | 9 | "FileDescription": "Converse with AI agents in channels", |
| 10 | - "LegalCopyright": "© 2026 Philippe Charrière", | |
| 10 | + "LegalCopyright": "© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0", | |
| 11 | 11 | "ProductName": "Sidekicks", |
| 12 | - "Comments": "This is a comment" | |
| 12 | + "Comments": "Sidekicks" | |
| 13 | 13 | } |
| 14 | 14 | } |
| 15 | 15 | } |
| \ No newline at end of file | ||
| @@ -1,15 +1,15 @@ | |||
| 1 | { | 1 | { |
| 2 | "fixed": { | 2 | "fixed": { |
| 3 | - "file_version": "0.0.1" | 3 | + "file_version": "0.1.0" |
| 4 | }, | 4 | }, |
| 5 | "info": { | 5 | "info": { |
| 6 | "0409": { | 6 | "0409": { |
| 7 | - "ProductVersion": "0.0.1", | 7 | + "ProductVersion": "0.1.0", |
| 8 | "CompanyName": "Philippe Charrière", | 8 | "CompanyName": "Philippe Charrière", |
| 9 | "FileDescription": "Converse with AI agents in channels", | 9 | "FileDescription": "Converse with AI agents in channels", |
| 10 | - "LegalCopyright": "© 2026 Philippe Charrière", | 10 | + "LegalCopyright": "© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0", |
| 11 | "ProductName": "Sidekicks", | 11 | "ProductName": "Sidekicks", |
| 12 | - "Comments": "This is a comment" | 12 | + "Comments": "Sidekicks" |
| 13 | } | 13 | } |
| 14 | } | 14 | } |
| 15 | } | 15 | } |
| \ No newline at end of file | \ No newline at end of file | ||
modified
build/windows/nsis/wails_tools.nsh +2 -2 | @@ -14,10 +14,10 @@ | ||
| 14 | 14 | !define INFO_PRODUCTNAME "Sidekicks" |
| 15 | 15 | !endif |
| 16 | 16 | !ifndef INFO_PRODUCTVERSION |
| 17 | - !define INFO_PRODUCTVERSION "0.0.1" | |
| 17 | + !define INFO_PRODUCTVERSION "0.1.0" | |
| 18 | 18 | !endif |
| 19 | 19 | !ifndef INFO_COPYRIGHT |
| 20 | - !define INFO_COPYRIGHT "© 2026 Philippe Charrière" | |
| 20 | + !define INFO_COPYRIGHT "© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0" | |
| 21 | 21 | !endif |
| 22 | 22 | !ifndef PRODUCT_EXECUTABLE |
| 23 | 23 | !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" |
| @@ -14,10 +14,10 @@ | |||
| 14 | !define INFO_PRODUCTNAME "Sidekicks" | 14 | !define INFO_PRODUCTNAME "Sidekicks" |
| 15 | !endif | 15 | !endif |
| 16 | !ifndef INFO_PRODUCTVERSION | 16 | !ifndef INFO_PRODUCTVERSION |
| 17 | - !define INFO_PRODUCTVERSION "0.0.1" | 17 | + !define INFO_PRODUCTVERSION "0.1.0" |
| 18 | !endif | 18 | !endif |
| 19 | !ifndef INFO_COPYRIGHT | 19 | !ifndef INFO_COPYRIGHT |
| 20 | - !define INFO_COPYRIGHT "© 2026 Philippe Charrière" | 20 | + !define INFO_COPYRIGHT "© 2026 Philippe Charrière — Sidekicks Source-Available License 1.0" |
| 21 | !endif | 21 | !endif |
| 22 | !ifndef PRODUCT_EXECUTABLE | 22 | !ifndef PRODUCT_EXECUTABLE |
| 23 | !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" | 23 | !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" |
modified
build/windows/wails.exe.manifest +1 -1 | @@ -1,6 +1,6 @@ | ||
| 1 | 1 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
| 2 | 2 | <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> |
| 3 | - <assemblyIdentity type="win32" name="com.k33g.sidekicks" version="0.0.1" processorArchitecture="*"/> | |
| 3 | + <assemblyIdentity type="win32" name="com.k33g.sidekicks" version="0.1.0" processorArchitecture="*"/> | |
| 4 | 4 | <dependency> |
| 5 | 5 | <dependentAssembly> |
| 6 | 6 | <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> |
| @@ -1,6 +1,6 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | 1 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
| 2 | <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> | 2 | <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> |
| 3 | - <assemblyIdentity type="win32" name="com.k33g.sidekicks" version="0.0.1" processorArchitecture="*"/> | 3 | + <assemblyIdentity type="win32" name="com.k33g.sidekicks" version="0.1.0" processorArchitecture="*"/> |
| 4 | <dependency> | 4 | <dependency> |
| 5 | <dependentAssembly> | 5 | <dependentAssembly> |
| 6 | <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> | 6 | <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> |
modified
docs/design/01-layout.png +0 -0 | Binary files a/docs/design/01-layout.png and b/docs/design/01-layout.png differ |
| Binary files a/docs/design/01-layout.png and b/docs/design/01-layout.png differ | Binary files a/docs/design/01-layout.png and b/docs/design/01-layout.png differ |
modified
docs/design/01-layout.svg +33 -33 | @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">1 · Layout global</text> | |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Docks façon Zed, mais seul l'essentiel est visible par défaut</text> | |
| 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">1 · Overall layout</text> | |
| 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Zed-like docks, but only the essentials are visible by default</text> | |
| 6 | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,14 +11,14 @@ | ||
| 11 | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | |
| 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> | |
| 15 | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | 19 | <rect x="28" y="158" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> |
| 20 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | |
| 21 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | |
| 20 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> | |
| 21 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> | |
| 22 | 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> |
| 23 | 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| 24 | 24 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> |
| @@ -30,18 +30,18 @@ | ||
| 30 | 30 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> |
| 31 | 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 32 | 32 | <rect x="251" y="116" width="709" height="44" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 33 | - <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | |
| 33 | + <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> | |
| 34 | 34 | <text x="944" y="144" font-size="13" fill="#6B6F7A" text-anchor="end" xml:space="preserve">👩 Alice · 🧔 Bob</text> |
| 35 | - <text x="275" y="196" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Vous</text> | |
| 36 | - <text x="275" y="218.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@alice résume-moi ce que fait ACP en deux phrases</text> | |
| 35 | + <text x="275" y="196" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">You</text> | |
| 36 | + <text x="275" y="218.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@alice sum up what ACP does in two sentences</text> | |
| 37 | 37 | <text x="275" y="252" font-size="13.5" fill="#C2185B" text-anchor="start" xml:space="preserve" font-weight="700">👩 Alice</text> |
| 38 | - <text x="275" y="274.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">ACP est un protocole qui permet à une application de dialoguer avec</text> | |
| 39 | - <text x="275" y="293.5" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">n'importe quel agent d'IA. Sidekicks l'utilise pour rester agnostique.</text> | |
| 38 | + <text x="275" y="274.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">ACP is a protocol that lets an application talk with any AI agent.</text> | |
| 39 | + <text x="275" y="293.5" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">Sidekicks uses it to stay agent-agnostic.</text> | |
| 40 | 40 | <rect x="271" y="724" width="669" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> |
| 41 | - <text x="285" y="750" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">Écrivez un message… (@ pour un agent, / pour une commande)</text> | |
| 42 | - <text x="285" y="774" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Entrée pour envoyer · Maj+Entrée nouvelle ligne</text> | |
| 41 | + <text x="285" y="750" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">Write a message… (@ for an agent, / for a command)</text> | |
| 42 | + <text x="285" y="774" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Enter to send · Shift+Enter for a new line</text> | |
| 43 | 43 | <rect x="960" y="116" width="300" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 44 | - <text x="976" y="144" font-size="13" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">⚙︎ Settings — equipe.yaml</text> | |
| 44 | + <text x="976" y="144" font-size="13" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">⚙︎ Settings — team.yaml</text> | |
| 45 | 45 | <rect x="970" y="160" width="280" height="300" rx="6" fill="#F4F5F7" stroke="#E2E3E6" stroke-width="1"/> |
| 46 | 46 | <text x="980" y="184" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">version: 1</text> |
| 47 | 47 | <text x="980" y="203" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">agents:</text> |
| @@ -50,13 +50,13 @@ | ||
| 50 | 50 | <text x="980" y="260" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> command: mm</text> |
| 51 | 51 | <text x="980" y="279" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> args: [-acp, ...]</text> |
| 52 | 52 | <text x="980" y="298" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">channels:</text> |
| 53 | - <text x="980" y="317" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> - name: général</text> | |
| 53 | + <text x="980" y="317" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> - name: general</text> | |
| 54 | 54 | <text x="980" y="336" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> agents: [alice, bob]</text> |
| 55 | - <text x="976" y="490" font-size="12.5" fill="#3E9B4F" text-anchor="start" xml:space="preserve" font-weight="700">✓ Configuration valide</text> | |
| 55 | + <text x="976" y="490" font-size="12.5" fill="#3E9B4F" text-anchor="start" xml:space="preserve" font-weight="700">✓ Valid configuration</text> | |
| 56 | 56 | <rect x="970" y="508" width="120" height="32" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> |
| 57 | - <text x="1030.0" y="529.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Enregistrer</text> | |
| 57 | + <text x="1030.0" y="529.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Save</text> | |
| 58 | 58 | <rect x="251" y="804" width="709" height="30" rx="0" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> |
| 59 | - <text x="265" y="824" font-size="12" fill="#6B6F7A" text-anchor="start" xml:space="preserve">▸ Terminal · Fichiers (repliés)</text> | |
| 59 | + <text x="265" y="824" font-size="12" fill="#6B6F7A" text-anchor="start" xml:space="preserve">▸ Terminal · Files (folded)</text> | |
| 60 | 60 | <circle cx="220" cy="142" r="12" fill="#6A1B9A"/> |
| 61 | 61 | <text x="220" y="146.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 62 | 62 | <circle cx="371" cy="240" r="12" fill="#6A1B9A"/> |
| @@ -70,32 +70,32 @@ | ||
| 70 | 70 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 71 | 71 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 72 | 72 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 73 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Dock gauche : channels et agents</text> | |
| 74 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Toujours visible. La pastille donne l'état de</text> | |
| 75 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">l'agent : vert prêt, orange occupé, gris arrêté.</text> | |
| 73 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Left dock: channels and agents</text> | |
| 74 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Always visible. The dot gives the agent's</text> | |
| 75 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">state: green ready, orange busy, grey stopped.</text> | |
| 76 | 76 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 77 | 77 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 78 | 78 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 79 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Centre : la conversation</text> | |
| 80 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Le seul panel indispensable. Pleine largeur</text> | |
| 81 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">quand les docks sont repliés.</text> | |
| 79 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Centre: the conversation</text> | |
| 80 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The only panel you cannot do without.</text> | |
| 81 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Full width when the docks are folded.</text> | |
| 82 | 82 | <rect x="1284" y="260" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 83 | 83 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 84 | 84 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 85 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Dock droit : Settings</text> | |
| 86 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Éditeur YAML (CodeMirror) avec validation</text> | |
| 87 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">en direct. Fermé par défaut ; s'ouvre</text> | |
| 88 | - <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">par ⚙︎ ou ⌘,.</text> | |
| 85 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Right dock: Settings</text> | |
| 86 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">YAML editor (CodeMirror) with live</text> | |
| 87 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">validation. Closed by default; opens</text> | |
| 88 | + <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">with ⚙︎ or ⌘,.</text> | |
| 89 | 89 | <rect x="1284" y="368" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 90 | 90 | <circle cx="1306" cy="390" r="12" fill="#6A1B9A"/> |
| 91 | 91 | <text x="1306" y="394.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 92 | - <text x="1328" y="395" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Dock bas : terminal et fichiers</text> | |
| 93 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Replié par défaut : utile aux curieux,</text> | |
| 94 | - <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">jamais imposé au citizen user.</text> | |
| 92 | + <text x="1328" y="395" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Bottom dock: terminal and files</text> | |
| 93 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Folded by default: there for the curious,</text> | |
| 94 | + <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">never forced on the citizen user.</text> | |
| 95 | 95 | <rect x="1284" y="458" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 96 | 96 | <circle cx="1306" cy="480" r="12" fill="#6A1B9A"/> |
| 97 | 97 | <text x="1306" y="484.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 98 | - <text x="1328" y="485" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Barre d'état</text> | |
| 99 | - <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Rappelle la limite d'agents simultanés</text> | |
| 100 | - <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">(mémoire) et la configuration ouverte.</text> | |
| 98 | + <text x="1328" y="485" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Status bar</text> | |
| 99 | + <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Shows the limit of agents running at once</text> | |
| 100 | + <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">(memory) and the open configuration.</text> | |
| 101 | 101 | </svg> |
| @@ -1,8 +1,8 @@ | |||
| 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | <rect width="1660" height="900" fill="#FFFFFF"/> | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">1 · Layout global</text> | 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">1 · Overall layout</text> |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Docks façon Zed, mais seul l'essentiel est visible par défaut</text> | 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Zed-like docks, but only the essentials are visible by default</text> |
| 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,14 +11,14 @@ | |||
| 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> |
| 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | <rect x="28" y="158" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> | 19 | <rect x="28" y="158" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> |
| 20 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | 20 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> |
| 21 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | 21 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> |
| 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> | 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> |
| 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> | 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| 24 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> | 24 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> |
| @@ -30,18 +30,18 @@ | |||
| 30 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> | 30 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> |
| 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> | 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 32 | <rect x="251" y="116" width="709" height="44" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 32 | <rect x="251" y="116" width="709" height="44" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 33 | - <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | 33 | + <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> |
| 34 | <text x="944" y="144" font-size="13" fill="#6B6F7A" text-anchor="end" xml:space="preserve">👩 Alice · 🧔 Bob</text> | 34 | <text x="944" y="144" font-size="13" fill="#6B6F7A" text-anchor="end" xml:space="preserve">👩 Alice · 🧔 Bob</text> |
| 35 | - <text x="275" y="196" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Vous</text> | 35 | + <text x="275" y="196" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">You</text> |
| 36 | - <text x="275" y="218.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@alice résume-moi ce que fait ACP en deux phrases</text> | 36 | + <text x="275" y="218.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@alice sum up what ACP does in two sentences</text> |
| 37 | <text x="275" y="252" font-size="13.5" fill="#C2185B" text-anchor="start" xml:space="preserve" font-weight="700">👩 Alice</text> | 37 | <text x="275" y="252" font-size="13.5" fill="#C2185B" text-anchor="start" xml:space="preserve" font-weight="700">👩 Alice</text> |
| 38 | - <text x="275" y="274.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">ACP est un protocole qui permet à une application de dialoguer avec</text> | 38 | + <text x="275" y="274.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">ACP is a protocol that lets an application talk with any AI agent.</text> |
| 39 | - <text x="275" y="293.5" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">n'importe quel agent d'IA. Sidekicks l'utilise pour rester agnostique.</text> | 39 | + <text x="275" y="293.5" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">Sidekicks uses it to stay agent-agnostic.</text> |
| 40 | <rect x="271" y="724" width="669" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> | 40 | <rect x="271" y="724" width="669" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> |
| 41 | - <text x="285" y="750" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">Écrivez un message… (@ pour un agent, / pour une commande)</text> | 41 | + <text x="285" y="750" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">Write a message… (@ for an agent, / for a command)</text> |
| 42 | - <text x="285" y="774" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Entrée pour envoyer · Maj+Entrée nouvelle ligne</text> | 42 | + <text x="285" y="774" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Enter to send · Shift+Enter for a new line</text> |
| 43 | <rect x="960" y="116" width="300" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 43 | <rect x="960" y="116" width="300" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 44 | - <text x="976" y="144" font-size="13" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">⚙︎ Settings — equipe.yaml</text> | 44 | + <text x="976" y="144" font-size="13" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">⚙︎ Settings — team.yaml</text> |
| 45 | <rect x="970" y="160" width="280" height="300" rx="6" fill="#F4F5F7" stroke="#E2E3E6" stroke-width="1"/> | 45 | <rect x="970" y="160" width="280" height="300" rx="6" fill="#F4F5F7" stroke="#E2E3E6" stroke-width="1"/> |
| 46 | <text x="980" y="184" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">version: 1</text> | 46 | <text x="980" y="184" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">version: 1</text> |
| 47 | <text x="980" y="203" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">agents:</text> | 47 | <text x="980" y="203" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">agents:</text> |
| @@ -50,13 +50,13 @@ | |||
| 50 | <text x="980" y="260" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> command: mm</text> | 50 | <text x="980" y="260" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> command: mm</text> |
| 51 | <text x="980" y="279" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> args: [-acp, ...]</text> | 51 | <text x="980" y="279" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> args: [-acp, ...]</text> |
| 52 | <text x="980" y="298" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">channels:</text> | 52 | <text x="980" y="298" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">channels:</text> |
| 53 | - <text x="980" y="317" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> - name: général</text> | 53 | + <text x="980" y="317" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> - name: general</text> |
| 54 | <text x="980" y="336" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> agents: [alice, bob]</text> | 54 | <text x="980" y="336" font-size="12" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> agents: [alice, bob]</text> |
| 55 | - <text x="976" y="490" font-size="12.5" fill="#3E9B4F" text-anchor="start" xml:space="preserve" font-weight="700">✓ Configuration valide</text> | 55 | + <text x="976" y="490" font-size="12.5" fill="#3E9B4F" text-anchor="start" xml:space="preserve" font-weight="700">✓ Valid configuration</text> |
| 56 | <rect x="970" y="508" width="120" height="32" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> | 56 | <rect x="970" y="508" width="120" height="32" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> |
| 57 | - <text x="1030.0" y="529.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Enregistrer</text> | 57 | + <text x="1030.0" y="529.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Save</text> |
| 58 | <rect x="251" y="804" width="709" height="30" rx="0" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> | 58 | <rect x="251" y="804" width="709" height="30" rx="0" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> |
| 59 | - <text x="265" y="824" font-size="12" fill="#6B6F7A" text-anchor="start" xml:space="preserve">▸ Terminal · Fichiers (repliés)</text> | 59 | + <text x="265" y="824" font-size="12" fill="#6B6F7A" text-anchor="start" xml:space="preserve">▸ Terminal · Files (folded)</text> |
| 60 | <circle cx="220" cy="142" r="12" fill="#6A1B9A"/> | 60 | <circle cx="220" cy="142" r="12" fill="#6A1B9A"/> |
| 61 | <text x="220" y="146.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 61 | <text x="220" y="146.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 62 | <circle cx="371" cy="240" r="12" fill="#6A1B9A"/> | 62 | <circle cx="371" cy="240" r="12" fill="#6A1B9A"/> |
| @@ -70,32 +70,32 @@ | |||
| 70 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 70 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 71 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> | 71 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 72 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 72 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 73 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Dock gauche : channels et agents</text> | 73 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Left dock: channels and agents</text> |
| 74 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Toujours visible. La pastille donne l'état de</text> | 74 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Always visible. The dot gives the agent's</text> |
| 75 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">l'agent : vert prêt, orange occupé, gris arrêté.</text> | 75 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">state: green ready, orange busy, grey stopped.</text> |
| 76 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 76 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 77 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> | 77 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 78 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> | 78 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 79 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Centre : la conversation</text> | 79 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Centre: the conversation</text> |
| 80 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Le seul panel indispensable. Pleine largeur</text> | 80 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The only panel you cannot do without.</text> |
| 81 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">quand les docks sont repliés.</text> | 81 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Full width when the docks are folded.</text> |
| 82 | <rect x="1284" y="260" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 82 | <rect x="1284" y="260" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 83 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> | 83 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 84 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> | 84 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 85 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Dock droit : Settings</text> | 85 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Right dock: Settings</text> |
| 86 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Éditeur YAML (CodeMirror) avec validation</text> | 86 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">YAML editor (CodeMirror) with live</text> |
| 87 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">en direct. Fermé par défaut ; s'ouvre</text> | 87 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">validation. Closed by default; opens</text> |
| 88 | - <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">par ⚙︎ ou ⌘,.</text> | 88 | + <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">with ⚙︎ or ⌘,.</text> |
| 89 | <rect x="1284" y="368" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 89 | <rect x="1284" y="368" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 90 | <circle cx="1306" cy="390" r="12" fill="#6A1B9A"/> | 90 | <circle cx="1306" cy="390" r="12" fill="#6A1B9A"/> |
| 91 | <text x="1306" y="394.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> | 91 | <text x="1306" y="394.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 92 | - <text x="1328" y="395" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Dock bas : terminal et fichiers</text> | 92 | + <text x="1328" y="395" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Bottom dock: terminal and files</text> |
| 93 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Replié par défaut : utile aux curieux,</text> | 93 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Folded by default: there for the curious,</text> |
| 94 | - <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">jamais imposé au citizen user.</text> | 94 | + <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">never forced on the citizen user.</text> |
| 95 | <rect x="1284" y="458" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 95 | <rect x="1284" y="458" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 96 | <circle cx="1306" cy="480" r="12" fill="#6A1B9A"/> | 96 | <circle cx="1306" cy="480" r="12" fill="#6A1B9A"/> |
| 97 | <text x="1306" y="484.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> | 97 | <text x="1306" y="484.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 98 | - <text x="1328" y="485" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Barre d'état</text> | 98 | + <text x="1328" y="485" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Status bar</text> |
| 99 | - <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Rappelle la limite d'agents simultanés</text> | 99 | + <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Shows the limit of agents running at once</text> |
| 100 | - <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">(mémoire) et la configuration ouverte.</text> | 100 | + <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">(memory) and the open configuration.</text> |
| 101 | </svg> | 101 | </svg> |
modified
docs/design/02-conversation.png +0 -0 | Binary files a/docs/design/02-conversation.png and b/docs/design/02-conversation.png differ |
| Binary files a/docs/design/02-conversation.png and b/docs/design/02-conversation.png differ | Binary files a/docs/design/02-conversation.png and b/docs/design/02-conversation.png differ |
modified
docs/design/02-conversation.svg +37 -37 | @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">2 · Conversation multi-agents</text> | |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Chaque agent a sa couleur ; les outils sont repliés ; on peut toujours arrêter</text> | |
| 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">2 · Multi-agent conversation</text> | |
| 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Each agent has its colour; tools are folded; you can always stop</text> | |
| 6 | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,14 +11,14 @@ | ||
| 11 | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | |
| 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> | |
| 15 | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | 19 | <rect x="28" y="158" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> |
| 20 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | |
| 21 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | |
| 20 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> | |
| 21 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> | |
| 22 | 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> |
| 23 | 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| 24 | 24 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> |
| @@ -30,31 +30,31 @@ | ||
| 30 | 30 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> |
| 31 | 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 32 | 32 | <rect x="251" y="116" width="1009" height="44" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 33 | - <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | |
| 33 | + <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> | |
| 34 | 34 | <text x="1244" y="144" font-size="13" fill="#6B6F7A" text-anchor="end" xml:space="preserve">👩 Alice · 🧔 Bob · 🧑🚀 Riker</text> |
| 35 | - <text x="275" y="196" font-size="12.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-style="italic">— Riker a rejoint le channel —</text> | |
| 36 | - <text x="275" y="228" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Vous</text> | |
| 37 | - <text x="275" y="250.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@alice propose un nom pour un script qui sauvegarde mes photos</text> | |
| 35 | + <text x="275" y="196" font-size="12.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-style="italic">— Riker joined the channel —</text> | |
| 36 | + <text x="275" y="228" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">You</text> | |
| 37 | + <text x="275" y="250.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@alice suggest a name for a script that backs up my photos</text> | |
| 38 | 38 | <text x="275" y="284" font-size="13.5" fill="#C2185B" text-anchor="start" xml:space="preserve" font-weight="700">👩 Alice</text> |
| 39 | - <text x="275" y="306.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">Je propose « photo-backup.sh » : court, explicite, et l'extension dit que</text> | |
| 40 | - <text x="275" y="325.5" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">c'est un script shell.</text> | |
| 41 | - <text x="275" y="360" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Vous</text> | |
| 42 | - <text x="275" y="382.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@bob tu valides ? @riker crée le fichier vide</text> | |
| 39 | + <text x="275" y="306.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">I suggest "photo-backup.sh": short, clear, and the extension says</text> | |
| 40 | + <text x="275" y="325.5" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">it is a shell script.</text> | |
| 41 | + <text x="275" y="360" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">You</text> | |
| 42 | + <text x="275" y="382.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@bob do you agree? @riker create the empty file</text> | |
| 43 | 43 | <text x="275" y="416" font-size="13.5" fill="#00838F" text-anchor="start" xml:space="preserve" font-weight="700">🧔 Bob</text> |
| 44 | - <text x="275" y="438.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">Bon choix. Alice a raison : un nom en minuscules, sans espace.</text> | |
| 44 | + <text x="275" y="438.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">Good choice. Alice is right: a lowercase name, no spaces.</text> | |
| 45 | 45 | <text x="275" y="472" font-size="13.5" fill="#5E35B1" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker</text> |
| 46 | - <text x="365" y="472" font-size="12.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-style="italic">travaille…</text> | |
| 46 | + <text x="365" y="472" font-size="12.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-style="italic">working…</text> | |
| 47 | 47 | <rect x="275" y="484" width="560" height="40" rx="8" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> |
| 48 | - <text x="289" y="509" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">▸ 🛠 write_file : photo-backup.sh (0 octet) ✓ terminé</text> | |
| 48 | + <text x="289" y="509" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">▸ 🛠 write_file: photo-backup.sh (0 bytes) ✓ done</text> | |
| 49 | 49 | <rect x="275" y="532" width="560" height="40" rx="8" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> |
| 50 | - <text x="289" y="557" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">▸ 🛠 bash : ls -la … en cours</text> | |
| 50 | + <text x="289" y="557" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">▸ 🛠 bash: ls -la … running</text> | |
| 51 | 51 | <rect x="271" y="754" width="849" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> |
| 52 | 52 | <text x="285" y="780" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve"></text> |
| 53 | - <text x="285" y="804" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Entrée pour envoyer · Maj+Entrée nouvelle ligne</text> | |
| 53 | + <text x="285" y="804" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Enter to send · Shift+Enter for a new line</text> | |
| 54 | 54 | <rect x="1132" y="770" width="108" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 55 | - <text x="1186.0" y="791.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">■ Arrêter</text> | |
| 55 | + <text x="1186.0" y="791.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">■ Stop</text> | |
| 56 | 56 | <rect x="1040" y="176" width="200" height="30" rx="15" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> |
| 57 | - <text x="1140" y="196" font-size="11.5" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">contexte Riker : 41 %</text> | |
| 57 | + <text x="1140" y="196" font-size="11.5" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Riker's context: 41%</text> | |
| 58 | 58 | <circle cx="575" cy="191" r="12" fill="#6A1B9A"/> |
| 59 | 59 | <text x="575" y="195.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 60 | 60 | <circle cx="355" cy="274" r="12" fill="#6A1B9A"/> |
| @@ -68,33 +68,33 @@ | ||
| 68 | 68 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 69 | 69 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 70 | 70 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 71 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Arrivée visible</text> | |
| 72 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">La 1re mention invite l'agent : un message</text> | |
| 73 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">système le dit. On sait qui « écoute ».</text> | |
| 71 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">A visible arrival</text> | |
| 72 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The first mention invites the agent: a system</text> | |
| 73 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">message says so. You know who is listening.</text> | |
| 74 | 74 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 75 | 75 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 76 | 76 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 77 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Une couleur par agent</text> | |
| 78 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Avatar + nom colorés, réponses en Markdown</text> | |
| 79 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">avec code coloré (ADR 0002).</text> | |
| 77 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">One colour per agent</text> | |
| 78 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Coloured avatar and name, answers in</text> | |
| 79 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Markdown with highlighted code (ADR 0002).</text> | |
| 80 | 80 | <rect x="1284" y="260" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 81 | 81 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 82 | 82 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 83 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Outils repliés</text> | |
| 84 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Une ligne par tool call : titre lisible et</text> | |
| 85 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">statut. Déplier montre la commande, le</text> | |
| 86 | - <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">diff ou la sortie.</text> | |
| 83 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Folded tools</text> | |
| 84 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">One line per tool call: a readable title</text> | |
| 85 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">and its status. Unfolding shows the</text> | |
| 86 | + <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">command, the diff or the output.</text> | |
| 87 | 87 | <rect x="1284" y="368" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 88 | 88 | <circle cx="1306" cy="390" r="12" fill="#6A1B9A"/> |
| 89 | 89 | <text x="1306" y="394.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 90 | - <text x="1328" y="395" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Toujours un bouton Arrêter</text> | |
| 91 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Envoie session/cancel aux agents qui</text> | |
| 92 | - <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">répondent dans ce channel (ADR 0001).</text> | |
| 90 | + <text x="1328" y="395" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Always a Stop button</text> | |
| 91 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Sends session/cancel to the agents</text> | |
| 92 | + <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">answering in this channel (ADR 0001).</text> | |
| 93 | 93 | <rect x="1284" y="458" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 94 | 94 | <circle cx="1306" cy="480" r="12" fill="#6A1B9A"/> |
| 95 | 95 | <text x="1306" y="484.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 96 | - <text x="1328" y="485" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Jauge de contexte</text> | |
| 97 | - <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">usage_update : prévient avant que la</text> | |
| 98 | - <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">conversation ne dépasse la mémoire de</text> | |
| 99 | - <text x="1300" y="544" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">l'agent.</text> | |
| 96 | + <text x="1328" y="485" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Context gauge</text> | |
| 97 | + <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">usage_update: warns before the</text> | |
| 98 | + <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">conversation outgrows the agent's</text> | |
| 99 | + <text x="1300" y="544" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">memory.</text> | |
| 100 | 100 | </svg> |
| @@ -1,8 +1,8 @@ | |||
| 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | <rect width="1660" height="900" fill="#FFFFFF"/> | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">2 · Conversation multi-agents</text> | 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">2 · Multi-agent conversation</text> |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Chaque agent a sa couleur ; les outils sont repliés ; on peut toujours arrêter</text> | 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Each agent has its colour; tools are folded; you can always stop</text> |
| 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,14 +11,14 @@ | |||
| 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> |
| 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | <rect x="28" y="158" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> | 19 | <rect x="28" y="158" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> |
| 20 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | 20 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> |
| 21 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | 21 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> |
| 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> | 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> |
| 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> | 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| 24 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> | 24 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> |
| @@ -30,31 +30,31 @@ | |||
| 30 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> | 30 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> |
| 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> | 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 32 | <rect x="251" y="116" width="1009" height="44" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 32 | <rect x="251" y="116" width="1009" height="44" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 33 | - <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | 33 | + <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> |
| 34 | <text x="1244" y="144" font-size="13" fill="#6B6F7A" text-anchor="end" xml:space="preserve">👩 Alice · 🧔 Bob · 🧑🚀 Riker</text> | 34 | <text x="1244" y="144" font-size="13" fill="#6B6F7A" text-anchor="end" xml:space="preserve">👩 Alice · 🧔 Bob · 🧑🚀 Riker</text> |
| 35 | - <text x="275" y="196" font-size="12.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-style="italic">— Riker a rejoint le channel —</text> | 35 | + <text x="275" y="196" font-size="12.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-style="italic">— Riker joined the channel —</text> |
| 36 | - <text x="275" y="228" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Vous</text> | 36 | + <text x="275" y="228" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">You</text> |
| 37 | - <text x="275" y="250.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@alice propose un nom pour un script qui sauvegarde mes photos</text> | 37 | + <text x="275" y="250.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@alice suggest a name for a script that backs up my photos</text> |
| 38 | <text x="275" y="284" font-size="13.5" fill="#C2185B" text-anchor="start" xml:space="preserve" font-weight="700">👩 Alice</text> | 38 | <text x="275" y="284" font-size="13.5" fill="#C2185B" text-anchor="start" xml:space="preserve" font-weight="700">👩 Alice</text> |
| 39 | - <text x="275" y="306.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">Je propose « photo-backup.sh » : court, explicite, et l'extension dit que</text> | 39 | + <text x="275" y="306.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">I suggest "photo-backup.sh": short, clear, and the extension says</text> |
| 40 | - <text x="275" y="325.5" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">c'est un script shell.</text> | 40 | + <text x="275" y="325.5" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">it is a shell script.</text> |
| 41 | - <text x="275" y="360" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Vous</text> | 41 | + <text x="275" y="360" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">You</text> |
| 42 | - <text x="275" y="382.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@bob tu valides ? @riker crée le fichier vide</text> | 42 | + <text x="275" y="382.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@bob do you agree? @riker create the empty file</text> |
| 43 | <text x="275" y="416" font-size="13.5" fill="#00838F" text-anchor="start" xml:space="preserve" font-weight="700">🧔 Bob</text> | 43 | <text x="275" y="416" font-size="13.5" fill="#00838F" text-anchor="start" xml:space="preserve" font-weight="700">🧔 Bob</text> |
| 44 | - <text x="275" y="438.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">Bon choix. Alice a raison : un nom en minuscules, sans espace.</text> | 44 | + <text x="275" y="438.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">Good choice. Alice is right: a lowercase name, no spaces.</text> |
| 45 | <text x="275" y="472" font-size="13.5" fill="#5E35B1" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker</text> | 45 | <text x="275" y="472" font-size="13.5" fill="#5E35B1" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker</text> |
| 46 | - <text x="365" y="472" font-size="12.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-style="italic">travaille…</text> | 46 | + <text x="365" y="472" font-size="12.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-style="italic">working…</text> |
| 47 | <rect x="275" y="484" width="560" height="40" rx="8" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> | 47 | <rect x="275" y="484" width="560" height="40" rx="8" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> |
| 48 | - <text x="289" y="509" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">▸ 🛠 write_file : photo-backup.sh (0 octet) ✓ terminé</text> | 48 | + <text x="289" y="509" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">▸ 🛠 write_file: photo-backup.sh (0 bytes) ✓ done</text> |
| 49 | <rect x="275" y="532" width="560" height="40" rx="8" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> | 49 | <rect x="275" y="532" width="560" height="40" rx="8" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> |
| 50 | - <text x="289" y="557" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">▸ 🛠 bash : ls -la … en cours</text> | 50 | + <text x="289" y="557" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">▸ 🛠 bash: ls -la … running</text> |
| 51 | <rect x="271" y="754" width="849" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> | 51 | <rect x="271" y="754" width="849" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> |
| 52 | <text x="285" y="780" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve"></text> | 52 | <text x="285" y="780" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve"></text> |
| 53 | - <text x="285" y="804" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Entrée pour envoyer · Maj+Entrée nouvelle ligne</text> | 53 | + <text x="285" y="804" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Enter to send · Shift+Enter for a new line</text> |
| 54 | <rect x="1132" y="770" width="108" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> | 54 | <rect x="1132" y="770" width="108" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 55 | - <text x="1186.0" y="791.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">■ Arrêter</text> | 55 | + <text x="1186.0" y="791.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">■ Stop</text> |
| 56 | <rect x="1040" y="176" width="200" height="30" rx="15" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> | 56 | <rect x="1040" y="176" width="200" height="30" rx="15" fill="#F0F1F3" stroke="#E2E3E6" stroke-width="1"/> |
| 57 | - <text x="1140" y="196" font-size="11.5" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">contexte Riker : 41 %</text> | 57 | + <text x="1140" y="196" font-size="11.5" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Riker's context: 41%</text> |
| 58 | <circle cx="575" cy="191" r="12" fill="#6A1B9A"/> | 58 | <circle cx="575" cy="191" r="12" fill="#6A1B9A"/> |
| 59 | <text x="575" y="195.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 59 | <text x="575" y="195.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 60 | <circle cx="355" cy="274" r="12" fill="#6A1B9A"/> | 60 | <circle cx="355" cy="274" r="12" fill="#6A1B9A"/> |
| @@ -68,33 +68,33 @@ | |||
| 68 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 68 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 69 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> | 69 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 70 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 70 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 71 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Arrivée visible</text> | 71 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">A visible arrival</text> |
| 72 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">La 1re mention invite l'agent : un message</text> | 72 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The first mention invites the agent: a system</text> |
| 73 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">système le dit. On sait qui « écoute ».</text> | 73 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">message says so. You know who is listening.</text> |
| 74 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 74 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 75 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> | 75 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 76 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> | 76 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 77 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Une couleur par agent</text> | 77 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">One colour per agent</text> |
| 78 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Avatar + nom colorés, réponses en Markdown</text> | 78 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Coloured avatar and name, answers in</text> |
| 79 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">avec code coloré (ADR 0002).</text> | 79 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Markdown with highlighted code (ADR 0002).</text> |
| 80 | <rect x="1284" y="260" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 80 | <rect x="1284" y="260" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 81 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> | 81 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 82 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> | 82 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 83 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Outils repliés</text> | 83 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Folded tools</text> |
| 84 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Une ligne par tool call : titre lisible et</text> | 84 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">One line per tool call: a readable title</text> |
| 85 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">statut. Déplier montre la commande, le</text> | 85 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">and its status. Unfolding shows the</text> |
| 86 | - <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">diff ou la sortie.</text> | 86 | + <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">command, the diff or the output.</text> |
| 87 | <rect x="1284" y="368" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 87 | <rect x="1284" y="368" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 88 | <circle cx="1306" cy="390" r="12" fill="#6A1B9A"/> | 88 | <circle cx="1306" cy="390" r="12" fill="#6A1B9A"/> |
| 89 | <text x="1306" y="394.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> | 89 | <text x="1306" y="394.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 90 | - <text x="1328" y="395" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Toujours un bouton Arrêter</text> | 90 | + <text x="1328" y="395" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Always a Stop button</text> |
| 91 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Envoie session/cancel aux agents qui</text> | 91 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Sends session/cancel to the agents</text> |
| 92 | - <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">répondent dans ce channel (ADR 0001).</text> | 92 | + <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">answering in this channel (ADR 0001).</text> |
| 93 | <rect x="1284" y="458" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 93 | <rect x="1284" y="458" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 94 | <circle cx="1306" cy="480" r="12" fill="#6A1B9A"/> | 94 | <circle cx="1306" cy="480" r="12" fill="#6A1B9A"/> |
| 95 | <text x="1306" y="484.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> | 95 | <text x="1306" y="484.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 96 | - <text x="1328" y="485" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Jauge de contexte</text> | 96 | + <text x="1328" y="485" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Context gauge</text> |
| 97 | - <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">usage_update : prévient avant que la</text> | 97 | + <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">usage_update: warns before the</text> |
| 98 | - <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">conversation ne dépasse la mémoire de</text> | 98 | + <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">conversation outgrows the agent's</text> |
| 99 | - <text x="1300" y="544" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">l'agent.</text> | 99 | + <text x="1300" y="544" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">memory.</text> |
| 100 | </svg> | 100 | </svg> |
modified
docs/design/03-mentions-commands.png +0 -0 | Binary files a/docs/design/03-mentions-commands.png and b/docs/design/03-mentions-commands.png differ |
| Binary files a/docs/design/03-mentions-commands.png and b/docs/design/03-mentions-commands.png differ | Binary files a/docs/design/03-mentions-commands.png and b/docs/design/03-mentions-commands.png differ |
modified
docs/design/03-mentions-commands.svg +34 -34 | @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">3 · Invoquer un agent (@) et une commande (/)</text> | |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Tab choisit la suggestion ; continuer à écrire filtre la liste</text> | |
| 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">3 · Calling an agent (@) and a command (/)</text> | |
| 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Tab picks the suggestion; typing on filters the list</text> | |
| 6 | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,14 +11,14 @@ | ||
| 11 | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | |
| 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> | |
| 15 | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | 19 | <rect x="28" y="158" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> |
| 20 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | |
| 21 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | |
| 20 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> | |
| 21 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> | |
| 22 | 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> |
| 23 | 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| 24 | 24 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> |
| @@ -29,36 +29,36 @@ | ||
| 29 | 29 | <text x="54" y="366" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🧑🚀 Riker</text> |
| 30 | 30 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> |
| 31 | 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 32 | - <text x="271" y="150" font-size="14" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">Mention d'un agent</text> | |
| 32 | + <text x="271" y="150" font-size="14" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">Mentioning an agent</text> | |
| 33 | 33 | <g filter="url(#shadow)"><rect x="271" y="164" width="420" height="150" rx="10" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/></g> |
| 34 | 34 | <rect x="277" y="172" width="408" height="40" rx="6" fill="#E8EFFD" stroke="none"/> |
| 35 | 35 | <text x="289" y="190" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🐮 garfield</text> |
| 36 | - <text x="289" y="206" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Garfield (traducteur) — traduit FR ⇄ EN</text> | |
| 36 | + <text x="289" y="206" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Garfield (translator) — translates FR ⇄ EN</text> | |
| 37 | 37 | <text x="289" y="234" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 riker</text> |
| 38 | - <text x="289" y="250" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Riker (outils) — commandes et fichiers</text> | |
| 38 | + <text x="289" y="250" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Riker (tools) — commands and files</text> | |
| 39 | 39 | <text x="289" y="278" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">👩 alice</text> |
| 40 | - <text x="289" y="294" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Alice (assistante) — questions simples</text> | |
| 40 | + <text x="289" y="294" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Alice (assistant) — simple questions</text> | |
| 41 | 41 | <rect x="271" y="324" width="969" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> |
| 42 | 42 | <text x="285" y="350" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">@ga</text> |
| 43 | - <text x="285" y="374" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Tab : @garfield · ↑↓ naviguer · Échap fermer</text> | |
| 44 | - <text x="271" y="440" font-size="14" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">Commande d'un agent (plusieurs agents dans le channel)</text> | |
| 43 | + <text x="285" y="374" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Tab: @garfield · ↑↓ move · Esc close</text> | |
| 44 | + <text x="271" y="440" font-size="14" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">An agent's command (several agents in the channel)</text> | |
| 45 | 45 | <g filter="url(#shadow)"><rect x="271" y="454" width="520" height="196" rx="10" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/></g> |
| 46 | 46 | <rect x="277" y="462" width="508" height="42" rx="6" fill="#E8EFFD" stroke="none"/> |
| 47 | 47 | <text x="289" y="481" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/garfield:idioms</text> |
| 48 | - <text x="771" y="481" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[texte]</text> | |
| 49 | - <text x="289" y="498" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Expressions idiomatiques et faux amis</text> | |
| 48 | + <text x="771" y="481" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[text]</text> | |
| 49 | + <text x="289" y="498" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Idioms and false friends</text> | |
| 50 | 50 | <text x="289" y="527" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/garfield:styles</text> |
| 51 | - <text x="771" y="527" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[texte]</text> | |
| 52 | - <text x="289" y="544" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Plusieurs versions d'une traduction</text> | |
| 51 | + <text x="771" y="527" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[text]</text> | |
| 52 | + <text x="289" y="544" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Several versions of a translation</text> | |
| 53 | 53 | <text x="289" y="573" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/garfield:email-letter</text> |
| 54 | - <text x="771" y="573" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[texte]</text> | |
| 55 | - <text x="289" y="590" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">E-mails et lettres : formules, tu ou vous</text> | |
| 54 | + <text x="771" y="573" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[text]</text> | |
| 55 | + <text x="289" y="590" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">E-mails and letters: greetings, tu or vous</text> | |
| 56 | 56 | <text x="289" y="619" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/alice:compact</text> |
| 57 | 57 | <text x="771" y="619" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"></text> |
| 58 | - <text x="289" y="636" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Résumer l'historique maintenant</text> | |
| 58 | + <text x="289" y="636" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Summarise the history now</text> | |
| 59 | 59 | <rect x="271" y="660" width="969" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> |
| 60 | 60 | <text x="285" y="686" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">/gar</text> |
| 61 | - <text x="285" y="710" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Tab : /garfield:idioms · le texte après la commande est son argument</text> | |
| 61 | + <text x="285" y="710" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Tab: /garfield:idioms · the text after the command is its argument</text> | |
| 62 | 62 | <circle cx="705" cy="180" r="12" fill="#6A1B9A"/> |
| 63 | 63 | <text x="705" y="184.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 64 | 64 | <circle cx="571" cy="356" r="12" fill="#6A1B9A"/> |
| @@ -72,31 +72,31 @@ | ||
| 72 | 72 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 73 | 73 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 74 | 74 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 75 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">@ liste les agents de la config</text> | |
| 76 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Nom technique + titre + description.</text> | |
| 77 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Filtrage flou sur nom et titre (« gar »).</text> | |
| 75 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">@ lists the configured agents</text> | |
| 76 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Technical name + title + description.</text> | |
| 77 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Fuzzy filter on name and title ("gar").</text> | |
| 78 | 78 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 79 | 79 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 80 | 80 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 81 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Tab sélectionne, sinon on écrit</text> | |
| 82 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Comportement demandé dans le draft (#1).</text> | |
| 83 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Échap ferme sans rien insérer.</text> | |
| 81 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Tab picks, otherwise you type</text> | |
| 82 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Behaviour asked for in the draft (#1).</text> | |
| 83 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Esc closes without inserting anything.</text> | |
| 84 | 84 | <rect x="1284" y="260" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 85 | 85 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 86 | 86 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 87 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">/agent:commande en multi-agents</text> | |
| 88 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Avec un seul agent : /commande. Sidekicks</text> | |
| 89 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">envoie « /idioms … » au seul Garfield.</text> | |
| 87 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">/agent:command with several agents</text> | |
| 88 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">With one agent: /command. Sidekicks</text> | |
| 89 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">sends "/idioms …" to Garfield only.</text> | |
| 90 | 90 | <rect x="1284" y="350" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 91 | 91 | <circle cx="1306" cy="372" r="12" fill="#6A1B9A"/> |
| 92 | 92 | <text x="1306" y="376.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 93 | - <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Skills et commandes intégrées</text> | |
| 94 | - <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">mm annonce compact, new, unload et ses</text> | |
| 95 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">skills (available_commands_update).</text> | |
| 93 | + <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Skills and built-in commands</text> | |
| 94 | + <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">mm announces compact, new, unload and</text> | |
| 95 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">its skills (available_commands_update).</text> | |
| 96 | 96 | <rect x="1284" y="440" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 97 | 97 | <circle cx="1306" cy="462" r="12" fill="#6A1B9A"/> |
| 98 | 98 | <text x="1306" y="466.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 99 | - <text x="1328" y="467" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Indice d'argument</text> | |
| 100 | - <text x="1300" y="490" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">input.hint de la commande ACP, affiché</text> | |
| 101 | - <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">tant que l'argument n'est pas saisi.</text> | |
| 99 | + <text x="1328" y="467" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Argument hint</text> | |
| 100 | + <text x="1300" y="490" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The ACP command's input.hint, shown</text> | |
| 101 | + <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">until the argument is typed.</text> | |
| 102 | 102 | </svg> |
| @@ -1,8 +1,8 @@ | |||
| 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | <rect width="1660" height="900" fill="#FFFFFF"/> | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">3 · Invoquer un agent (@) et une commande (/)</text> | 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">3 · Calling an agent (@) and a command (/)</text> |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Tab choisit la suggestion ; continuer à écrire filtre la liste</text> | 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Tab picks the suggestion; typing on filters the list</text> |
| 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,14 +11,14 @@ | |||
| 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> |
| 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | <rect x="28" y="158" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> | 19 | <rect x="28" y="158" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> |
| 20 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># général</text> | 20 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># general</text> |
| 21 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | 21 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> |
| 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> | 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> |
| 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> | 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| 24 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> | 24 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> |
| @@ -29,36 +29,36 @@ | |||
| 29 | <text x="54" y="366" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🧑🚀 Riker</text> | 29 | <text x="54" y="366" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🧑🚀 Riker</text> |
| 30 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> | 30 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> |
| 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> | 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 32 | - <text x="271" y="150" font-size="14" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">Mention d'un agent</text> | 32 | + <text x="271" y="150" font-size="14" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">Mentioning an agent</text> |
| 33 | <g filter="url(#shadow)"><rect x="271" y="164" width="420" height="150" rx="10" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/></g> | 33 | <g filter="url(#shadow)"><rect x="271" y="164" width="420" height="150" rx="10" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/></g> |
| 34 | <rect x="277" y="172" width="408" height="40" rx="6" fill="#E8EFFD" stroke="none"/> | 34 | <rect x="277" y="172" width="408" height="40" rx="6" fill="#E8EFFD" stroke="none"/> |
| 35 | <text x="289" y="190" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🐮 garfield</text> | 35 | <text x="289" y="190" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🐮 garfield</text> |
| 36 | - <text x="289" y="206" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Garfield (traducteur) — traduit FR ⇄ EN</text> | 36 | + <text x="289" y="206" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Garfield (translator) — translates FR ⇄ EN</text> |
| 37 | <text x="289" y="234" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 riker</text> | 37 | <text x="289" y="234" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 riker</text> |
| 38 | - <text x="289" y="250" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Riker (outils) — commandes et fichiers</text> | 38 | + <text x="289" y="250" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Riker (tools) — commands and files</text> |
| 39 | <text x="289" y="278" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">👩 alice</text> | 39 | <text x="289" y="278" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">👩 alice</text> |
| 40 | - <text x="289" y="294" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Alice (assistante) — questions simples</text> | 40 | + <text x="289" y="294" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Alice (assistant) — simple questions</text> |
| 41 | <rect x="271" y="324" width="969" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> | 41 | <rect x="271" y="324" width="969" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> |
| 42 | <text x="285" y="350" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">@ga</text> | 42 | <text x="285" y="350" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">@ga</text> |
| 43 | - <text x="285" y="374" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Tab : @garfield · ↑↓ naviguer · Échap fermer</text> | 43 | + <text x="285" y="374" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Tab: @garfield · ↑↓ move · Esc close</text> |
| 44 | - <text x="271" y="440" font-size="14" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">Commande d'un agent (plusieurs agents dans le channel)</text> | 44 | + <text x="271" y="440" font-size="14" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">An agent's command (several agents in the channel)</text> |
| 45 | <g filter="url(#shadow)"><rect x="271" y="454" width="520" height="196" rx="10" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/></g> | 45 | <g filter="url(#shadow)"><rect x="271" y="454" width="520" height="196" rx="10" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/></g> |
| 46 | <rect x="277" y="462" width="508" height="42" rx="6" fill="#E8EFFD" stroke="none"/> | 46 | <rect x="277" y="462" width="508" height="42" rx="6" fill="#E8EFFD" stroke="none"/> |
| 47 | <text x="289" y="481" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/garfield:idioms</text> | 47 | <text x="289" y="481" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/garfield:idioms</text> |
| 48 | - <text x="771" y="481" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[texte]</text> | 48 | + <text x="771" y="481" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[text]</text> |
| 49 | - <text x="289" y="498" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Expressions idiomatiques et faux amis</text> | 49 | + <text x="289" y="498" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Idioms and false friends</text> |
| 50 | <text x="289" y="527" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/garfield:styles</text> | 50 | <text x="289" y="527" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/garfield:styles</text> |
| 51 | - <text x="771" y="527" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[texte]</text> | 51 | + <text x="771" y="527" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[text]</text> |
| 52 | - <text x="289" y="544" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Plusieurs versions d'une traduction</text> | 52 | + <text x="289" y="544" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Several versions of a translation</text> |
| 53 | <text x="289" y="573" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/garfield:email-letter</text> | 53 | <text x="289" y="573" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/garfield:email-letter</text> |
| 54 | - <text x="771" y="573" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[texte]</text> | 54 | + <text x="771" y="573" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">[text]</text> |
| 55 | - <text x="289" y="590" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">E-mails et lettres : formules, tu ou vous</text> | 55 | + <text x="289" y="590" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">E-mails and letters: greetings, tu or vous</text> |
| 56 | <text x="289" y="619" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/alice:compact</text> | 56 | <text x="289" y="619" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700" font-family="DejaVu Sans Mono, monospace">/alice:compact</text> |
| 57 | <text x="771" y="619" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"></text> | 57 | <text x="771" y="619" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"></text> |
| 58 | - <text x="289" y="636" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Résumer l'historique maintenant</text> | 58 | + <text x="289" y="636" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Summarise the history now</text> |
| 59 | <rect x="271" y="660" width="969" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> | 59 | <rect x="271" y="660" width="969" height="64" rx="10" fill="#FFFFFF" stroke="#3B6FE0" stroke-width="1.5"/> |
| 60 | <text x="285" y="686" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">/gar</text> | 60 | <text x="285" y="686" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve">/gar</text> |
| 61 | - <text x="285" y="710" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Tab : /garfield:idioms · le texte après la commande est son argument</text> | 61 | + <text x="285" y="710" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Tab: /garfield:idioms · the text after the command is its argument</text> |
| 62 | <circle cx="705" cy="180" r="12" fill="#6A1B9A"/> | 62 | <circle cx="705" cy="180" r="12" fill="#6A1B9A"/> |
| 63 | <text x="705" y="184.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 63 | <text x="705" y="184.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 64 | <circle cx="571" cy="356" r="12" fill="#6A1B9A"/> | 64 | <circle cx="571" cy="356" r="12" fill="#6A1B9A"/> |
| @@ -72,31 +72,31 @@ | |||
| 72 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 72 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 73 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> | 73 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 74 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 74 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 75 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">@ liste les agents de la config</text> | 75 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">@ lists the configured agents</text> |
| 76 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Nom technique + titre + description.</text> | 76 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Technical name + title + description.</text> |
| 77 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Filtrage flou sur nom et titre (« gar »).</text> | 77 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Fuzzy filter on name and title ("gar").</text> |
| 78 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 78 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 79 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> | 79 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 80 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> | 80 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 81 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Tab sélectionne, sinon on écrit</text> | 81 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Tab picks, otherwise you type</text> |
| 82 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Comportement demandé dans le draft (#1).</text> | 82 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Behaviour asked for in the draft (#1).</text> |
| 83 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Échap ferme sans rien insérer.</text> | 83 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Esc closes without inserting anything.</text> |
| 84 | <rect x="1284" y="260" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 84 | <rect x="1284" y="260" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 85 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> | 85 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 86 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> | 86 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 87 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">/agent:commande en multi-agents</text> | 87 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">/agent:command with several agents</text> |
| 88 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Avec un seul agent : /commande. Sidekicks</text> | 88 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">With one agent: /command. Sidekicks</text> |
| 89 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">envoie « /idioms … » au seul Garfield.</text> | 89 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">sends "/idioms …" to Garfield only.</text> |
| 90 | <rect x="1284" y="350" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 90 | <rect x="1284" y="350" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 91 | <circle cx="1306" cy="372" r="12" fill="#6A1B9A"/> | 91 | <circle cx="1306" cy="372" r="12" fill="#6A1B9A"/> |
| 92 | <text x="1306" y="376.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> | 92 | <text x="1306" y="376.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 93 | - <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Skills et commandes intégrées</text> | 93 | + <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Skills and built-in commands</text> |
| 94 | - <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">mm annonce compact, new, unload et ses</text> | 94 | + <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">mm announces compact, new, unload and</text> |
| 95 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">skills (available_commands_update).</text> | 95 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">its skills (available_commands_update).</text> |
| 96 | <rect x="1284" y="440" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 96 | <rect x="1284" y="440" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 97 | <circle cx="1306" cy="462" r="12" fill="#6A1B9A"/> | 97 | <circle cx="1306" cy="462" r="12" fill="#6A1B9A"/> |
| 98 | <text x="1306" y="466.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> | 98 | <text x="1306" y="466.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 99 | - <text x="1328" y="467" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Indice d'argument</text> | 99 | + <text x="1328" y="467" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Argument hint</text> |
| 100 | - <text x="1300" y="490" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">input.hint de la commande ACP, affiché</text> | 100 | + <text x="1300" y="490" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The ACP command's input.hint, shown</text> |
| 101 | - <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">tant que l'argument n'est pas saisi.</text> | 101 | + <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">until the argument is typed.</text> |
| 102 | </svg> | 102 | </svg> |
modified
docs/design/04-permission.png +0 -0 | Binary files a/docs/design/04-permission.png and b/docs/design/04-permission.png differ |
| Binary files a/docs/design/04-permission.png and b/docs/design/04-permission.png differ | Binary files a/docs/design/04-permission.png and b/docs/design/04-permission.png differ |
modified
docs/design/04-permission.svg +33 -33 | @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">4 · Demande de permission</text> | |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">En langage clair, sur la conversation concernée, avec une sortie de secours</text> | |
| 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">4 · Permission request</text> | |
| 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">In plain words, on the conversation concerned, with a way out</text> | |
| 6 | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,13 +11,13 @@ | ||
| 11 | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | |
| 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> | |
| 15 | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># général</text> | |
| 20 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | |
| 19 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># general</text> | |
| 20 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> | |
| 21 | 21 | <rect x="28" y="218" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> |
| 22 | 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># code</text> |
| 23 | 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| @@ -31,28 +31,28 @@ | ||
| 31 | 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 32 | 32 | <rect x="251" y="116" width="1009" height="44" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 33 | 33 | <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># code</text> |
| 34 | - <text x="275" y="196" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Vous</text> | |
| 35 | - <text x="275" y="218.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@riker supprime les fichiers temporaires du dossier</text> | |
| 34 | + <text x="275" y="196" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">You</text> | |
| 35 | + <text x="275" y="218.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@riker delete the temporary files in the folder</text> | |
| 36 | 36 | <text x="275" y="252" font-size="13.5" fill="#5E35B1" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker</text> |
| 37 | - <text x="365" y="252" font-size="12.5" fill="#C98A1B" text-anchor="start" xml:space="preserve" font-style="italic">attend votre réponse</text> | |
| 37 | + <text x="365" y="252" font-size="12.5" fill="#C98A1B" text-anchor="start" xml:space="preserve" font-style="italic">waiting for your answer</text> | |
| 38 | 38 | <g filter="url(#shadow)"><rect x="275" y="270" width="720" height="330" rx="12" fill="#FFFFFF" stroke="#C98A1B" stroke-width="2"/></g> |
| 39 | - <text x="295" y="304" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker veut exécuter une commande sur votre ordinateur</text> | |
| 39 | + <text x="295" y="304" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker wants to run a command on your computer</text> | |
| 40 | 40 | <rect x="295" y="322" width="680" height="40" rx="6" fill="#F4F5F7" stroke="#E2E3E6" stroke-width="1"/> |
| 41 | 41 | <text x="309" y="347" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">rm -f *.tmp</text> |
| 42 | - <text x="295" y="388" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">Ce que cela fait : supprime définitivement les fichiers se terminant par .tmp</text> | |
| 43 | - <text x="295" y="408" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">dans agents/riker . Ils ne passent pas par la corbeille.</text> | |
| 44 | - <text x="295" y="438" font-size="13" fill="#D64561" text-anchor="start" xml:space="preserve" font-weight="700">⚠ Action irréversible</text> | |
| 42 | + <text x="295" y="388" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">What it does: permanently deletes the files ending in .tmp</text> | |
| 43 | + <text x="295" y="408" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">in agents/riker . They do not go to the trash.</text> | |
| 44 | + <text x="295" y="438" font-size="13" fill="#D64561" text-anchor="start" xml:space="preserve" font-weight="700">⚠ Cannot be undone</text> | |
| 45 | 45 | <rect x="295" y="460" width="170" height="32" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> |
| 46 | - <text x="380.0" y="481.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Autoriser une fois</text> | |
| 46 | + <text x="380.0" y="481.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Allow once</text> | |
| 47 | 47 | <rect x="475" y="460" width="300" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 48 | - <text x="625.0" y="481.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Toujours autoriser bash ici</text> | |
| 48 | + <text x="625.0" y="481.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Always allow bash here</text> | |
| 49 | 49 | <rect x="295" y="504" width="170" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 50 | - <text x="380.0" y="525.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Refuser</text> | |
| 50 | + <text x="380.0" y="525.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Reject</text> | |
| 51 | 51 | <rect x="475" y="504" width="300" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 52 | - <text x="625.0" y="525.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Ne plus jamais proposer bash ici</text> | |
| 52 | + <text x="625.0" y="525.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Never offer bash here again</text> | |
| 53 | 53 | <rect x="795" y="504" width="180" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 54 | - <text x="885.0" y="525.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">■ Arrêter Riker</text> | |
| 55 | - <text x="295" y="570" font-size="12" fill="#6B6F7A" text-anchor="start" xml:space="preserve">▸ Détails techniques (tool call bash, rawInput)</text> | |
| 54 | + <text x="885.0" y="525.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">■ Stop Riker</text> | |
| 55 | + <text x="295" y="570" font-size="12" fill="#6B6F7A" text-anchor="start" xml:space="preserve">▸ Technical details (bash tool call, rawInput)</text> | |
| 56 | 56 | <circle cx="979" cy="300" r="12" fill="#6A1B9A"/> |
| 57 | 57 | <text x="979" y="304.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 58 | 58 | <circle cx="955" cy="398" r="12" fill="#6A1B9A"/> |
| @@ -66,32 +66,32 @@ | ||
| 66 | 66 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 67 | 67 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 68 | 68 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 69 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Attaché à la conversation</text> | |
| 70 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Bloque seulement la session de Riker ; les</text> | |
| 71 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">autres channels continuent (#17).</text> | |
| 69 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Attached to the conversation</text> | |
| 70 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Blocks only Riker's session; the other</text> | |
| 71 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">channels go on (#17).</text> | |
| 72 | 72 | <rect x="1284" y="170" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 73 | 73 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 74 | 74 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 75 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Expliquer, pas montrer du JSON</text> | |
| 76 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Titre ACP + kind + rawInput traduits en</text> | |
| 77 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">phrase. Les actions destructives sont</text> | |
| 78 | - <text x="1300" y="256" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">signalées.</text> | |
| 75 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Explain, do not show JSON</text> | |
| 76 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">ACP title + kind + rawInput turned into</text> | |
| 77 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">a sentence. Destructive actions are</text> | |
| 78 | + <text x="1300" y="256" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">flagged.</text> | |
| 79 | 79 | <rect x="1284" y="278" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 80 | 80 | <circle cx="1306" cy="300" r="12" fill="#6A1B9A"/> |
| 81 | 81 | <text x="1306" y="304.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 82 | - <text x="1328" y="305" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Les 4 options ACP, par ids</text> | |
| 82 | + <text x="1328" y="305" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">The 4 ACP options, by id</text> | |
| 83 | 83 | <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">allow · allow_always · reject · never.</text> |
| 84 | - <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">« Ne plus jamais » est mis en avant au</text> | |
| 85 | - <text x="1300" y="364" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">lieu de « Refuser une fois ».</text> | |
| 84 | + <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">"Never again" is put forward rather</text> | |
| 85 | + <text x="1300" y="364" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">than "Reject once".</text> | |
| 86 | 86 | <rect x="1284" y="386" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 87 | 87 | <circle cx="1306" cy="408" r="12" fill="#6A1B9A"/> |
| 88 | 88 | <text x="1306" y="412.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 89 | - <text x="1328" y="413" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Toujours une sortie de secours</text> | |
| 90 | - <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Spike ACP : après un refus, un petit modèle</text> | |
| 91 | - <text x="1300" y="454" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">a réessayé 40 fois. Arrêter = session/cancel.</text> | |
| 89 | + <text x="1328" y="413" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Always a way out</text> | |
| 90 | + <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">ACP spike: after a rejection, a small model</text> | |
| 91 | + <text x="1300" y="454" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">retried 40 times. Stop = session/cancel.</text> | |
| 92 | 92 | <rect x="1284" y="476" width="356" height="58" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 93 | 93 | <circle cx="1306" cy="498" r="12" fill="#6A1B9A"/> |
| 94 | 94 | <text x="1306" y="502.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 95 | - <text x="1328" y="503" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Détails pour les curieux</text> | |
| 96 | - <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Repliés par défaut.</text> | |
| 95 | + <text x="1328" y="503" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Details for the curious</text> | |
| 96 | + <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Folded by default.</text> | |
| 97 | 97 | </svg> |
| @@ -1,8 +1,8 @@ | |||
| 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | <rect width="1660" height="900" fill="#FFFFFF"/> | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">4 · Demande de permission</text> | 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">4 · Permission request</text> |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">En langage clair, sur la conversation concernée, avec une sortie de secours</text> | 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">In plain words, on the conversation concerned, with a way out</text> |
| 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,13 +11,13 @@ | |||
| 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> |
| 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># général</text> | 19 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># general</text> |
| 20 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | 20 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> |
| 21 | <rect x="28" y="218" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> | 21 | <rect x="28" y="218" width="214" height="26" rx="6" fill="#F0F1F3" stroke="none"/> |
| 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># code</text> | 22 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># code</text> |
| 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> | 23 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| @@ -31,28 +31,28 @@ | |||
| 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> | 31 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 32 | <rect x="251" y="116" width="1009" height="44" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 32 | <rect x="251" y="116" width="1009" height="44" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 33 | <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># code</text> | 33 | <text x="267" y="144" font-size="15" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700"># code</text> |
| 34 | - <text x="275" y="196" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Vous</text> | 34 | + <text x="275" y="196" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">You</text> |
| 35 | - <text x="275" y="218.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@riker supprime les fichiers temporaires du dossier</text> | 35 | + <text x="275" y="218.0" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">@riker delete the temporary files in the folder</text> |
| 36 | <text x="275" y="252" font-size="13.5" fill="#5E35B1" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker</text> | 36 | <text x="275" y="252" font-size="13.5" fill="#5E35B1" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker</text> |
| 37 | - <text x="365" y="252" font-size="12.5" fill="#C98A1B" text-anchor="start" xml:space="preserve" font-style="italic">attend votre réponse</text> | 37 | + <text x="365" y="252" font-size="12.5" fill="#C98A1B" text-anchor="start" xml:space="preserve" font-style="italic">waiting for your answer</text> |
| 38 | <g filter="url(#shadow)"><rect x="275" y="270" width="720" height="330" rx="12" fill="#FFFFFF" stroke="#C98A1B" stroke-width="2"/></g> | 38 | <g filter="url(#shadow)"><rect x="275" y="270" width="720" height="330" rx="12" fill="#FFFFFF" stroke="#C98A1B" stroke-width="2"/></g> |
| 39 | - <text x="295" y="304" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker veut exécuter une commande sur votre ordinateur</text> | 39 | + <text x="295" y="304" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🧑🚀 Riker wants to run a command on your computer</text> |
| 40 | <rect x="295" y="322" width="680" height="40" rx="6" fill="#F4F5F7" stroke="#E2E3E6" stroke-width="1"/> | 40 | <rect x="295" y="322" width="680" height="40" rx="6" fill="#F4F5F7" stroke="#E2E3E6" stroke-width="1"/> |
| 41 | <text x="309" y="347" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">rm -f *.tmp</text> | 41 | <text x="309" y="347" font-size="14" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">rm -f *.tmp</text> |
| 42 | - <text x="295" y="388" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">Ce que cela fait : supprime définitivement les fichiers se terminant par .tmp</text> | 42 | + <text x="295" y="388" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">What it does: permanently deletes the files ending in .tmp</text> |
| 43 | - <text x="295" y="408" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">dans agents/riker . Ils ne passent pas par la corbeille.</text> | 43 | + <text x="295" y="408" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">in agents/riker . They do not go to the trash.</text> |
| 44 | - <text x="295" y="438" font-size="13" fill="#D64561" text-anchor="start" xml:space="preserve" font-weight="700">⚠ Action irréversible</text> | 44 | + <text x="295" y="438" font-size="13" fill="#D64561" text-anchor="start" xml:space="preserve" font-weight="700">⚠ Cannot be undone</text> |
| 45 | <rect x="295" y="460" width="170" height="32" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> | 45 | <rect x="295" y="460" width="170" height="32" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> |
| 46 | - <text x="380.0" y="481.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Autoriser une fois</text> | 46 | + <text x="380.0" y="481.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Allow once</text> |
| 47 | <rect x="475" y="460" width="300" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 47 | <rect x="475" y="460" width="300" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 48 | - <text x="625.0" y="481.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Toujours autoriser bash ici</text> | 48 | + <text x="625.0" y="481.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Always allow bash here</text> |
| 49 | <rect x="295" y="504" width="170" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 49 | <rect x="295" y="504" width="170" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 50 | - <text x="380.0" y="525.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Refuser</text> | 50 | + <text x="380.0" y="525.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Reject</text> |
| 51 | <rect x="475" y="504" width="300" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 51 | <rect x="475" y="504" width="300" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 52 | - <text x="625.0" y="525.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Ne plus jamais proposer bash ici</text> | 52 | + <text x="625.0" y="525.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Never offer bash here again</text> |
| 53 | <rect x="795" y="504" width="180" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> | 53 | <rect x="795" y="504" width="180" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 54 | - <text x="885.0" y="525.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">■ Arrêter Riker</text> | 54 | + <text x="885.0" y="525.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">■ Stop Riker</text> |
| 55 | - <text x="295" y="570" font-size="12" fill="#6B6F7A" text-anchor="start" xml:space="preserve">▸ Détails techniques (tool call bash, rawInput)</text> | 55 | + <text x="295" y="570" font-size="12" fill="#6B6F7A" text-anchor="start" xml:space="preserve">▸ Technical details (bash tool call, rawInput)</text> |
| 56 | <circle cx="979" cy="300" r="12" fill="#6A1B9A"/> | 56 | <circle cx="979" cy="300" r="12" fill="#6A1B9A"/> |
| 57 | <text x="979" y="304.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 57 | <text x="979" y="304.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 58 | <circle cx="955" cy="398" r="12" fill="#6A1B9A"/> | 58 | <circle cx="955" cy="398" r="12" fill="#6A1B9A"/> |
| @@ -66,32 +66,32 @@ | |||
| 66 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 66 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 67 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> | 67 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 68 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 68 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 69 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Attaché à la conversation</text> | 69 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Attached to the conversation</text> |
| 70 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Bloque seulement la session de Riker ; les</text> | 70 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Blocks only Riker's session; the other</text> |
| 71 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">autres channels continuent (#17).</text> | 71 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">channels go on (#17).</text> |
| 72 | <rect x="1284" y="170" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 72 | <rect x="1284" y="170" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 73 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> | 73 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 74 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> | 74 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 75 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Expliquer, pas montrer du JSON</text> | 75 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Explain, do not show JSON</text> |
| 76 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Titre ACP + kind + rawInput traduits en</text> | 76 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">ACP title + kind + rawInput turned into</text> |
| 77 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">phrase. Les actions destructives sont</text> | 77 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">a sentence. Destructive actions are</text> |
| 78 | - <text x="1300" y="256" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">signalées.</text> | 78 | + <text x="1300" y="256" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">flagged.</text> |
| 79 | <rect x="1284" y="278" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 79 | <rect x="1284" y="278" width="356" height="94" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 80 | <circle cx="1306" cy="300" r="12" fill="#6A1B9A"/> | 80 | <circle cx="1306" cy="300" r="12" fill="#6A1B9A"/> |
| 81 | <text x="1306" y="304.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> | 81 | <text x="1306" y="304.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 82 | - <text x="1328" y="305" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Les 4 options ACP, par ids</text> | 82 | + <text x="1328" y="305" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">The 4 ACP options, by id</text> |
| 83 | <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">allow · allow_always · reject · never.</text> | 83 | <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">allow · allow_always · reject · never.</text> |
| 84 | - <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">« Ne plus jamais » est mis en avant au</text> | 84 | + <text x="1300" y="346" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">"Never again" is put forward rather</text> |
| 85 | - <text x="1300" y="364" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">lieu de « Refuser une fois ».</text> | 85 | + <text x="1300" y="364" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">than "Reject once".</text> |
| 86 | <rect x="1284" y="386" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 86 | <rect x="1284" y="386" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 87 | <circle cx="1306" cy="408" r="12" fill="#6A1B9A"/> | 87 | <circle cx="1306" cy="408" r="12" fill="#6A1B9A"/> |
| 88 | <text x="1306" y="412.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> | 88 | <text x="1306" y="412.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 89 | - <text x="1328" y="413" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Toujours une sortie de secours</text> | 89 | + <text x="1328" y="413" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Always a way out</text> |
| 90 | - <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Spike ACP : après un refus, un petit modèle</text> | 90 | + <text x="1300" y="436" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">ACP spike: after a rejection, a small model</text> |
| 91 | - <text x="1300" y="454" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">a réessayé 40 fois. Arrêter = session/cancel.</text> | 91 | + <text x="1300" y="454" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">retried 40 times. Stop = session/cancel.</text> |
| 92 | <rect x="1284" y="476" width="356" height="58" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 92 | <rect x="1284" y="476" width="356" height="58" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 93 | <circle cx="1306" cy="498" r="12" fill="#6A1B9A"/> | 93 | <circle cx="1306" cy="498" r="12" fill="#6A1B9A"/> |
| 94 | <text x="1306" y="502.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> | 94 | <text x="1306" y="502.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 95 | - <text x="1328" y="503" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Détails pour les curieux</text> | 95 | + <text x="1328" y="503" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Details for the curious</text> |
| 96 | - <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Repliés par défaut.</text> | 96 | + <text x="1300" y="526" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Folded by default.</text> |
| 97 | </svg> | 97 | </svg> |
modified
docs/design/05-agents-panel.png +0 -0 | Binary files a/docs/design/05-agents-panel.png and b/docs/design/05-agents-panel.png differ |
| Binary files a/docs/design/05-agents-panel.png and b/docs/design/05-agents-panel.png differ | Binary files a/docs/design/05-agents-panel.png and b/docs/design/05-agents-panel.png differ |
modified
docs/design/05-agents-panel.svg +35 -35 | @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">5 · Panel Agents : fichiers, éditeur, terminal</text> | |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Le workspace de l'agent, qu'il tourne en local, dans un conteneur ou une sandbox sbx</text> | |
| 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">5 · Agents panel: files, editor, terminal</text> | |
| 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">The agent's workspace, whether it runs locally, in a container or in an sbx sandbox</text> | |
| 6 | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,13 +11,13 @@ | ||
| 11 | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | |
| 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> | |
| 15 | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># général</text> | |
| 20 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | |
| 19 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># general</text> | |
| 20 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> | |
| 21 | 21 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> |
| 22 | 22 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| 23 | 23 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> |
| @@ -29,15 +29,15 @@ | ||
| 29 | 29 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> |
| 30 | 30 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 31 | 31 | <rect x="251" y="116" width="1009" height="56" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 32 | - <text x="267" y="142" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🐮 Garfield (traducteur)</text> | |
| 33 | - <text x="267" y="162" font-size="12" fill="#C98A1B" text-anchor="start" xml:space="preserve">● occupé · local · agents/garfield · gemma-4-E4B</text> | |
| 32 | + <text x="267" y="142" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🐮 Garfield (translator)</text> | |
| 33 | + <text x="267" y="162" font-size="12" fill="#C98A1B" text-anchor="start" xml:space="preserve">● busy · local · agents/garfield · gemma-4-E4B</text> | |
| 34 | 34 | <rect x="1010" y="128" width="110" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 35 | - <text x="1065.0" y="149.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Redémarrer</text> | |
| 35 | + <text x="1065.0" y="149.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Restart</text> | |
| 36 | 36 | <rect x="1130" y="128" width="110" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 37 | - <text x="1185.0" y="149.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">Arrêter</text> | |
| 38 | - <text x="275" y="198" font-size="13.5" fill="#3B6FE0" text-anchor="start" xml:space="preserve" font-weight="700">Fichiers</text> | |
| 37 | + <text x="1185.0" y="149.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">Stop</text> | |
| 38 | + <text x="275" y="198" font-size="13.5" fill="#3B6FE0" text-anchor="start" xml:space="preserve" font-weight="700">Files</text> | |
| 39 | 39 | <text x="375" y="198" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Terminal</text> |
| 40 | - <text x="475" y="198" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Journal</text> | |
| 40 | + <text x="475" y="198" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Log</text> | |
| 41 | 41 | <rect x="267" y="206" width="70" height="2" rx="0" fill="#3B6FE0" stroke="none"/> |
| 42 | 42 | <rect x="251" y="216" width="260" height="420" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 43 | 43 | <text x="265" y="245" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">▾ garfield</text> |
| @@ -50,20 +50,20 @@ | ||
| 50 | 50 | <text x="265" y="401" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> ▸ idioms</text> |
| 51 | 51 | <text x="265" y="427" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> ▸ styles</text> |
| 52 | 52 | <text x="265" y="453" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> ▸ technical-text</text> |
| 53 | - <text x="265" y="479" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> traduction.md</text> | |
| 54 | - <text x="265" y="516" font-size="12.5" fill="#3B6FE0" text-anchor="start" xml:space="preserve">+ Nouveau fichier</text> | |
| 53 | + <text x="265" y="479" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> translation.md</text> | |
| 54 | + <text x="265" y="516" font-size="12.5" fill="#3B6FE0" text-anchor="start" xml:space="preserve">+ New file</text> | |
| 55 | 55 | <rect x="521" y="216" width="729" height="420" rx="0" fill="#F4F5F7" stroke="#E2E3E6" stroke-width="1"/> |
| 56 | 56 | <text x="535" y="240" font-size="13" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS.md</text> |
| 57 | - <text x="535" y="270" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"># Style de traduction</text> | |
| 57 | + <text x="535" y="270" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"># Translation style</text> | |
| 58 | 58 | <text x="535" y="292" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"></text> |
| 59 | - <text x="535" y="314" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Registre : celui du texte source.</text> | |
| 60 | - <text x="535" y="336" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Typographie française : espaces insécables</text> | |
| 61 | - <text x="535" y="358" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> avant ; : ! ? et entre « guillemets ».</text> | |
| 62 | - <text x="535" y="380" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Ne jamais traduire le code ni les noms propres.</text> | |
| 59 | + <text x="535" y="314" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Register: the one of the source text.</text> | |
| 60 | + <text x="535" y="336" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- French typography: non-breaking spaces</text> | |
| 61 | + <text x="535" y="358" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> before ; : ! ? and inside « quotes ».</text> | |
| 62 | + <text x="535" y="380" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Never translate code or proper names.</text> | |
| 63 | 63 | <rect x="1010" y="590" width="110" height="32" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> |
| 64 | - <text x="1065.0" y="611.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Enregistrer</text> | |
| 64 | + <text x="1065.0" y="611.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Save</text> | |
| 65 | 65 | <rect x="1130" y="590" width="110" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 66 | - <text x="1185.0" y="611.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">Supprimer</text> | |
| 66 | + <text x="1185.0" y="611.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">Delete</text> | |
| 67 | 67 | <rect x="251" y="646" width="1009" height="188" rx="0" fill="#111317" stroke="#E2E3E6" stroke-width="1"/> |
| 68 | 68 | <text x="265" y="672" font-size="12.5" fill="#D7DAE0" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">garfield $ ls skills</text> |
| 69 | 69 | <text x="265" y="692" font-size="12.5" fill="#D7DAE0" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">email-letter idioms styles technical-text</text> |
| @@ -81,31 +81,31 @@ | ||
| 81 | 81 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 82 | 82 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 83 | 83 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 84 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">État et emplacement de l'agent</text> | |
| 85 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Statut temps réel (#11), runtime (local,</text> | |
| 86 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">container, sbx), dossier et modèle.</text> | |
| 84 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">The agent's state and location</text> | |
| 85 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Live status (#11), runtime (local,</text> | |
| 86 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">container, sbx), folder and model.</text> | |
| 87 | 87 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 88 | 88 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 89 | 89 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 90 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Arbre du workspace</text> | |
| 91 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Chargement paresseux, rafraîchi quand</text> | |
| 92 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">l'agent modifie un fichier (#29).</text> | |
| 90 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Workspace tree</text> | |
| 91 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Loaded lazily, refreshed when the</text> | |
| 92 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">agent changes a file (#29).</text> | |
| 93 | 93 | <rect x="1284" y="260" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 94 | 94 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 95 | 95 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 96 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Éditer, supprimer avec confirmation</text> | |
| 97 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Même éditeur que Settings. Conflit signalé</text> | |
| 98 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">si l'agent modifie le fichier (#30).</text> | |
| 96 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Edit, delete with confirmation</text> | |
| 97 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Same editor as Settings. A conflict is</text> | |
| 98 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">flagged if the agent changes the file (#30).</text> | |
| 99 | 99 | <rect x="1284" y="350" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 100 | 100 | <circle cx="1306" cy="372" r="12" fill="#6A1B9A"/> |
| 101 | 101 | <text x="1306" y="376.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 102 | - <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Terminal sur le workspace</text> | |
| 103 | - <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">PTY local, docker exec ou sbx selon le</text> | |
| 104 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">runtime (#28, #31). Replié par défaut.</text> | |
| 102 | + <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Terminal in the workspace</text> | |
| 103 | + <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Local PTY, docker exec or sbx depending on</text> | |
| 104 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">the runtime (#28, #31). Folded by default.</text> | |
| 105 | 105 | <rect x="1284" y="440" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 106 | 106 | <circle cx="1306" cy="462" r="12" fill="#6A1B9A"/> |
| 107 | 107 | <text x="1306" y="466.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 108 | - <text x="1328" y="467" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Journal</text> | |
| 109 | - <text x="1300" y="490" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">stderr de l'agent, pour comprendre</text> | |
| 110 | - <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">une erreur sans ouvrir un terminal.</text> | |
| 108 | + <text x="1328" y="467" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Log</text> | |
| 109 | + <text x="1300" y="490" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The agent's stderr, to understand</text> | |
| 110 | + <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">an error without opening a terminal.</text> | |
| 111 | 111 | </svg> |
| @@ -1,8 +1,8 @@ | |||
| 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | <rect width="1660" height="900" fill="#FFFFFF"/> | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">5 · Panel Agents : fichiers, éditeur, terminal</text> | 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">5 · Agents panel: files, editor, terminal</text> |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Le workspace de l'agent, qu'il tourne en local, dans un conteneur ou une sandbox sbx</text> | 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">The agent's workspace, whether it runs locally, in a container or in an sbx sandbox</text> |
| 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,13 +11,13 @@ | |||
| 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml</text> | 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">● 2 of 2 agents running · config: ~/agents/team.yaml</text> |
| 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 16 | <rect x="20" y="116" width="230" height="718" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> | 17 | <text x="36" y="144" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">CHANNELS</text> |
| 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> | 18 | <text x="234" y="144" font-size="16" fill="#6B6F7A" text-anchor="end" xml:space="preserve" font-weight="700">+</text> |
| 19 | - <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># général</text> | 19 | + <text x="38" y="176" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># general</text> |
| 20 | - <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># traductions</text> | 20 | + <text x="38" y="206" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># translations</text> |
| 21 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> | 21 | <text x="38" y="236" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve"># code</text> |
| 22 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> | 22 | <text x="36" y="274" font-size="11" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS</text> |
| 23 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> | 23 | <circle cx="42" cy="301" r="4.5" fill="#3E9B4F"/> |
| @@ -29,15 +29,15 @@ | |||
| 29 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> | 29 | <circle cx="42" cy="391" r="4.5" fill="#C98A1B"/> |
| 30 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> | 30 | <text x="54" y="396" font-size="13.5" fill="#1D1F24" text-anchor="start" xml:space="preserve">🐮 Garfield</text> |
| 31 | <rect x="251" y="116" width="1009" height="56" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 31 | <rect x="251" y="116" width="1009" height="56" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 32 | - <text x="267" y="142" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🐮 Garfield (traducteur)</text> | 32 | + <text x="267" y="142" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">🐮 Garfield (translator)</text> |
| 33 | - <text x="267" y="162" font-size="12" fill="#C98A1B" text-anchor="start" xml:space="preserve">● occupé · local · agents/garfield · gemma-4-E4B</text> | 33 | + <text x="267" y="162" font-size="12" fill="#C98A1B" text-anchor="start" xml:space="preserve">● busy · local · agents/garfield · gemma-4-E4B</text> |
| 34 | <rect x="1010" y="128" width="110" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 34 | <rect x="1010" y="128" width="110" height="32" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 35 | - <text x="1065.0" y="149.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Redémarrer</text> | 35 | + <text x="1065.0" y="149.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Restart</text> |
| 36 | <rect x="1130" y="128" width="110" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> | 36 | <rect x="1130" y="128" width="110" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 37 | - <text x="1185.0" y="149.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">Arrêter</text> | 37 | + <text x="1185.0" y="149.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">Stop</text> |
| 38 | - <text x="275" y="198" font-size="13.5" fill="#3B6FE0" text-anchor="start" xml:space="preserve" font-weight="700">Fichiers</text> | 38 | + <text x="275" y="198" font-size="13.5" fill="#3B6FE0" text-anchor="start" xml:space="preserve" font-weight="700">Files</text> |
| 39 | <text x="375" y="198" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Terminal</text> | 39 | <text x="375" y="198" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Terminal</text> |
| 40 | - <text x="475" y="198" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Journal</text> | 40 | + <text x="475" y="198" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Log</text> |
| 41 | <rect x="267" y="206" width="70" height="2" rx="0" fill="#3B6FE0" stroke="none"/> | 41 | <rect x="267" y="206" width="70" height="2" rx="0" fill="#3B6FE0" stroke="none"/> |
| 42 | <rect x="251" y="216" width="260" height="420" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 42 | <rect x="251" y="216" width="260" height="420" rx="0" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 43 | <text x="265" y="245" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">▾ garfield</text> | 43 | <text x="265" y="245" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">▾ garfield</text> |
| @@ -50,20 +50,20 @@ | |||
| 50 | <text x="265" y="401" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> ▸ idioms</text> | 50 | <text x="265" y="401" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> ▸ idioms</text> |
| 51 | <text x="265" y="427" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> ▸ styles</text> | 51 | <text x="265" y="427" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> ▸ styles</text> |
| 52 | <text x="265" y="453" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> ▸ technical-text</text> | 52 | <text x="265" y="453" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> ▸ technical-text</text> |
| 53 | - <text x="265" y="479" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> traduction.md</text> | 53 | + <text x="265" y="479" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> translation.md</text> |
| 54 | - <text x="265" y="516" font-size="12.5" fill="#3B6FE0" text-anchor="start" xml:space="preserve">+ Nouveau fichier</text> | 54 | + <text x="265" y="516" font-size="12.5" fill="#3B6FE0" text-anchor="start" xml:space="preserve">+ New file</text> |
| 55 | <rect x="521" y="216" width="729" height="420" rx="0" fill="#F4F5F7" stroke="#E2E3E6" stroke-width="1"/> | 55 | <rect x="521" y="216" width="729" height="420" rx="0" fill="#F4F5F7" stroke="#E2E3E6" stroke-width="1"/> |
| 56 | <text x="535" y="240" font-size="13" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS.md</text> | 56 | <text x="535" y="240" font-size="13" fill="#6B6F7A" text-anchor="start" xml:space="preserve" font-weight="700">AGENTS.md</text> |
| 57 | - <text x="535" y="270" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"># Style de traduction</text> | 57 | + <text x="535" y="270" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"># Translation style</text> |
| 58 | <text x="535" y="292" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"></text> | 58 | <text x="535" y="292" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"></text> |
| 59 | - <text x="535" y="314" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Registre : celui du texte source.</text> | 59 | + <text x="535" y="314" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Register: the one of the source text.</text> |
| 60 | - <text x="535" y="336" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Typographie française : espaces insécables</text> | 60 | + <text x="535" y="336" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- French typography: non-breaking spaces</text> |
| 61 | - <text x="535" y="358" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> avant ; : ! ? et entre « guillemets ».</text> | 61 | + <text x="535" y="358" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace"> before ; : ! ? and inside « quotes ».</text> |
| 62 | - <text x="535" y="380" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Ne jamais traduire le code ni les noms propres.</text> | 62 | + <text x="535" y="380" font-size="12.5" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">- Never translate code or proper names.</text> |
| 63 | <rect x="1010" y="590" width="110" height="32" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> | 63 | <rect x="1010" y="590" width="110" height="32" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> |
| 64 | - <text x="1065.0" y="611.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Enregistrer</text> | 64 | + <text x="1065.0" y="611.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">Save</text> |
| 65 | <rect x="1130" y="590" width="110" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> | 65 | <rect x="1130" y="590" width="110" height="32" rx="6" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 66 | - <text x="1185.0" y="611.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">Supprimer</text> | 66 | + <text x="1185.0" y="611.0" font-size="13" fill="#D64561" text-anchor="middle" xml:space="preserve">Delete</text> |
| 67 | <rect x="251" y="646" width="1009" height="188" rx="0" fill="#111317" stroke="#E2E3E6" stroke-width="1"/> | 67 | <rect x="251" y="646" width="1009" height="188" rx="0" fill="#111317" stroke="#E2E3E6" stroke-width="1"/> |
| 68 | <text x="265" y="672" font-size="12.5" fill="#D7DAE0" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">garfield $ ls skills</text> | 68 | <text x="265" y="672" font-size="12.5" fill="#D7DAE0" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">garfield $ ls skills</text> |
| 69 | <text x="265" y="692" font-size="12.5" fill="#D7DAE0" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">email-letter idioms styles technical-text</text> | 69 | <text x="265" y="692" font-size="12.5" fill="#D7DAE0" text-anchor="start" xml:space="preserve" font-family="DejaVu Sans Mono, monospace">email-letter idioms styles technical-text</text> |
| @@ -81,31 +81,31 @@ | |||
| 81 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 81 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 82 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> | 82 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 83 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 83 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 84 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">État et emplacement de l'agent</text> | 84 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">The agent's state and location</text> |
| 85 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Statut temps réel (#11), runtime (local,</text> | 85 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Live status (#11), runtime (local,</text> |
| 86 | - <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">container, sbx), dossier et modèle.</text> | 86 | + <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">container, sbx), folder and model.</text> |
| 87 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 87 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 88 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> | 88 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 89 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> | 89 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 90 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Arbre du workspace</text> | 90 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Workspace tree</text> |
| 91 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Chargement paresseux, rafraîchi quand</text> | 91 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Loaded lazily, refreshed when the</text> |
| 92 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">l'agent modifie un fichier (#29).</text> | 92 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">agent changes a file (#29).</text> |
| 93 | <rect x="1284" y="260" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 93 | <rect x="1284" y="260" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 94 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> | 94 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 95 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> | 95 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 96 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Éditer, supprimer avec confirmation</text> | 96 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Edit, delete with confirmation</text> |
| 97 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Même éditeur que Settings. Conflit signalé</text> | 97 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Same editor as Settings. A conflict is</text> |
| 98 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">si l'agent modifie le fichier (#30).</text> | 98 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">flagged if the agent changes the file (#30).</text> |
| 99 | <rect x="1284" y="350" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 99 | <rect x="1284" y="350" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 100 | <circle cx="1306" cy="372" r="12" fill="#6A1B9A"/> | 100 | <circle cx="1306" cy="372" r="12" fill="#6A1B9A"/> |
| 101 | <text x="1306" y="376.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> | 101 | <text x="1306" y="376.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 102 | - <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Terminal sur le workspace</text> | 102 | + <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Terminal in the workspace</text> |
| 103 | - <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">PTY local, docker exec ou sbx selon le</text> | 103 | + <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Local PTY, docker exec or sbx depending on</text> |
| 104 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">runtime (#28, #31). Replié par défaut.</text> | 104 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">the runtime (#28, #31). Folded by default.</text> |
| 105 | <rect x="1284" y="440" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 105 | <rect x="1284" y="440" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 106 | <circle cx="1306" cy="462" r="12" fill="#6A1B9A"/> | 106 | <circle cx="1306" cy="462" r="12" fill="#6A1B9A"/> |
| 107 | <text x="1306" y="466.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> | 107 | <text x="1306" y="466.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">5</text> |
| 108 | - <text x="1328" y="467" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Journal</text> | 108 | + <text x="1328" y="467" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Log</text> |
| 109 | - <text x="1300" y="490" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">stderr de l'agent, pour comprendre</text> | 109 | + <text x="1300" y="490" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The agent's stderr, to understand</text> |
| 110 | - <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">une erreur sans ouvrir un terminal.</text> | 110 | + <text x="1300" y="508" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">an error without opening a terminal.</text> |
| 111 | </svg> | 111 | </svg> |
modified
docs/design/06-first-launch.png +0 -0 | Binary files a/docs/design/06-first-launch.png and b/docs/design/06-first-launch.png differ |
| Binary files a/docs/design/06-first-launch.png and b/docs/design/06-first-launch.png differ | Binary files a/docs/design/06-first-launch.png and b/docs/design/06-first-launch.png differ |
modified
docs/design/06-first-launch.svg +27 -27 | @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">6 · Premier lancement</text> | |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Moins d'une minute pour savoir quoi faire, sans lire de documentation</text> | |
| 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">6 · First launch</text> | |
| 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Less than a minute to know what to do, without reading any documentation</text> | |
| 6 | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,33 +11,33 @@ | ||
| 11 | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">○ aucun agent configuré · config : créée à l'emplacement par défaut</text> | |
| 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">○ no agent configured · config: created at the default location</text> | |
| 15 | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | - <text x="640.0" y="200" font-size="26" fill="#1D1F24" text-anchor="middle" xml:space="preserve" font-weight="700">👋 Bienvenue dans Sidekicks</text> | |
| 17 | - <text x="640.0" y="234" font-size="15" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Discutez avec des agents d'IA dans des channels, comme avec des collègues.</text> | |
| 16 | + <text x="640.0" y="200" font-size="26" fill="#1D1F24" text-anchor="middle" xml:space="preserve" font-weight="700">👋 Welcome to Sidekicks</text> | |
| 17 | + <text x="640.0" y="234" font-size="15" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Talk with AI agents in channels, as you would with colleagues.</text> | |
| 18 | 18 | <rect x="240" y="280" width="800" height="76" rx="12" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 19 | 19 | <circle cx="280" cy="318" r="18" fill="#3B6FE0"/> |
| 20 | 20 | <text x="280" y="324" font-size="16" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">1</text> |
| 21 | - <text x="316" y="312" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Ajoutez un agent</text> | |
| 22 | - <text x="316" y="336" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Un assistant qui tourne sur votre ordinateur, par exemple avec mm.</text> | |
| 21 | + <text x="316" y="312" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Add an agent</text> | |
| 22 | + <text x="316" y="336" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">An assistant that runs on your computer, for example with mm.</text> | |
| 23 | 23 | <rect x="240" y="372" width="800" height="76" rx="12" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 24 | 24 | <circle cx="280" cy="410" r="18" fill="#3B6FE0"/> |
| 25 | 25 | <text x="280" y="416" font-size="16" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">2</text> |
| 26 | - <text x="316" y="404" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Ouvrez un channel</text> | |
| 27 | - <text x="316" y="428" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">#général est déjà prêt. Créez-en d'autres par sujet.</text> | |
| 26 | + <text x="316" y="404" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Open a channel</text> | |
| 27 | + <text x="316" y="428" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">#general is ready. Create others, one per topic.</text> | |
| 28 | 28 | <rect x="240" y="464" width="800" height="76" rx="12" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 29 | 29 | <circle cx="280" cy="502" r="18" fill="#3B6FE0"/> |
| 30 | 30 | <text x="280" y="508" font-size="16" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">3</text> |
| 31 | - <text x="316" y="496" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Appelez-le avec @</text> | |
| 32 | - <text x="316" y="520" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">« @alice bonjour » : Alice rejoint le channel et vous répond.</text> | |
| 31 | + <text x="316" y="496" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Call it with @</text> | |
| 32 | + <text x="316" y="520" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">"@alice hello": Alice joins the channel and answers you.</text> | |
| 33 | 33 | <rect x="420" y="570" width="240" height="40" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> |
| 34 | - <text x="540.0" y="595.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">+ Ajouter mon premier agent</text> | |
| 34 | + <text x="540.0" y="595.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">+ Add my first agent</text> | |
| 35 | 35 | <rect x="680" y="570" width="200" height="40" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 36 | - <text x="780.0" y="595.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Ouvrir une configuration…</text> | |
| 37 | - <text x="640.0" y="650" font-size="12" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Configuration : ~/Library/Application Support/sidekicks/config.yaml (créée pour vous, commentée)</text> | |
| 36 | + <text x="780.0" y="595.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Open a configuration…</text> | |
| 37 | + <text x="640.0" y="650" font-size="12" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Configuration: ~/Library/Application Support/sidekicks/config.yaml (created for you, with comments)</text> | |
| 38 | 38 | <rect x="240" y="680" width="800" height="70" rx="10" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 39 | - <text x="260" y="708" font-size="14" fill="#D64561" text-anchor="start" xml:space="preserve" font-weight="700">La commande « mm » est introuvable.</text> | |
| 40 | - <text x="260" y="732" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">Installez-la (lien vers le guide) ou choisissez un autre programme pour cet agent.</text> | |
| 39 | + <text x="260" y="708" font-size="14" fill="#D64561" text-anchor="start" xml:space="preserve" font-weight="700">The command "mm" cannot be found.</text> | |
| 40 | + <text x="260" y="732" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">Install it (link to the guide) or choose another program for this agent.</text> | |
| 41 | 41 | <circle cx="1052" cy="312" r="12" fill="#6A1B9A"/> |
| 42 | 42 | <text x="1052" y="316.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 43 | 43 | <circle cx="892" cy="590" r="12" fill="#6A1B9A"/> |
| @@ -49,25 +49,25 @@ | ||
| 49 | 49 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 50 | 50 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 51 | 51 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 52 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Trois étapes, pas plus</text> | |
| 53 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">L'état vide explique le modèle mental :</text> | |
| 52 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Three steps, no more</text> | |
| 53 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The empty state explains the mental model:</text> | |
| 54 | 54 | <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">agents, channels, @ (#33).</text> |
| 55 | 55 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 56 | 56 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 57 | 57 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 58 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Un assistant plutôt que du YAML</text> | |
| 59 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Le formulaire écrit le YAML à la place de</text> | |
| 60 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">l'utilisateur ; Settings reste accessible.</text> | |
| 58 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">An assistant rather than YAML</text> | |
| 59 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The form writes the YAML for the user;</text> | |
| 60 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Settings stays at hand.</text> | |
| 61 | 61 | <rect x="1284" y="260" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 62 | 62 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 63 | 63 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 64 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Rien à créer à la main</text> | |
| 65 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Le fichier par défaut existe déjà, avec des</text> | |
| 66 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">commentaires (#9).</text> | |
| 64 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Nothing to create by hand</text> | |
| 65 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The default file already exists, with</text> | |
| 66 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">comments (#9).</text> | |
| 67 | 67 | <rect x="1284" y="350" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 68 | 68 | <circle cx="1306" cy="372" r="12" fill="#6A1B9A"/> |
| 69 | 69 | <text x="1306" y="376.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 70 | - <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Erreurs humaines</text> | |
| 71 | - <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Dire ce qui ne va pas et quoi faire ;</text> | |
| 72 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">jamais de trace technique (#33).</text> | |
| 70 | + <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Human errors</text> | |
| 71 | + <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Say what is wrong and what to do;</text> | |
| 72 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">never a technical trace (#33).</text> | |
| 73 | 73 | </svg> |
| @@ -1,8 +1,8 @@ | |||
| 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> | 1 | <svg xmlns="http://www.w3.org/2000/svg" width="1660" height="900" viewBox="0 0 1660 900" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> | 2 | <defs><filter id="shadow" x="-10%" y="-10%" width="120%" height="120%"><feDropShadow dx="0" dy="3" stdDeviation="6" flood-color="#000" flood-opacity="0.18"/></filter></defs> |
| 3 | <rect width="1660" height="900" fill="#FFFFFF"/> | 3 | <rect width="1660" height="900" fill="#FFFFFF"/> |
| 4 | - <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">6 · Premier lancement</text> | 4 | + <text x="20" y="38" font-size="24" font-weight="700" fill="#1A237E">6 · First launch</text> |
| 5 | - <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Moins d'une minute pour savoir quoi faire, sans lire de documentation</text> | 5 | + <text x="20" y="62" font-size="14" font-style="italic" fill="#546E7A">Less than a minute to know what to do, without reading any documentation</text> |
| 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> | 6 | <g filter="url(#shadow)"><rect x="20" y="80" width="1240" height="780" rx="12" fill="#F6F6F7" stroke="#C9CBD1" stroke-width="1"/></g> |
| 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> | 7 | <rect x="20" y="80" width="1240" height="36" rx="12" fill="#F0F1F3" stroke="none"/> |
| 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> | 8 | <rect x="20" y="104" width="1240" height="12" rx="0" fill="#F0F1F3" stroke="none"/> |
| @@ -11,33 +11,33 @@ | |||
| 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> | 11 | <circle cx="80" cy="98" r="6" fill="#28C840"/> |
| 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> | 12 | <text x="640.0" y="103" font-size="13" fill="#6B6F7A" text-anchor="middle" xml:space="preserve" font-weight="700">Sidekicks</text> |
| 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> | 13 | <rect x="20" y="834" width="1240" height="26" rx="0" fill="#F0F1F3" stroke="none"/> |
| 14 | - <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">○ aucun agent configuré · config : créée à l'emplacement par défaut</text> | 14 | + <text x="32" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">○ no agent configured · config: created at the default location</text> |
| 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> | 15 | <text x="1248" y="851" font-size="11.5" fill="#6B6F7A" text-anchor="end" xml:space="preserve">⚙︎ Settings ⌘K</text> |
| 16 | - <text x="640.0" y="200" font-size="26" fill="#1D1F24" text-anchor="middle" xml:space="preserve" font-weight="700">👋 Bienvenue dans Sidekicks</text> | 16 | + <text x="640.0" y="200" font-size="26" fill="#1D1F24" text-anchor="middle" xml:space="preserve" font-weight="700">👋 Welcome to Sidekicks</text> |
| 17 | - <text x="640.0" y="234" font-size="15" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Discutez avec des agents d'IA dans des channels, comme avec des collègues.</text> | 17 | + <text x="640.0" y="234" font-size="15" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Talk with AI agents in channels, as you would with colleagues.</text> |
| 18 | <rect x="240" y="280" width="800" height="76" rx="12" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 18 | <rect x="240" y="280" width="800" height="76" rx="12" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 19 | <circle cx="280" cy="318" r="18" fill="#3B6FE0"/> | 19 | <circle cx="280" cy="318" r="18" fill="#3B6FE0"/> |
| 20 | <text x="280" y="324" font-size="16" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">1</text> | 20 | <text x="280" y="324" font-size="16" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">1</text> |
| 21 | - <text x="316" y="312" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Ajoutez un agent</text> | 21 | + <text x="316" y="312" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Add an agent</text> |
| 22 | - <text x="316" y="336" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">Un assistant qui tourne sur votre ordinateur, par exemple avec mm.</text> | 22 | + <text x="316" y="336" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">An assistant that runs on your computer, for example with mm.</text> |
| 23 | <rect x="240" y="372" width="800" height="76" rx="12" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 23 | <rect x="240" y="372" width="800" height="76" rx="12" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 24 | <circle cx="280" cy="410" r="18" fill="#3B6FE0"/> | 24 | <circle cx="280" cy="410" r="18" fill="#3B6FE0"/> |
| 25 | <text x="280" y="416" font-size="16" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">2</text> | 25 | <text x="280" y="416" font-size="16" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">2</text> |
| 26 | - <text x="316" y="404" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Ouvrez un channel</text> | 26 | + <text x="316" y="404" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Open a channel</text> |
| 27 | - <text x="316" y="428" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">#général est déjà prêt. Créez-en d'autres par sujet.</text> | 27 | + <text x="316" y="428" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">#general is ready. Create others, one per topic.</text> |
| 28 | <rect x="240" y="464" width="800" height="76" rx="12" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 28 | <rect x="240" y="464" width="800" height="76" rx="12" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 29 | <circle cx="280" cy="502" r="18" fill="#3B6FE0"/> | 29 | <circle cx="280" cy="502" r="18" fill="#3B6FE0"/> |
| 30 | <text x="280" y="508" font-size="16" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">3</text> | 30 | <text x="280" y="508" font-size="16" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">3</text> |
| 31 | - <text x="316" y="496" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Appelez-le avec @</text> | 31 | + <text x="316" y="496" font-size="16" fill="#1D1F24" text-anchor="start" xml:space="preserve" font-weight="700">Call it with @</text> |
| 32 | - <text x="316" y="520" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">« @alice bonjour » : Alice rejoint le channel et vous répond.</text> | 32 | + <text x="316" y="520" font-size="13.5" fill="#6B6F7A" text-anchor="start" xml:space="preserve">"@alice hello": Alice joins the channel and answers you.</text> |
| 33 | <rect x="420" y="570" width="240" height="40" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> | 33 | <rect x="420" y="570" width="240" height="40" rx="6" fill="#3B6FE0" stroke="#3B6FE0" stroke-width="1"/> |
| 34 | - <text x="540.0" y="595.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">+ Ajouter mon premier agent</text> | 34 | + <text x="540.0" y="595.0" font-size="13" fill="#FFFFFF" text-anchor="middle" xml:space="preserve" font-weight="700">+ Add my first agent</text> |
| 35 | <rect x="680" y="570" width="200" height="40" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> | 35 | <rect x="680" y="570" width="200" height="40" rx="6" fill="#FFFFFF" stroke="#E2E3E6" stroke-width="1"/> |
| 36 | - <text x="780.0" y="595.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Ouvrir une configuration…</text> | 36 | + <text x="780.0" y="595.0" font-size="13" fill="#1D1F24" text-anchor="middle" xml:space="preserve">Open a configuration…</text> |
| 37 | - <text x="640.0" y="650" font-size="12" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Configuration : ~/Library/Application Support/sidekicks/config.yaml (créée pour vous, commentée)</text> | 37 | + <text x="640.0" y="650" font-size="12" fill="#6B6F7A" text-anchor="middle" xml:space="preserve">Configuration: ~/Library/Application Support/sidekicks/config.yaml (created for you, with comments)</text> |
| 38 | <rect x="240" y="680" width="800" height="70" rx="10" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> | 38 | <rect x="240" y="680" width="800" height="70" rx="10" fill="#FDECEF" stroke="#D64561" stroke-width="1"/> |
| 39 | - <text x="260" y="708" font-size="14" fill="#D64561" text-anchor="start" xml:space="preserve" font-weight="700">La commande « mm » est introuvable.</text> | 39 | + <text x="260" y="708" font-size="14" fill="#D64561" text-anchor="start" xml:space="preserve" font-weight="700">The command "mm" cannot be found.</text> |
| 40 | - <text x="260" y="732" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">Installez-la (lien vers le guide) ou choisissez un autre programme pour cet agent.</text> | 40 | + <text x="260" y="732" font-size="13" fill="#1D1F24" text-anchor="start" xml:space="preserve">Install it (link to the guide) or choose another program for this agent.</text> |
| 41 | <circle cx="1052" cy="312" r="12" fill="#6A1B9A"/> | 41 | <circle cx="1052" cy="312" r="12" fill="#6A1B9A"/> |
| 42 | <text x="1052" y="316.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 42 | <text x="1052" y="316.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 43 | <circle cx="892" cy="590" r="12" fill="#6A1B9A"/> | 43 | <circle cx="892" cy="590" r="12" fill="#6A1B9A"/> |
| @@ -49,25 +49,25 @@ | |||
| 49 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 49 | <rect x="1284" y="80" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 50 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> | 50 | <circle cx="1306" cy="102" r="12" fill="#6A1B9A"/> |
| 51 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> | 51 | <text x="1306" y="106.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">1</text> |
| 52 | - <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Trois étapes, pas plus</text> | 52 | + <text x="1328" y="107" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Three steps, no more</text> |
| 53 | - <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">L'état vide explique le modèle mental :</text> | 53 | + <text x="1300" y="130" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The empty state explains the mental model:</text> |
| 54 | <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">agents, channels, @ (#33).</text> | 54 | <text x="1300" y="148" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">agents, channels, @ (#33).</text> |
| 55 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 55 | <rect x="1284" y="170" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 56 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> | 56 | <circle cx="1306" cy="192" r="12" fill="#6A1B9A"/> |
| 57 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> | 57 | <text x="1306" y="196.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">2</text> |
| 58 | - <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Un assistant plutôt que du YAML</text> | 58 | + <text x="1328" y="197" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">An assistant rather than YAML</text> |
| 59 | - <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Le formulaire écrit le YAML à la place de</text> | 59 | + <text x="1300" y="220" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The form writes the YAML for the user;</text> |
| 60 | - <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">l'utilisateur ; Settings reste accessible.</text> | 60 | + <text x="1300" y="238" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Settings stays at hand.</text> |
| 61 | <rect x="1284" y="260" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 61 | <rect x="1284" y="260" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 62 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> | 62 | <circle cx="1306" cy="282" r="12" fill="#6A1B9A"/> |
| 63 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> | 63 | <text x="1306" y="286.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">3</text> |
| 64 | - <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Rien à créer à la main</text> | 64 | + <text x="1328" y="287" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Nothing to create by hand</text> |
| 65 | - <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Le fichier par défaut existe déjà, avec des</text> | 65 | + <text x="1300" y="310" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">The default file already exists, with</text> |
| 66 | - <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">commentaires (#9).</text> | 66 | + <text x="1300" y="328" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">comments (#9).</text> |
| 67 | <rect x="1284" y="350" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> | 67 | <rect x="1284" y="350" width="356" height="76" rx="10" fill="#F3E5F5" stroke="#6A1B9A" stroke-width="1"/> |
| 68 | <circle cx="1306" cy="372" r="12" fill="#6A1B9A"/> | 68 | <circle cx="1306" cy="372" r="12" fill="#6A1B9A"/> |
| 69 | <text x="1306" y="376.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> | 69 | <text x="1306" y="376.5" font-size="13" font-weight="700" fill="#FFFFFF" text-anchor="middle">4</text> |
| 70 | - <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Erreurs humaines</text> | 70 | + <text x="1328" y="377" font-size="13.5" fill="#4A148C" text-anchor="start" xml:space="preserve" font-weight="700">Human errors</text> |
| 71 | - <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Dire ce qui ne va pas et quoi faire ;</text> | 71 | + <text x="1300" y="400" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">Say what is wrong and what to do;</text> |
| 72 | - <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">jamais de trace technique (#33).</text> | 72 | + <text x="1300" y="418" font-size="12" fill="#4A148C" text-anchor="start" xml:space="preserve">never a technical trace (#33).</text> |
| 73 | </svg> | 73 | </svg> |
modified
docs/design/README.md +26 -6 | @@ -1,15 +1,15 @@ | ||
| 1 | 1 | # Wireframes |
| 2 | 2 | |
| 3 | -Six screens for issue [#6](../../.tickets/issues/0006-maquettes-ux-des-panels-pour-le-citizen-user.yaml), drawn for a user who is not a developer. Each screen shows the window on the left and numbered design notes on the right; the purple badges point at what each note explains. The interface text is in French, the default language. | |
| 3 | +Six screens for issue [#6](../../.tickets/issues/0006-maquettes-ux-des-panels-pour-le-citizen-user.yaml), drawn for a user who is not a developer. Each screen shows the window on the left and numbered design notes on the right; the purple badges point at what each note explains. The interface text is in English, the default language (French is chosen with `ui.language: fr`). | |
| 4 | 4 | |
| 5 | 5 | | Screen | Shows | |
| 6 | 6 | | --- | --- | |
| 7 | -| [1 · Layout global](01-layout.png) | Docks: channels and agents on the left, the conversation in the centre, Settings on the right, terminal and files folded at the bottom | | |
| 8 | -| [2 · Conversation multi-agents](02-conversation.png) | One colour per agent, the "joined the channel" message, folded tool calls, the Stop button, the context gauge | | |
| 9 | -| [3 · @ et /](03-mentions-commands.png) | The `@` agent list and the `/agent:command` list, Tab to pick | | |
| 7 | +| [1 · Overall layout](01-layout.png) | Docks: channels and agents on the left, the conversation in the centre, Settings on the right, terminal and files folded at the bottom | | |
| 8 | +| [2 · Multi-agent conversation](02-conversation.png) | One colour per agent, the "joined the channel" message, folded tool calls, the Stop button, the context gauge | | |
| 9 | +| [3 · @ and /](03-mentions-commands.png) | The `@` agent list and the `/agent:command` list, Tab to pick | | |
| 10 | 10 | | [4 · Permission](04-permission.png) | A permission request in plain language, the four ACP options and "Stop Riker" | |
| 11 | -| [5 · Panel Agents](05-agents-panel.png) | An agent's state, workspace tree, editor and terminal | | |
| 12 | -| [6 · Premier lancement](06-first-launch.png) | The empty state: three steps, an "add my first agent" assistant, a human error message | | |
| 11 | +| [5 · Agents panel](05-agents-panel.png) | An agent's state, workspace tree, editor and terminal | | |
| 12 | +| [6 · First launch](06-first-launch.png) | The empty state: three steps, an "add my first agent" assistant, a human error message | | |
| 13 | 13 | |
| 14 | 14 | ## Files |
| 15 | 15 | |
| @@ -26,6 +26,26 @@ for f in docs/design/*.svg; do rsvg-convert -o "${f%.svg}.png" "$f"; done | ||
| 26 | 26 | |
| 27 | 27 | Editing `wireframes.drawio` by hand is fine for exploring, but the next generation overwrites it: carry the change over into `wireframes.py`. |
| 28 | 28 | |
| 29 | +## Logo | |
| 30 | + | |
| 31 | +The logo is **Orbite**: you in the centre, your agents in orbit around you. Colours: ink `#1E2240`, ring `#C9CCE8`, teal `#12A39A` and coral `#FF7A59` on a light ground; white, `#4A5078`, `#2FD1C5` and coral on a dark one. | |
| 32 | + | |
| 33 | +| File | Use | | |
| 34 | +| --- | --- | | |
| 35 | +| [logo/sidekicks-mark.svg](logo/sidekicks-mark.svg) | The mark on a light ground | | |
| 36 | +| [logo/sidekicks-mark-dark.svg](logo/sidekicks-mark-dark.svg) | The mark on a dark ground | | |
| 37 | +| [logo/sidekicks-favicon.svg](logo/sidekicks-favicon.svg) | 16–32 px: the ring is dropped, it no longer reads at that size | | |
| 38 | +| [logo/sidekicks-app-icon.svg](logo/sidekicks-app-icon.svg) | The application icon, a copy of `build/appicon.svg` | | |
| 39 | + | |
| 40 | +The application icon's source is `build/appicon.svg`. After changing it, regenerate the images: | |
| 41 | + | |
| 42 | +```bash | |
| 43 | +rsvg-convert -w 1024 -h 1024 -o build/appicon.png build/appicon.svg | |
| 44 | +cd build && wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin | |
| 45 | +``` | |
| 46 | + | |
| 47 | +The last two options rebuild `build/darwin/Assets.car` from `build/appicon.icon` (its glyph is `Assets/sidekicks-mark.svg`); they only work on macOS. | |
| 48 | + | |
| 29 | 49 | ## Decisions taken in these screens |
| 30 | 50 | |
| 31 | 51 | - Only the conversation and the left dock are visible by default; Settings, terminal and files are one click away (screens 1, 5). |
| @@ -1,15 +1,15 @@ | |||
| 1 | # Wireframes | 1 | # Wireframes |
| 2 | 2 | ||
| 3 | -Six screens for issue [#6](../../.tickets/issues/0006-maquettes-ux-des-panels-pour-le-citizen-user.yaml), drawn for a user who is not a developer. Each screen shows the window on the left and numbered design notes on the right; the purple badges point at what each note explains. The interface text is in French, the default language. | 3 | +Six screens for issue [#6](../../.tickets/issues/0006-maquettes-ux-des-panels-pour-le-citizen-user.yaml), drawn for a user who is not a developer. Each screen shows the window on the left and numbered design notes on the right; the purple badges point at what each note explains. The interface text is in English, the default language (French is chosen with `ui.language: fr`). |
| 4 | 4 | ||
| 5 | | Screen | Shows | | 5 | | Screen | Shows | |
| 6 | | --- | --- | | 6 | | --- | --- | |
| 7 | -| [1 · Layout global](01-layout.png) | Docks: channels and agents on the left, the conversation in the centre, Settings on the right, terminal and files folded at the bottom | | 7 | +| [1 · Overall layout](01-layout.png) | Docks: channels and agents on the left, the conversation in the centre, Settings on the right, terminal and files folded at the bottom | |
| 8 | -| [2 · Conversation multi-agents](02-conversation.png) | One colour per agent, the "joined the channel" message, folded tool calls, the Stop button, the context gauge | | 8 | +| [2 · Multi-agent conversation](02-conversation.png) | One colour per agent, the "joined the channel" message, folded tool calls, the Stop button, the context gauge | |
| 9 | -| [3 · @ et /](03-mentions-commands.png) | The `@` agent list and the `/agent:command` list, Tab to pick | | 9 | +| [3 · @ and /](03-mentions-commands.png) | The `@` agent list and the `/agent:command` list, Tab to pick | |
| 10 | | [4 · Permission](04-permission.png) | A permission request in plain language, the four ACP options and "Stop Riker" | | 10 | | [4 · Permission](04-permission.png) | A permission request in plain language, the four ACP options and "Stop Riker" | |
| 11 | -| [5 · Panel Agents](05-agents-panel.png) | An agent's state, workspace tree, editor and terminal | | 11 | +| [5 · Agents panel](05-agents-panel.png) | An agent's state, workspace tree, editor and terminal | |
| 12 | -| [6 · Premier lancement](06-first-launch.png) | The empty state: three steps, an "add my first agent" assistant, a human error message | | 12 | +| [6 · First launch](06-first-launch.png) | The empty state: three steps, an "add my first agent" assistant, a human error message | |
| 13 | 13 | ||
| 14 | ## Files | 14 | ## Files |
| 15 | 15 | ||
| @@ -26,6 +26,26 @@ for f in docs/design/*.svg; do rsvg-convert -o "${f%.svg}.png" "$f"; done | |||
| 26 | 26 | ||
| 27 | Editing `wireframes.drawio` by hand is fine for exploring, but the next generation overwrites it: carry the change over into `wireframes.py`. | 27 | Editing `wireframes.drawio` by hand is fine for exploring, but the next generation overwrites it: carry the change over into `wireframes.py`. |
| 28 | 28 | ||
| 29 | +## Logo | ||
| 30 | + | ||
| 31 | +The logo is **Orbite**: you in the centre, your agents in orbit around you. Colours: ink `#1E2240`, ring `#C9CCE8`, teal `#12A39A` and coral `#FF7A59` on a light ground; white, `#4A5078`, `#2FD1C5` and coral on a dark one. | ||
| 32 | + | ||
| 33 | +| File | Use | | ||
| 34 | +| --- | --- | | ||
| 35 | +| [logo/sidekicks-mark.svg](logo/sidekicks-mark.svg) | The mark on a light ground | | ||
| 36 | +| [logo/sidekicks-mark-dark.svg](logo/sidekicks-mark-dark.svg) | The mark on a dark ground | | ||
| 37 | +| [logo/sidekicks-favicon.svg](logo/sidekicks-favicon.svg) | 16–32 px: the ring is dropped, it no longer reads at that size | | ||
| 38 | +| [logo/sidekicks-app-icon.svg](logo/sidekicks-app-icon.svg) | The application icon, a copy of `build/appicon.svg` | | ||
| 39 | + | ||
| 40 | +The application icon's source is `build/appicon.svg`. After changing it, regenerate the images: | ||
| 41 | + | ||
| 42 | +```bash | ||
| 43 | +rsvg-convert -w 1024 -h 1024 -o build/appicon.png build/appicon.svg | ||
| 44 | +cd build && wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin | ||
| 45 | +``` | ||
| 46 | + | ||
| 47 | +The last two options rebuild `build/darwin/Assets.car` from `build/appicon.icon` (its glyph is `Assets/sidekicks-mark.svg`); they only work on macOS. | ||
| 48 | + | ||
| 29 | ## Decisions taken in these screens | 49 | ## Decisions taken in these screens |
| 30 | 50 | ||
| 31 | - Only the conversation and the left dock are visible by default; Settings, terminal and files are one click away (screens 1, 5). | 51 | - Only the conversation and the left dock are visible by default; Settings, terminal and files are one click away (screens 1, 5). |
added
docs/design/logo/sidekicks-app-icon.svg +15 -0 | new file mode 100644 | ||
| @@ -0,0 +1,15 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024"> | |
| 3 | + <rect x="100" y="100" width="824" height="824" rx="185" fill="#1E2240"/> | |
| 4 | + <svg x="212" y="212" width="600" height="600" viewBox="0 0 100 100"> | |
| 5 | + <mask id="cut"> | |
| 6 | + <rect width="100" height="100" fill="#fff"/> | |
| 7 | + <circle cx="76" cy="28" r="12" fill="#000"/> | |
| 8 | + <circle cx="18" cy="39" r="10" fill="#000"/> | |
| 9 | + </mask> | |
| 10 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#4A5078" stroke-width="4" mask="url(#cut)"/> | |
| 11 | + <circle cx="50" cy="50" r="15" fill="#FFFFFF"/> | |
| 12 | + <circle cx="76" cy="28" r="9" fill="#2FD1C5"/> | |
| 13 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | |
| 14 | + </svg> | |
| 15 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024"> | ||
| 3 | + <rect x="100" y="100" width="824" height="824" rx="185" fill="#1E2240"/> | ||
| 4 | + <svg x="212" y="212" width="600" height="600" viewBox="0 0 100 100"> | ||
| 5 | + <mask id="cut"> | ||
| 6 | + <rect width="100" height="100" fill="#fff"/> | ||
| 7 | + <circle cx="76" cy="28" r="12" fill="#000"/> | ||
| 8 | + <circle cx="18" cy="39" r="10" fill="#000"/> | ||
| 9 | + </mask> | ||
| 10 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#4A5078" stroke-width="4" mask="url(#cut)"/> | ||
| 11 | + <circle cx="50" cy="50" r="15" fill="#FFFFFF"/> | ||
| 12 | + <circle cx="76" cy="28" r="9" fill="#2FD1C5"/> | ||
| 13 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | ||
| 14 | + </svg> | ||
| 15 | +</svg> | ||
added
docs/design/logo/sidekicks-favicon.svg +6 -0 | new file mode 100644 | ||
| @@ -0,0 +1,6 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 100 100" role="img" aria-label="Sidekicks"> | |
| 3 | + <circle cx="50" cy="50" r="20" fill="#1E2240"/> | |
| 4 | + <circle cx="78" cy="26" r="14" fill="#12A39A"/> | |
| 5 | + <circle cx="18" cy="40" r="12" fill="#FF7A59"/> | |
| 6 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 100 100" role="img" aria-label="Sidekicks"> | ||
| 3 | + <circle cx="50" cy="50" r="20" fill="#1E2240"/> | ||
| 4 | + <circle cx="78" cy="26" r="14" fill="#12A39A"/> | ||
| 5 | + <circle cx="18" cy="40" r="12" fill="#FF7A59"/> | ||
| 6 | +</svg> | ||
added
docs/design/logo/sidekicks-mark-dark.svg +12 -0 | new file mode 100644 | ||
| @@ -0,0 +1,12 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 100 100" role="img" aria-label="Sidekicks"> | |
| 3 | + <mask id="cut"> | |
| 4 | + <rect width="100" height="100" fill="#fff"/> | |
| 5 | + <circle cx="76" cy="28" r="12" fill="#000"/> | |
| 6 | + <circle cx="18" cy="39" r="10" fill="#000"/> | |
| 7 | + </mask> | |
| 8 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#4A5078" stroke-width="4" mask="url(#cut)"/> | |
| 9 | + <circle cx="50" cy="50" r="15" fill="#FFFFFF"/> | |
| 10 | + <circle cx="76" cy="28" r="9" fill="#2FD1C5"/> | |
| 11 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | |
| 12 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 100 100" role="img" aria-label="Sidekicks"> | ||
| 3 | + <mask id="cut"> | ||
| 4 | + <rect width="100" height="100" fill="#fff"/> | ||
| 5 | + <circle cx="76" cy="28" r="12" fill="#000"/> | ||
| 6 | + <circle cx="18" cy="39" r="10" fill="#000"/> | ||
| 7 | + </mask> | ||
| 8 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#4A5078" stroke-width="4" mask="url(#cut)"/> | ||
| 9 | + <circle cx="50" cy="50" r="15" fill="#FFFFFF"/> | ||
| 10 | + <circle cx="76" cy="28" r="9" fill="#2FD1C5"/> | ||
| 11 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | ||
| 12 | +</svg> | ||
added
docs/design/logo/sidekicks-mark.svg +12 -0 | new file mode 100644 | ||
| @@ -0,0 +1,12 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 100 100" role="img" aria-label="Sidekicks"> | |
| 3 | + <mask id="cut"> | |
| 4 | + <rect width="100" height="100" fill="#fff"/> | |
| 5 | + <circle cx="76" cy="28" r="12" fill="#000"/> | |
| 6 | + <circle cx="18" cy="39" r="10" fill="#000"/> | |
| 7 | + </mask> | |
| 8 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#C9CCE8" stroke-width="4" mask="url(#cut)"/> | |
| 9 | + <circle cx="50" cy="50" r="15" fill="#1E2240"/> | |
| 10 | + <circle cx="76" cy="28" r="9" fill="#12A39A"/> | |
| 11 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | |
| 12 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 100 100" role="img" aria-label="Sidekicks"> | ||
| 3 | + <mask id="cut"> | ||
| 4 | + <rect width="100" height="100" fill="#fff"/> | ||
| 5 | + <circle cx="76" cy="28" r="12" fill="#000"/> | ||
| 6 | + <circle cx="18" cy="39" r="10" fill="#000"/> | ||
| 7 | + </mask> | ||
| 8 | + <circle cx="50" cy="50" r="35" fill="none" stroke="#C9CCE8" stroke-width="4" mask="url(#cut)"/> | ||
| 9 | + <circle cx="50" cy="50" r="15" fill="#1E2240"/> | ||
| 10 | + <circle cx="76" cy="28" r="9" fill="#12A39A"/> | ||
| 11 | + <circle cx="18" cy="39" r="7" fill="#FF7A59"/> | ||
| 12 | +</svg> | ||
modified
docs/design/wireframes.drawio +199 -199 | @@ -1,10 +1,10 @@ | ||
| 1 | 1 | <mxfile host="app.diagrams.net"> |
| 2 | - <diagram id="01-layout" name="1 · Layout global"> | |
| 2 | + <diagram id="01-layout" name="1 · Overall layout"> | |
| 3 | 3 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 4 | 4 | <root> |
| 5 | 5 | <mxCell id="0"/> |
| 6 | 6 | <mxCell id="1" parent="0"/> |
| 7 | - <mxCell id="01-layout-title" value="<b>1 · Layout global</b><br><i>Docks façon Zed, mais seul l'essentiel est visible par défaut</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 7 | + <mxCell id="01-layout-title" value="<b>1 · Overall layout</b><br><i>Zed-like docks, but only the essentials are visible by default</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 8 | 8 | <mxCell id="01-layout-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 9 | 9 | <mxCell id="01-layout-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 10 | 10 | <mxCell id="01-layout-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -13,14 +13,14 @@ | ||
| 13 | 13 | <mxCell id="01-layout-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 14 | 14 | <mxCell id="01-layout-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 15 | 15 | <mxCell id="01-layout-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 16 | - <mxCell id="01-layout-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | |
| 16 | + <mxCell id="01-layout-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> | |
| 17 | 17 | <mxCell id="01-layout-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 18 | 18 | <mxCell id="01-layout-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 19 | 19 | <mxCell id="01-layout-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 20 | 20 | <mxCell id="01-layout-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 21 | 21 | <mxCell id="01-layout-14" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="158" width="214" height="26" as="geometry"/></mxCell> |
| 22 | - <mxCell id="01-layout-15" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 23 | - <mxCell id="01-layout-16" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | |
| 22 | + <mxCell id="01-layout-15" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 23 | + <mxCell id="01-layout-16" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> | |
| 24 | 24 | <mxCell id="01-layout-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 25 | 25 | <mxCell id="01-layout-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| 26 | 26 | <mxCell id="01-layout-19" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> |
| @@ -32,18 +32,18 @@ | ||
| 32 | 32 | <mxCell id="01-layout-25" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> |
| 33 | 33 | <mxCell id="01-layout-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 34 | 34 | <mxCell id="01-layout-27" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="709" height="44" as="geometry"/></mxCell> |
| 35 | - <mxCell id="01-layout-28" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="78.3" height="20" as="geometry"/></mxCell> | |
| 35 | + <mxCell id="01-layout-28" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="78.3" height="20" as="geometry"/></mxCell> | |
| 36 | 36 | <mxCell id="01-layout-29" value="👩 Alice · 🧔 Bob" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="830.9" y="131" width="113.1" height="18" as="geometry"/></mxCell> |
| 37 | - <mxCell id="01-layout-30" value="Vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="182.5" width="31.319999999999997" height="18.5" as="geometry"/></mxCell> | |
| 38 | - <mxCell id="01-layout-31" value="@alice résume-moi ce que fait ACP en deux phrases" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="204.5" width="383.66999999999996" height="18.5" as="geometry"/></mxCell> | |
| 37 | + <mxCell id="01-layout-30" value="You" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="182.5" width="23.49" height="18.5" as="geometry"/></mxCell> | |
| 38 | + <mxCell id="01-layout-31" value="@alice sum up what ACP does in two sentences" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="204.5" width="344.52" height="18.5" as="geometry"/></mxCell> | |
| 39 | 39 | <mxCell id="01-layout-32" value="👩 Alice" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#C2185B;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="238.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> |
| 40 | - <mxCell id="01-layout-33" value="ACP est un protocole qui permet à une application de dialoguer avec" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="260.5" width="524.61" height="18.5" as="geometry"/></mxCell> | |
| 41 | - <mxCell id="01-layout-34" value="n'importe quel agent d'IA. Sidekicks l'utilise pour rester agnostique." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="280.0" width="548.0999999999999" height="18.5" as="geometry"/></mxCell> | |
| 40 | + <mxCell id="01-layout-33" value="ACP is a protocol that lets an application talk with any AI agent." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="260.5" width="516.78" height="18.5" as="geometry"/></mxCell> | |
| 41 | + <mxCell id="01-layout-34" value="Sidekicks uses it to stay agent-agnostic." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="280.0" width="321.03" height="18.5" as="geometry"/></mxCell> | |
| 42 | 42 | <mxCell id="01-layout-35" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="724" width="669" height="64" as="geometry"/></mxCell> |
| 43 | - <mxCell id="01-layout-36" value="Écrivez un message… (@ pour un agent, / pour une commande)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="736" width="479.08" height="19" as="geometry"/></mxCell> | |
| 44 | - <mxCell id="01-layout-37" value="Entrée pour envoyer · Maj+Entrée nouvelle ligne" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="763" width="299.85999999999996" height="16" as="geometry"/></mxCell> | |
| 43 | + <mxCell id="01-layout-36" value="Write a message… (@ for an agent, / for a command)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="736" width="414.11999999999995" height="19" as="geometry"/></mxCell> | |
| 44 | + <mxCell id="01-layout-37" value="Enter to send · Shift+Enter for a new line" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="763" width="267.96" height="16" as="geometry"/></mxCell> | |
| 45 | 45 | <mxCell id="01-layout-38" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="960" y="116" width="300" height="718" as="geometry"/></mxCell> |
| 46 | - <mxCell id="01-layout-39" value="⚙︎ Settings — equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="976" y="131" width="188.5" height="18" as="geometry"/></mxCell> | |
| 46 | + <mxCell id="01-layout-39" value="⚙︎ Settings — team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="976" y="131" width="173.42" height="18" as="geometry"/></mxCell> | |
| 47 | 47 | <mxCell id="01-layout-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F4F5F7;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="970" y="160" width="280" height="300" as="geometry"/></mxCell> |
| 48 | 48 | <mxCell id="01-layout-41" value="version: 1" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="172" width="74.4" height="17" as="geometry"/></mxCell> |
| 49 | 49 | <mxCell id="01-layout-42" value="agents:" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="191" width="52.08" height="17" as="geometry"/></mxCell> |
| @@ -52,13 +52,13 @@ | ||
| 52 | 52 | <mxCell id="01-layout-45" value=" command: mm" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="248" width="111.6" height="17" as="geometry"/></mxCell> |
| 53 | 53 | <mxCell id="01-layout-46" value=" args: [-acp, ...]" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="267" width="156.24" height="17" as="geometry"/></mxCell> |
| 54 | 54 | <mxCell id="01-layout-47" value="channels:" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="286" width="66.96" height="17" as="geometry"/></mxCell> |
| 55 | - <mxCell id="01-layout-48" value=" - name: général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="305" width="126.48" height="17" as="geometry"/></mxCell> | |
| 55 | + <mxCell id="01-layout-48" value=" - name: general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="305" width="126.48" height="17" as="geometry"/></mxCell> | |
| 56 | 56 | <mxCell id="01-layout-49" value=" agents: [alice, bob]" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="324" width="178.56" height="17" as="geometry"/></mxCell> |
| 57 | - <mxCell id="01-layout-50" value="✓ Configuration valide" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#3E9B4F;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="976" y="477.5" width="159.5" height="17.5" as="geometry"/></mxCell> | |
| 57 | + <mxCell id="01-layout-50" value="✓ Valid configuration" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#3E9B4F;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="976" y="477.5" width="152.25" height="17.5" as="geometry"/></mxCell> | |
| 58 | 58 | <mxCell id="01-layout-51" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="970" y="508" width="120" height="32" as="geometry"/></mxCell> |
| 59 | - <mxCell id="01-layout-52" value="Enregistrer" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="988.53" y="516.0" width="82.94" height="18" as="geometry"/></mxCell> | |
| 59 | + <mxCell id="01-layout-52" value="Save" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1014.92" y="516.0" width="30.159999999999997" height="18" as="geometry"/></mxCell> | |
| 60 | 60 | <mxCell id="01-layout-53" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="804" width="709" height="30" as="geometry"/></mxCell> |
| 61 | - <mxCell id="01-layout-54" value="▸ Terminal · Fichiers (repliés)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="265" y="812" width="229.67999999999998" height="17" as="geometry"/></mxCell> | |
| 61 | + <mxCell id="01-layout-54" value="▸ Terminal · Files (folded)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="265" y="812" width="201.83999999999997" height="17" as="geometry"/></mxCell> | |
| 62 | 62 | <mxCell id="01-layout-55" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="208" y="130" width="24" height="24" as="geometry"/></mxCell> |
| 63 | 63 | <mxCell id="01-layout-56" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="359" y="228" width="24" height="24" as="geometry"/></mxCell> |
| 64 | 64 | <mxCell id="01-layout-57" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1218" y="128" width="24" height="24" as="geometry"/></mxCell> |
| @@ -66,39 +66,39 @@ | ||
| 66 | 66 | <mxCell id="01-layout-59" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="428" y="835" width="24" height="24" as="geometry"/></mxCell> |
| 67 | 67 | <mxCell id="01-layout-60" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 68 | 68 | <mxCell id="01-layout-61" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 69 | - <mxCell id="01-layout-62" value="Dock gauche : channels et agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="250.55999999999997" height="18.5" as="geometry"/></mxCell> | |
| 70 | - <mxCell id="01-layout-63" value="Toujours visible. La pastille donne l'état de" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="313.2" height="17" as="geometry"/></mxCell> | |
| 71 | - <mxCell id="01-layout-64" value="l'agent : vert prêt, orange occupé, gris arrêté." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="334.08" height="17" as="geometry"/></mxCell> | |
| 69 | + <mxCell id="01-layout-62" value="Left dock: channels and agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> | |
| 70 | + <mxCell id="01-layout-63" value="Always visible. The dot gives the agent's" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="285.35999999999996" height="17" as="geometry"/></mxCell> | |
| 71 | + <mxCell id="01-layout-64" value="state: green ready, orange busy, grey stopped." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="320.15999999999997" height="17" as="geometry"/></mxCell> | |
| 72 | 72 | <mxCell id="01-layout-65" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 73 | 73 | <mxCell id="01-layout-66" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 74 | - <mxCell id="01-layout-67" value="Centre : la conversation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="187.92" height="18.5" as="geometry"/></mxCell> | |
| 75 | - <mxCell id="01-layout-68" value="Le seul panel indispensable. Pleine largeur" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="299.28" height="17" as="geometry"/></mxCell> | |
| 76 | - <mxCell id="01-layout-69" value="quand les docks sont repliés." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="201.83999999999997" height="17" as="geometry"/></mxCell> | |
| 74 | + <mxCell id="01-layout-67" value="Centre: the conversation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="187.92" height="18.5" as="geometry"/></mxCell> | |
| 75 | + <mxCell id="01-layout-68" value="The only panel you cannot do without." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="257.52" height="17" as="geometry"/></mxCell> | |
| 76 | + <mxCell id="01-layout-69" value="Full width when the docks are folded." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="257.52" height="17" as="geometry"/></mxCell> | |
| 77 | 77 | <mxCell id="01-layout-70" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="94" as="geometry"/></mxCell> |
| 78 | 78 | <mxCell id="01-layout-71" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 79 | - <mxCell id="01-layout-72" value="Dock droit : Settings" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="164.42999999999998" height="18.5" as="geometry"/></mxCell> | |
| 80 | - <mxCell id="01-layout-73" value="Éditeur YAML (CodeMirror) avec validation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="285.35999999999996" height="17" as="geometry"/></mxCell> | |
| 81 | - <mxCell id="01-layout-74" value="en direct. Fermé par défaut ; s'ouvre" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="257.52" height="17" as="geometry"/></mxCell> | |
| 82 | - <mxCell id="01-layout-75" value="par ⚙︎ ou ⌘,." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="90.47999999999999" height="17" as="geometry"/></mxCell> | |
| 79 | + <mxCell id="01-layout-72" value="Right dock: Settings" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="156.6" height="18.5" as="geometry"/></mxCell> | |
| 80 | + <mxCell id="01-layout-73" value="YAML editor (CodeMirror) with live" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="236.64" height="17" as="geometry"/></mxCell> | |
| 81 | + <mxCell id="01-layout-74" value="validation. Closed by default; opens" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="250.55999999999997" height="17" as="geometry"/></mxCell> | |
| 82 | + <mxCell id="01-layout-75" value="with ⚙︎ or ⌘,." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="97.44" height="17" as="geometry"/></mxCell> | |
| 83 | 83 | <mxCell id="01-layout-76" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="368" width="356" height="76" as="geometry"/></mxCell> |
| 84 | 84 | <mxCell id="01-layout-77" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="378" width="24" height="24" as="geometry"/></mxCell> |
| 85 | - <mxCell id="01-layout-78" value="Dock bas : terminal et fichiers" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="381.5" width="242.73" height="18.5" as="geometry"/></mxCell> | |
| 86 | - <mxCell id="01-layout-79" value="Replié par défaut : utile aux curieux," style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 87 | - <mxCell id="01-layout-80" value="jamais imposé au citizen user." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="208.79999999999998" height="17" as="geometry"/></mxCell> | |
| 85 | + <mxCell id="01-layout-78" value="Bottom dock: terminal and files" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="381.5" width="242.73" height="18.5" as="geometry"/></mxCell> | |
| 86 | + <mxCell id="01-layout-79" value="Folded by default: there for the curious," style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="285.35999999999996" height="17" as="geometry"/></mxCell> | |
| 87 | + <mxCell id="01-layout-80" value="never forced on the citizen user." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="229.67999999999998" height="17" as="geometry"/></mxCell> | |
| 88 | 88 | <mxCell id="01-layout-81" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="458" width="356" height="76" as="geometry"/></mxCell> |
| 89 | 89 | <mxCell id="01-layout-82" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="468" width="24" height="24" as="geometry"/></mxCell> |
| 90 | - <mxCell id="01-layout-83" value="Barre d'état" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="471.5" width="93.96" height="18.5" as="geometry"/></mxCell> | |
| 91 | - <mxCell id="01-layout-84" value="Rappelle la limite d'agents simultanés" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 92 | - <mxCell id="01-layout-85" value="(mémoire) et la configuration ouverte." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 90 | + <mxCell id="01-layout-83" value="Status bar" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="471.5" width="78.3" height="18.5" as="geometry"/></mxCell> | |
| 91 | + <mxCell id="01-layout-84" value="Shows the limit of agents running at once" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="285.35999999999996" height="17" as="geometry"/></mxCell> | |
| 92 | + <mxCell id="01-layout-85" value="(memory) and the open configuration." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="250.55999999999997" height="17" as="geometry"/></mxCell> | |
| 93 | 93 | </root> |
| 94 | 94 | </mxGraphModel> |
| 95 | 95 | </diagram> |
| 96 | - <diagram id="02-conversation" name="2 · Conversation multi-agents"> | |
| 96 | + <diagram id="02-conversation" name="2 · Multi-agent conversation"> | |
| 97 | 97 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 98 | 98 | <root> |
| 99 | 99 | <mxCell id="0"/> |
| 100 | 100 | <mxCell id="1" parent="0"/> |
| 101 | - <mxCell id="02-conversation-title" value="<b>2 · Conversation multi-agents</b><br><i>Chaque agent a sa couleur ; les outils sont repliés ; on peut toujours arrêter</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 101 | + <mxCell id="02-conversation-title" value="<b>2 · Multi-agent conversation</b><br><i>Each agent has its colour; tools are folded; you can always stop</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 102 | 102 | <mxCell id="02-conversation-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 103 | 103 | <mxCell id="02-conversation-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 104 | 104 | <mxCell id="02-conversation-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -107,14 +107,14 @@ | ||
| 107 | 107 | <mxCell id="02-conversation-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 108 | 108 | <mxCell id="02-conversation-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 109 | 109 | <mxCell id="02-conversation-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 110 | - <mxCell id="02-conversation-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | |
| 110 | + <mxCell id="02-conversation-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> | |
| 111 | 111 | <mxCell id="02-conversation-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 112 | 112 | <mxCell id="02-conversation-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 113 | 113 | <mxCell id="02-conversation-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 114 | 114 | <mxCell id="02-conversation-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 115 | 115 | <mxCell id="02-conversation-14" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="158" width="214" height="26" as="geometry"/></mxCell> |
| 116 | - <mxCell id="02-conversation-15" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 117 | - <mxCell id="02-conversation-16" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | |
| 116 | + <mxCell id="02-conversation-15" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 117 | + <mxCell id="02-conversation-16" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> | |
| 118 | 118 | <mxCell id="02-conversation-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 119 | 119 | <mxCell id="02-conversation-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| 120 | 120 | <mxCell id="02-conversation-19" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> |
| @@ -126,31 +126,31 @@ | ||
| 126 | 126 | <mxCell id="02-conversation-25" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> |
| 127 | 127 | <mxCell id="02-conversation-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 128 | 128 | <mxCell id="02-conversation-27" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="1009" height="44" as="geometry"/></mxCell> |
| 129 | - <mxCell id="02-conversation-28" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="78.3" height="20" as="geometry"/></mxCell> | |
| 129 | + <mxCell id="02-conversation-28" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="78.3" height="20" as="geometry"/></mxCell> | |
| 130 | 130 | <mxCell id="02-conversation-29" value="👩 Alice · 🧔 Bob · 🧑🚀 Riker" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1040.42" y="131" width="203.57999999999998" height="18" as="geometry"/></mxCell> |
| 131 | - <mxCell id="02-conversation-30" value="— Riker a rejoint le channel —" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#6B6F7A;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="275" y="183.5" width="217.49999999999997" height="17.5" as="geometry"/></mxCell> | |
| 132 | - <mxCell id="02-conversation-31" value="Vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="214.5" width="31.319999999999997" height="18.5" as="geometry"/></mxCell> | |
| 133 | - <mxCell id="02-conversation-32" value="@alice propose un nom pour un script qui sauvegarde mes photos" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="236.5" width="485.46" height="18.5" as="geometry"/></mxCell> | |
| 131 | + <mxCell id="02-conversation-30" value="— Riker joined the channel —" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#6B6F7A;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="275" y="183.5" width="203.0" height="17.5" as="geometry"/></mxCell> | |
| 132 | + <mxCell id="02-conversation-31" value="You" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="214.5" width="23.49" height="18.5" as="geometry"/></mxCell> | |
| 133 | + <mxCell id="02-conversation-32" value="@alice suggest a name for a script that backs up my photos" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="236.5" width="454.14" height="18.5" as="geometry"/></mxCell> | |
| 134 | 134 | <mxCell id="02-conversation-33" value="👩 Alice" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#C2185B;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="270.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> |
| 135 | - <mxCell id="02-conversation-34" value="Je propose « photo-backup.sh » : court, explicite, et l'extension dit que" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="292.5" width="571.5899999999999" height="18.5" as="geometry"/></mxCell> | |
| 136 | - <mxCell id="02-conversation-35" value="c'est un script shell." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="312.0" width="172.26" height="18.5" as="geometry"/></mxCell> | |
| 137 | - <mxCell id="02-conversation-36" value="Vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="346.5" width="31.319999999999997" height="18.5" as="geometry"/></mxCell> | |
| 138 | - <mxCell id="02-conversation-37" value="@bob tu valides ? @riker crée le fichier vide" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="368.5" width="352.34999999999997" height="18.5" as="geometry"/></mxCell> | |
| 135 | + <mxCell id="02-conversation-34" value="I suggest "photo-backup.sh": short, clear, and the extension says" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="292.5" width="508.95" height="18.5" as="geometry"/></mxCell> | |
| 136 | + <mxCell id="02-conversation-35" value="it is a shell script." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="312.0" width="164.42999999999998" height="18.5" as="geometry"/></mxCell> | |
| 137 | + <mxCell id="02-conversation-36" value="You" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="346.5" width="23.49" height="18.5" as="geometry"/></mxCell> | |
| 138 | + <mxCell id="02-conversation-37" value="@bob do you agree? @riker create the empty file" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="368.5" width="368.01" height="18.5" as="geometry"/></mxCell> | |
| 139 | 139 | <mxCell id="02-conversation-38" value="🧔 Bob" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#00838F;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="402.5" width="39.15" height="18.5" as="geometry"/></mxCell> |
| 140 | - <mxCell id="02-conversation-39" value="Bon choix. Alice a raison : un nom en minuscules, sans espace." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="424.5" width="485.46" height="18.5" as="geometry"/></mxCell> | |
| 140 | + <mxCell id="02-conversation-39" value="Good choice. Alice is right: a lowercase name, no spaces." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="424.5" width="446.30999999999995" height="18.5" as="geometry"/></mxCell> | |
| 141 | 141 | <mxCell id="02-conversation-40" value="🧑🚀 Riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#5E35B1;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="458.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 142 | - <mxCell id="02-conversation-41" value="travaille…" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#6B6F7A;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="365" y="459.5" width="72.5" height="17.5" as="geometry"/></mxCell> | |
| 142 | + <mxCell id="02-conversation-41" value="working…" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#6B6F7A;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="365" y="459.5" width="57.99999999999999" height="17.5" as="geometry"/></mxCell> | |
| 143 | 143 | <mxCell id="02-conversation-42" value="" style="rounded=1;absoluteArcSize=1;arcSize=16;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="275" y="484" width="560" height="40" as="geometry"/></mxCell> |
| 144 | - <mxCell id="02-conversation-43" value="▸ 🛠 write_file : photo-backup.sh (0 octet) ✓ terminé" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="496.5" width="434.99999999999994" height="17.5" as="geometry"/></mxCell> | |
| 144 | + <mxCell id="02-conversation-43" value="▸ 🛠 write_file: photo-backup.sh (0 bytes) ✓ done" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="496.5" width="406.0" height="17.5" as="geometry"/></mxCell> | |
| 145 | 145 | <mxCell id="02-conversation-44" value="" style="rounded=1;absoluteArcSize=1;arcSize=16;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="275" y="532" width="560" height="40" as="geometry"/></mxCell> |
| 146 | - <mxCell id="02-conversation-45" value="▸ 🛠 bash : ls -la … en cours" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="544.5" width="449.49999999999994" height="17.5" as="geometry"/></mxCell> | |
| 146 | + <mxCell id="02-conversation-45" value="▸ 🛠 bash: ls -la … running" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="544.5" width="434.99999999999994" height="17.5" as="geometry"/></mxCell> | |
| 147 | 147 | <mxCell id="02-conversation-46" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="754" width="849" height="64" as="geometry"/></mxCell> |
| 148 | 148 | <mxCell id="02-conversation-47" value="" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="766" width="20" height="19" as="geometry"/></mxCell> |
| 149 | - <mxCell id="02-conversation-48" value="Entrée pour envoyer · Maj+Entrée nouvelle ligne" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="793" width="299.85999999999996" height="16" as="geometry"/></mxCell> | |
| 149 | + <mxCell id="02-conversation-48" value="Enter to send · Shift+Enter for a new line" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="793" width="267.96" height="16" as="geometry"/></mxCell> | |
| 150 | 150 | <mxCell id="02-conversation-49" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1132" y="770" width="108" height="32" as="geometry"/></mxCell> |
| 151 | - <mxCell id="02-conversation-50" value="■ Arrêter" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1152.07" y="778.0" width="67.86" height="18" as="geometry"/></mxCell> | |
| 151 | + <mxCell id="02-conversation-50" value="■ Stop" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1163.38" y="778.0" width="45.239999999999995" height="18" as="geometry"/></mxCell> | |
| 152 | 152 | <mxCell id="02-conversation-51" value="" style="rounded=1;absoluteArcSize=1;arcSize=30;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1040" y="176" width="200" height="30" as="geometry"/></mxCell> |
| 153 | - <mxCell id="02-conversation-52" value="contexte Riker : 41 %" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1069.965" y="184.5" width="140.07" height="16.5" as="geometry"/></mxCell> | |
| 153 | + <mxCell id="02-conversation-52" value="Riker's context: 41%" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1073.3" y="184.5" width="133.39999999999998" height="16.5" as="geometry"/></mxCell> | |
| 154 | 154 | <mxCell id="02-conversation-53" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="563" y="179" width="24" height="24" as="geometry"/></mxCell> |
| 155 | 155 | <mxCell id="02-conversation-54" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="343" y="262" width="24" height="24" as="geometry"/></mxCell> |
| 156 | 156 | <mxCell id="02-conversation-55" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="843" y="492" width="24" height="24" as="geometry"/></mxCell> |
| @@ -158,40 +158,40 @@ | ||
| 158 | 158 | <mxCell id="02-conversation-57" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1016" y="179" width="24" height="24" as="geometry"/></mxCell> |
| 159 | 159 | <mxCell id="02-conversation-58" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 160 | 160 | <mxCell id="02-conversation-59" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 161 | - <mxCell id="02-conversation-60" value="Arrivée visible" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="117.44999999999999" height="18.5" as="geometry"/></mxCell> | |
| 162 | - <mxCell id="02-conversation-61" value="La 1re mention invite l'agent : un message" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="292.32" height="17" as="geometry"/></mxCell> | |
| 163 | - <mxCell id="02-conversation-62" value="système le dit. On sait qui « écoute »." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="271.44" height="17" as="geometry"/></mxCell> | |
| 161 | + <mxCell id="02-conversation-60" value="A visible arrival" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="133.10999999999999" height="18.5" as="geometry"/></mxCell> | |
| 162 | + <mxCell id="02-conversation-61" value="The first mention invites the agent: a system" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="313.2" height="17" as="geometry"/></mxCell> | |
| 163 | + <mxCell id="02-conversation-62" value="message says so. You know who is listening." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="299.28" height="17" as="geometry"/></mxCell> | |
| 164 | 164 | <mxCell id="02-conversation-63" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 165 | 165 | <mxCell id="02-conversation-64" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 166 | - <mxCell id="02-conversation-65" value="Une couleur par agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="164.42999999999998" height="18.5" as="geometry"/></mxCell> | |
| 167 | - <mxCell id="02-conversation-66" value="Avatar + nom colorés, réponses en Markdown" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="292.32" height="17" as="geometry"/></mxCell> | |
| 168 | - <mxCell id="02-conversation-67" value="avec code coloré (ADR 0002)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="194.88" height="17" as="geometry"/></mxCell> | |
| 166 | + <mxCell id="02-conversation-65" value="One colour per agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="156.6" height="18.5" as="geometry"/></mxCell> | |
| 167 | + <mxCell id="02-conversation-66" value="Coloured avatar and name, answers in" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="250.55999999999997" height="17" as="geometry"/></mxCell> | |
| 168 | + <mxCell id="02-conversation-67" value="Markdown with highlighted code (ADR 0002)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="292.32" height="17" as="geometry"/></mxCell> | |
| 169 | 169 | <mxCell id="02-conversation-68" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="94" as="geometry"/></mxCell> |
| 170 | 170 | <mxCell id="02-conversation-69" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 171 | - <mxCell id="02-conversation-70" value="Outils repliés" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> | |
| 172 | - <mxCell id="02-conversation-71" value="Une ligne par tool call : titre lisible et" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="292.32" height="17" as="geometry"/></mxCell> | |
| 173 | - <mxCell id="02-conversation-72" value="statut. Déplier montre la commande, le" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 174 | - <mxCell id="02-conversation-73" value="diff ou la sortie." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="125.27999999999999" height="17" as="geometry"/></mxCell> | |
| 171 | + <mxCell id="02-conversation-70" value="Folded tools" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="93.96" height="18.5" as="geometry"/></mxCell> | |
| 172 | + <mxCell id="02-conversation-71" value="One line per tool call: a readable title" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="278.4" height="17" as="geometry"/></mxCell> | |
| 173 | + <mxCell id="02-conversation-72" value="and its status. Unfolding shows the" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="243.6" height="17" as="geometry"/></mxCell> | |
| 174 | + <mxCell id="02-conversation-73" value="command, the diff or the output." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="222.71999999999997" height="17" as="geometry"/></mxCell> | |
| 175 | 175 | <mxCell id="02-conversation-74" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="368" width="356" height="76" as="geometry"/></mxCell> |
| 176 | 176 | <mxCell id="02-conversation-75" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="378" width="24" height="24" as="geometry"/></mxCell> |
| 177 | - <mxCell id="02-conversation-76" value="Toujours un bouton Arrêter" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="381.5" width="203.57999999999998" height="18.5" as="geometry"/></mxCell> | |
| 178 | - <mxCell id="02-conversation-77" value="Envoie session/cancel aux agents qui" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="250.55999999999997" height="17" as="geometry"/></mxCell> | |
| 179 | - <mxCell id="02-conversation-78" value="répondent dans ce channel (ADR 0001)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="257.52" height="17" as="geometry"/></mxCell> | |
| 177 | + <mxCell id="02-conversation-76" value="Always a Stop button" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="381.5" width="156.6" height="18.5" as="geometry"/></mxCell> | |
| 178 | + <mxCell id="02-conversation-77" value="Sends session/cancel to the agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="236.64" height="17" as="geometry"/></mxCell> | |
| 179 | + <mxCell id="02-conversation-78" value="answering in this channel (ADR 0001)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="257.52" height="17" as="geometry"/></mxCell> | |
| 180 | 180 | <mxCell id="02-conversation-79" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="458" width="356" height="94" as="geometry"/></mxCell> |
| 181 | 181 | <mxCell id="02-conversation-80" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="468" width="24" height="24" as="geometry"/></mxCell> |
| 182 | - <mxCell id="02-conversation-81" value="Jauge de contexte" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="471.5" width="133.10999999999999" height="18.5" as="geometry"/></mxCell> | |
| 183 | - <mxCell id="02-conversation-82" value="usage_update : prévient avant que la" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="250.55999999999997" height="17" as="geometry"/></mxCell> | |
| 184 | - <mxCell id="02-conversation-83" value="conversation ne dépasse la mémoire de" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="257.52" height="17" as="geometry"/></mxCell> | |
| 185 | - <mxCell id="02-conversation-84" value="l'agent." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="532" width="55.67999999999999" height="17" as="geometry"/></mxCell> | |
| 182 | + <mxCell id="02-conversation-81" value="Context gauge" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="471.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | |
| 183 | + <mxCell id="02-conversation-82" value="usage_update: warns before the" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="208.79999999999998" height="17" as="geometry"/></mxCell> | |
| 184 | + <mxCell id="02-conversation-83" value="conversation outgrows the agent's" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="229.67999999999998" height="17" as="geometry"/></mxCell> | |
| 185 | + <mxCell id="02-conversation-84" value="memory." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="532" width="48.72" height="17" as="geometry"/></mxCell> | |
| 186 | 186 | </root> |
| 187 | 187 | </mxGraphModel> |
| 188 | 188 | </diagram> |
| 189 | - <diagram id="03-mentions-commands" name="3 · Invoquer un agent (@) et une commande (/)"> | |
| 189 | + <diagram id="03-mentions-commands" name="3 · Calling an agent (@) and a command (/)"> | |
| 190 | 190 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 191 | 191 | <root> |
| 192 | 192 | <mxCell id="0"/> |
| 193 | 193 | <mxCell id="1" parent="0"/> |
| 194 | - <mxCell id="03-mentions-commands-title" value="<b>3 · Invoquer un agent (@) et une commande (/)</b><br><i>Tab choisit la suggestion ; continuer à écrire filtre la liste</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 194 | + <mxCell id="03-mentions-commands-title" value="<b>3 · Calling an agent (@) and a command (/)</b><br><i>Tab picks the suggestion; typing on filters the list</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 195 | 195 | <mxCell id="03-mentions-commands-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 196 | 196 | <mxCell id="03-mentions-commands-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 197 | 197 | <mxCell id="03-mentions-commands-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -200,14 +200,14 @@ | ||
| 200 | 200 | <mxCell id="03-mentions-commands-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 201 | 201 | <mxCell id="03-mentions-commands-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 202 | 202 | <mxCell id="03-mentions-commands-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 203 | - <mxCell id="03-mentions-commands-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | |
| 203 | + <mxCell id="03-mentions-commands-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> | |
| 204 | 204 | <mxCell id="03-mentions-commands-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 205 | 205 | <mxCell id="03-mentions-commands-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 206 | 206 | <mxCell id="03-mentions-commands-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 207 | 207 | <mxCell id="03-mentions-commands-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 208 | 208 | <mxCell id="03-mentions-commands-14" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="158" width="214" height="26" as="geometry"/></mxCell> |
| 209 | - <mxCell id="03-mentions-commands-15" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 210 | - <mxCell id="03-mentions-commands-16" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | |
| 209 | + <mxCell id="03-mentions-commands-15" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 210 | + <mxCell id="03-mentions-commands-16" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> | |
| 211 | 211 | <mxCell id="03-mentions-commands-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 212 | 212 | <mxCell id="03-mentions-commands-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| 213 | 213 | <mxCell id="03-mentions-commands-19" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> |
| @@ -218,36 +218,36 @@ | ||
| 218 | 218 | <mxCell id="03-mentions-commands-24" value="🧑🚀 Riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="352.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 219 | 219 | <mxCell id="03-mentions-commands-25" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> |
| 220 | 220 | <mxCell id="03-mentions-commands-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 221 | - <mxCell id="03-mentions-commands-27" value="Mention d'un agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="271" y="136" width="146.16" height="19" as="geometry"/></mxCell> | |
| 221 | + <mxCell id="03-mentions-commands-27" value="Mentioning an agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="271" y="136" width="154.28" height="19" as="geometry"/></mxCell> | |
| 222 | 222 | <mxCell id="03-mentions-commands-28" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="164" width="420" height="150" as="geometry"/></mxCell> |
| 223 | 223 | <mxCell id="03-mentions-commands-29" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#E8EFFD;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="277" y="172" width="408" height="40" as="geometry"/></mxCell> |
| 224 | 224 | <mxCell id="03-mentions-commands-30" value="🐮 garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="289" y="176.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 225 | - <mxCell id="03-mentions-commands-31" value="Garfield (traducteur) — traduit FR ⇄ EN" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="194.5" width="260.13" height="16.5" as="geometry"/></mxCell> | |
| 225 | + <mxCell id="03-mentions-commands-31" value="Garfield (translator) — translates FR ⇄ EN" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="194.5" width="280.14" height="16.5" as="geometry"/></mxCell> | |
| 226 | 226 | <mxCell id="03-mentions-commands-32" value="🧑🚀 riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="289" y="220.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 227 | - <mxCell id="03-mentions-commands-33" value="Riker (outils) — commandes et fichiers" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="238.5" width="253.45999999999998" height="16.5" as="geometry"/></mxCell> | |
| 227 | + <mxCell id="03-mentions-commands-33" value="Riker (tools) — commands and files" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="238.5" width="226.77999999999997" height="16.5" as="geometry"/></mxCell> | |
| 228 | 228 | <mxCell id="03-mentions-commands-34" value="👩 alice" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="289" y="264.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> |
| 229 | - <mxCell id="03-mentions-commands-35" value="Alice (assistante) — questions simples" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="282.5" width="253.45999999999998" height="16.5" as="geometry"/></mxCell> | |
| 229 | + <mxCell id="03-mentions-commands-35" value="Alice (assistant) — simple questions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="282.5" width="240.11999999999998" height="16.5" as="geometry"/></mxCell> | |
| 230 | 230 | <mxCell id="03-mentions-commands-36" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="324" width="969" height="64" as="geometry"/></mxCell> |
| 231 | 231 | <mxCell id="03-mentions-commands-37" value="@ga" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="336" width="24.36" height="19" as="geometry"/></mxCell> |
| 232 | - <mxCell id="03-mentions-commands-38" value="Tab : @garfield · ↑↓ naviguer · Échap fermer" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="363" width="280.71999999999997" height="16" as="geometry"/></mxCell> | |
| 233 | - <mxCell id="03-mentions-commands-39" value="Commande d'un agent (plusieurs agents dans le channel)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="271" y="426" width="438.47999999999996" height="19" as="geometry"/></mxCell> | |
| 232 | + <mxCell id="03-mentions-commands-38" value="Tab: @garfield · ↑↓ move · Esc close" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="363" width="229.67999999999998" height="16" as="geometry"/></mxCell> | |
| 233 | + <mxCell id="03-mentions-commands-39" value="An agent's command (several agents in the channel)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="271" y="426" width="406.0" height="19" as="geometry"/></mxCell> | |
| 234 | 234 | <mxCell id="03-mentions-commands-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="454" width="520" height="196" as="geometry"/></mxCell> |
| 235 | 235 | <mxCell id="03-mentions-commands-41" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#E8EFFD;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="277" y="462" width="508" height="42" as="geometry"/></mxCell> |
| 236 | 236 | <mxCell id="03-mentions-commands-42" value="/garfield:idioms" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="467.5" width="133.92" height="18.5" as="geometry"/></mxCell> |
| 237 | - <mxCell id="03-mentions-commands-43" value="[texte]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="721.09" y="469.5" width="49.91" height="16.5" as="geometry"/></mxCell> | |
| 238 | - <mxCell id="03-mentions-commands-44" value="Expressions idiomatiques et faux amis" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="486.5" width="246.79" height="16.5" as="geometry"/></mxCell> | |
| 237 | + <mxCell id="03-mentions-commands-43" value="[text]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="728.22" y="469.5" width="42.78" height="16.5" as="geometry"/></mxCell> | |
| 238 | + <mxCell id="03-mentions-commands-44" value="Idioms and false friends" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="486.5" width="160.07999999999998" height="16.5" as="geometry"/></mxCell> | |
| 239 | 239 | <mxCell id="03-mentions-commands-45" value="/garfield:styles" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="513.5" width="133.92" height="18.5" as="geometry"/></mxCell> |
| 240 | - <mxCell id="03-mentions-commands-46" value="[texte]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="721.09" y="515.5" width="49.91" height="16.5" as="geometry"/></mxCell> | |
| 241 | - <mxCell id="03-mentions-commands-47" value="Plusieurs versions d'une traduction" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="532.5" width="233.45" height="16.5" as="geometry"/></mxCell> | |
| 240 | + <mxCell id="03-mentions-commands-46" value="[text]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="728.22" y="515.5" width="42.78" height="16.5" as="geometry"/></mxCell> | |
| 241 | + <mxCell id="03-mentions-commands-47" value="Several versions of a translation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="532.5" width="220.10999999999999" height="16.5" as="geometry"/></mxCell> | |
| 242 | 242 | <mxCell id="03-mentions-commands-48" value="/garfield:email-letter" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="559.5" width="184.14" height="18.5" as="geometry"/></mxCell> |
| 243 | - <mxCell id="03-mentions-commands-49" value="[texte]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="721.09" y="561.5" width="49.91" height="16.5" as="geometry"/></mxCell> | |
| 244 | - <mxCell id="03-mentions-commands-50" value="E-mails et lettres : formules, tu ou vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="578.5" width="273.46999999999997" height="16.5" as="geometry"/></mxCell> | |
| 243 | + <mxCell id="03-mentions-commands-49" value="[text]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="728.22" y="561.5" width="42.78" height="16.5" as="geometry"/></mxCell> | |
| 244 | + <mxCell id="03-mentions-commands-50" value="E-mails and letters: greetings, tu or vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="578.5" width="280.14" height="16.5" as="geometry"/></mxCell> | |
| 245 | 245 | <mxCell id="03-mentions-commands-51" value="/alice:compact" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="605.5" width="117.17999999999999" height="18.5" as="geometry"/></mxCell> |
| 246 | 246 | <mxCell id="03-mentions-commands-52" value="" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="751" y="607.5" width="20" height="16.5" as="geometry"/></mxCell> |
| 247 | - <mxCell id="03-mentions-commands-53" value="Résumer l'historique maintenant" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="624.5" width="206.76999999999998" height="16.5" as="geometry"/></mxCell> | |
| 247 | + <mxCell id="03-mentions-commands-53" value="Summarise the history now" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="624.5" width="166.75" height="16.5" as="geometry"/></mxCell> | |
| 248 | 248 | <mxCell id="03-mentions-commands-54" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="660" width="969" height="64" as="geometry"/></mxCell> |
| 249 | 249 | <mxCell id="03-mentions-commands-55" value="/gar" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="672" width="32.48" height="19" as="geometry"/></mxCell> |
| 250 | - <mxCell id="03-mentions-commands-56" value="Tab : /garfield:idioms · le texte après la commande est son argument" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="699" width="433.84" height="16" as="geometry"/></mxCell> | |
| 250 | + <mxCell id="03-mentions-commands-56" value="Tab: /garfield:idioms · the text after the command is its argument" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="699" width="421.08" height="16" as="geometry"/></mxCell> | |
| 251 | 251 | <mxCell id="03-mentions-commands-57" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="693" y="168" width="24" height="24" as="geometry"/></mxCell> |
| 252 | 252 | <mxCell id="03-mentions-commands-58" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="559" y="344" width="24" height="24" as="geometry"/></mxCell> |
| 253 | 253 | <mxCell id="03-mentions-commands-59" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="793" y="458" width="24" height="24" as="geometry"/></mxCell> |
| @@ -255,38 +255,38 @@ | ||
| 255 | 255 | <mxCell id="03-mentions-commands-61" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1208" y="680" width="24" height="24" as="geometry"/></mxCell> |
| 256 | 256 | <mxCell id="03-mentions-commands-62" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 257 | 257 | <mxCell id="03-mentions-commands-63" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 258 | - <mxCell id="03-mentions-commands-64" value="@ liste les agents de la config" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="242.73" height="18.5" as="geometry"/></mxCell> | |
| 259 | - <mxCell id="03-mentions-commands-65" value="Nom technique + titre + description." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="250.55999999999997" height="17" as="geometry"/></mxCell> | |
| 260 | - <mxCell id="03-mentions-commands-66" value="Filtrage flou sur nom et titre (« gar »)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="285.35999999999996" height="17" as="geometry"/></mxCell> | |
| 258 | + <mxCell id="03-mentions-commands-64" value="@ lists the configured agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="227.07" height="18.5" as="geometry"/></mxCell> | |
| 259 | + <mxCell id="03-mentions-commands-65" value="Technical name + title + description." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="257.52" height="17" as="geometry"/></mxCell> | |
| 260 | + <mxCell id="03-mentions-commands-66" value="Fuzzy filter on name and title ("gar")." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="271.44" height="17" as="geometry"/></mxCell> | |
| 261 | 261 | <mxCell id="03-mentions-commands-67" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 262 | 262 | <mxCell id="03-mentions-commands-68" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 263 | - <mxCell id="03-mentions-commands-69" value="Tab sélectionne, sinon on écrit" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="242.73" height="18.5" as="geometry"/></mxCell> | |
| 264 | - <mxCell id="03-mentions-commands-70" value="Comportement demandé dans le draft (#1)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="278.4" height="17" as="geometry"/></mxCell> | |
| 265 | - <mxCell id="03-mentions-commands-71" value="Échap ferme sans rien insérer." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="208.79999999999998" height="17" as="geometry"/></mxCell> | |
| 263 | + <mxCell id="03-mentions-commands-69" value="Tab picks, otherwise you type" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="227.07" height="18.5" as="geometry"/></mxCell> | |
| 264 | + <mxCell id="03-mentions-commands-70" value="Behaviour asked for in the draft (#1)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 265 | + <mxCell id="03-mentions-commands-71" value="Esc closes without inserting anything." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 266 | 266 | <mxCell id="03-mentions-commands-72" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="76" as="geometry"/></mxCell> |
| 267 | 267 | <mxCell id="03-mentions-commands-73" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 268 | - <mxCell id="03-mentions-commands-74" value="/agent:commande en multi-agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="242.73" height="18.5" as="geometry"/></mxCell> | |
| 269 | - <mxCell id="03-mentions-commands-75" value="Avec un seul agent : /commande. Sidekicks" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="285.35999999999996" height="17" as="geometry"/></mxCell> | |
| 270 | - <mxCell id="03-mentions-commands-76" value="envoie « /idioms … » au seul Garfield." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 268 | + <mxCell id="03-mentions-commands-74" value="/agent:command with several agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="266.21999999999997" height="18.5" as="geometry"/></mxCell> | |
| 269 | + <mxCell id="03-mentions-commands-75" value="With one agent: /command. Sidekicks" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="243.6" height="17" as="geometry"/></mxCell> | |
| 270 | + <mxCell id="03-mentions-commands-76" value="sends "/idioms …" to Garfield only." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="243.6" height="17" as="geometry"/></mxCell> | |
| 271 | 271 | <mxCell id="03-mentions-commands-77" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="350" width="356" height="76" as="geometry"/></mxCell> |
| 272 | 272 | <mxCell id="03-mentions-commands-78" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="360" width="24" height="24" as="geometry"/></mxCell> |
| 273 | - <mxCell id="03-mentions-commands-79" value="Skills et commandes intégrées" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="227.07" height="18.5" as="geometry"/></mxCell> | |
| 274 | - <mxCell id="03-mentions-commands-80" value="mm annonce compact, new, unload et ses" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 275 | - <mxCell id="03-mentions-commands-81" value="skills (available_commands_update)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="243.6" height="17" as="geometry"/></mxCell> | |
| 273 | + <mxCell id="03-mentions-commands-79" value="Skills and built-in commands" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="219.23999999999998" height="18.5" as="geometry"/></mxCell> | |
| 274 | + <mxCell id="03-mentions-commands-80" value="mm announces compact, new, unload and" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="257.52" height="17" as="geometry"/></mxCell> | |
| 275 | + <mxCell id="03-mentions-commands-81" value="its skills (available_commands_update)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="271.44" height="17" as="geometry"/></mxCell> | |
| 276 | 276 | <mxCell id="03-mentions-commands-82" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="440" width="356" height="76" as="geometry"/></mxCell> |
| 277 | 277 | <mxCell id="03-mentions-commands-83" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="450" width="24" height="24" as="geometry"/></mxCell> |
| 278 | - <mxCell id="03-mentions-commands-84" value="Indice d'argument" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="453.5" width="133.10999999999999" height="18.5" as="geometry"/></mxCell> | |
| 279 | - <mxCell id="03-mentions-commands-85" value="input.hint de la commande ACP, affiché" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="478" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 280 | - <mxCell id="03-mentions-commands-86" value="tant que l'argument n'est pas saisi." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="250.55999999999997" height="17" as="geometry"/></mxCell> | |
| 278 | + <mxCell id="03-mentions-commands-84" value="Argument hint" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="453.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | |
| 279 | + <mxCell id="03-mentions-commands-85" value="The ACP command's input.hint, shown" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="478" width="243.6" height="17" as="geometry"/></mxCell> | |
| 280 | + <mxCell id="03-mentions-commands-86" value="until the argument is typed." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="194.88" height="17" as="geometry"/></mxCell> | |
| 281 | 281 | </root> |
| 282 | 282 | </mxGraphModel> |
| 283 | 283 | </diagram> |
| 284 | - <diagram id="04-permission" name="4 · Demande de permission"> | |
| 284 | + <diagram id="04-permission" name="4 · Permission request"> | |
| 285 | 285 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 286 | 286 | <root> |
| 287 | 287 | <mxCell id="0"/> |
| 288 | 288 | <mxCell id="1" parent="0"/> |
| 289 | - <mxCell id="04-permission-title" value="<b>4 · Demande de permission</b><br><i>En langage clair, sur la conversation concernée, avec une sortie de secours</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 289 | + <mxCell id="04-permission-title" value="<b>4 · Permission request</b><br><i>In plain words, on the conversation concerned, with a way out</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 290 | 290 | <mxCell id="04-permission-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 291 | 291 | <mxCell id="04-permission-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 292 | 292 | <mxCell id="04-permission-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -295,13 +295,13 @@ | ||
| 295 | 295 | <mxCell id="04-permission-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 296 | 296 | <mxCell id="04-permission-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 297 | 297 | <mxCell id="04-permission-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 298 | - <mxCell id="04-permission-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | |
| 298 | + <mxCell id="04-permission-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> | |
| 299 | 299 | <mxCell id="04-permission-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 300 | 300 | <mxCell id="04-permission-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 301 | 301 | <mxCell id="04-permission-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 302 | 302 | <mxCell id="04-permission-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 303 | - <mxCell id="04-permission-14" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 304 | - <mxCell id="04-permission-15" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | |
| 303 | + <mxCell id="04-permission-14" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 304 | + <mxCell id="04-permission-15" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> | |
| 305 | 305 | <mxCell id="04-permission-16" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="218" width="214" height="26" as="geometry"/></mxCell> |
| 306 | 306 | <mxCell id="04-permission-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 307 | 307 | <mxCell id="04-permission-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| @@ -315,28 +315,28 @@ | ||
| 315 | 315 | <mxCell id="04-permission-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 316 | 316 | <mxCell id="04-permission-27" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="1009" height="44" as="geometry"/></mxCell> |
| 317 | 317 | <mxCell id="04-permission-28" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="52.199999999999996" height="20" as="geometry"/></mxCell> |
| 318 | - <mxCell id="04-permission-29" value="Vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="182.5" width="31.319999999999997" height="18.5" as="geometry"/></mxCell> | |
| 319 | - <mxCell id="04-permission-30" value="@riker supprime les fichiers temporaires du dossier" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="204.5" width="399.33" height="18.5" as="geometry"/></mxCell> | |
| 318 | + <mxCell id="04-permission-29" value="You" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="182.5" width="23.49" height="18.5" as="geometry"/></mxCell> | |
| 319 | + <mxCell id="04-permission-30" value="@riker delete the temporary files in the folder" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="204.5" width="368.01" height="18.5" as="geometry"/></mxCell> | |
| 320 | 320 | <mxCell id="04-permission-31" value="🧑🚀 Riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#5E35B1;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="238.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 321 | - <mxCell id="04-permission-32" value="attend votre réponse" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#C98A1B;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="365" y="239.5" width="145.0" height="17.5" as="geometry"/></mxCell> | |
| 321 | + <mxCell id="04-permission-32" value="waiting for your answer" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#C98A1B;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="365" y="239.5" width="166.75" height="17.5" as="geometry"/></mxCell> | |
| 322 | 322 | <mxCell id="04-permission-33" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#C98A1B;strokeWidth=2;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="275" y="270" width="720" height="330" as="geometry"/></mxCell> |
| 323 | - <mxCell id="04-permission-34" value="🧑🚀 Riker veut exécuter une commande sur votre ordinateur" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="295" y="288" width="528.9599999999999" height="21" as="geometry"/></mxCell> | |
| 323 | + <mxCell id="04-permission-34" value="🧑🚀 Riker wants to run a command on your computer" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="295" y="288" width="454.71999999999997" height="21" as="geometry"/></mxCell> | |
| 324 | 324 | <mxCell id="04-permission-35" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F4F5F7;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="295" y="322" width="680" height="40" as="geometry"/></mxCell> |
| 325 | 325 | <mxCell id="04-permission-36" value="rm -f *.tmp" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="309" y="333" width="95.48" height="19" as="geometry"/></mxCell> |
| 326 | - <mxCell id="04-permission-37" value="Ce que cela fait : supprime définitivement les fichiers se terminant par .tmp" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="375" width="580.5799999999999" height="18" as="geometry"/></mxCell> | |
| 327 | - <mxCell id="04-permission-38" value="dans agents/riker . Ils ne passent pas par la corbeille." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="395" width="429.78" height="18" as="geometry"/></mxCell> | |
| 328 | - <mxCell id="04-permission-39" value="⚠ Action irréversible" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="295" y="425" width="165.88" height="18" as="geometry"/></mxCell> | |
| 326 | + <mxCell id="04-permission-37" value="What it does: permanently deletes the files ending in .tmp" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="375" width="437.32" height="18" as="geometry"/></mxCell> | |
| 327 | + <mxCell id="04-permission-38" value="in agents/riker . They do not go to the trash." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="395" width="354.38" height="18" as="geometry"/></mxCell> | |
| 328 | + <mxCell id="04-permission-39" value="⚠ Cannot be undone" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="295" y="425" width="143.26" height="18" as="geometry"/></mxCell> | |
| 329 | 329 | <mxCell id="04-permission-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="295" y="460" width="170" height="32" as="geometry"/></mxCell> |
| 330 | - <mxCell id="04-permission-41" value="Autoriser une fois" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="312.14" y="468.0" width="135.72" height="18" as="geometry"/></mxCell> | |
| 330 | + <mxCell id="04-permission-41" value="Allow once" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="342.3" y="468.0" width="75.39999999999999" height="18" as="geometry"/></mxCell> | |
| 331 | 331 | <mxCell id="04-permission-42" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="475" y="460" width="300" height="32" as="geometry"/></mxCell> |
| 332 | - <mxCell id="04-permission-43" value="Toujours autoriser bash ici" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="523.21" y="468.0" width="203.57999999999998" height="18" as="geometry"/></mxCell> | |
| 332 | + <mxCell id="04-permission-43" value="Always allow bash here" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="542.06" y="468.0" width="165.88" height="18" as="geometry"/></mxCell> | |
| 333 | 333 | <mxCell id="04-permission-44" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="295" y="504" width="170" height="32" as="geometry"/></mxCell> |
| 334 | - <mxCell id="04-permission-45" value="Refuser" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="353.61" y="512.0" width="52.779999999999994" height="18" as="geometry"/></mxCell> | |
| 334 | + <mxCell id="04-permission-45" value="Reject" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="357.38" y="512.0" width="45.239999999999995" height="18" as="geometry"/></mxCell> | |
| 335 | 335 | <mxCell id="04-permission-46" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="475" y="504" width="300" height="32" as="geometry"/></mxCell> |
| 336 | - <mxCell id="04-permission-47" value="Ne plus jamais proposer bash ici" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="504.36" y="512.0" width="241.27999999999997" height="18" as="geometry"/></mxCell> | |
| 336 | + <mxCell id="04-permission-47" value="Never offer bash here again" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="523.21" y="512.0" width="203.57999999999998" height="18" as="geometry"/></mxCell> | |
| 337 | 337 | <mxCell id="04-permission-48" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="795" y="504" width="180" height="32" as="geometry"/></mxCell> |
| 338 | - <mxCell id="04-permission-49" value="■ Arrêter Riker" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="828.45" y="512.0" width="113.1" height="18" as="geometry"/></mxCell> | |
| 339 | - <mxCell id="04-permission-50" value="▸ Détails techniques (tool call bash, rawInput)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="558" width="327.12" height="17" as="geometry"/></mxCell> | |
| 338 | + <mxCell id="04-permission-49" value="■ Stop Riker" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="839.76" y="512.0" width="90.47999999999999" height="18" as="geometry"/></mxCell> | |
| 339 | + <mxCell id="04-permission-50" value="▸ Technical details (bash tool call, rawInput)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="558" width="320.15999999999997" height="17" as="geometry"/></mxCell> | |
| 340 | 340 | <mxCell id="04-permission-51" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="967" y="288" width="24" height="24" as="geometry"/></mxCell> |
| 341 | 341 | <mxCell id="04-permission-52" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="943" y="386" width="24" height="24" as="geometry"/></mxCell> |
| 342 | 342 | <mxCell id="04-permission-53" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="775" y="464" width="24" height="24" as="geometry"/></mxCell> |
| @@ -344,39 +344,39 @@ | ||
| 344 | 344 | <mxCell id="04-permission-55" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="643" y="554" width="24" height="24" as="geometry"/></mxCell> |
| 345 | 345 | <mxCell id="04-permission-56" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 346 | 346 | <mxCell id="04-permission-57" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 347 | - <mxCell id="04-permission-58" value="Attaché à la conversation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="195.75" height="18.5" as="geometry"/></mxCell> | |
| 348 | - <mxCell id="04-permission-59" value="Bloque seulement la session de Riker ; les" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="292.32" height="17" as="geometry"/></mxCell> | |
| 349 | - <mxCell id="04-permission-60" value="autres channels continuent (#17)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="229.67999999999998" height="17" as="geometry"/></mxCell> | |
| 347 | + <mxCell id="04-permission-58" value="Attached to the conversation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="219.23999999999998" height="18.5" as="geometry"/></mxCell> | |
| 348 | + <mxCell id="04-permission-59" value="Blocks only Riker's session; the other" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 349 | + <mxCell id="04-permission-60" value="channels go on (#17)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="146.16" height="17" as="geometry"/></mxCell> | |
| 350 | 350 | <mxCell id="04-permission-61" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="94" as="geometry"/></mxCell> |
| 351 | 351 | <mxCell id="04-permission-62" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 352 | - <mxCell id="04-permission-63" value="Expliquer, pas montrer du JSON" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> | |
| 353 | - <mxCell id="04-permission-64" value="Titre ACP + kind + rawInput traduits en" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="271.44" height="17" as="geometry"/></mxCell> | |
| 354 | - <mxCell id="04-permission-65" value="phrase. Les actions destructives sont" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="257.52" height="17" as="geometry"/></mxCell> | |
| 355 | - <mxCell id="04-permission-66" value="signalées." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="244" width="69.6" height="17" as="geometry"/></mxCell> | |
| 352 | + <mxCell id="04-permission-63" value="Explain, do not show JSON" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="195.75" height="18.5" as="geometry"/></mxCell> | |
| 353 | + <mxCell id="04-permission-64" value="ACP title + kind + rawInput turned into" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="271.44" height="17" as="geometry"/></mxCell> | |
| 354 | + <mxCell id="04-permission-65" value="a sentence. Destructive actions are" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="243.6" height="17" as="geometry"/></mxCell> | |
| 355 | + <mxCell id="04-permission-66" value="flagged." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="244" width="55.67999999999999" height="17" as="geometry"/></mxCell> | |
| 356 | 356 | <mxCell id="04-permission-67" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="278" width="356" height="94" as="geometry"/></mxCell> |
| 357 | 357 | <mxCell id="04-permission-68" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="288" width="24" height="24" as="geometry"/></mxCell> |
| 358 | - <mxCell id="04-permission-69" value="Les 4 options ACP, par ids" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="291.5" width="203.57999999999998" height="18.5" as="geometry"/></mxCell> | |
| 358 | + <mxCell id="04-permission-69" value="The 4 ACP options, by id" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="291.5" width="187.92" height="18.5" as="geometry"/></mxCell> | |
| 359 | 359 | <mxCell id="04-permission-70" value="allow · allow_always · reject · never." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="264.47999999999996" height="17" as="geometry"/></mxCell> |
| 360 | - <mxCell id="04-permission-71" value="« Ne plus jamais » est mis en avant au" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 361 | - <mxCell id="04-permission-72" value="lieu de « Refuser une fois »." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="352" width="201.83999999999997" height="17" as="geometry"/></mxCell> | |
| 360 | + <mxCell id="04-permission-71" value=""Never again" is put forward rather" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="243.6" height="17" as="geometry"/></mxCell> | |
| 361 | + <mxCell id="04-permission-72" value="than "Reject once"." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="352" width="132.23999999999998" height="17" as="geometry"/></mxCell> | |
| 362 | 362 | <mxCell id="04-permission-73" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="386" width="356" height="76" as="geometry"/></mxCell> |
| 363 | 363 | <mxCell id="04-permission-74" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="396" width="24" height="24" as="geometry"/></mxCell> |
| 364 | - <mxCell id="04-permission-75" value="Toujours une sortie de secours" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="399.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> | |
| 365 | - <mxCell id="04-permission-76" value="Spike ACP : après un refus, un petit modèle" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="299.28" height="17" as="geometry"/></mxCell> | |
| 366 | - <mxCell id="04-permission-77" value="a réessayé 40 fois. Arrêter = session/cancel." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="442" width="313.2" height="17" as="geometry"/></mxCell> | |
| 364 | + <mxCell id="04-permission-75" value="Always a way out" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="399.5" width="125.27999999999999" height="18.5" as="geometry"/></mxCell> | |
| 365 | + <mxCell id="04-permission-76" value="ACP spike: after a rejection, a small model" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="299.28" height="17" as="geometry"/></mxCell> | |
| 366 | + <mxCell id="04-permission-77" value="retried 40 times. Stop = session/cancel." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="442" width="278.4" height="17" as="geometry"/></mxCell> | |
| 367 | 367 | <mxCell id="04-permission-78" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="476" width="356" height="58" as="geometry"/></mxCell> |
| 368 | 368 | <mxCell id="04-permission-79" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="486" width="24" height="24" as="geometry"/></mxCell> |
| 369 | - <mxCell id="04-permission-80" value="Détails pour les curieux" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="489.5" width="187.92" height="18.5" as="geometry"/></mxCell> | |
| 370 | - <mxCell id="04-permission-81" value="Repliés par défaut." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="132.23999999999998" height="17" as="geometry"/></mxCell> | |
| 369 | + <mxCell id="04-permission-80" value="Details for the curious" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="489.5" width="180.08999999999997" height="18.5" as="geometry"/></mxCell> | |
| 370 | + <mxCell id="04-permission-81" value="Folded by default." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="125.27999999999999" height="17" as="geometry"/></mxCell> | |
| 371 | 371 | </root> |
| 372 | 372 | </mxGraphModel> |
| 373 | 373 | </diagram> |
| 374 | - <diagram id="05-agents-panel" name="5 · Panel Agents : fichiers, éditeur, terminal"> | |
| 374 | + <diagram id="05-agents-panel" name="5 · Agents panel: files, editor, terminal"> | |
| 375 | 375 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 376 | 376 | <root> |
| 377 | 377 | <mxCell id="0"/> |
| 378 | 378 | <mxCell id="1" parent="0"/> |
| 379 | - <mxCell id="05-agents-panel-title" value="<b>5 · Panel Agents : fichiers, éditeur, terminal</b><br><i>Le workspace de l'agent, qu'il tourne en local, dans un conteneur ou une sandbox sbx</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 379 | + <mxCell id="05-agents-panel-title" value="<b>5 · Agents panel: files, editor, terminal</b><br><i>The agent's workspace, whether it runs locally, in a container or in an sbx sandbox</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 380 | 380 | <mxCell id="05-agents-panel-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 381 | 381 | <mxCell id="05-agents-panel-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 382 | 382 | <mxCell id="05-agents-panel-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -385,13 +385,13 @@ | ||
| 385 | 385 | <mxCell id="05-agents-panel-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 386 | 386 | <mxCell id="05-agents-panel-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 387 | 387 | <mxCell id="05-agents-panel-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 388 | - <mxCell id="05-agents-panel-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | |
| 388 | + <mxCell id="05-agents-panel-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> | |
| 389 | 389 | <mxCell id="05-agents-panel-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 390 | 390 | <mxCell id="05-agents-panel-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 391 | 391 | <mxCell id="05-agents-panel-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 392 | 392 | <mxCell id="05-agents-panel-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 393 | - <mxCell id="05-agents-panel-14" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 394 | - <mxCell id="05-agents-panel-15" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | |
| 393 | + <mxCell id="05-agents-panel-14" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | |
| 394 | + <mxCell id="05-agents-panel-15" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> | |
| 395 | 395 | <mxCell id="05-agents-panel-16" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 396 | 396 | <mxCell id="05-agents-panel-17" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| 397 | 397 | <mxCell id="05-agents-panel-18" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> |
| @@ -403,15 +403,15 @@ | ||
| 403 | 403 | <mxCell id="05-agents-panel-24" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> |
| 404 | 404 | <mxCell id="05-agents-panel-25" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 405 | 405 | <mxCell id="05-agents-panel-26" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="1009" height="56" as="geometry"/></mxCell> |
| 406 | - <mxCell id="05-agents-panel-27" value="🐮 Garfield (traducteur)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="126" width="213.44" height="21" as="geometry"/></mxCell> | |
| 407 | - <mxCell id="05-agents-panel-28" value="● occupé · local · agents/garfield · gemma-4-E4B" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#C98A1B;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="267" y="150" width="334.08" height="17" as="geometry"/></mxCell> | |
| 406 | + <mxCell id="05-agents-panel-27" value="🐮 Garfield (translator)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="126" width="213.44" height="21" as="geometry"/></mxCell> | |
| 407 | + <mxCell id="05-agents-panel-28" value="● busy · local · agents/garfield · gemma-4-E4B" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#C98A1B;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="267" y="150" width="320.15999999999997" height="17" as="geometry"/></mxCell> | |
| 408 | 408 | <mxCell id="05-agents-panel-29" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1010" y="128" width="110" height="32" as="geometry"/></mxCell> |
| 409 | - <mxCell id="05-agents-panel-30" value="Redémarrer" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1027.3" y="136.0" width="75.39999999999999" height="18" as="geometry"/></mxCell> | |
| 409 | + <mxCell id="05-agents-panel-30" value="Restart" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1038.61" y="136.0" width="52.779999999999994" height="18" as="geometry"/></mxCell> | |
| 410 | 410 | <mxCell id="05-agents-panel-31" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1130" y="128" width="110" height="32" as="geometry"/></mxCell> |
| 411 | - <mxCell id="05-agents-panel-32" value="Arrêter" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1158.61" y="136.0" width="52.779999999999994" height="18" as="geometry"/></mxCell> | |
| 412 | - <mxCell id="05-agents-panel-33" value="Fichiers" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#3B6FE0;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="184.5" width="62.63999999999999" height="18.5" as="geometry"/></mxCell> | |
| 411 | + <mxCell id="05-agents-panel-32" value="Stop" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1169.92" y="136.0" width="30.159999999999997" height="18" as="geometry"/></mxCell> | |
| 412 | + <mxCell id="05-agents-panel-33" value="Files" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#3B6FE0;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="184.5" width="39.15" height="18.5" as="geometry"/></mxCell> | |
| 413 | 413 | <mxCell id="05-agents-panel-34" value="Terminal" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="375" y="184.5" width="62.63999999999999" height="18.5" as="geometry"/></mxCell> |
| 414 | - <mxCell id="05-agents-panel-35" value="Journal" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="475" y="184.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> | |
| 414 | + <mxCell id="05-agents-panel-35" value="Log" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="475" y="184.5" width="23.49" height="18.5" as="geometry"/></mxCell> | |
| 415 | 415 | <mxCell id="05-agents-panel-36" value="" style="rounded=0;fillColor=#3B6FE0;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="267" y="206" width="70" height="2" as="geometry"/></mxCell> |
| 416 | 416 | <mxCell id="05-agents-panel-37" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="216" width="260" height="420" as="geometry"/></mxCell> |
| 417 | 417 | <mxCell id="05-agents-panel-38" value="▾ garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="232.5" width="77.5" height="17.5" as="geometry"/></mxCell> |
| @@ -424,20 +424,20 @@ | ||
| 424 | 424 | <mxCell id="05-agents-panel-45" value=" ▸ idioms" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="388.5" width="93.0" height="17.5" as="geometry"/></mxCell> |
| 425 | 425 | <mxCell id="05-agents-panel-46" value=" ▸ styles" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="414.5" width="93.0" height="17.5" as="geometry"/></mxCell> |
| 426 | 426 | <mxCell id="05-agents-panel-47" value=" ▸ technical-text" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="440.5" width="155.0" height="17.5" as="geometry"/></mxCell> |
| 427 | - <mxCell id="05-agents-panel-48" value=" traduction.md" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="466.5" width="131.75" height="17.5" as="geometry"/></mxCell> | |
| 428 | - <mxCell id="05-agents-panel-49" value="+ Nouveau fichier" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#3B6FE0;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="265" y="503.5" width="123.24999999999999" height="17.5" as="geometry"/></mxCell> | |
| 427 | + <mxCell id="05-agents-panel-48" value=" translation.md" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="466.5" width="139.5" height="17.5" as="geometry"/></mxCell> | |
| 428 | + <mxCell id="05-agents-panel-49" value="+ New file" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#3B6FE0;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="265" y="503.5" width="72.5" height="17.5" as="geometry"/></mxCell> | |
| 429 | 429 | <mxCell id="05-agents-panel-50" value="" style="rounded=0;fillColor=#F4F5F7;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="521" y="216" width="729" height="420" as="geometry"/></mxCell> |
| 430 | 430 | <mxCell id="05-agents-panel-51" value="AGENTS.md" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="535" y="227" width="67.86" height="18" as="geometry"/></mxCell> |
| 431 | - <mxCell id="05-agents-panel-52" value="# Style de traduction" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="257.5" width="162.75" height="17.5" as="geometry"/></mxCell> | |
| 431 | + <mxCell id="05-agents-panel-52" value="# Translation style" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="257.5" width="147.25" height="17.5" as="geometry"/></mxCell> | |
| 432 | 432 | <mxCell id="05-agents-panel-53" value="" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="279.5" width="20" height="17.5" as="geometry"/></mxCell> |
| 433 | - <mxCell id="05-agents-panel-54" value="- Registre : celui du texte source." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="301.5" width="271.25" height="17.5" as="geometry"/></mxCell> | |
| 434 | - <mxCell id="05-agents-panel-55" value="- Typographie française : espaces insécables" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="323.5" width="341.0" height="17.5" as="geometry"/></mxCell> | |
| 435 | - <mxCell id="05-agents-panel-56" value=" avant ; : ! ? et entre « guillemets »." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="345.5" width="310.0" height="17.5" as="geometry"/></mxCell> | |
| 436 | - <mxCell id="05-agents-panel-57" value="- Ne jamais traduire le code ni les noms propres." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="367.5" width="379.75" height="17.5" as="geometry"/></mxCell> | |
| 433 | + <mxCell id="05-agents-panel-54" value="- Register: the one of the source text." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="301.5" width="302.25" height="17.5" as="geometry"/></mxCell> | |
| 434 | + <mxCell id="05-agents-panel-55" value="- French typography: non-breaking spaces" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="323.5" width="310.0" height="17.5" as="geometry"/></mxCell> | |
| 435 | + <mxCell id="05-agents-panel-56" value=" before ; : ! ? and inside « quotes »." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="345.5" width="302.25" height="17.5" as="geometry"/></mxCell> | |
| 436 | + <mxCell id="05-agents-panel-57" value="- Never translate code or proper names." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="367.5" width="302.25" height="17.5" as="geometry"/></mxCell> | |
| 437 | 437 | <mxCell id="05-agents-panel-58" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1010" y="590" width="110" height="32" as="geometry"/></mxCell> |
| 438 | - <mxCell id="05-agents-panel-59" value="Enregistrer" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1023.53" y="598.0" width="82.94" height="18" as="geometry"/></mxCell> | |
| 438 | + <mxCell id="05-agents-panel-59" value="Save" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1049.92" y="598.0" width="30.159999999999997" height="18" as="geometry"/></mxCell> | |
| 439 | 439 | <mxCell id="05-agents-panel-60" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1130" y="590" width="110" height="32" as="geometry"/></mxCell> |
| 440 | - <mxCell id="05-agents-panel-61" value="Supprimer" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1151.07" y="598.0" width="67.86" height="18" as="geometry"/></mxCell> | |
| 440 | + <mxCell id="05-agents-panel-61" value="Delete" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1162.38" y="598.0" width="45.239999999999995" height="18" as="geometry"/></mxCell> | |
| 441 | 441 | <mxCell id="05-agents-panel-62" value="" style="rounded=0;fillColor=#111317;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="646" width="1009" height="188" as="geometry"/></mxCell> |
| 442 | 442 | <mxCell id="05-agents-panel-63" value="garfield $ ls skills" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#D7DAE0;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="659.5" width="155.0" height="17.5" as="geometry"/></mxCell> |
| 443 | 443 | <mxCell id="05-agents-panel-64" value="email-letter idioms styles technical-text" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#D7DAE0;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="679.5" width="341.0" height="17.5" as="geometry"/></mxCell> |
| @@ -449,38 +449,38 @@ | ||
| 449 | 449 | <mxCell id="05-agents-panel-70" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="569" y="186" width="24" height="24" as="geometry"/></mxCell> |
| 450 | 450 | <mxCell id="05-agents-panel-71" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 451 | 451 | <mxCell id="05-agents-panel-72" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 452 | - <mxCell id="05-agents-panel-73" value="État et emplacement de l'agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> | |
| 453 | - <mxCell id="05-agents-panel-74" value="Statut temps réel (#11), runtime (local," style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="278.4" height="17" as="geometry"/></mxCell> | |
| 454 | - <mxCell id="05-agents-panel-75" value="container, sbx), dossier et modèle." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="243.6" height="17" as="geometry"/></mxCell> | |
| 452 | + <mxCell id="05-agents-panel-73" value="The agent's state and location" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> | |
| 453 | + <mxCell id="05-agents-panel-74" value="Live status (#11), runtime (local," style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="236.64" height="17" as="geometry"/></mxCell> | |
| 454 | + <mxCell id="05-agents-panel-75" value="container, sbx), folder and model." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="236.64" height="17" as="geometry"/></mxCell> | |
| 455 | 455 | <mxCell id="05-agents-panel-76" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 456 | 456 | <mxCell id="05-agents-panel-77" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 457 | - <mxCell id="05-agents-panel-78" value="Arbre du workspace" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="140.94" height="18.5" as="geometry"/></mxCell> | |
| 458 | - <mxCell id="05-agents-panel-79" value="Chargement paresseux, rafraîchi quand" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="257.52" height="17" as="geometry"/></mxCell> | |
| 459 | - <mxCell id="05-agents-panel-80" value="l'agent modifie un fichier (#29)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="229.67999999999998" height="17" as="geometry"/></mxCell> | |
| 457 | + <mxCell id="05-agents-panel-78" value="Workspace tree" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> | |
| 458 | + <mxCell id="05-agents-panel-79" value="Loaded lazily, refreshed when the" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="229.67999999999998" height="17" as="geometry"/></mxCell> | |
| 459 | + <mxCell id="05-agents-panel-80" value="agent changes a file (#29)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="187.92" height="17" as="geometry"/></mxCell> | |
| 460 | 460 | <mxCell id="05-agents-panel-81" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="76" as="geometry"/></mxCell> |
| 461 | 461 | <mxCell id="05-agents-panel-82" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 462 | - <mxCell id="05-agents-panel-83" value="Éditer, supprimer avec confirmation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="274.04999999999995" height="18.5" as="geometry"/></mxCell> | |
| 463 | - <mxCell id="05-agents-panel-84" value="Même éditeur que Settings. Conflit signalé" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="292.32" height="17" as="geometry"/></mxCell> | |
| 464 | - <mxCell id="05-agents-panel-85" value="si l'agent modifie le fichier (#30)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="250.55999999999997" height="17" as="geometry"/></mxCell> | |
| 462 | + <mxCell id="05-agents-panel-83" value="Edit, delete with confirmation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> | |
| 463 | + <mxCell id="05-agents-panel-84" value="Same editor as Settings. A conflict is" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 464 | + <mxCell id="05-agents-panel-85" value="flagged if the agent changes the file (#30)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="306.23999999999995" height="17" as="geometry"/></mxCell> | |
| 465 | 465 | <mxCell id="05-agents-panel-86" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="350" width="356" height="76" as="geometry"/></mxCell> |
| 466 | 466 | <mxCell id="05-agents-panel-87" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="360" width="24" height="24" as="geometry"/></mxCell> |
| 467 | - <mxCell id="05-agents-panel-88" value="Terminal sur le workspace" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="195.75" height="18.5" as="geometry"/></mxCell> | |
| 468 | - <mxCell id="05-agents-panel-89" value="PTY local, docker exec ou sbx selon le" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 469 | - <mxCell id="05-agents-panel-90" value="runtime (#28, #31). Replié par défaut." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 467 | + <mxCell id="05-agents-panel-88" value="Terminal in the workspace" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="195.75" height="18.5" as="geometry"/></mxCell> | |
| 468 | + <mxCell id="05-agents-panel-89" value="Local PTY, docker exec or sbx depending on" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="292.32" height="17" as="geometry"/></mxCell> | |
| 469 | + <mxCell id="05-agents-panel-90" value="the runtime (#28, #31). Folded by default." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="292.32" height="17" as="geometry"/></mxCell> | |
| 470 | 470 | <mxCell id="05-agents-panel-91" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="440" width="356" height="76" as="geometry"/></mxCell> |
| 471 | 471 | <mxCell id="05-agents-panel-92" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="450" width="24" height="24" as="geometry"/></mxCell> |
| 472 | - <mxCell id="05-agents-panel-93" value="Journal" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="453.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> | |
| 473 | - <mxCell id="05-agents-panel-94" value="stderr de l'agent, pour comprendre" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="478" width="236.64" height="17" as="geometry"/></mxCell> | |
| 474 | - <mxCell id="05-agents-panel-95" value="une erreur sans ouvrir un terminal." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="243.6" height="17" as="geometry"/></mxCell> | |
| 472 | + <mxCell id="05-agents-panel-93" value="Log" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="453.5" width="23.49" height="18.5" as="geometry"/></mxCell> | |
| 473 | + <mxCell id="05-agents-panel-94" value="The agent's stderr, to understand" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="478" width="229.67999999999998" height="17" as="geometry"/></mxCell> | |
| 474 | + <mxCell id="05-agents-panel-95" value="an error without opening a terminal." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="250.55999999999997" height="17" as="geometry"/></mxCell> | |
| 475 | 475 | </root> |
| 476 | 476 | </mxGraphModel> |
| 477 | 477 | </diagram> |
| 478 | - <diagram id="06-first-launch" name="6 · Premier lancement"> | |
| 478 | + <diagram id="06-first-launch" name="6 · First launch"> | |
| 479 | 479 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 480 | 480 | <root> |
| 481 | 481 | <mxCell id="0"/> |
| 482 | 482 | <mxCell id="1" parent="0"/> |
| 483 | - <mxCell id="06-first-launch-title" value="<b>6 · Premier lancement</b><br><i>Moins d'une minute pour savoir quoi faire, sans lire de documentation</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 483 | + <mxCell id="06-first-launch-title" value="<b>6 · First launch</b><br><i>Less than a minute to know what to do, without reading any documentation</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | |
| 484 | 484 | <mxCell id="06-first-launch-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 485 | 485 | <mxCell id="06-first-launch-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 486 | 486 | <mxCell id="06-first-launch-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -489,57 +489,57 @@ | ||
| 489 | 489 | <mxCell id="06-first-launch-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 490 | 490 | <mxCell id="06-first-launch-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 491 | 491 | <mxCell id="06-first-launch-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 492 | - <mxCell id="06-first-launch-9" value="○ aucun agent configuré · config : créée à l'emplacement par défaut" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="446.89" height="16.5" as="geometry"/></mxCell> | |
| 492 | + <mxCell id="06-first-launch-9" value="○ no agent configured · config: created at the default location" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="420.21" height="16.5" as="geometry"/></mxCell> | |
| 493 | 493 | <mxCell id="06-first-launch-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 494 | - <mxCell id="06-first-launch-11" value="👋 Bienvenue dans Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=26;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="443.96000000000004" y="174" width="392.08" height="31" as="geometry"/></mxCell> | |
| 495 | - <mxCell id="06-first-launch-12" value="Discutez avec des agents d'IA dans des channels, comme avec des collègues." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="318.1" y="219" width="643.8" height="20" as="geometry"/></mxCell> | |
| 494 | + <mxCell id="06-first-launch-11" value="👋 Welcome to Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=26;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="474.12" y="174" width="331.76" height="31" as="geometry"/></mxCell> | |
| 495 | + <mxCell id="06-first-launch-12" value="Talk with AI agents in channels, as you would with colleagues." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="370.3" y="219" width="539.4" height="20" as="geometry"/></mxCell> | |
| 496 | 496 | <mxCell id="06-first-launch-13" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="280" width="800" height="76" as="geometry"/></mxCell> |
| 497 | 497 | <mxCell id="06-first-launch-14" value="<b>1</b>" style="ellipse;html=1;fillColor=#3B6FE0;strokeColor=none;fontColor=#FFFFFF;fontSize=16;" vertex="1" parent="1"><mxGeometry x="262" y="300" width="36" height="36" as="geometry"/></mxCell> |
| 498 | 498 | <mxCell id="06-first-launch-15" value="1" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="270.0" y="308" width="20" height="21" as="geometry"/></mxCell> |
| 499 | - <mxCell id="06-first-launch-16" value="Ajoutez un agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="296" width="148.48" height="21" as="geometry"/></mxCell> | |
| 500 | - <mxCell id="06-first-launch-17" value="Un assistant qui tourne sur votre ordinateur, par exemple avec mm." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="322.5" width="516.78" height="18.5" as="geometry"/></mxCell> | |
| 499 | + <mxCell id="06-first-launch-16" value="Add an agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="296" width="111.35999999999999" height="21" as="geometry"/></mxCell> | |
| 500 | + <mxCell id="06-first-launch-17" value="An assistant that runs on your computer, for example with mm." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="322.5" width="477.63" height="18.5" as="geometry"/></mxCell> | |
| 501 | 501 | <mxCell id="06-first-launch-18" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="372" width="800" height="76" as="geometry"/></mxCell> |
| 502 | 502 | <mxCell id="06-first-launch-19" value="<b>2</b>" style="ellipse;html=1;fillColor=#3B6FE0;strokeColor=none;fontColor=#FFFFFF;fontSize=16;" vertex="1" parent="1"><mxGeometry x="262" y="392" width="36" height="36" as="geometry"/></mxCell> |
| 503 | 503 | <mxCell id="06-first-launch-20" value="2" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="270.0" y="400" width="20" height="21" as="geometry"/></mxCell> |
| 504 | - <mxCell id="06-first-launch-21" value="Ouvrez un channel" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="388" width="157.76" height="21" as="geometry"/></mxCell> | |
| 505 | - <mxCell id="06-first-launch-22" value="#général est déjà prêt. Créez-en d'autres par sujet." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="414.5" width="407.15999999999997" height="18.5" as="geometry"/></mxCell> | |
| 504 | + <mxCell id="06-first-launch-21" value="Open a channel" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="388" width="129.92" height="21" as="geometry"/></mxCell> | |
| 505 | + <mxCell id="06-first-launch-22" value="#general is ready. Create others, one per topic." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="414.5" width="375.84" height="18.5" as="geometry"/></mxCell> | |
| 506 | 506 | <mxCell id="06-first-launch-23" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="464" width="800" height="76" as="geometry"/></mxCell> |
| 507 | 507 | <mxCell id="06-first-launch-24" value="<b>3</b>" style="ellipse;html=1;fillColor=#3B6FE0;strokeColor=none;fontColor=#FFFFFF;fontSize=16;" vertex="1" parent="1"><mxGeometry x="262" y="484" width="36" height="36" as="geometry"/></mxCell> |
| 508 | 508 | <mxCell id="06-first-launch-25" value="3" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="270.0" y="492" width="20" height="21" as="geometry"/></mxCell> |
| 509 | - <mxCell id="06-first-launch-26" value="Appelez-le avec @" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="480" width="157.76" height="21" as="geometry"/></mxCell> | |
| 510 | - <mxCell id="06-first-launch-27" value="« @alice bonjour » : Alice rejoint le channel et vous répond." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="506.5" width="477.63" height="18.5" as="geometry"/></mxCell> | |
| 509 | + <mxCell id="06-first-launch-26" value="Call it with @" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="480" width="129.92" height="21" as="geometry"/></mxCell> | |
| 510 | + <mxCell id="06-first-launch-27" value=""@alice hello": Alice joins the channel and answers you." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="506.5" width="438.47999999999996" height="18.5" as="geometry"/></mxCell> | |
| 511 | 511 | <mxCell id="06-first-launch-28" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="420" y="570" width="240" height="40" as="geometry"/></mxCell> |
| 512 | - <mxCell id="06-first-launch-29" value="+ Ajouter mon premier agent" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="438.21000000000004" y="582.0" width="203.57999999999998" height="18" as="geometry"/></mxCell> | |
| 512 | + <mxCell id="06-first-launch-29" value="+ Add my first agent" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="464.6" y="582.0" width="150.79999999999998" height="18" as="geometry"/></mxCell> | |
| 513 | 513 | <mxCell id="06-first-launch-30" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="680" y="570" width="200" height="40" as="geometry"/></mxCell> |
| 514 | - <mxCell id="06-first-launch-31" value="Ouvrir une configuration…" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="685.75" y="582.0" width="188.5" height="18" as="geometry"/></mxCell> | |
| 515 | - <mxCell id="06-first-launch-32" value="Configuration : ~/Library/Application Support/sidekicks/config.yaml (créée pour vous, commentée)" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="305.92" y="638" width="668.16" height="17" as="geometry"/></mxCell> | |
| 514 | + <mxCell id="06-first-launch-31" value="Open a configuration…" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="700.83" y="582.0" width="158.33999999999997" height="18" as="geometry"/></mxCell> | |
| 515 | + <mxCell id="06-first-launch-32" value="Configuration: ~/Library/Application Support/sidekicks/config.yaml (created for you, with comments)" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295.48" y="638" width="689.04" height="17" as="geometry"/></mxCell> | |
| 516 | 516 | <mxCell id="06-first-launch-33" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="680" width="800" height="70" as="geometry"/></mxCell> |
| 517 | - <mxCell id="06-first-launch-34" value="La commande « mm » est introuvable." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#D64561;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="260" y="694" width="284.2" height="19" as="geometry"/></mxCell> | |
| 518 | - <mxCell id="06-first-launch-35" value="Installez-la (lien vers le guide) ou choisissez un autre programme pour cet agent." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="260" y="719" width="618.28" height="18" as="geometry"/></mxCell> | |
| 517 | + <mxCell id="06-first-launch-34" value="The command "mm" cannot be found." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#D64561;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="260" y="694" width="267.96" height="19" as="geometry"/></mxCell> | |
| 518 | + <mxCell id="06-first-launch-35" value="Install it (link to the guide) or choose another program for this agent." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="260" y="719" width="542.88" height="18" as="geometry"/></mxCell> | |
| 519 | 519 | <mxCell id="06-first-launch-36" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1040" y="300" width="24" height="24" as="geometry"/></mxCell> |
| 520 | 520 | <mxCell id="06-first-launch-37" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="880" y="578" width="24" height="24" as="geometry"/></mxCell> |
| 521 | 521 | <mxCell id="06-first-launch-38" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1018.0" y="634" width="24" height="24" as="geometry"/></mxCell> |
| 522 | 522 | <mxCell id="06-first-launch-39" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1040" y="688" width="24" height="24" as="geometry"/></mxCell> |
| 523 | 523 | <mxCell id="06-first-launch-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 524 | 524 | <mxCell id="06-first-launch-41" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 525 | - <mxCell id="06-first-launch-42" value="Trois étapes, pas plus" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="172.26" height="18.5" as="geometry"/></mxCell> | |
| 526 | - <mxCell id="06-first-launch-43" value="L'état vide explique le modèle mental :" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="271.44" height="17" as="geometry"/></mxCell> | |
| 525 | + <mxCell id="06-first-launch-42" value="Three steps, no more" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="156.6" height="18.5" as="geometry"/></mxCell> | |
| 526 | + <mxCell id="06-first-launch-43" value="The empty state explains the mental model:" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="292.32" height="17" as="geometry"/></mxCell> | |
| 527 | 527 | <mxCell id="06-first-launch-44" value="agents, channels, @ (#33)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="180.95999999999998" height="17" as="geometry"/></mxCell> |
| 528 | 528 | <mxCell id="06-first-launch-45" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 529 | 529 | <mxCell id="06-first-launch-46" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 530 | - <mxCell id="06-first-launch-47" value="Un assistant plutôt que du YAML" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="242.73" height="18.5" as="geometry"/></mxCell> | |
| 531 | - <mxCell id="06-first-launch-48" value="Le formulaire écrit le YAML à la place de" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="285.35999999999996" height="17" as="geometry"/></mxCell> | |
| 532 | - <mxCell id="06-first-launch-49" value="l'utilisateur ; Settings reste accessible." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="292.32" height="17" as="geometry"/></mxCell> | |
| 530 | + <mxCell id="06-first-launch-47" value="An assistant rather than YAML" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="227.07" height="18.5" as="geometry"/></mxCell> | |
| 531 | + <mxCell id="06-first-launch-48" value="The form writes the YAML for the user;" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="264.47999999999996" height="17" as="geometry"/></mxCell> | |
| 532 | + <mxCell id="06-first-launch-49" value="Settings stays at hand." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="160.07999999999998" height="17" as="geometry"/></mxCell> | |
| 533 | 533 | <mxCell id="06-first-launch-50" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="76" as="geometry"/></mxCell> |
| 534 | 534 | <mxCell id="06-first-launch-51" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 535 | - <mxCell id="06-first-launch-52" value="Rien à créer à la main" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="172.26" height="18.5" as="geometry"/></mxCell> | |
| 536 | - <mxCell id="06-first-launch-53" value="Le fichier par défaut existe déjà, avec des" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="299.28" height="17" as="geometry"/></mxCell> | |
| 537 | - <mxCell id="06-first-launch-54" value="commentaires (#9)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="125.27999999999999" height="17" as="geometry"/></mxCell> | |
| 535 | + <mxCell id="06-first-launch-52" value="Nothing to create by hand" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="195.75" height="18.5" as="geometry"/></mxCell> | |
| 536 | + <mxCell id="06-first-launch-53" value="The default file already exists, with" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="257.52" height="17" as="geometry"/></mxCell> | |
| 537 | + <mxCell id="06-first-launch-54" value="comments (#9)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="97.44" height="17" as="geometry"/></mxCell> | |
| 538 | 538 | <mxCell id="06-first-launch-55" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="350" width="356" height="76" as="geometry"/></mxCell> |
| 539 | 539 | <mxCell id="06-first-launch-56" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="360" width="24" height="24" as="geometry"/></mxCell> |
| 540 | - <mxCell id="06-first-launch-57" value="Erreurs humaines" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="125.27999999999999" height="18.5" as="geometry"/></mxCell> | |
| 541 | - <mxCell id="06-first-launch-58" value="Dire ce qui ne va pas et quoi faire ;" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="257.52" height="17" as="geometry"/></mxCell> | |
| 542 | - <mxCell id="06-first-launch-59" value="jamais de trace technique (#33)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="222.71999999999997" height="17" as="geometry"/></mxCell> | |
| 540 | + <mxCell id="06-first-launch-57" value="Human errors" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="93.96" height="18.5" as="geometry"/></mxCell> | |
| 541 | + <mxCell id="06-first-launch-58" value="Say what is wrong and what to do;" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="229.67999999999998" height="17" as="geometry"/></mxCell> | |
| 542 | + <mxCell id="06-first-launch-59" value="never a technical trace (#33)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="208.79999999999998" height="17" as="geometry"/></mxCell> | |
| 543 | 543 | </root> |
| 544 | 544 | </mxGraphModel> |
| 545 | 545 | </diagram> |
| @@ -1,10 +1,10 @@ | |||
| 1 | <mxfile host="app.diagrams.net"> | 1 | <mxfile host="app.diagrams.net"> |
| 2 | - <diagram id="01-layout" name="1 · Layout global"> | 2 | + <diagram id="01-layout" name="1 · Overall layout"> |
| 3 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> | 3 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 4 | <root> | 4 | <root> |
| 5 | <mxCell id="0"/> | 5 | <mxCell id="0"/> |
| 6 | <mxCell id="1" parent="0"/> | 6 | <mxCell id="1" parent="0"/> |
| 7 | - <mxCell id="01-layout-title" value="<b>1 · Layout global</b><br><i>Docks façon Zed, mais seul l'essentiel est visible par défaut</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | 7 | + <mxCell id="01-layout-title" value="<b>1 · Overall layout</b><br><i>Zed-like docks, but only the essentials are visible by default</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> |
| 8 | <mxCell id="01-layout-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> | 8 | <mxCell id="01-layout-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 9 | <mxCell id="01-layout-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> | 9 | <mxCell id="01-layout-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 10 | <mxCell id="01-layout-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> | 10 | <mxCell id="01-layout-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -13,14 +13,14 @@ | |||
| 13 | <mxCell id="01-layout-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> | 13 | <mxCell id="01-layout-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 14 | <mxCell id="01-layout-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> | 14 | <mxCell id="01-layout-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 15 | <mxCell id="01-layout-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> | 15 | <mxCell id="01-layout-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 16 | - <mxCell id="01-layout-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | 16 | + <mxCell id="01-layout-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> |
| 17 | <mxCell id="01-layout-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> | 17 | <mxCell id="01-layout-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 18 | <mxCell id="01-layout-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> | 18 | <mxCell id="01-layout-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 19 | <mxCell id="01-layout-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> | 19 | <mxCell id="01-layout-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 20 | <mxCell id="01-layout-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> | 20 | <mxCell id="01-layout-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 21 | <mxCell id="01-layout-14" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="158" width="214" height="26" as="geometry"/></mxCell> | 21 | <mxCell id="01-layout-14" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="158" width="214" height="26" as="geometry"/></mxCell> |
| 22 | - <mxCell id="01-layout-15" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | 22 | + <mxCell id="01-layout-15" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 23 | - <mxCell id="01-layout-16" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | 23 | + <mxCell id="01-layout-16" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> |
| 24 | <mxCell id="01-layout-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> | 24 | <mxCell id="01-layout-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 25 | <mxCell id="01-layout-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> | 25 | <mxCell id="01-layout-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| 26 | <mxCell id="01-layout-19" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> | 26 | <mxCell id="01-layout-19" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> |
| @@ -32,18 +32,18 @@ | |||
| 32 | <mxCell id="01-layout-25" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> | 32 | <mxCell id="01-layout-25" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> |
| 33 | <mxCell id="01-layout-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> | 33 | <mxCell id="01-layout-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 34 | <mxCell id="01-layout-27" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="709" height="44" as="geometry"/></mxCell> | 34 | <mxCell id="01-layout-27" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="709" height="44" as="geometry"/></mxCell> |
| 35 | - <mxCell id="01-layout-28" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="78.3" height="20" as="geometry"/></mxCell> | 35 | + <mxCell id="01-layout-28" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="78.3" height="20" as="geometry"/></mxCell> |
| 36 | <mxCell id="01-layout-29" value="👩 Alice · 🧔 Bob" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="830.9" y="131" width="113.1" height="18" as="geometry"/></mxCell> | 36 | <mxCell id="01-layout-29" value="👩 Alice · 🧔 Bob" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="830.9" y="131" width="113.1" height="18" as="geometry"/></mxCell> |
| 37 | - <mxCell id="01-layout-30" value="Vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="182.5" width="31.319999999999997" height="18.5" as="geometry"/></mxCell> | 37 | + <mxCell id="01-layout-30" value="You" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="182.5" width="23.49" height="18.5" as="geometry"/></mxCell> |
| 38 | - <mxCell id="01-layout-31" value="@alice résume-moi ce que fait ACP en deux phrases" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="204.5" width="383.66999999999996" height="18.5" as="geometry"/></mxCell> | 38 | + <mxCell id="01-layout-31" value="@alice sum up what ACP does in two sentences" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="204.5" width="344.52" height="18.5" as="geometry"/></mxCell> |
| 39 | <mxCell id="01-layout-32" value="👩 Alice" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#C2185B;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="238.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> | 39 | <mxCell id="01-layout-32" value="👩 Alice" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#C2185B;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="238.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> |
| 40 | - <mxCell id="01-layout-33" value="ACP est un protocole qui permet à une application de dialoguer avec" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="260.5" width="524.61" height="18.5" as="geometry"/></mxCell> | 40 | + <mxCell id="01-layout-33" value="ACP is a protocol that lets an application talk with any AI agent." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="260.5" width="516.78" height="18.5" as="geometry"/></mxCell> |
| 41 | - <mxCell id="01-layout-34" value="n'importe quel agent d'IA. Sidekicks l'utilise pour rester agnostique." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="280.0" width="548.0999999999999" height="18.5" as="geometry"/></mxCell> | 41 | + <mxCell id="01-layout-34" value="Sidekicks uses it to stay agent-agnostic." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="280.0" width="321.03" height="18.5" as="geometry"/></mxCell> |
| 42 | <mxCell id="01-layout-35" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="724" width="669" height="64" as="geometry"/></mxCell> | 42 | <mxCell id="01-layout-35" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="724" width="669" height="64" as="geometry"/></mxCell> |
| 43 | - <mxCell id="01-layout-36" value="Écrivez un message… (@ pour un agent, / pour une commande)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="736" width="479.08" height="19" as="geometry"/></mxCell> | 43 | + <mxCell id="01-layout-36" value="Write a message… (@ for an agent, / for a command)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="736" width="414.11999999999995" height="19" as="geometry"/></mxCell> |
| 44 | - <mxCell id="01-layout-37" value="Entrée pour envoyer · Maj+Entrée nouvelle ligne" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="763" width="299.85999999999996" height="16" as="geometry"/></mxCell> | 44 | + <mxCell id="01-layout-37" value="Enter to send · Shift+Enter for a new line" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="763" width="267.96" height="16" as="geometry"/></mxCell> |
| 45 | <mxCell id="01-layout-38" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="960" y="116" width="300" height="718" as="geometry"/></mxCell> | 45 | <mxCell id="01-layout-38" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="960" y="116" width="300" height="718" as="geometry"/></mxCell> |
| 46 | - <mxCell id="01-layout-39" value="⚙︎ Settings — equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="976" y="131" width="188.5" height="18" as="geometry"/></mxCell> | 46 | + <mxCell id="01-layout-39" value="⚙︎ Settings — team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="976" y="131" width="173.42" height="18" as="geometry"/></mxCell> |
| 47 | <mxCell id="01-layout-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F4F5F7;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="970" y="160" width="280" height="300" as="geometry"/></mxCell> | 47 | <mxCell id="01-layout-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F4F5F7;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="970" y="160" width="280" height="300" as="geometry"/></mxCell> |
| 48 | <mxCell id="01-layout-41" value="version: 1" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="172" width="74.4" height="17" as="geometry"/></mxCell> | 48 | <mxCell id="01-layout-41" value="version: 1" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="172" width="74.4" height="17" as="geometry"/></mxCell> |
| 49 | <mxCell id="01-layout-42" value="agents:" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="191" width="52.08" height="17" as="geometry"/></mxCell> | 49 | <mxCell id="01-layout-42" value="agents:" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="191" width="52.08" height="17" as="geometry"/></mxCell> |
| @@ -52,13 +52,13 @@ | |||
| 52 | <mxCell id="01-layout-45" value=" command: mm" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="248" width="111.6" height="17" as="geometry"/></mxCell> | 52 | <mxCell id="01-layout-45" value=" command: mm" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="248" width="111.6" height="17" as="geometry"/></mxCell> |
| 53 | <mxCell id="01-layout-46" value=" args: [-acp, ...]" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="267" width="156.24" height="17" as="geometry"/></mxCell> | 53 | <mxCell id="01-layout-46" value=" args: [-acp, ...]" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="267" width="156.24" height="17" as="geometry"/></mxCell> |
| 54 | <mxCell id="01-layout-47" value="channels:" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="286" width="66.96" height="17" as="geometry"/></mxCell> | 54 | <mxCell id="01-layout-47" value="channels:" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="286" width="66.96" height="17" as="geometry"/></mxCell> |
| 55 | - <mxCell id="01-layout-48" value=" - name: général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="305" width="126.48" height="17" as="geometry"/></mxCell> | 55 | + <mxCell id="01-layout-48" value=" - name: general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="305" width="126.48" height="17" as="geometry"/></mxCell> |
| 56 | <mxCell id="01-layout-49" value=" agents: [alice, bob]" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="324" width="178.56" height="17" as="geometry"/></mxCell> | 56 | <mxCell id="01-layout-49" value=" agents: [alice, bob]" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="980" y="324" width="178.56" height="17" as="geometry"/></mxCell> |
| 57 | - <mxCell id="01-layout-50" value="✓ Configuration valide" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#3E9B4F;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="976" y="477.5" width="159.5" height="17.5" as="geometry"/></mxCell> | 57 | + <mxCell id="01-layout-50" value="✓ Valid configuration" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#3E9B4F;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="976" y="477.5" width="152.25" height="17.5" as="geometry"/></mxCell> |
| 58 | <mxCell id="01-layout-51" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="970" y="508" width="120" height="32" as="geometry"/></mxCell> | 58 | <mxCell id="01-layout-51" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="970" y="508" width="120" height="32" as="geometry"/></mxCell> |
| 59 | - <mxCell id="01-layout-52" value="Enregistrer" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="988.53" y="516.0" width="82.94" height="18" as="geometry"/></mxCell> | 59 | + <mxCell id="01-layout-52" value="Save" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1014.92" y="516.0" width="30.159999999999997" height="18" as="geometry"/></mxCell> |
| 60 | <mxCell id="01-layout-53" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="804" width="709" height="30" as="geometry"/></mxCell> | 60 | <mxCell id="01-layout-53" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="804" width="709" height="30" as="geometry"/></mxCell> |
| 61 | - <mxCell id="01-layout-54" value="▸ Terminal · Fichiers (repliés)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="265" y="812" width="229.67999999999998" height="17" as="geometry"/></mxCell> | 61 | + <mxCell id="01-layout-54" value="▸ Terminal · Files (folded)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="265" y="812" width="201.83999999999997" height="17" as="geometry"/></mxCell> |
| 62 | <mxCell id="01-layout-55" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="208" y="130" width="24" height="24" as="geometry"/></mxCell> | 62 | <mxCell id="01-layout-55" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="208" y="130" width="24" height="24" as="geometry"/></mxCell> |
| 63 | <mxCell id="01-layout-56" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="359" y="228" width="24" height="24" as="geometry"/></mxCell> | 63 | <mxCell id="01-layout-56" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="359" y="228" width="24" height="24" as="geometry"/></mxCell> |
| 64 | <mxCell id="01-layout-57" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1218" y="128" width="24" height="24" as="geometry"/></mxCell> | 64 | <mxCell id="01-layout-57" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1218" y="128" width="24" height="24" as="geometry"/></mxCell> |
| @@ -66,39 +66,39 @@ | |||
| 66 | <mxCell id="01-layout-59" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="428" y="835" width="24" height="24" as="geometry"/></mxCell> | 66 | <mxCell id="01-layout-59" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="428" y="835" width="24" height="24" as="geometry"/></mxCell> |
| 67 | <mxCell id="01-layout-60" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> | 67 | <mxCell id="01-layout-60" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 68 | <mxCell id="01-layout-61" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> | 68 | <mxCell id="01-layout-61" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 69 | - <mxCell id="01-layout-62" value="Dock gauche : channels et agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="250.55999999999997" height="18.5" as="geometry"/></mxCell> | 69 | + <mxCell id="01-layout-62" value="Left dock: channels and agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> |
| 70 | - <mxCell id="01-layout-63" value="Toujours visible. La pastille donne l'état de" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="313.2" height="17" as="geometry"/></mxCell> | 70 | + <mxCell id="01-layout-63" value="Always visible. The dot gives the agent's" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="285.35999999999996" height="17" as="geometry"/></mxCell> |
| 71 | - <mxCell id="01-layout-64" value="l'agent : vert prêt, orange occupé, gris arrêté." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="334.08" height="17" as="geometry"/></mxCell> | 71 | + <mxCell id="01-layout-64" value="state: green ready, orange busy, grey stopped." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="320.15999999999997" height="17" as="geometry"/></mxCell> |
| 72 | <mxCell id="01-layout-65" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> | 72 | <mxCell id="01-layout-65" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 73 | <mxCell id="01-layout-66" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> | 73 | <mxCell id="01-layout-66" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 74 | - <mxCell id="01-layout-67" value="Centre : la conversation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="187.92" height="18.5" as="geometry"/></mxCell> | 74 | + <mxCell id="01-layout-67" value="Centre: the conversation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="187.92" height="18.5" as="geometry"/></mxCell> |
| 75 | - <mxCell id="01-layout-68" value="Le seul panel indispensable. Pleine largeur" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="299.28" height="17" as="geometry"/></mxCell> | 75 | + <mxCell id="01-layout-68" value="The only panel you cannot do without." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="257.52" height="17" as="geometry"/></mxCell> |
| 76 | - <mxCell id="01-layout-69" value="quand les docks sont repliés." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="201.83999999999997" height="17" as="geometry"/></mxCell> | 76 | + <mxCell id="01-layout-69" value="Full width when the docks are folded." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="257.52" height="17" as="geometry"/></mxCell> |
| 77 | <mxCell id="01-layout-70" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="94" as="geometry"/></mxCell> | 77 | <mxCell id="01-layout-70" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="94" as="geometry"/></mxCell> |
| 78 | <mxCell id="01-layout-71" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> | 78 | <mxCell id="01-layout-71" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 79 | - <mxCell id="01-layout-72" value="Dock droit : Settings" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="164.42999999999998" height="18.5" as="geometry"/></mxCell> | 79 | + <mxCell id="01-layout-72" value="Right dock: Settings" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="156.6" height="18.5" as="geometry"/></mxCell> |
| 80 | - <mxCell id="01-layout-73" value="Éditeur YAML (CodeMirror) avec validation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="285.35999999999996" height="17" as="geometry"/></mxCell> | 80 | + <mxCell id="01-layout-73" value="YAML editor (CodeMirror) with live" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="236.64" height="17" as="geometry"/></mxCell> |
| 81 | - <mxCell id="01-layout-74" value="en direct. Fermé par défaut ; s'ouvre" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="257.52" height="17" as="geometry"/></mxCell> | 81 | + <mxCell id="01-layout-74" value="validation. Closed by default; opens" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="250.55999999999997" height="17" as="geometry"/></mxCell> |
| 82 | - <mxCell id="01-layout-75" value="par ⚙︎ ou ⌘,." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="90.47999999999999" height="17" as="geometry"/></mxCell> | 82 | + <mxCell id="01-layout-75" value="with ⚙︎ or ⌘,." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="97.44" height="17" as="geometry"/></mxCell> |
| 83 | <mxCell id="01-layout-76" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="368" width="356" height="76" as="geometry"/></mxCell> | 83 | <mxCell id="01-layout-76" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="368" width="356" height="76" as="geometry"/></mxCell> |
| 84 | <mxCell id="01-layout-77" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="378" width="24" height="24" as="geometry"/></mxCell> | 84 | <mxCell id="01-layout-77" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="378" width="24" height="24" as="geometry"/></mxCell> |
| 85 | - <mxCell id="01-layout-78" value="Dock bas : terminal et fichiers" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="381.5" width="242.73" height="18.5" as="geometry"/></mxCell> | 85 | + <mxCell id="01-layout-78" value="Bottom dock: terminal and files" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="381.5" width="242.73" height="18.5" as="geometry"/></mxCell> |
| 86 | - <mxCell id="01-layout-79" value="Replié par défaut : utile aux curieux," style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 86 | + <mxCell id="01-layout-79" value="Folded by default: there for the curious," style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="285.35999999999996" height="17" as="geometry"/></mxCell> |
| 87 | - <mxCell id="01-layout-80" value="jamais imposé au citizen user." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="208.79999999999998" height="17" as="geometry"/></mxCell> | 87 | + <mxCell id="01-layout-80" value="never forced on the citizen user." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="229.67999999999998" height="17" as="geometry"/></mxCell> |
| 88 | <mxCell id="01-layout-81" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="458" width="356" height="76" as="geometry"/></mxCell> | 88 | <mxCell id="01-layout-81" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="458" width="356" height="76" as="geometry"/></mxCell> |
| 89 | <mxCell id="01-layout-82" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="468" width="24" height="24" as="geometry"/></mxCell> | 89 | <mxCell id="01-layout-82" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="468" width="24" height="24" as="geometry"/></mxCell> |
| 90 | - <mxCell id="01-layout-83" value="Barre d'état" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="471.5" width="93.96" height="18.5" as="geometry"/></mxCell> | 90 | + <mxCell id="01-layout-83" value="Status bar" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="471.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 91 | - <mxCell id="01-layout-84" value="Rappelle la limite d'agents simultanés" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 91 | + <mxCell id="01-layout-84" value="Shows the limit of agents running at once" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="285.35999999999996" height="17" as="geometry"/></mxCell> |
| 92 | - <mxCell id="01-layout-85" value="(mémoire) et la configuration ouverte." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 92 | + <mxCell id="01-layout-85" value="(memory) and the open configuration." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="250.55999999999997" height="17" as="geometry"/></mxCell> |
| 93 | </root> | 93 | </root> |
| 94 | </mxGraphModel> | 94 | </mxGraphModel> |
| 95 | </diagram> | 95 | </diagram> |
| 96 | - <diagram id="02-conversation" name="2 · Conversation multi-agents"> | 96 | + <diagram id="02-conversation" name="2 · Multi-agent conversation"> |
| 97 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> | 97 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 98 | <root> | 98 | <root> |
| 99 | <mxCell id="0"/> | 99 | <mxCell id="0"/> |
| 100 | <mxCell id="1" parent="0"/> | 100 | <mxCell id="1" parent="0"/> |
| 101 | - <mxCell id="02-conversation-title" value="<b>2 · Conversation multi-agents</b><br><i>Chaque agent a sa couleur ; les outils sont repliés ; on peut toujours arrêter</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | 101 | + <mxCell id="02-conversation-title" value="<b>2 · Multi-agent conversation</b><br><i>Each agent has its colour; tools are folded; you can always stop</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> |
| 102 | <mxCell id="02-conversation-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> | 102 | <mxCell id="02-conversation-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 103 | <mxCell id="02-conversation-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> | 103 | <mxCell id="02-conversation-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 104 | <mxCell id="02-conversation-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> | 104 | <mxCell id="02-conversation-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -107,14 +107,14 @@ | |||
| 107 | <mxCell id="02-conversation-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> | 107 | <mxCell id="02-conversation-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 108 | <mxCell id="02-conversation-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> | 108 | <mxCell id="02-conversation-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 109 | <mxCell id="02-conversation-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> | 109 | <mxCell id="02-conversation-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 110 | - <mxCell id="02-conversation-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | 110 | + <mxCell id="02-conversation-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> |
| 111 | <mxCell id="02-conversation-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> | 111 | <mxCell id="02-conversation-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 112 | <mxCell id="02-conversation-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> | 112 | <mxCell id="02-conversation-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 113 | <mxCell id="02-conversation-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> | 113 | <mxCell id="02-conversation-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 114 | <mxCell id="02-conversation-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> | 114 | <mxCell id="02-conversation-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 115 | <mxCell id="02-conversation-14" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="158" width="214" height="26" as="geometry"/></mxCell> | 115 | <mxCell id="02-conversation-14" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="158" width="214" height="26" as="geometry"/></mxCell> |
| 116 | - <mxCell id="02-conversation-15" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | 116 | + <mxCell id="02-conversation-15" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 117 | - <mxCell id="02-conversation-16" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | 117 | + <mxCell id="02-conversation-16" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> |
| 118 | <mxCell id="02-conversation-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> | 118 | <mxCell id="02-conversation-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 119 | <mxCell id="02-conversation-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> | 119 | <mxCell id="02-conversation-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| 120 | <mxCell id="02-conversation-19" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> | 120 | <mxCell id="02-conversation-19" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> |
| @@ -126,31 +126,31 @@ | |||
| 126 | <mxCell id="02-conversation-25" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> | 126 | <mxCell id="02-conversation-25" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> |
| 127 | <mxCell id="02-conversation-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> | 127 | <mxCell id="02-conversation-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 128 | <mxCell id="02-conversation-27" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="1009" height="44" as="geometry"/></mxCell> | 128 | <mxCell id="02-conversation-27" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="1009" height="44" as="geometry"/></mxCell> |
| 129 | - <mxCell id="02-conversation-28" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="78.3" height="20" as="geometry"/></mxCell> | 129 | + <mxCell id="02-conversation-28" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="78.3" height="20" as="geometry"/></mxCell> |
| 130 | <mxCell id="02-conversation-29" value="👩 Alice · 🧔 Bob · 🧑🚀 Riker" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1040.42" y="131" width="203.57999999999998" height="18" as="geometry"/></mxCell> | 130 | <mxCell id="02-conversation-29" value="👩 Alice · 🧔 Bob · 🧑🚀 Riker" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1040.42" y="131" width="203.57999999999998" height="18" as="geometry"/></mxCell> |
| 131 | - <mxCell id="02-conversation-30" value="— Riker a rejoint le channel —" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#6B6F7A;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="275" y="183.5" width="217.49999999999997" height="17.5" as="geometry"/></mxCell> | 131 | + <mxCell id="02-conversation-30" value="— Riker joined the channel —" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#6B6F7A;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="275" y="183.5" width="203.0" height="17.5" as="geometry"/></mxCell> |
| 132 | - <mxCell id="02-conversation-31" value="Vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="214.5" width="31.319999999999997" height="18.5" as="geometry"/></mxCell> | 132 | + <mxCell id="02-conversation-31" value="You" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="214.5" width="23.49" height="18.5" as="geometry"/></mxCell> |
| 133 | - <mxCell id="02-conversation-32" value="@alice propose un nom pour un script qui sauvegarde mes photos" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="236.5" width="485.46" height="18.5" as="geometry"/></mxCell> | 133 | + <mxCell id="02-conversation-32" value="@alice suggest a name for a script that backs up my photos" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="236.5" width="454.14" height="18.5" as="geometry"/></mxCell> |
| 134 | <mxCell id="02-conversation-33" value="👩 Alice" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#C2185B;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="270.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> | 134 | <mxCell id="02-conversation-33" value="👩 Alice" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#C2185B;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="270.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> |
| 135 | - <mxCell id="02-conversation-34" value="Je propose « photo-backup.sh » : court, explicite, et l'extension dit que" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="292.5" width="571.5899999999999" height="18.5" as="geometry"/></mxCell> | 135 | + <mxCell id="02-conversation-34" value="I suggest "photo-backup.sh": short, clear, and the extension says" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="292.5" width="508.95" height="18.5" as="geometry"/></mxCell> |
| 136 | - <mxCell id="02-conversation-35" value="c'est un script shell." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="312.0" width="172.26" height="18.5" as="geometry"/></mxCell> | 136 | + <mxCell id="02-conversation-35" value="it is a shell script." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="312.0" width="164.42999999999998" height="18.5" as="geometry"/></mxCell> |
| 137 | - <mxCell id="02-conversation-36" value="Vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="346.5" width="31.319999999999997" height="18.5" as="geometry"/></mxCell> | 137 | + <mxCell id="02-conversation-36" value="You" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="346.5" width="23.49" height="18.5" as="geometry"/></mxCell> |
| 138 | - <mxCell id="02-conversation-37" value="@bob tu valides ? @riker crée le fichier vide" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="368.5" width="352.34999999999997" height="18.5" as="geometry"/></mxCell> | 138 | + <mxCell id="02-conversation-37" value="@bob do you agree? @riker create the empty file" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="368.5" width="368.01" height="18.5" as="geometry"/></mxCell> |
| 139 | <mxCell id="02-conversation-38" value="🧔 Bob" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#00838F;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="402.5" width="39.15" height="18.5" as="geometry"/></mxCell> | 139 | <mxCell id="02-conversation-38" value="🧔 Bob" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#00838F;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="402.5" width="39.15" height="18.5" as="geometry"/></mxCell> |
| 140 | - <mxCell id="02-conversation-39" value="Bon choix. Alice a raison : un nom en minuscules, sans espace." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="424.5" width="485.46" height="18.5" as="geometry"/></mxCell> | 140 | + <mxCell id="02-conversation-39" value="Good choice. Alice is right: a lowercase name, no spaces." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="424.5" width="446.30999999999995" height="18.5" as="geometry"/></mxCell> |
| 141 | <mxCell id="02-conversation-40" value="🧑🚀 Riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#5E35B1;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="458.5" width="70.47" height="18.5" as="geometry"/></mxCell> | 141 | <mxCell id="02-conversation-40" value="🧑🚀 Riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#5E35B1;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="458.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 142 | - <mxCell id="02-conversation-41" value="travaille…" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#6B6F7A;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="365" y="459.5" width="72.5" height="17.5" as="geometry"/></mxCell> | 142 | + <mxCell id="02-conversation-41" value="working…" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#6B6F7A;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="365" y="459.5" width="57.99999999999999" height="17.5" as="geometry"/></mxCell> |
| 143 | <mxCell id="02-conversation-42" value="" style="rounded=1;absoluteArcSize=1;arcSize=16;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="275" y="484" width="560" height="40" as="geometry"/></mxCell> | 143 | <mxCell id="02-conversation-42" value="" style="rounded=1;absoluteArcSize=1;arcSize=16;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="275" y="484" width="560" height="40" as="geometry"/></mxCell> |
| 144 | - <mxCell id="02-conversation-43" value="▸ 🛠 write_file : photo-backup.sh (0 octet) ✓ terminé" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="496.5" width="434.99999999999994" height="17.5" as="geometry"/></mxCell> | 144 | + <mxCell id="02-conversation-43" value="▸ 🛠 write_file: photo-backup.sh (0 bytes) ✓ done" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="496.5" width="406.0" height="17.5" as="geometry"/></mxCell> |
| 145 | <mxCell id="02-conversation-44" value="" style="rounded=1;absoluteArcSize=1;arcSize=16;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="275" y="532" width="560" height="40" as="geometry"/></mxCell> | 145 | <mxCell id="02-conversation-44" value="" style="rounded=1;absoluteArcSize=1;arcSize=16;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="275" y="532" width="560" height="40" as="geometry"/></mxCell> |
| 146 | - <mxCell id="02-conversation-45" value="▸ 🛠 bash : ls -la … en cours" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="544.5" width="449.49999999999994" height="17.5" as="geometry"/></mxCell> | 146 | + <mxCell id="02-conversation-45" value="▸ 🛠 bash: ls -la … running" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="544.5" width="434.99999999999994" height="17.5" as="geometry"/></mxCell> |
| 147 | <mxCell id="02-conversation-46" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="754" width="849" height="64" as="geometry"/></mxCell> | 147 | <mxCell id="02-conversation-46" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="754" width="849" height="64" as="geometry"/></mxCell> |
| 148 | <mxCell id="02-conversation-47" value="" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="766" width="20" height="19" as="geometry"/></mxCell> | 148 | <mxCell id="02-conversation-47" value="" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="766" width="20" height="19" as="geometry"/></mxCell> |
| 149 | - <mxCell id="02-conversation-48" value="Entrée pour envoyer · Maj+Entrée nouvelle ligne" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="793" width="299.85999999999996" height="16" as="geometry"/></mxCell> | 149 | + <mxCell id="02-conversation-48" value="Enter to send · Shift+Enter for a new line" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="793" width="267.96" height="16" as="geometry"/></mxCell> |
| 150 | <mxCell id="02-conversation-49" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1132" y="770" width="108" height="32" as="geometry"/></mxCell> | 150 | <mxCell id="02-conversation-49" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1132" y="770" width="108" height="32" as="geometry"/></mxCell> |
| 151 | - <mxCell id="02-conversation-50" value="■ Arrêter" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1152.07" y="778.0" width="67.86" height="18" as="geometry"/></mxCell> | 151 | + <mxCell id="02-conversation-50" value="■ Stop" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1163.38" y="778.0" width="45.239999999999995" height="18" as="geometry"/></mxCell> |
| 152 | <mxCell id="02-conversation-51" value="" style="rounded=1;absoluteArcSize=1;arcSize=30;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1040" y="176" width="200" height="30" as="geometry"/></mxCell> | 152 | <mxCell id="02-conversation-51" value="" style="rounded=1;absoluteArcSize=1;arcSize=30;fillColor=#F0F1F3;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1040" y="176" width="200" height="30" as="geometry"/></mxCell> |
| 153 | - <mxCell id="02-conversation-52" value="contexte Riker : 41 %" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1069.965" y="184.5" width="140.07" height="16.5" as="geometry"/></mxCell> | 153 | + <mxCell id="02-conversation-52" value="Riker's context: 41%" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1073.3" y="184.5" width="133.39999999999998" height="16.5" as="geometry"/></mxCell> |
| 154 | <mxCell id="02-conversation-53" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="563" y="179" width="24" height="24" as="geometry"/></mxCell> | 154 | <mxCell id="02-conversation-53" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="563" y="179" width="24" height="24" as="geometry"/></mxCell> |
| 155 | <mxCell id="02-conversation-54" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="343" y="262" width="24" height="24" as="geometry"/></mxCell> | 155 | <mxCell id="02-conversation-54" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="343" y="262" width="24" height="24" as="geometry"/></mxCell> |
| 156 | <mxCell id="02-conversation-55" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="843" y="492" width="24" height="24" as="geometry"/></mxCell> | 156 | <mxCell id="02-conversation-55" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="843" y="492" width="24" height="24" as="geometry"/></mxCell> |
| @@ -158,40 +158,40 @@ | |||
| 158 | <mxCell id="02-conversation-57" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1016" y="179" width="24" height="24" as="geometry"/></mxCell> | 158 | <mxCell id="02-conversation-57" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1016" y="179" width="24" height="24" as="geometry"/></mxCell> |
| 159 | <mxCell id="02-conversation-58" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> | 159 | <mxCell id="02-conversation-58" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 160 | <mxCell id="02-conversation-59" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> | 160 | <mxCell id="02-conversation-59" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 161 | - <mxCell id="02-conversation-60" value="Arrivée visible" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="117.44999999999999" height="18.5" as="geometry"/></mxCell> | 161 | + <mxCell id="02-conversation-60" value="A visible arrival" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="133.10999999999999" height="18.5" as="geometry"/></mxCell> |
| 162 | - <mxCell id="02-conversation-61" value="La 1re mention invite l'agent : un message" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="292.32" height="17" as="geometry"/></mxCell> | 162 | + <mxCell id="02-conversation-61" value="The first mention invites the agent: a system" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="313.2" height="17" as="geometry"/></mxCell> |
| 163 | - <mxCell id="02-conversation-62" value="système le dit. On sait qui « écoute »." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="271.44" height="17" as="geometry"/></mxCell> | 163 | + <mxCell id="02-conversation-62" value="message says so. You know who is listening." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="299.28" height="17" as="geometry"/></mxCell> |
| 164 | <mxCell id="02-conversation-63" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> | 164 | <mxCell id="02-conversation-63" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 165 | <mxCell id="02-conversation-64" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> | 165 | <mxCell id="02-conversation-64" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 166 | - <mxCell id="02-conversation-65" value="Une couleur par agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="164.42999999999998" height="18.5" as="geometry"/></mxCell> | 166 | + <mxCell id="02-conversation-65" value="One colour per agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="156.6" height="18.5" as="geometry"/></mxCell> |
| 167 | - <mxCell id="02-conversation-66" value="Avatar + nom colorés, réponses en Markdown" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="292.32" height="17" as="geometry"/></mxCell> | 167 | + <mxCell id="02-conversation-66" value="Coloured avatar and name, answers in" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="250.55999999999997" height="17" as="geometry"/></mxCell> |
| 168 | - <mxCell id="02-conversation-67" value="avec code coloré (ADR 0002)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="194.88" height="17" as="geometry"/></mxCell> | 168 | + <mxCell id="02-conversation-67" value="Markdown with highlighted code (ADR 0002)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="292.32" height="17" as="geometry"/></mxCell> |
| 169 | <mxCell id="02-conversation-68" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="94" as="geometry"/></mxCell> | 169 | <mxCell id="02-conversation-68" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="94" as="geometry"/></mxCell> |
| 170 | <mxCell id="02-conversation-69" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> | 170 | <mxCell id="02-conversation-69" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 171 | - <mxCell id="02-conversation-70" value="Outils repliés" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> | 171 | + <mxCell id="02-conversation-70" value="Folded tools" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="93.96" height="18.5" as="geometry"/></mxCell> |
| 172 | - <mxCell id="02-conversation-71" value="Une ligne par tool call : titre lisible et" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="292.32" height="17" as="geometry"/></mxCell> | 172 | + <mxCell id="02-conversation-71" value="One line per tool call: a readable title" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="278.4" height="17" as="geometry"/></mxCell> |
| 173 | - <mxCell id="02-conversation-72" value="statut. Déplier montre la commande, le" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 173 | + <mxCell id="02-conversation-72" value="and its status. Unfolding shows the" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="243.6" height="17" as="geometry"/></mxCell> |
| 174 | - <mxCell id="02-conversation-73" value="diff ou la sortie." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="125.27999999999999" height="17" as="geometry"/></mxCell> | 174 | + <mxCell id="02-conversation-73" value="command, the diff or the output." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="222.71999999999997" height="17" as="geometry"/></mxCell> |
| 175 | <mxCell id="02-conversation-74" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="368" width="356" height="76" as="geometry"/></mxCell> | 175 | <mxCell id="02-conversation-74" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="368" width="356" height="76" as="geometry"/></mxCell> |
| 176 | <mxCell id="02-conversation-75" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="378" width="24" height="24" as="geometry"/></mxCell> | 176 | <mxCell id="02-conversation-75" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="378" width="24" height="24" as="geometry"/></mxCell> |
| 177 | - <mxCell id="02-conversation-76" value="Toujours un bouton Arrêter" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="381.5" width="203.57999999999998" height="18.5" as="geometry"/></mxCell> | 177 | + <mxCell id="02-conversation-76" value="Always a Stop button" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="381.5" width="156.6" height="18.5" as="geometry"/></mxCell> |
| 178 | - <mxCell id="02-conversation-77" value="Envoie session/cancel aux agents qui" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="250.55999999999997" height="17" as="geometry"/></mxCell> | 178 | + <mxCell id="02-conversation-77" value="Sends session/cancel to the agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="236.64" height="17" as="geometry"/></mxCell> |
| 179 | - <mxCell id="02-conversation-78" value="répondent dans ce channel (ADR 0001)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="257.52" height="17" as="geometry"/></mxCell> | 179 | + <mxCell id="02-conversation-78" value="answering in this channel (ADR 0001)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="257.52" height="17" as="geometry"/></mxCell> |
| 180 | <mxCell id="02-conversation-79" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="458" width="356" height="94" as="geometry"/></mxCell> | 180 | <mxCell id="02-conversation-79" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="458" width="356" height="94" as="geometry"/></mxCell> |
| 181 | <mxCell id="02-conversation-80" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="468" width="24" height="24" as="geometry"/></mxCell> | 181 | <mxCell id="02-conversation-80" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="468" width="24" height="24" as="geometry"/></mxCell> |
| 182 | - <mxCell id="02-conversation-81" value="Jauge de contexte" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="471.5" width="133.10999999999999" height="18.5" as="geometry"/></mxCell> | 182 | + <mxCell id="02-conversation-81" value="Context gauge" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="471.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> |
| 183 | - <mxCell id="02-conversation-82" value="usage_update : prévient avant que la" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="250.55999999999997" height="17" as="geometry"/></mxCell> | 183 | + <mxCell id="02-conversation-82" value="usage_update: warns before the" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="208.79999999999998" height="17" as="geometry"/></mxCell> |
| 184 | - <mxCell id="02-conversation-83" value="conversation ne dépasse la mémoire de" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="257.52" height="17" as="geometry"/></mxCell> | 184 | + <mxCell id="02-conversation-83" value="conversation outgrows the agent's" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="229.67999999999998" height="17" as="geometry"/></mxCell> |
| 185 | - <mxCell id="02-conversation-84" value="l'agent." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="532" width="55.67999999999999" height="17" as="geometry"/></mxCell> | 185 | + <mxCell id="02-conversation-84" value="memory." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="532" width="48.72" height="17" as="geometry"/></mxCell> |
| 186 | </root> | 186 | </root> |
| 187 | </mxGraphModel> | 187 | </mxGraphModel> |
| 188 | </diagram> | 188 | </diagram> |
| 189 | - <diagram id="03-mentions-commands" name="3 · Invoquer un agent (@) et une commande (/)"> | 189 | + <diagram id="03-mentions-commands" name="3 · Calling an agent (@) and a command (/)"> |
| 190 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> | 190 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 191 | <root> | 191 | <root> |
| 192 | <mxCell id="0"/> | 192 | <mxCell id="0"/> |
| 193 | <mxCell id="1" parent="0"/> | 193 | <mxCell id="1" parent="0"/> |
| 194 | - <mxCell id="03-mentions-commands-title" value="<b>3 · Invoquer un agent (@) et une commande (/)</b><br><i>Tab choisit la suggestion ; continuer à écrire filtre la liste</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | 194 | + <mxCell id="03-mentions-commands-title" value="<b>3 · Calling an agent (@) and a command (/)</b><br><i>Tab picks the suggestion; typing on filters the list</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> |
| 195 | <mxCell id="03-mentions-commands-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> | 195 | <mxCell id="03-mentions-commands-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 196 | <mxCell id="03-mentions-commands-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> | 196 | <mxCell id="03-mentions-commands-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 197 | <mxCell id="03-mentions-commands-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> | 197 | <mxCell id="03-mentions-commands-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -200,14 +200,14 @@ | |||
| 200 | <mxCell id="03-mentions-commands-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> | 200 | <mxCell id="03-mentions-commands-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 201 | <mxCell id="03-mentions-commands-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> | 201 | <mxCell id="03-mentions-commands-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 202 | <mxCell id="03-mentions-commands-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> | 202 | <mxCell id="03-mentions-commands-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 203 | - <mxCell id="03-mentions-commands-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | 203 | + <mxCell id="03-mentions-commands-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> |
| 204 | <mxCell id="03-mentions-commands-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> | 204 | <mxCell id="03-mentions-commands-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 205 | <mxCell id="03-mentions-commands-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> | 205 | <mxCell id="03-mentions-commands-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 206 | <mxCell id="03-mentions-commands-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> | 206 | <mxCell id="03-mentions-commands-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 207 | <mxCell id="03-mentions-commands-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> | 207 | <mxCell id="03-mentions-commands-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 208 | <mxCell id="03-mentions-commands-14" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="158" width="214" height="26" as="geometry"/></mxCell> | 208 | <mxCell id="03-mentions-commands-14" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="158" width="214" height="26" as="geometry"/></mxCell> |
| 209 | - <mxCell id="03-mentions-commands-15" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | 209 | + <mxCell id="03-mentions-commands-15" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 210 | - <mxCell id="03-mentions-commands-16" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | 210 | + <mxCell id="03-mentions-commands-16" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> |
| 211 | <mxCell id="03-mentions-commands-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> | 211 | <mxCell id="03-mentions-commands-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 212 | <mxCell id="03-mentions-commands-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> | 212 | <mxCell id="03-mentions-commands-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| 213 | <mxCell id="03-mentions-commands-19" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> | 213 | <mxCell id="03-mentions-commands-19" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> |
| @@ -218,36 +218,36 @@ | |||
| 218 | <mxCell id="03-mentions-commands-24" value="🧑🚀 Riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="352.5" width="70.47" height="18.5" as="geometry"/></mxCell> | 218 | <mxCell id="03-mentions-commands-24" value="🧑🚀 Riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="352.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 219 | <mxCell id="03-mentions-commands-25" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> | 219 | <mxCell id="03-mentions-commands-25" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> |
| 220 | <mxCell id="03-mentions-commands-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> | 220 | <mxCell id="03-mentions-commands-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 221 | - <mxCell id="03-mentions-commands-27" value="Mention d'un agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="271" y="136" width="146.16" height="19" as="geometry"/></mxCell> | 221 | + <mxCell id="03-mentions-commands-27" value="Mentioning an agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="271" y="136" width="154.28" height="19" as="geometry"/></mxCell> |
| 222 | <mxCell id="03-mentions-commands-28" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="164" width="420" height="150" as="geometry"/></mxCell> | 222 | <mxCell id="03-mentions-commands-28" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="164" width="420" height="150" as="geometry"/></mxCell> |
| 223 | <mxCell id="03-mentions-commands-29" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#E8EFFD;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="277" y="172" width="408" height="40" as="geometry"/></mxCell> | 223 | <mxCell id="03-mentions-commands-29" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#E8EFFD;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="277" y="172" width="408" height="40" as="geometry"/></mxCell> |
| 224 | <mxCell id="03-mentions-commands-30" value="🐮 garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="289" y="176.5" width="78.3" height="18.5" as="geometry"/></mxCell> | 224 | <mxCell id="03-mentions-commands-30" value="🐮 garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="289" y="176.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 225 | - <mxCell id="03-mentions-commands-31" value="Garfield (traducteur) — traduit FR ⇄ EN" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="194.5" width="260.13" height="16.5" as="geometry"/></mxCell> | 225 | + <mxCell id="03-mentions-commands-31" value="Garfield (translator) — translates FR ⇄ EN" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="194.5" width="280.14" height="16.5" as="geometry"/></mxCell> |
| 226 | <mxCell id="03-mentions-commands-32" value="🧑🚀 riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="289" y="220.5" width="70.47" height="18.5" as="geometry"/></mxCell> | 226 | <mxCell id="03-mentions-commands-32" value="🧑🚀 riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="289" y="220.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 227 | - <mxCell id="03-mentions-commands-33" value="Riker (outils) — commandes et fichiers" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="238.5" width="253.45999999999998" height="16.5" as="geometry"/></mxCell> | 227 | + <mxCell id="03-mentions-commands-33" value="Riker (tools) — commands and files" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="238.5" width="226.77999999999997" height="16.5" as="geometry"/></mxCell> |
| 228 | <mxCell id="03-mentions-commands-34" value="👩 alice" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="289" y="264.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> | 228 | <mxCell id="03-mentions-commands-34" value="👩 alice" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="289" y="264.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> |
| 229 | - <mxCell id="03-mentions-commands-35" value="Alice (assistante) — questions simples" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="282.5" width="253.45999999999998" height="16.5" as="geometry"/></mxCell> | 229 | + <mxCell id="03-mentions-commands-35" value="Alice (assistant) — simple questions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="282.5" width="240.11999999999998" height="16.5" as="geometry"/></mxCell> |
| 230 | <mxCell id="03-mentions-commands-36" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="324" width="969" height="64" as="geometry"/></mxCell> | 230 | <mxCell id="03-mentions-commands-36" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="324" width="969" height="64" as="geometry"/></mxCell> |
| 231 | <mxCell id="03-mentions-commands-37" value="@ga" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="336" width="24.36" height="19" as="geometry"/></mxCell> | 231 | <mxCell id="03-mentions-commands-37" value="@ga" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="336" width="24.36" height="19" as="geometry"/></mxCell> |
| 232 | - <mxCell id="03-mentions-commands-38" value="Tab : @garfield · ↑↓ naviguer · Échap fermer" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="363" width="280.71999999999997" height="16" as="geometry"/></mxCell> | 232 | + <mxCell id="03-mentions-commands-38" value="Tab: @garfield · ↑↓ move · Esc close" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="363" width="229.67999999999998" height="16" as="geometry"/></mxCell> |
| 233 | - <mxCell id="03-mentions-commands-39" value="Commande d'un agent (plusieurs agents dans le channel)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="271" y="426" width="438.47999999999996" height="19" as="geometry"/></mxCell> | 233 | + <mxCell id="03-mentions-commands-39" value="An agent's command (several agents in the channel)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="271" y="426" width="406.0" height="19" as="geometry"/></mxCell> |
| 234 | <mxCell id="03-mentions-commands-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="454" width="520" height="196" as="geometry"/></mxCell> | 234 | <mxCell id="03-mentions-commands-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="454" width="520" height="196" as="geometry"/></mxCell> |
| 235 | <mxCell id="03-mentions-commands-41" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#E8EFFD;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="277" y="462" width="508" height="42" as="geometry"/></mxCell> | 235 | <mxCell id="03-mentions-commands-41" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#E8EFFD;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="277" y="462" width="508" height="42" as="geometry"/></mxCell> |
| 236 | <mxCell id="03-mentions-commands-42" value="/garfield:idioms" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="467.5" width="133.92" height="18.5" as="geometry"/></mxCell> | 236 | <mxCell id="03-mentions-commands-42" value="/garfield:idioms" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="467.5" width="133.92" height="18.5" as="geometry"/></mxCell> |
| 237 | - <mxCell id="03-mentions-commands-43" value="[texte]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="721.09" y="469.5" width="49.91" height="16.5" as="geometry"/></mxCell> | 237 | + <mxCell id="03-mentions-commands-43" value="[text]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="728.22" y="469.5" width="42.78" height="16.5" as="geometry"/></mxCell> |
| 238 | - <mxCell id="03-mentions-commands-44" value="Expressions idiomatiques et faux amis" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="486.5" width="246.79" height="16.5" as="geometry"/></mxCell> | 238 | + <mxCell id="03-mentions-commands-44" value="Idioms and false friends" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="486.5" width="160.07999999999998" height="16.5" as="geometry"/></mxCell> |
| 239 | <mxCell id="03-mentions-commands-45" value="/garfield:styles" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="513.5" width="133.92" height="18.5" as="geometry"/></mxCell> | 239 | <mxCell id="03-mentions-commands-45" value="/garfield:styles" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="513.5" width="133.92" height="18.5" as="geometry"/></mxCell> |
| 240 | - <mxCell id="03-mentions-commands-46" value="[texte]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="721.09" y="515.5" width="49.91" height="16.5" as="geometry"/></mxCell> | 240 | + <mxCell id="03-mentions-commands-46" value="[text]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="728.22" y="515.5" width="42.78" height="16.5" as="geometry"/></mxCell> |
| 241 | - <mxCell id="03-mentions-commands-47" value="Plusieurs versions d'une traduction" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="532.5" width="233.45" height="16.5" as="geometry"/></mxCell> | 241 | + <mxCell id="03-mentions-commands-47" value="Several versions of a translation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="532.5" width="220.10999999999999" height="16.5" as="geometry"/></mxCell> |
| 242 | <mxCell id="03-mentions-commands-48" value="/garfield:email-letter" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="559.5" width="184.14" height="18.5" as="geometry"/></mxCell> | 242 | <mxCell id="03-mentions-commands-48" value="/garfield:email-letter" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="559.5" width="184.14" height="18.5" as="geometry"/></mxCell> |
| 243 | - <mxCell id="03-mentions-commands-49" value="[texte]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="721.09" y="561.5" width="49.91" height="16.5" as="geometry"/></mxCell> | 243 | + <mxCell id="03-mentions-commands-49" value="[text]" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="728.22" y="561.5" width="42.78" height="16.5" as="geometry"/></mxCell> |
| 244 | - <mxCell id="03-mentions-commands-50" value="E-mails et lettres : formules, tu ou vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="578.5" width="273.46999999999997" height="16.5" as="geometry"/></mxCell> | 244 | + <mxCell id="03-mentions-commands-50" value="E-mails and letters: greetings, tu or vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="578.5" width="280.14" height="16.5" as="geometry"/></mxCell> |
| 245 | <mxCell id="03-mentions-commands-51" value="/alice:compact" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="605.5" width="117.17999999999999" height="18.5" as="geometry"/></mxCell> | 245 | <mxCell id="03-mentions-commands-51" value="/alice:compact" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="289" y="605.5" width="117.17999999999999" height="18.5" as="geometry"/></mxCell> |
| 246 | <mxCell id="03-mentions-commands-52" value="" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="751" y="607.5" width="20" height="16.5" as="geometry"/></mxCell> | 246 | <mxCell id="03-mentions-commands-52" value="" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="751" y="607.5" width="20" height="16.5" as="geometry"/></mxCell> |
| 247 | - <mxCell id="03-mentions-commands-53" value="Résumer l'historique maintenant" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="624.5" width="206.76999999999998" height="16.5" as="geometry"/></mxCell> | 247 | + <mxCell id="03-mentions-commands-53" value="Summarise the history now" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="289" y="624.5" width="166.75" height="16.5" as="geometry"/></mxCell> |
| 248 | <mxCell id="03-mentions-commands-54" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="660" width="969" height="64" as="geometry"/></mxCell> | 248 | <mxCell id="03-mentions-commands-54" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FFFFFF;strokeColor=#3B6FE0;strokeWidth=1.5;html=1;" vertex="1" parent="1"><mxGeometry x="271" y="660" width="969" height="64" as="geometry"/></mxCell> |
| 249 | <mxCell id="03-mentions-commands-55" value="/gar" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="672" width="32.48" height="19" as="geometry"/></mxCell> | 249 | <mxCell id="03-mentions-commands-55" value="/gar" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="672" width="32.48" height="19" as="geometry"/></mxCell> |
| 250 | - <mxCell id="03-mentions-commands-56" value="Tab : /garfield:idioms · le texte après la commande est son argument" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="699" width="433.84" height="16" as="geometry"/></mxCell> | 250 | + <mxCell id="03-mentions-commands-56" value="Tab: /garfield:idioms · the text after the command is its argument" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="285" y="699" width="421.08" height="16" as="geometry"/></mxCell> |
| 251 | <mxCell id="03-mentions-commands-57" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="693" y="168" width="24" height="24" as="geometry"/></mxCell> | 251 | <mxCell id="03-mentions-commands-57" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="693" y="168" width="24" height="24" as="geometry"/></mxCell> |
| 252 | <mxCell id="03-mentions-commands-58" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="559" y="344" width="24" height="24" as="geometry"/></mxCell> | 252 | <mxCell id="03-mentions-commands-58" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="559" y="344" width="24" height="24" as="geometry"/></mxCell> |
| 253 | <mxCell id="03-mentions-commands-59" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="793" y="458" width="24" height="24" as="geometry"/></mxCell> | 253 | <mxCell id="03-mentions-commands-59" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="793" y="458" width="24" height="24" as="geometry"/></mxCell> |
| @@ -255,38 +255,38 @@ | |||
| 255 | <mxCell id="03-mentions-commands-61" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1208" y="680" width="24" height="24" as="geometry"/></mxCell> | 255 | <mxCell id="03-mentions-commands-61" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1208" y="680" width="24" height="24" as="geometry"/></mxCell> |
| 256 | <mxCell id="03-mentions-commands-62" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> | 256 | <mxCell id="03-mentions-commands-62" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 257 | <mxCell id="03-mentions-commands-63" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> | 257 | <mxCell id="03-mentions-commands-63" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 258 | - <mxCell id="03-mentions-commands-64" value="@ liste les agents de la config" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="242.73" height="18.5" as="geometry"/></mxCell> | 258 | + <mxCell id="03-mentions-commands-64" value="@ lists the configured agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="227.07" height="18.5" as="geometry"/></mxCell> |
| 259 | - <mxCell id="03-mentions-commands-65" value="Nom technique + titre + description." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="250.55999999999997" height="17" as="geometry"/></mxCell> | 259 | + <mxCell id="03-mentions-commands-65" value="Technical name + title + description." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="257.52" height="17" as="geometry"/></mxCell> |
| 260 | - <mxCell id="03-mentions-commands-66" value="Filtrage flou sur nom et titre (« gar »)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="285.35999999999996" height="17" as="geometry"/></mxCell> | 260 | + <mxCell id="03-mentions-commands-66" value="Fuzzy filter on name and title ("gar")." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="271.44" height="17" as="geometry"/></mxCell> |
| 261 | <mxCell id="03-mentions-commands-67" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> | 261 | <mxCell id="03-mentions-commands-67" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 262 | <mxCell id="03-mentions-commands-68" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> | 262 | <mxCell id="03-mentions-commands-68" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 263 | - <mxCell id="03-mentions-commands-69" value="Tab sélectionne, sinon on écrit" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="242.73" height="18.5" as="geometry"/></mxCell> | 263 | + <mxCell id="03-mentions-commands-69" value="Tab picks, otherwise you type" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="227.07" height="18.5" as="geometry"/></mxCell> |
| 264 | - <mxCell id="03-mentions-commands-70" value="Comportement demandé dans le draft (#1)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="278.4" height="17" as="geometry"/></mxCell> | 264 | + <mxCell id="03-mentions-commands-70" value="Behaviour asked for in the draft (#1)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="264.47999999999996" height="17" as="geometry"/></mxCell> |
| 265 | - <mxCell id="03-mentions-commands-71" value="Échap ferme sans rien insérer." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="208.79999999999998" height="17" as="geometry"/></mxCell> | 265 | + <mxCell id="03-mentions-commands-71" value="Esc closes without inserting anything." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="264.47999999999996" height="17" as="geometry"/></mxCell> |
| 266 | <mxCell id="03-mentions-commands-72" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="76" as="geometry"/></mxCell> | 266 | <mxCell id="03-mentions-commands-72" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="76" as="geometry"/></mxCell> |
| 267 | <mxCell id="03-mentions-commands-73" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> | 267 | <mxCell id="03-mentions-commands-73" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 268 | - <mxCell id="03-mentions-commands-74" value="/agent:commande en multi-agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="242.73" height="18.5" as="geometry"/></mxCell> | 268 | + <mxCell id="03-mentions-commands-74" value="/agent:command with several agents" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="266.21999999999997" height="18.5" as="geometry"/></mxCell> |
| 269 | - <mxCell id="03-mentions-commands-75" value="Avec un seul agent : /commande. Sidekicks" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="285.35999999999996" height="17" as="geometry"/></mxCell> | 269 | + <mxCell id="03-mentions-commands-75" value="With one agent: /command. Sidekicks" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="243.6" height="17" as="geometry"/></mxCell> |
| 270 | - <mxCell id="03-mentions-commands-76" value="envoie « /idioms … » au seul Garfield." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 270 | + <mxCell id="03-mentions-commands-76" value="sends "/idioms …" to Garfield only." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="243.6" height="17" as="geometry"/></mxCell> |
| 271 | <mxCell id="03-mentions-commands-77" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="350" width="356" height="76" as="geometry"/></mxCell> | 271 | <mxCell id="03-mentions-commands-77" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="350" width="356" height="76" as="geometry"/></mxCell> |
| 272 | <mxCell id="03-mentions-commands-78" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="360" width="24" height="24" as="geometry"/></mxCell> | 272 | <mxCell id="03-mentions-commands-78" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="360" width="24" height="24" as="geometry"/></mxCell> |
| 273 | - <mxCell id="03-mentions-commands-79" value="Skills et commandes intégrées" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="227.07" height="18.5" as="geometry"/></mxCell> | 273 | + <mxCell id="03-mentions-commands-79" value="Skills and built-in commands" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="219.23999999999998" height="18.5" as="geometry"/></mxCell> |
| 274 | - <mxCell id="03-mentions-commands-80" value="mm annonce compact, new, unload et ses" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 274 | + <mxCell id="03-mentions-commands-80" value="mm announces compact, new, unload and" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="257.52" height="17" as="geometry"/></mxCell> |
| 275 | - <mxCell id="03-mentions-commands-81" value="skills (available_commands_update)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="243.6" height="17" as="geometry"/></mxCell> | 275 | + <mxCell id="03-mentions-commands-81" value="its skills (available_commands_update)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="271.44" height="17" as="geometry"/></mxCell> |
| 276 | <mxCell id="03-mentions-commands-82" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="440" width="356" height="76" as="geometry"/></mxCell> | 276 | <mxCell id="03-mentions-commands-82" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="440" width="356" height="76" as="geometry"/></mxCell> |
| 277 | <mxCell id="03-mentions-commands-83" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="450" width="24" height="24" as="geometry"/></mxCell> | 277 | <mxCell id="03-mentions-commands-83" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="450" width="24" height="24" as="geometry"/></mxCell> |
| 278 | - <mxCell id="03-mentions-commands-84" value="Indice d'argument" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="453.5" width="133.10999999999999" height="18.5" as="geometry"/></mxCell> | 278 | + <mxCell id="03-mentions-commands-84" value="Argument hint" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="453.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> |
| 279 | - <mxCell id="03-mentions-commands-85" value="input.hint de la commande ACP, affiché" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="478" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 279 | + <mxCell id="03-mentions-commands-85" value="The ACP command's input.hint, shown" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="478" width="243.6" height="17" as="geometry"/></mxCell> |
| 280 | - <mxCell id="03-mentions-commands-86" value="tant que l'argument n'est pas saisi." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="250.55999999999997" height="17" as="geometry"/></mxCell> | 280 | + <mxCell id="03-mentions-commands-86" value="until the argument is typed." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="194.88" height="17" as="geometry"/></mxCell> |
| 281 | </root> | 281 | </root> |
| 282 | </mxGraphModel> | 282 | </mxGraphModel> |
| 283 | </diagram> | 283 | </diagram> |
| 284 | - <diagram id="04-permission" name="4 · Demande de permission"> | 284 | + <diagram id="04-permission" name="4 · Permission request"> |
| 285 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> | 285 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 286 | <root> | 286 | <root> |
| 287 | <mxCell id="0"/> | 287 | <mxCell id="0"/> |
| 288 | <mxCell id="1" parent="0"/> | 288 | <mxCell id="1" parent="0"/> |
| 289 | - <mxCell id="04-permission-title" value="<b>4 · Demande de permission</b><br><i>En langage clair, sur la conversation concernée, avec une sortie de secours</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | 289 | + <mxCell id="04-permission-title" value="<b>4 · Permission request</b><br><i>In plain words, on the conversation concerned, with a way out</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> |
| 290 | <mxCell id="04-permission-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> | 290 | <mxCell id="04-permission-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 291 | <mxCell id="04-permission-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> | 291 | <mxCell id="04-permission-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 292 | <mxCell id="04-permission-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> | 292 | <mxCell id="04-permission-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -295,13 +295,13 @@ | |||
| 295 | <mxCell id="04-permission-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> | 295 | <mxCell id="04-permission-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 296 | <mxCell id="04-permission-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> | 296 | <mxCell id="04-permission-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 297 | <mxCell id="04-permission-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> | 297 | <mxCell id="04-permission-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 298 | - <mxCell id="04-permission-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | 298 | + <mxCell id="04-permission-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> |
| 299 | <mxCell id="04-permission-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> | 299 | <mxCell id="04-permission-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 300 | <mxCell id="04-permission-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> | 300 | <mxCell id="04-permission-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 301 | <mxCell id="04-permission-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> | 301 | <mxCell id="04-permission-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 302 | <mxCell id="04-permission-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> | 302 | <mxCell id="04-permission-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 303 | - <mxCell id="04-permission-14" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | 303 | + <mxCell id="04-permission-14" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 304 | - <mxCell id="04-permission-15" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | 304 | + <mxCell id="04-permission-15" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> |
| 305 | <mxCell id="04-permission-16" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="218" width="214" height="26" as="geometry"/></mxCell> | 305 | <mxCell id="04-permission-16" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="28" y="218" width="214" height="26" as="geometry"/></mxCell> |
| 306 | <mxCell id="04-permission-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> | 306 | <mxCell id="04-permission-17" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 307 | <mxCell id="04-permission-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> | 307 | <mxCell id="04-permission-18" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| @@ -315,28 +315,28 @@ | |||
| 315 | <mxCell id="04-permission-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> | 315 | <mxCell id="04-permission-26" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 316 | <mxCell id="04-permission-27" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="1009" height="44" as="geometry"/></mxCell> | 316 | <mxCell id="04-permission-27" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="1009" height="44" as="geometry"/></mxCell> |
| 317 | <mxCell id="04-permission-28" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="52.199999999999996" height="20" as="geometry"/></mxCell> | 317 | <mxCell id="04-permission-28" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="129" width="52.199999999999996" height="20" as="geometry"/></mxCell> |
| 318 | - <mxCell id="04-permission-29" value="Vous" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="182.5" width="31.319999999999997" height="18.5" as="geometry"/></mxCell> | 318 | + <mxCell id="04-permission-29" value="You" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="182.5" width="23.49" height="18.5" as="geometry"/></mxCell> |
| 319 | - <mxCell id="04-permission-30" value="@riker supprime les fichiers temporaires du dossier" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="204.5" width="399.33" height="18.5" as="geometry"/></mxCell> | 319 | + <mxCell id="04-permission-30" value="@riker delete the temporary files in the folder" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="275" y="204.5" width="368.01" height="18.5" as="geometry"/></mxCell> |
| 320 | <mxCell id="04-permission-31" value="🧑🚀 Riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#5E35B1;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="238.5" width="70.47" height="18.5" as="geometry"/></mxCell> | 320 | <mxCell id="04-permission-31" value="🧑🚀 Riker" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#5E35B1;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="238.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 321 | - <mxCell id="04-permission-32" value="attend votre réponse" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#C98A1B;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="365" y="239.5" width="145.0" height="17.5" as="geometry"/></mxCell> | 321 | + <mxCell id="04-permission-32" value="waiting for your answer" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#C98A1B;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="365" y="239.5" width="166.75" height="17.5" as="geometry"/></mxCell> |
| 322 | <mxCell id="04-permission-33" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#C98A1B;strokeWidth=2;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="275" y="270" width="720" height="330" as="geometry"/></mxCell> | 322 | <mxCell id="04-permission-33" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#C98A1B;strokeWidth=2;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="275" y="270" width="720" height="330" as="geometry"/></mxCell> |
| 323 | - <mxCell id="04-permission-34" value="🧑🚀 Riker veut exécuter une commande sur votre ordinateur" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="295" y="288" width="528.9599999999999" height="21" as="geometry"/></mxCell> | 323 | + <mxCell id="04-permission-34" value="🧑🚀 Riker wants to run a command on your computer" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="295" y="288" width="454.71999999999997" height="21" as="geometry"/></mxCell> |
| 324 | <mxCell id="04-permission-35" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F4F5F7;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="295" y="322" width="680" height="40" as="geometry"/></mxCell> | 324 | <mxCell id="04-permission-35" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#F4F5F7;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="295" y="322" width="680" height="40" as="geometry"/></mxCell> |
| 325 | <mxCell id="04-permission-36" value="rm -f *.tmp" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="309" y="333" width="95.48" height="19" as="geometry"/></mxCell> | 325 | <mxCell id="04-permission-36" value="rm -f *.tmp" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="309" y="333" width="95.48" height="19" as="geometry"/></mxCell> |
| 326 | - <mxCell id="04-permission-37" value="Ce que cela fait : supprime définitivement les fichiers se terminant par .tmp" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="375" width="580.5799999999999" height="18" as="geometry"/></mxCell> | 326 | + <mxCell id="04-permission-37" value="What it does: permanently deletes the files ending in .tmp" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="375" width="437.32" height="18" as="geometry"/></mxCell> |
| 327 | - <mxCell id="04-permission-38" value="dans agents/riker . Ils ne passent pas par la corbeille." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="395" width="429.78" height="18" as="geometry"/></mxCell> | 327 | + <mxCell id="04-permission-38" value="in agents/riker . They do not go to the trash." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="395" width="354.38" height="18" as="geometry"/></mxCell> |
| 328 | - <mxCell id="04-permission-39" value="⚠ Action irréversible" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="295" y="425" width="165.88" height="18" as="geometry"/></mxCell> | 328 | + <mxCell id="04-permission-39" value="⚠ Cannot be undone" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="295" y="425" width="143.26" height="18" as="geometry"/></mxCell> |
| 329 | <mxCell id="04-permission-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="295" y="460" width="170" height="32" as="geometry"/></mxCell> | 329 | <mxCell id="04-permission-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="295" y="460" width="170" height="32" as="geometry"/></mxCell> |
| 330 | - <mxCell id="04-permission-41" value="Autoriser une fois" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="312.14" y="468.0" width="135.72" height="18" as="geometry"/></mxCell> | 330 | + <mxCell id="04-permission-41" value="Allow once" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="342.3" y="468.0" width="75.39999999999999" height="18" as="geometry"/></mxCell> |
| 331 | <mxCell id="04-permission-42" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="475" y="460" width="300" height="32" as="geometry"/></mxCell> | 331 | <mxCell id="04-permission-42" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="475" y="460" width="300" height="32" as="geometry"/></mxCell> |
| 332 | - <mxCell id="04-permission-43" value="Toujours autoriser bash ici" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="523.21" y="468.0" width="203.57999999999998" height="18" as="geometry"/></mxCell> | 332 | + <mxCell id="04-permission-43" value="Always allow bash here" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="542.06" y="468.0" width="165.88" height="18" as="geometry"/></mxCell> |
| 333 | <mxCell id="04-permission-44" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="295" y="504" width="170" height="32" as="geometry"/></mxCell> | 333 | <mxCell id="04-permission-44" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="295" y="504" width="170" height="32" as="geometry"/></mxCell> |
| 334 | - <mxCell id="04-permission-45" value="Refuser" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="353.61" y="512.0" width="52.779999999999994" height="18" as="geometry"/></mxCell> | 334 | + <mxCell id="04-permission-45" value="Reject" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="357.38" y="512.0" width="45.239999999999995" height="18" as="geometry"/></mxCell> |
| 335 | <mxCell id="04-permission-46" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="475" y="504" width="300" height="32" as="geometry"/></mxCell> | 335 | <mxCell id="04-permission-46" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="475" y="504" width="300" height="32" as="geometry"/></mxCell> |
| 336 | - <mxCell id="04-permission-47" value="Ne plus jamais proposer bash ici" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="504.36" y="512.0" width="241.27999999999997" height="18" as="geometry"/></mxCell> | 336 | + <mxCell id="04-permission-47" value="Never offer bash here again" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="523.21" y="512.0" width="203.57999999999998" height="18" as="geometry"/></mxCell> |
| 337 | <mxCell id="04-permission-48" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="795" y="504" width="180" height="32" as="geometry"/></mxCell> | 337 | <mxCell id="04-permission-48" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="795" y="504" width="180" height="32" as="geometry"/></mxCell> |
| 338 | - <mxCell id="04-permission-49" value="■ Arrêter Riker" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="828.45" y="512.0" width="113.1" height="18" as="geometry"/></mxCell> | 338 | + <mxCell id="04-permission-49" value="■ Stop Riker" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="839.76" y="512.0" width="90.47999999999999" height="18" as="geometry"/></mxCell> |
| 339 | - <mxCell id="04-permission-50" value="▸ Détails techniques (tool call bash, rawInput)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="558" width="327.12" height="17" as="geometry"/></mxCell> | 339 | + <mxCell id="04-permission-50" value="▸ Technical details (bash tool call, rawInput)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295" y="558" width="320.15999999999997" height="17" as="geometry"/></mxCell> |
| 340 | <mxCell id="04-permission-51" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="967" y="288" width="24" height="24" as="geometry"/></mxCell> | 340 | <mxCell id="04-permission-51" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="967" y="288" width="24" height="24" as="geometry"/></mxCell> |
| 341 | <mxCell id="04-permission-52" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="943" y="386" width="24" height="24" as="geometry"/></mxCell> | 341 | <mxCell id="04-permission-52" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="943" y="386" width="24" height="24" as="geometry"/></mxCell> |
| 342 | <mxCell id="04-permission-53" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="775" y="464" width="24" height="24" as="geometry"/></mxCell> | 342 | <mxCell id="04-permission-53" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="775" y="464" width="24" height="24" as="geometry"/></mxCell> |
| @@ -344,39 +344,39 @@ | |||
| 344 | <mxCell id="04-permission-55" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="643" y="554" width="24" height="24" as="geometry"/></mxCell> | 344 | <mxCell id="04-permission-55" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="643" y="554" width="24" height="24" as="geometry"/></mxCell> |
| 345 | <mxCell id="04-permission-56" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> | 345 | <mxCell id="04-permission-56" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 346 | <mxCell id="04-permission-57" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> | 346 | <mxCell id="04-permission-57" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 347 | - <mxCell id="04-permission-58" value="Attaché à la conversation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="195.75" height="18.5" as="geometry"/></mxCell> | 347 | + <mxCell id="04-permission-58" value="Attached to the conversation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="219.23999999999998" height="18.5" as="geometry"/></mxCell> |
| 348 | - <mxCell id="04-permission-59" value="Bloque seulement la session de Riker ; les" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="292.32" height="17" as="geometry"/></mxCell> | 348 | + <mxCell id="04-permission-59" value="Blocks only Riker's session; the other" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="264.47999999999996" height="17" as="geometry"/></mxCell> |
| 349 | - <mxCell id="04-permission-60" value="autres channels continuent (#17)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="229.67999999999998" height="17" as="geometry"/></mxCell> | 349 | + <mxCell id="04-permission-60" value="channels go on (#17)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="146.16" height="17" as="geometry"/></mxCell> |
| 350 | <mxCell id="04-permission-61" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="94" as="geometry"/></mxCell> | 350 | <mxCell id="04-permission-61" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="94" as="geometry"/></mxCell> |
| 351 | <mxCell id="04-permission-62" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> | 351 | <mxCell id="04-permission-62" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 352 | - <mxCell id="04-permission-63" value="Expliquer, pas montrer du JSON" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> | 352 | + <mxCell id="04-permission-63" value="Explain, do not show JSON" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="195.75" height="18.5" as="geometry"/></mxCell> |
| 353 | - <mxCell id="04-permission-64" value="Titre ACP + kind + rawInput traduits en" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="271.44" height="17" as="geometry"/></mxCell> | 353 | + <mxCell id="04-permission-64" value="ACP title + kind + rawInput turned into" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="271.44" height="17" as="geometry"/></mxCell> |
| 354 | - <mxCell id="04-permission-65" value="phrase. Les actions destructives sont" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="257.52" height="17" as="geometry"/></mxCell> | 354 | + <mxCell id="04-permission-65" value="a sentence. Destructive actions are" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="243.6" height="17" as="geometry"/></mxCell> |
| 355 | - <mxCell id="04-permission-66" value="signalées." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="244" width="69.6" height="17" as="geometry"/></mxCell> | 355 | + <mxCell id="04-permission-66" value="flagged." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="244" width="55.67999999999999" height="17" as="geometry"/></mxCell> |
| 356 | <mxCell id="04-permission-67" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="278" width="356" height="94" as="geometry"/></mxCell> | 356 | <mxCell id="04-permission-67" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="278" width="356" height="94" as="geometry"/></mxCell> |
| 357 | <mxCell id="04-permission-68" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="288" width="24" height="24" as="geometry"/></mxCell> | 357 | <mxCell id="04-permission-68" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="288" width="24" height="24" as="geometry"/></mxCell> |
| 358 | - <mxCell id="04-permission-69" value="Les 4 options ACP, par ids" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="291.5" width="203.57999999999998" height="18.5" as="geometry"/></mxCell> | 358 | + <mxCell id="04-permission-69" value="The 4 ACP options, by id" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="291.5" width="187.92" height="18.5" as="geometry"/></mxCell> |
| 359 | <mxCell id="04-permission-70" value="allow · allow_always · reject · never." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 359 | <mxCell id="04-permission-70" value="allow · allow_always · reject · never." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="264.47999999999996" height="17" as="geometry"/></mxCell> |
| 360 | - <mxCell id="04-permission-71" value="« Ne plus jamais » est mis en avant au" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 360 | + <mxCell id="04-permission-71" value=""Never again" is put forward rather" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="334" width="243.6" height="17" as="geometry"/></mxCell> |
| 361 | - <mxCell id="04-permission-72" value="lieu de « Refuser une fois »." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="352" width="201.83999999999997" height="17" as="geometry"/></mxCell> | 361 | + <mxCell id="04-permission-72" value="than "Reject once"." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="352" width="132.23999999999998" height="17" as="geometry"/></mxCell> |
| 362 | <mxCell id="04-permission-73" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="386" width="356" height="76" as="geometry"/></mxCell> | 362 | <mxCell id="04-permission-73" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="386" width="356" height="76" as="geometry"/></mxCell> |
| 363 | <mxCell id="04-permission-74" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="396" width="24" height="24" as="geometry"/></mxCell> | 363 | <mxCell id="04-permission-74" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="396" width="24" height="24" as="geometry"/></mxCell> |
| 364 | - <mxCell id="04-permission-75" value="Toujours une sortie de secours" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="399.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> | 364 | + <mxCell id="04-permission-75" value="Always a way out" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="399.5" width="125.27999999999999" height="18.5" as="geometry"/></mxCell> |
| 365 | - <mxCell id="04-permission-76" value="Spike ACP : après un refus, un petit modèle" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="299.28" height="17" as="geometry"/></mxCell> | 365 | + <mxCell id="04-permission-76" value="ACP spike: after a rejection, a small model" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="424" width="299.28" height="17" as="geometry"/></mxCell> |
| 366 | - <mxCell id="04-permission-77" value="a réessayé 40 fois. Arrêter = session/cancel." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="442" width="313.2" height="17" as="geometry"/></mxCell> | 366 | + <mxCell id="04-permission-77" value="retried 40 times. Stop = session/cancel." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="442" width="278.4" height="17" as="geometry"/></mxCell> |
| 367 | <mxCell id="04-permission-78" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="476" width="356" height="58" as="geometry"/></mxCell> | 367 | <mxCell id="04-permission-78" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="476" width="356" height="58" as="geometry"/></mxCell> |
| 368 | <mxCell id="04-permission-79" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="486" width="24" height="24" as="geometry"/></mxCell> | 368 | <mxCell id="04-permission-79" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="486" width="24" height="24" as="geometry"/></mxCell> |
| 369 | - <mxCell id="04-permission-80" value="Détails pour les curieux" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="489.5" width="187.92" height="18.5" as="geometry"/></mxCell> | 369 | + <mxCell id="04-permission-80" value="Details for the curious" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="489.5" width="180.08999999999997" height="18.5" as="geometry"/></mxCell> |
| 370 | - <mxCell id="04-permission-81" value="Repliés par défaut." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="132.23999999999998" height="17" as="geometry"/></mxCell> | 370 | + <mxCell id="04-permission-81" value="Folded by default." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="514" width="125.27999999999999" height="17" as="geometry"/></mxCell> |
| 371 | </root> | 371 | </root> |
| 372 | </mxGraphModel> | 372 | </mxGraphModel> |
| 373 | </diagram> | 373 | </diagram> |
| 374 | - <diagram id="05-agents-panel" name="5 · Panel Agents : fichiers, éditeur, terminal"> | 374 | + <diagram id="05-agents-panel" name="5 · Agents panel: files, editor, terminal"> |
| 375 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> | 375 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 376 | <root> | 376 | <root> |
| 377 | <mxCell id="0"/> | 377 | <mxCell id="0"/> |
| 378 | <mxCell id="1" parent="0"/> | 378 | <mxCell id="1" parent="0"/> |
| 379 | - <mxCell id="05-agents-panel-title" value="<b>5 · Panel Agents : fichiers, éditeur, terminal</b><br><i>Le workspace de l'agent, qu'il tourne en local, dans un conteneur ou une sandbox sbx</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | 379 | + <mxCell id="05-agents-panel-title" value="<b>5 · Agents panel: files, editor, terminal</b><br><i>The agent's workspace, whether it runs locally, in a container or in an sbx sandbox</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> |
| 380 | <mxCell id="05-agents-panel-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> | 380 | <mxCell id="05-agents-panel-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 381 | <mxCell id="05-agents-panel-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> | 381 | <mxCell id="05-agents-panel-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 382 | <mxCell id="05-agents-panel-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> | 382 | <mxCell id="05-agents-panel-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -385,13 +385,13 @@ | |||
| 385 | <mxCell id="05-agents-panel-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> | 385 | <mxCell id="05-agents-panel-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 386 | <mxCell id="05-agents-panel-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> | 386 | <mxCell id="05-agents-panel-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 387 | <mxCell id="05-agents-panel-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> | 387 | <mxCell id="05-agents-panel-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 388 | - <mxCell id="05-agents-panel-9" value="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="366.84999999999997" height="16.5" as="geometry"/></mxCell> | 388 | + <mxCell id="05-agents-panel-9" value="● 2 of 2 agents running · config: ~/agents/team.yaml" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="346.84" height="16.5" as="geometry"/></mxCell> |
| 389 | <mxCell id="05-agents-panel-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> | 389 | <mxCell id="05-agents-panel-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 390 | <mxCell id="05-agents-panel-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> | 390 | <mxCell id="05-agents-panel-11" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="116" width="230" height="718" as="geometry"/></mxCell> |
| 391 | <mxCell id="05-agents-panel-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> | 391 | <mxCell id="05-agents-panel-12" value="CHANNELS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="133" width="51.04" height="16" as="geometry"/></mxCell> |
| 392 | <mxCell id="05-agents-panel-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> | 392 | <mxCell id="05-agents-panel-13" value="+" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="214" y="128" width="20" height="21" as="geometry"/></mxCell> |
| 393 | - <mxCell id="05-agents-panel-14" value="# général" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> | 393 | + <mxCell id="05-agents-panel-14" value="# general" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="162.5" width="70.47" height="18.5" as="geometry"/></mxCell> |
| 394 | - <mxCell id="05-agents-panel-15" value="# traductions" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="101.78999999999999" height="18.5" as="geometry"/></mxCell> | 394 | + <mxCell id="05-agents-panel-15" value="# translations" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="192.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> |
| 395 | <mxCell id="05-agents-panel-16" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> | 395 | <mxCell id="05-agents-panel-16" value="# code" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="38" y="222.5" width="46.98" height="18.5" as="geometry"/></mxCell> |
| 396 | <mxCell id="05-agents-panel-17" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> | 396 | <mxCell id="05-agents-panel-17" value="AGENTS" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="36" y="263" width="38.279999999999994" height="16" as="geometry"/></mxCell> |
| 397 | <mxCell id="05-agents-panel-18" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> | 397 | <mxCell id="05-agents-panel-18" value="" style="ellipse;fillColor=#3E9B4F;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="296.5" width="9" height="9" as="geometry"/></mxCell> |
| @@ -403,15 +403,15 @@ | |||
| 403 | <mxCell id="05-agents-panel-24" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> | 403 | <mxCell id="05-agents-panel-24" value="" style="ellipse;fillColor=#C98A1B;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="37.5" y="386.5" width="9" height="9" as="geometry"/></mxCell> |
| 404 | <mxCell id="05-agents-panel-25" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> | 404 | <mxCell id="05-agents-panel-25" value="🐮 Garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="54" y="382.5" width="78.3" height="18.5" as="geometry"/></mxCell> |
| 405 | <mxCell id="05-agents-panel-26" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="1009" height="56" as="geometry"/></mxCell> | 405 | <mxCell id="05-agents-panel-26" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="116" width="1009" height="56" as="geometry"/></mxCell> |
| 406 | - <mxCell id="05-agents-panel-27" value="🐮 Garfield (traducteur)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="126" width="213.44" height="21" as="geometry"/></mxCell> | 406 | + <mxCell id="05-agents-panel-27" value="🐮 Garfield (translator)" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="267" y="126" width="213.44" height="21" as="geometry"/></mxCell> |
| 407 | - <mxCell id="05-agents-panel-28" value="● occupé · local · agents/garfield · gemma-4-E4B" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#C98A1B;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="267" y="150" width="334.08" height="17" as="geometry"/></mxCell> | 407 | + <mxCell id="05-agents-panel-28" value="● busy · local · agents/garfield · gemma-4-E4B" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#C98A1B;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="267" y="150" width="320.15999999999997" height="17" as="geometry"/></mxCell> |
| 408 | <mxCell id="05-agents-panel-29" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1010" y="128" width="110" height="32" as="geometry"/></mxCell> | 408 | <mxCell id="05-agents-panel-29" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1010" y="128" width="110" height="32" as="geometry"/></mxCell> |
| 409 | - <mxCell id="05-agents-panel-30" value="Redémarrer" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1027.3" y="136.0" width="75.39999999999999" height="18" as="geometry"/></mxCell> | 409 | + <mxCell id="05-agents-panel-30" value="Restart" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1038.61" y="136.0" width="52.779999999999994" height="18" as="geometry"/></mxCell> |
| 410 | <mxCell id="05-agents-panel-31" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1130" y="128" width="110" height="32" as="geometry"/></mxCell> | 410 | <mxCell id="05-agents-panel-31" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1130" y="128" width="110" height="32" as="geometry"/></mxCell> |
| 411 | - <mxCell id="05-agents-panel-32" value="Arrêter" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1158.61" y="136.0" width="52.779999999999994" height="18" as="geometry"/></mxCell> | 411 | + <mxCell id="05-agents-panel-32" value="Stop" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1169.92" y="136.0" width="30.159999999999997" height="18" as="geometry"/></mxCell> |
| 412 | - <mxCell id="05-agents-panel-33" value="Fichiers" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#3B6FE0;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="184.5" width="62.63999999999999" height="18.5" as="geometry"/></mxCell> | 412 | + <mxCell id="05-agents-panel-33" value="Files" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#3B6FE0;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="275" y="184.5" width="39.15" height="18.5" as="geometry"/></mxCell> |
| 413 | <mxCell id="05-agents-panel-34" value="Terminal" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="375" y="184.5" width="62.63999999999999" height="18.5" as="geometry"/></mxCell> | 413 | <mxCell id="05-agents-panel-34" value="Terminal" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="375" y="184.5" width="62.63999999999999" height="18.5" as="geometry"/></mxCell> |
| 414 | - <mxCell id="05-agents-panel-35" value="Journal" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="475" y="184.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> | 414 | + <mxCell id="05-agents-panel-35" value="Log" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="475" y="184.5" width="23.49" height="18.5" as="geometry"/></mxCell> |
| 415 | <mxCell id="05-agents-panel-36" value="" style="rounded=0;fillColor=#3B6FE0;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="267" y="206" width="70" height="2" as="geometry"/></mxCell> | 415 | <mxCell id="05-agents-panel-36" value="" style="rounded=0;fillColor=#3B6FE0;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="267" y="206" width="70" height="2" as="geometry"/></mxCell> |
| 416 | <mxCell id="05-agents-panel-37" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="216" width="260" height="420" as="geometry"/></mxCell> | 416 | <mxCell id="05-agents-panel-37" value="" style="rounded=0;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="216" width="260" height="420" as="geometry"/></mxCell> |
| 417 | <mxCell id="05-agents-panel-38" value="▾ garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="232.5" width="77.5" height="17.5" as="geometry"/></mxCell> | 417 | <mxCell id="05-agents-panel-38" value="▾ garfield" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="232.5" width="77.5" height="17.5" as="geometry"/></mxCell> |
| @@ -424,20 +424,20 @@ | |||
| 424 | <mxCell id="05-agents-panel-45" value=" ▸ idioms" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="388.5" width="93.0" height="17.5" as="geometry"/></mxCell> | 424 | <mxCell id="05-agents-panel-45" value=" ▸ idioms" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="388.5" width="93.0" height="17.5" as="geometry"/></mxCell> |
| 425 | <mxCell id="05-agents-panel-46" value=" ▸ styles" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="414.5" width="93.0" height="17.5" as="geometry"/></mxCell> | 425 | <mxCell id="05-agents-panel-46" value=" ▸ styles" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="414.5" width="93.0" height="17.5" as="geometry"/></mxCell> |
| 426 | <mxCell id="05-agents-panel-47" value=" ▸ technical-text" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="440.5" width="155.0" height="17.5" as="geometry"/></mxCell> | 426 | <mxCell id="05-agents-panel-47" value=" ▸ technical-text" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="440.5" width="155.0" height="17.5" as="geometry"/></mxCell> |
| 427 | - <mxCell id="05-agents-panel-48" value=" traduction.md" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="466.5" width="131.75" height="17.5" as="geometry"/></mxCell> | 427 | + <mxCell id="05-agents-panel-48" value=" translation.md" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="466.5" width="139.5" height="17.5" as="geometry"/></mxCell> |
| 428 | - <mxCell id="05-agents-panel-49" value="+ Nouveau fichier" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#3B6FE0;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="265" y="503.5" width="123.24999999999999" height="17.5" as="geometry"/></mxCell> | 428 | + <mxCell id="05-agents-panel-49" value="+ New file" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#3B6FE0;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="265" y="503.5" width="72.5" height="17.5" as="geometry"/></mxCell> |
| 429 | <mxCell id="05-agents-panel-50" value="" style="rounded=0;fillColor=#F4F5F7;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="521" y="216" width="729" height="420" as="geometry"/></mxCell> | 429 | <mxCell id="05-agents-panel-50" value="" style="rounded=0;fillColor=#F4F5F7;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="521" y="216" width="729" height="420" as="geometry"/></mxCell> |
| 430 | <mxCell id="05-agents-panel-51" value="AGENTS.md" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="535" y="227" width="67.86" height="18" as="geometry"/></mxCell> | 430 | <mxCell id="05-agents-panel-51" value="AGENTS.md" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="535" y="227" width="67.86" height="18" as="geometry"/></mxCell> |
| 431 | - <mxCell id="05-agents-panel-52" value="# Style de traduction" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="257.5" width="162.75" height="17.5" as="geometry"/></mxCell> | 431 | + <mxCell id="05-agents-panel-52" value="# Translation style" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="257.5" width="147.25" height="17.5" as="geometry"/></mxCell> |
| 432 | <mxCell id="05-agents-panel-53" value="" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="279.5" width="20" height="17.5" as="geometry"/></mxCell> | 432 | <mxCell id="05-agents-panel-53" value="" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="279.5" width="20" height="17.5" as="geometry"/></mxCell> |
| 433 | - <mxCell id="05-agents-panel-54" value="- Registre : celui du texte source." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="301.5" width="271.25" height="17.5" as="geometry"/></mxCell> | 433 | + <mxCell id="05-agents-panel-54" value="- Register: the one of the source text." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="301.5" width="302.25" height="17.5" as="geometry"/></mxCell> |
| 434 | - <mxCell id="05-agents-panel-55" value="- Typographie française : espaces insécables" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="323.5" width="341.0" height="17.5" as="geometry"/></mxCell> | 434 | + <mxCell id="05-agents-panel-55" value="- French typography: non-breaking spaces" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="323.5" width="310.0" height="17.5" as="geometry"/></mxCell> |
| 435 | - <mxCell id="05-agents-panel-56" value=" avant ; : ! ? et entre « guillemets »." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="345.5" width="310.0" height="17.5" as="geometry"/></mxCell> | 435 | + <mxCell id="05-agents-panel-56" value=" before ; : ! ? and inside « quotes »." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="345.5" width="302.25" height="17.5" as="geometry"/></mxCell> |
| 436 | - <mxCell id="05-agents-panel-57" value="- Ne jamais traduire le code ni les noms propres." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="367.5" width="379.75" height="17.5" as="geometry"/></mxCell> | 436 | + <mxCell id="05-agents-panel-57" value="- Never translate code or proper names." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#1D1F24;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="535" y="367.5" width="302.25" height="17.5" as="geometry"/></mxCell> |
| 437 | <mxCell id="05-agents-panel-58" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1010" y="590" width="110" height="32" as="geometry"/></mxCell> | 437 | <mxCell id="05-agents-panel-58" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1010" y="590" width="110" height="32" as="geometry"/></mxCell> |
| 438 | - <mxCell id="05-agents-panel-59" value="Enregistrer" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1023.53" y="598.0" width="82.94" height="18" as="geometry"/></mxCell> | 438 | + <mxCell id="05-agents-panel-59" value="Save" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1049.92" y="598.0" width="30.159999999999997" height="18" as="geometry"/></mxCell> |
| 439 | <mxCell id="05-agents-panel-60" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1130" y="590" width="110" height="32" as="geometry"/></mxCell> | 439 | <mxCell id="05-agents-panel-60" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1130" y="590" width="110" height="32" as="geometry"/></mxCell> |
| 440 | - <mxCell id="05-agents-panel-61" value="Supprimer" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1151.07" y="598.0" width="67.86" height="18" as="geometry"/></mxCell> | 440 | + <mxCell id="05-agents-panel-61" value="Delete" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#D64561;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1162.38" y="598.0" width="45.239999999999995" height="18" as="geometry"/></mxCell> |
| 441 | <mxCell id="05-agents-panel-62" value="" style="rounded=0;fillColor=#111317;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="646" width="1009" height="188" as="geometry"/></mxCell> | 441 | <mxCell id="05-agents-panel-62" value="" style="rounded=0;fillColor=#111317;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="251" y="646" width="1009" height="188" as="geometry"/></mxCell> |
| 442 | <mxCell id="05-agents-panel-63" value="garfield $ ls skills" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#D7DAE0;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="659.5" width="155.0" height="17.5" as="geometry"/></mxCell> | 442 | <mxCell id="05-agents-panel-63" value="garfield $ ls skills" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#D7DAE0;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="659.5" width="155.0" height="17.5" as="geometry"/></mxCell> |
| 443 | <mxCell id="05-agents-panel-64" value="email-letter idioms styles technical-text" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#D7DAE0;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="679.5" width="341.0" height="17.5" as="geometry"/></mxCell> | 443 | <mxCell id="05-agents-panel-64" value="email-letter idioms styles technical-text" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12.5;fontColor=#D7DAE0;fontStyle=0;fontFamily=DejaVu Sans Mono;" vertex="1" parent="1"><mxGeometry x="265" y="679.5" width="341.0" height="17.5" as="geometry"/></mxCell> |
| @@ -449,38 +449,38 @@ | |||
| 449 | <mxCell id="05-agents-panel-70" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="569" y="186" width="24" height="24" as="geometry"/></mxCell> | 449 | <mxCell id="05-agents-panel-70" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="569" y="186" width="24" height="24" as="geometry"/></mxCell> |
| 450 | <mxCell id="05-agents-panel-71" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> | 450 | <mxCell id="05-agents-panel-71" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 451 | <mxCell id="05-agents-panel-72" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> | 451 | <mxCell id="05-agents-panel-72" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 452 | - <mxCell id="05-agents-panel-73" value="État et emplacement de l'agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> | 452 | + <mxCell id="05-agents-panel-73" value="The agent's state and location" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> |
| 453 | - <mxCell id="05-agents-panel-74" value="Statut temps réel (#11), runtime (local," style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="278.4" height="17" as="geometry"/></mxCell> | 453 | + <mxCell id="05-agents-panel-74" value="Live status (#11), runtime (local," style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="236.64" height="17" as="geometry"/></mxCell> |
| 454 | - <mxCell id="05-agents-panel-75" value="container, sbx), dossier et modèle." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="243.6" height="17" as="geometry"/></mxCell> | 454 | + <mxCell id="05-agents-panel-75" value="container, sbx), folder and model." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="236.64" height="17" as="geometry"/></mxCell> |
| 455 | <mxCell id="05-agents-panel-76" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> | 455 | <mxCell id="05-agents-panel-76" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 456 | <mxCell id="05-agents-panel-77" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> | 456 | <mxCell id="05-agents-panel-77" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 457 | - <mxCell id="05-agents-panel-78" value="Arbre du workspace" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="140.94" height="18.5" as="geometry"/></mxCell> | 457 | + <mxCell id="05-agents-panel-78" value="Workspace tree" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="109.61999999999999" height="18.5" as="geometry"/></mxCell> |
| 458 | - <mxCell id="05-agents-panel-79" value="Chargement paresseux, rafraîchi quand" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="257.52" height="17" as="geometry"/></mxCell> | 458 | + <mxCell id="05-agents-panel-79" value="Loaded lazily, refreshed when the" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="229.67999999999998" height="17" as="geometry"/></mxCell> |
| 459 | - <mxCell id="05-agents-panel-80" value="l'agent modifie un fichier (#29)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="229.67999999999998" height="17" as="geometry"/></mxCell> | 459 | + <mxCell id="05-agents-panel-80" value="agent changes a file (#29)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="187.92" height="17" as="geometry"/></mxCell> |
| 460 | <mxCell id="05-agents-panel-81" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="76" as="geometry"/></mxCell> | 460 | <mxCell id="05-agents-panel-81" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="76" as="geometry"/></mxCell> |
| 461 | <mxCell id="05-agents-panel-82" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> | 461 | <mxCell id="05-agents-panel-82" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 462 | - <mxCell id="05-agents-panel-83" value="Éditer, supprimer avec confirmation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="274.04999999999995" height="18.5" as="geometry"/></mxCell> | 462 | + <mxCell id="05-agents-panel-83" value="Edit, delete with confirmation" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="234.89999999999998" height="18.5" as="geometry"/></mxCell> |
| 463 | - <mxCell id="05-agents-panel-84" value="Même éditeur que Settings. Conflit signalé" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="292.32" height="17" as="geometry"/></mxCell> | 463 | + <mxCell id="05-agents-panel-84" value="Same editor as Settings. A conflict is" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="264.47999999999996" height="17" as="geometry"/></mxCell> |
| 464 | - <mxCell id="05-agents-panel-85" value="si l'agent modifie le fichier (#30)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="250.55999999999997" height="17" as="geometry"/></mxCell> | 464 | + <mxCell id="05-agents-panel-85" value="flagged if the agent changes the file (#30)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="306.23999999999995" height="17" as="geometry"/></mxCell> |
| 465 | <mxCell id="05-agents-panel-86" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="350" width="356" height="76" as="geometry"/></mxCell> | 465 | <mxCell id="05-agents-panel-86" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="350" width="356" height="76" as="geometry"/></mxCell> |
| 466 | <mxCell id="05-agents-panel-87" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="360" width="24" height="24" as="geometry"/></mxCell> | 466 | <mxCell id="05-agents-panel-87" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="360" width="24" height="24" as="geometry"/></mxCell> |
| 467 | - <mxCell id="05-agents-panel-88" value="Terminal sur le workspace" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="195.75" height="18.5" as="geometry"/></mxCell> | 467 | + <mxCell id="05-agents-panel-88" value="Terminal in the workspace" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="195.75" height="18.5" as="geometry"/></mxCell> |
| 468 | - <mxCell id="05-agents-panel-89" value="PTY local, docker exec ou sbx selon le" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 468 | + <mxCell id="05-agents-panel-89" value="Local PTY, docker exec or sbx depending on" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="292.32" height="17" as="geometry"/></mxCell> |
| 469 | - <mxCell id="05-agents-panel-90" value="runtime (#28, #31). Replié par défaut." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="264.47999999999996" height="17" as="geometry"/></mxCell> | 469 | + <mxCell id="05-agents-panel-90" value="the runtime (#28, #31). Folded by default." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="292.32" height="17" as="geometry"/></mxCell> |
| 470 | <mxCell id="05-agents-panel-91" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="440" width="356" height="76" as="geometry"/></mxCell> | 470 | <mxCell id="05-agents-panel-91" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="440" width="356" height="76" as="geometry"/></mxCell> |
| 471 | <mxCell id="05-agents-panel-92" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="450" width="24" height="24" as="geometry"/></mxCell> | 471 | <mxCell id="05-agents-panel-92" value="<b>5</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="450" width="24" height="24" as="geometry"/></mxCell> |
| 472 | - <mxCell id="05-agents-panel-93" value="Journal" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="453.5" width="54.809999999999995" height="18.5" as="geometry"/></mxCell> | 472 | + <mxCell id="05-agents-panel-93" value="Log" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="453.5" width="23.49" height="18.5" as="geometry"/></mxCell> |
| 473 | - <mxCell id="05-agents-panel-94" value="stderr de l'agent, pour comprendre" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="478" width="236.64" height="17" as="geometry"/></mxCell> | 473 | + <mxCell id="05-agents-panel-94" value="The agent's stderr, to understand" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="478" width="229.67999999999998" height="17" as="geometry"/></mxCell> |
| 474 | - <mxCell id="05-agents-panel-95" value="une erreur sans ouvrir un terminal." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="243.6" height="17" as="geometry"/></mxCell> | 474 | + <mxCell id="05-agents-panel-95" value="an error without opening a terminal." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="496" width="250.55999999999997" height="17" as="geometry"/></mxCell> |
| 475 | </root> | 475 | </root> |
| 476 | </mxGraphModel> | 476 | </mxGraphModel> |
| 477 | </diagram> | 477 | </diagram> |
| 478 | - <diagram id="06-first-launch" name="6 · Premier lancement"> | 478 | + <diagram id="06-first-launch" name="6 · First launch"> |
| 479 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> | 479 | <mxGraphModel dx="1660" dy="900" grid="1" gridSize="10" page="1" pageWidth="1660" pageHeight="900" math="0" shadow="0"> |
| 480 | <root> | 480 | <root> |
| 481 | <mxCell id="0"/> | 481 | <mxCell id="0"/> |
| 482 | <mxCell id="1" parent="0"/> | 482 | <mxCell id="1" parent="0"/> |
| 483 | - <mxCell id="06-first-launch-title" value="<b>6 · Premier lancement</b><br><i>Moins d'une minute pour savoir quoi faire, sans lire de documentation</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> | 483 | + <mxCell id="06-first-launch-title" value="<b>6 · First launch</b><br><i>Less than a minute to know what to do, without reading any documentation</i>" style="text;html=1;align=left;verticalAlign=top;fontSize=16;fontColor=#1A237E;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="20" y="10" width="1200" height="60" as="geometry"/></mxCell> |
| 484 | <mxCell id="06-first-launch-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> | 484 | <mxCell id="06-first-launch-1" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F6F6F7;strokeColor=#C9CBD1;strokeWidth=1;shadow=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="780" as="geometry"/></mxCell> |
| 485 | <mxCell id="06-first-launch-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> | 485 | <mxCell id="06-first-launch-2" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="80" width="1240" height="36" as="geometry"/></mxCell> |
| 486 | <mxCell id="06-first-launch-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> | 486 | <mxCell id="06-first-launch-3" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="104" width="1240" height="12" as="geometry"/></mxCell> |
| @@ -489,57 +489,57 @@ | |||
| 489 | <mxCell id="06-first-launch-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> | 489 | <mxCell id="06-first-launch-6" value="" style="ellipse;fillColor=#28C840;strokeColor=none;" vertex="1" parent="1"><mxGeometry x="74" y="92" width="12" height="12" as="geometry"/></mxCell> |
| 490 | <mxCell id="06-first-launch-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> | 490 | <mxCell id="06-first-launch-7" value="Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#6B6F7A;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="606.07" y="90" width="67.86" height="18" as="geometry"/></mxCell> |
| 491 | <mxCell id="06-first-launch-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> | 491 | <mxCell id="06-first-launch-8" value="" style="rounded=0;fillColor=#F0F1F3;strokeColor=none;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="20" y="834" width="1240" height="26" as="geometry"/></mxCell> |
| 492 | - <mxCell id="06-first-launch-9" value="○ aucun agent configuré · config : créée à l'emplacement par défaut" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="446.89" height="16.5" as="geometry"/></mxCell> | 492 | + <mxCell id="06-first-launch-9" value="○ no agent configured · config: created at the default location" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="32" y="839.5" width="420.21" height="16.5" as="geometry"/></mxCell> |
| 493 | <mxCell id="06-first-launch-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> | 493 | <mxCell id="06-first-launch-10" value="⚙︎ Settings ⌘K" style="text;html=1;align=right;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=11.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1141.28" y="839.5" width="106.72" height="16.5" as="geometry"/></mxCell> |
| 494 | - <mxCell id="06-first-launch-11" value="👋 Bienvenue dans Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=26;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="443.96000000000004" y="174" width="392.08" height="31" as="geometry"/></mxCell> | 494 | + <mxCell id="06-first-launch-11" value="👋 Welcome to Sidekicks" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=26;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="474.12" y="174" width="331.76" height="31" as="geometry"/></mxCell> |
| 495 | - <mxCell id="06-first-launch-12" value="Discutez avec des agents d'IA dans des channels, comme avec des collègues." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="318.1" y="219" width="643.8" height="20" as="geometry"/></mxCell> | 495 | + <mxCell id="06-first-launch-12" value="Talk with AI agents in channels, as you would with colleagues." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=15;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="370.3" y="219" width="539.4" height="20" as="geometry"/></mxCell> |
| 496 | <mxCell id="06-first-launch-13" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="280" width="800" height="76" as="geometry"/></mxCell> | 496 | <mxCell id="06-first-launch-13" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="280" width="800" height="76" as="geometry"/></mxCell> |
| 497 | <mxCell id="06-first-launch-14" value="<b>1</b>" style="ellipse;html=1;fillColor=#3B6FE0;strokeColor=none;fontColor=#FFFFFF;fontSize=16;" vertex="1" parent="1"><mxGeometry x="262" y="300" width="36" height="36" as="geometry"/></mxCell> | 497 | <mxCell id="06-first-launch-14" value="<b>1</b>" style="ellipse;html=1;fillColor=#3B6FE0;strokeColor=none;fontColor=#FFFFFF;fontSize=16;" vertex="1" parent="1"><mxGeometry x="262" y="300" width="36" height="36" as="geometry"/></mxCell> |
| 498 | <mxCell id="06-first-launch-15" value="1" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="270.0" y="308" width="20" height="21" as="geometry"/></mxCell> | 498 | <mxCell id="06-first-launch-15" value="1" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="270.0" y="308" width="20" height="21" as="geometry"/></mxCell> |
| 499 | - <mxCell id="06-first-launch-16" value="Ajoutez un agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="296" width="148.48" height="21" as="geometry"/></mxCell> | 499 | + <mxCell id="06-first-launch-16" value="Add an agent" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="296" width="111.35999999999999" height="21" as="geometry"/></mxCell> |
| 500 | - <mxCell id="06-first-launch-17" value="Un assistant qui tourne sur votre ordinateur, par exemple avec mm." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="322.5" width="516.78" height="18.5" as="geometry"/></mxCell> | 500 | + <mxCell id="06-first-launch-17" value="An assistant that runs on your computer, for example with mm." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="322.5" width="477.63" height="18.5" as="geometry"/></mxCell> |
| 501 | <mxCell id="06-first-launch-18" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="372" width="800" height="76" as="geometry"/></mxCell> | 501 | <mxCell id="06-first-launch-18" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="372" width="800" height="76" as="geometry"/></mxCell> |
| 502 | <mxCell id="06-first-launch-19" value="<b>2</b>" style="ellipse;html=1;fillColor=#3B6FE0;strokeColor=none;fontColor=#FFFFFF;fontSize=16;" vertex="1" parent="1"><mxGeometry x="262" y="392" width="36" height="36" as="geometry"/></mxCell> | 502 | <mxCell id="06-first-launch-19" value="<b>2</b>" style="ellipse;html=1;fillColor=#3B6FE0;strokeColor=none;fontColor=#FFFFFF;fontSize=16;" vertex="1" parent="1"><mxGeometry x="262" y="392" width="36" height="36" as="geometry"/></mxCell> |
| 503 | <mxCell id="06-first-launch-20" value="2" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="270.0" y="400" width="20" height="21" as="geometry"/></mxCell> | 503 | <mxCell id="06-first-launch-20" value="2" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="270.0" y="400" width="20" height="21" as="geometry"/></mxCell> |
| 504 | - <mxCell id="06-first-launch-21" value="Ouvrez un channel" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="388" width="157.76" height="21" as="geometry"/></mxCell> | 504 | + <mxCell id="06-first-launch-21" value="Open a channel" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="388" width="129.92" height="21" as="geometry"/></mxCell> |
| 505 | - <mxCell id="06-first-launch-22" value="#général est déjà prêt. Créez-en d'autres par sujet." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="414.5" width="407.15999999999997" height="18.5" as="geometry"/></mxCell> | 505 | + <mxCell id="06-first-launch-22" value="#general is ready. Create others, one per topic." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="414.5" width="375.84" height="18.5" as="geometry"/></mxCell> |
| 506 | <mxCell id="06-first-launch-23" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="464" width="800" height="76" as="geometry"/></mxCell> | 506 | <mxCell id="06-first-launch-23" value="" style="rounded=1;absoluteArcSize=1;arcSize=24;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="464" width="800" height="76" as="geometry"/></mxCell> |
| 507 | <mxCell id="06-first-launch-24" value="<b>3</b>" style="ellipse;html=1;fillColor=#3B6FE0;strokeColor=none;fontColor=#FFFFFF;fontSize=16;" vertex="1" parent="1"><mxGeometry x="262" y="484" width="36" height="36" as="geometry"/></mxCell> | 507 | <mxCell id="06-first-launch-24" value="<b>3</b>" style="ellipse;html=1;fillColor=#3B6FE0;strokeColor=none;fontColor=#FFFFFF;fontSize=16;" vertex="1" parent="1"><mxGeometry x="262" y="484" width="36" height="36" as="geometry"/></mxCell> |
| 508 | <mxCell id="06-first-launch-25" value="3" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="270.0" y="492" width="20" height="21" as="geometry"/></mxCell> | 508 | <mxCell id="06-first-launch-25" value="3" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="270.0" y="492" width="20" height="21" as="geometry"/></mxCell> |
| 509 | - <mxCell id="06-first-launch-26" value="Appelez-le avec @" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="480" width="157.76" height="21" as="geometry"/></mxCell> | 509 | + <mxCell id="06-first-launch-26" value="Call it with @" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=16;fontColor=#1D1F24;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="316" y="480" width="129.92" height="21" as="geometry"/></mxCell> |
| 510 | - <mxCell id="06-first-launch-27" value="« @alice bonjour » : Alice rejoint le channel et vous répond." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="506.5" width="477.63" height="18.5" as="geometry"/></mxCell> | 510 | + <mxCell id="06-first-launch-27" value=""@alice hello": Alice joins the channel and answers you." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="316" y="506.5" width="438.47999999999996" height="18.5" as="geometry"/></mxCell> |
| 511 | <mxCell id="06-first-launch-28" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="420" y="570" width="240" height="40" as="geometry"/></mxCell> | 511 | <mxCell id="06-first-launch-28" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#3B6FE0;strokeColor=#3B6FE0;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="420" y="570" width="240" height="40" as="geometry"/></mxCell> |
| 512 | - <mxCell id="06-first-launch-29" value="+ Ajouter mon premier agent" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="438.21000000000004" y="582.0" width="203.57999999999998" height="18" as="geometry"/></mxCell> | 512 | + <mxCell id="06-first-launch-29" value="+ Add my first agent" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#FFFFFF;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="464.6" y="582.0" width="150.79999999999998" height="18" as="geometry"/></mxCell> |
| 513 | <mxCell id="06-first-launch-30" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="680" y="570" width="200" height="40" as="geometry"/></mxCell> | 513 | <mxCell id="06-first-launch-30" value="" style="rounded=1;absoluteArcSize=1;arcSize=12;fillColor=#FFFFFF;strokeColor=#E2E3E6;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="680" y="570" width="200" height="40" as="geometry"/></mxCell> |
| 514 | - <mxCell id="06-first-launch-31" value="Ouvrir une configuration…" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="685.75" y="582.0" width="188.5" height="18" as="geometry"/></mxCell> | 514 | + <mxCell id="06-first-launch-31" value="Open a configuration…" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="700.83" y="582.0" width="158.33999999999997" height="18" as="geometry"/></mxCell> |
| 515 | - <mxCell id="06-first-launch-32" value="Configuration : ~/Library/Application Support/sidekicks/config.yaml (créée pour vous, commentée)" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="305.92" y="638" width="668.16" height="17" as="geometry"/></mxCell> | 515 | + <mxCell id="06-first-launch-32" value="Configuration: ~/Library/Application Support/sidekicks/config.yaml (created for you, with comments)" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#6B6F7A;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="295.48" y="638" width="689.04" height="17" as="geometry"/></mxCell> |
| 516 | <mxCell id="06-first-launch-33" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="680" width="800" height="70" as="geometry"/></mxCell> | 516 | <mxCell id="06-first-launch-33" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#FDECEF;strokeColor=#D64561;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="240" y="680" width="800" height="70" as="geometry"/></mxCell> |
| 517 | - <mxCell id="06-first-launch-34" value="La commande « mm » est introuvable." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#D64561;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="260" y="694" width="284.2" height="19" as="geometry"/></mxCell> | 517 | + <mxCell id="06-first-launch-34" value="The command "mm" cannot be found." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=14;fontColor=#D64561;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="260" y="694" width="267.96" height="19" as="geometry"/></mxCell> |
| 518 | - <mxCell id="06-first-launch-35" value="Installez-la (lien vers le guide) ou choisissez un autre programme pour cet agent." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="260" y="719" width="618.28" height="18" as="geometry"/></mxCell> | 518 | + <mxCell id="06-first-launch-35" value="Install it (link to the guide) or choose another program for this agent." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13;fontColor=#1D1F24;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="260" y="719" width="542.88" height="18" as="geometry"/></mxCell> |
| 519 | <mxCell id="06-first-launch-36" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1040" y="300" width="24" height="24" as="geometry"/></mxCell> | 519 | <mxCell id="06-first-launch-36" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1040" y="300" width="24" height="24" as="geometry"/></mxCell> |
| 520 | <mxCell id="06-first-launch-37" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="880" y="578" width="24" height="24" as="geometry"/></mxCell> | 520 | <mxCell id="06-first-launch-37" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="880" y="578" width="24" height="24" as="geometry"/></mxCell> |
| 521 | <mxCell id="06-first-launch-38" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1018.0" y="634" width="24" height="24" as="geometry"/></mxCell> | 521 | <mxCell id="06-first-launch-38" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1018.0" y="634" width="24" height="24" as="geometry"/></mxCell> |
| 522 | <mxCell id="06-first-launch-39" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1040" y="688" width="24" height="24" as="geometry"/></mxCell> | 522 | <mxCell id="06-first-launch-39" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1040" y="688" width="24" height="24" as="geometry"/></mxCell> |
| 523 | <mxCell id="06-first-launch-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> | 523 | <mxCell id="06-first-launch-40" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="80" width="356" height="76" as="geometry"/></mxCell> |
| 524 | <mxCell id="06-first-launch-41" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> | 524 | <mxCell id="06-first-launch-41" value="<b>1</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="90" width="24" height="24" as="geometry"/></mxCell> |
| 525 | - <mxCell id="06-first-launch-42" value="Trois étapes, pas plus" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="172.26" height="18.5" as="geometry"/></mxCell> | 525 | + <mxCell id="06-first-launch-42" value="Three steps, no more" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="93.5" width="156.6" height="18.5" as="geometry"/></mxCell> |
| 526 | - <mxCell id="06-first-launch-43" value="L'état vide explique le modèle mental :" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="271.44" height="17" as="geometry"/></mxCell> | 526 | + <mxCell id="06-first-launch-43" value="The empty state explains the mental model:" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="118" width="292.32" height="17" as="geometry"/></mxCell> |
| 527 | <mxCell id="06-first-launch-44" value="agents, channels, @ (#33)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="180.95999999999998" height="17" as="geometry"/></mxCell> | 527 | <mxCell id="06-first-launch-44" value="agents, channels, @ (#33)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="136" width="180.95999999999998" height="17" as="geometry"/></mxCell> |
| 528 | <mxCell id="06-first-launch-45" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> | 528 | <mxCell id="06-first-launch-45" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="170" width="356" height="76" as="geometry"/></mxCell> |
| 529 | <mxCell id="06-first-launch-46" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> | 529 | <mxCell id="06-first-launch-46" value="<b>2</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="180" width="24" height="24" as="geometry"/></mxCell> |
| 530 | - <mxCell id="06-first-launch-47" value="Un assistant plutôt que du YAML" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="242.73" height="18.5" as="geometry"/></mxCell> | 530 | + <mxCell id="06-first-launch-47" value="An assistant rather than YAML" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="183.5" width="227.07" height="18.5" as="geometry"/></mxCell> |
| 531 | - <mxCell id="06-first-launch-48" value="Le formulaire écrit le YAML à la place de" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="285.35999999999996" height="17" as="geometry"/></mxCell> | 531 | + <mxCell id="06-first-launch-48" value="The form writes the YAML for the user;" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="208" width="264.47999999999996" height="17" as="geometry"/></mxCell> |
| 532 | - <mxCell id="06-first-launch-49" value="l'utilisateur ; Settings reste accessible." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="292.32" height="17" as="geometry"/></mxCell> | 532 | + <mxCell id="06-first-launch-49" value="Settings stays at hand." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="226" width="160.07999999999998" height="17" as="geometry"/></mxCell> |
| 533 | <mxCell id="06-first-launch-50" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="76" as="geometry"/></mxCell> | 533 | <mxCell id="06-first-launch-50" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="260" width="356" height="76" as="geometry"/></mxCell> |
| 534 | <mxCell id="06-first-launch-51" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> | 534 | <mxCell id="06-first-launch-51" value="<b>3</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="270" width="24" height="24" as="geometry"/></mxCell> |
| 535 | - <mxCell id="06-first-launch-52" value="Rien à créer à la main" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="172.26" height="18.5" as="geometry"/></mxCell> | 535 | + <mxCell id="06-first-launch-52" value="Nothing to create by hand" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="273.5" width="195.75" height="18.5" as="geometry"/></mxCell> |
| 536 | - <mxCell id="06-first-launch-53" value="Le fichier par défaut existe déjà, avec des" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="299.28" height="17" as="geometry"/></mxCell> | 536 | + <mxCell id="06-first-launch-53" value="The default file already exists, with" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="298" width="257.52" height="17" as="geometry"/></mxCell> |
| 537 | - <mxCell id="06-first-launch-54" value="commentaires (#9)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="125.27999999999999" height="17" as="geometry"/></mxCell> | 537 | + <mxCell id="06-first-launch-54" value="comments (#9)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="316" width="97.44" height="17" as="geometry"/></mxCell> |
| 538 | <mxCell id="06-first-launch-55" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="350" width="356" height="76" as="geometry"/></mxCell> | 538 | <mxCell id="06-first-launch-55" value="" style="rounded=1;absoluteArcSize=1;arcSize=20;fillColor=#F3E5F5;strokeColor=#6A1B9A;strokeWidth=1;html=1;" vertex="1" parent="1"><mxGeometry x="1284" y="350" width="356" height="76" as="geometry"/></mxCell> |
| 539 | <mxCell id="06-first-launch-56" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="360" width="24" height="24" as="geometry"/></mxCell> | 539 | <mxCell id="06-first-launch-56" value="<b>4</b>" style="ellipse;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=13;" vertex="1" parent="1"><mxGeometry x="1294" y="360" width="24" height="24" as="geometry"/></mxCell> |
| 540 | - <mxCell id="06-first-launch-57" value="Erreurs humaines" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="125.27999999999999" height="18.5" as="geometry"/></mxCell> | 540 | + <mxCell id="06-first-launch-57" value="Human errors" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=13.5;fontColor=#4A148C;fontStyle=1;" vertex="1" parent="1"><mxGeometry x="1328" y="363.5" width="93.96" height="18.5" as="geometry"/></mxCell> |
| 541 | - <mxCell id="06-first-launch-58" value="Dire ce qui ne va pas et quoi faire ;" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="257.52" height="17" as="geometry"/></mxCell> | 541 | + <mxCell id="06-first-launch-58" value="Say what is wrong and what to do;" style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="388" width="229.67999999999998" height="17" as="geometry"/></mxCell> |
| 542 | - <mxCell id="06-first-launch-59" value="jamais de trace technique (#33)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="222.71999999999997" height="17" as="geometry"/></mxCell> | 542 | + <mxCell id="06-first-launch-59" value="never a technical trace (#33)." style="text;html=1;align=left;verticalAlign=middle;strokeColor=none;fillColor=none;spacing=0;fontSize=12;fontColor=#4A148C;fontStyle=0;" vertex="1" parent="1"><mxGeometry x="1300" y="406" width="208.79999999999998" height="17" as="geometry"/></mxCell> |
| 543 | </root> | 543 | </root> |
| 544 | </mxGraphModel> | 544 | </mxGraphModel> |
| 545 | </diagram> | 545 | </diagram> |
modified
docs/design/wireframes.py +97 -97 | @@ -98,7 +98,7 @@ class Screen: | ||
| 98 | 98 | |
| 99 | 99 | # -- common pieces of the window ------------------------------------------------- |
| 100 | 100 | |
| 101 | - def window(self, status="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml"): | |
| 101 | + def window(self, status="● 2 of 2 agents running · config: ~/agents/team.yaml"): | |
| 102 | 102 | """The window chrome: title bar, left dock, status bar.""" |
| 103 | 103 | self.rect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, BG, "#C9CBD1", rx=12, shadow=True) |
| 104 | 104 | self.rect(FRAME_X, FRAME_Y, FRAME_W, 36, PANEL2, None, rx=12) |
| @@ -111,12 +111,12 @@ class Screen: | ||
| 111 | 111 | self.text(FRAME_X + 12, FRAME_Y + FRAME_H - 9, status, 11.5, MUTED) |
| 112 | 112 | self.text(FRAME_X + FRAME_W - 12, FRAME_Y + FRAME_H - 9, "⚙︎ Settings ⌘K", 11.5, MUTED, anchor="end") |
| 113 | 113 | |
| 114 | - def left_dock(self, active="général", agents=(("alice", "👩 Alice", OK), ("bob", "🧔 Bob", OK), ("riker", "🧑🚀 Riker", MUTED), ("garfield", "🐮 Garfield", WARN))): | |
| 114 | + def left_dock(self, active="general", agents=(("alice", "👩 Alice", OK), ("bob", "🧔 Bob", OK), ("riker", "🧑🚀 Riker", MUTED), ("garfield", "🐮 Garfield", WARN))): | |
| 115 | 115 | x, y = FRAME_X, FRAME_Y + 36 |
| 116 | 116 | self.rect(x, y, 230, FRAME_H - 62, PANEL, BORDER) |
| 117 | 117 | self.text(x + 16, y + 28, "CHANNELS", 11, MUTED, bold=True) |
| 118 | 118 | self.text(x + 214, y + 28, "+", 16, MUTED, bold=True, anchor="end") |
| 119 | - for index, name in enumerate(("général", "traductions", "code")): | |
| 119 | + for index, name in enumerate(("general", "translations", "code")): | |
| 120 | 120 | top = y + 42 + index * 30 |
| 121 | 121 | if name == active: |
| 122 | 122 | self.rect(x + 8, top, 214, 26, PANEL2, None, rx=6) |
| @@ -136,7 +136,7 @@ class Screen: | ||
| 136 | 136 | self.lines(x, y + 22, lines, 13.5) |
| 137 | 137 | return y + 22 + 20 * len(lines) + 14 |
| 138 | 138 | |
| 139 | - def composer(self, x, y, w, value, hint="Entrée pour envoyer · Maj+Entrée nouvelle ligne"): | |
| 139 | + def composer(self, x, y, w, value, hint="Enter to send · Shift+Enter for a new line"): | |
| 140 | 140 | self.rect(x, y, w, 64, PANEL, ACCENT, rx=10, width=1.5) |
| 141 | 141 | self.text(x + 14, y + 26, value, 14) |
| 142 | 142 | self.text(x + 14, y + 50, hint, 11, MUTED) |
| @@ -163,98 +163,98 @@ CENTER_W = FRAME_W - 231 | ||
| 163 | 163 | |
| 164 | 164 | |
| 165 | 165 | def screen_layout(): |
| 166 | - s = Screen("01-layout", "1 · Layout global", "Docks façon Zed, mais seul l'essentiel est visible par défaut") | |
| 166 | + s = Screen("01-layout", "1 · Overall layout", "Zed-like docks, but only the essentials are visible by default") | |
| 167 | 167 | s.window() |
| 168 | 168 | s.left_dock() |
| 169 | 169 | s.rect(CENTER_X, FRAME_Y + 36, CENTER_W - 300, 44, PANEL, BORDER) |
| 170 | - s.text(CENTER_X + 16, FRAME_Y + 64, "# général", 15, bold=True) | |
| 170 | + s.text(CENTER_X + 16, FRAME_Y + 64, "# general", 15, bold=True) | |
| 171 | 171 | s.text(CENTER_X + CENTER_W - 316, FRAME_Y + 64, "👩 Alice · 🧔 Bob", 13, MUTED, anchor="end") |
| 172 | - y = s.message(CENTER_X + 24, FRAME_Y + 116, "Vous", TEXT, ["@alice résume-moi ce que fait ACP en deux phrases"]) | |
| 173 | - y = s.message(CENTER_X + 24, y, "👩 Alice", AGENT_COLOURS["alice"], ["ACP est un protocole qui permet à une application de dialoguer avec", "n'importe quel agent d'IA. Sidekicks l'utilise pour rester agnostique."]) | |
| 174 | - s.composer(CENTER_X + 20, FRAME_Y + FRAME_H - 136, CENTER_W - 340, "Écrivez un message… (@ pour un agent, / pour une commande)") | |
| 172 | + y = s.message(CENTER_X + 24, FRAME_Y + 116, "You", TEXT, ["@alice sum up what ACP does in two sentences"]) | |
| 173 | + y = s.message(CENTER_X + 24, y, "👩 Alice", AGENT_COLOURS["alice"], ["ACP is a protocol that lets an application talk with any AI agent.", "Sidekicks uses it to stay agent-agnostic."]) | |
| 174 | + s.composer(CENTER_X + 20, FRAME_Y + FRAME_H - 136, CENTER_W - 340, "Write a message… (@ for an agent, / for a command)") | |
| 175 | 175 | # Right dock (Settings), shown here opened. |
| 176 | 176 | s.rect(FRAME_X + FRAME_W - 300, FRAME_Y + 36, 300, FRAME_H - 62, PANEL, BORDER) |
| 177 | - s.text(FRAME_X + FRAME_W - 284, FRAME_Y + 64, "⚙︎ Settings — equipe.yaml", 13, MUTED, bold=True) | |
| 177 | + s.text(FRAME_X + FRAME_W - 284, FRAME_Y + 64, "⚙︎ Settings — team.yaml", 13, MUTED, bold=True) | |
| 178 | 178 | s.rect(FRAME_X + FRAME_W - 290, FRAME_Y + 80, 280, 300, CODE, BORDER, rx=6) |
| 179 | - s.lines(FRAME_X + FRAME_W - 280, FRAME_Y + 104, ["version: 1", "agents:", " - name: alice", " title: Alice", " command: mm", " args: [-acp, ...]", "channels:", " - name: général", " agents: [alice, bob]"], 12, TEXT, gap=19, mono=True) | |
| 180 | - s.text(FRAME_X + FRAME_W - 284, FRAME_Y + 410, "✓ Configuration valide", 12.5, OK, bold=True) | |
| 181 | - s.button(FRAME_X + FRAME_W - 290, FRAME_Y + 428, 120, "Enregistrer", primary=True) | |
| 179 | + s.lines(FRAME_X + FRAME_W - 280, FRAME_Y + 104, ["version: 1", "agents:", " - name: alice", " title: Alice", " command: mm", " args: [-acp, ...]", "channels:", " - name: general", " agents: [alice, bob]"], 12, TEXT, gap=19, mono=True) | |
| 180 | + s.text(FRAME_X + FRAME_W - 284, FRAME_Y + 410, "✓ Valid configuration", 12.5, OK, bold=True) | |
| 181 | + s.button(FRAME_X + FRAME_W - 290, FRAME_Y + 428, 120, "Save", primary=True) | |
| 182 | 182 | # Collapsed bottom dock. |
| 183 | 183 | s.rect(CENTER_X, FRAME_Y + FRAME_H - 26 - 30, CENTER_W - 300, 30, PANEL2, BORDER) |
| 184 | - s.text(CENTER_X + 14, FRAME_Y + FRAME_H - 36, "▸ Terminal · Fichiers (repliés)", 12, MUTED) | |
| 184 | + s.text(CENTER_X + 14, FRAME_Y + FRAME_H - 36, "▸ Terminal · Files (folded)", 12, MUTED) | |
| 185 | 185 | s.badge(FRAME_X + 200, FRAME_Y + 62, 1) |
| 186 | 186 | s.badge(CENTER_X + 120, FRAME_Y + 160, 2) |
| 187 | 187 | s.badge(FRAME_X + FRAME_W - 30, FRAME_Y + 60, 3) |
| 188 | 188 | s.badge(CENTER_X + 330, FRAME_Y + FRAME_H - 41, 4) |
| 189 | 189 | s.badge(FRAME_X + 420, FRAME_Y + FRAME_H - 13, 5) |
| 190 | 190 | s.notes([ |
| 191 | - (1, "Dock gauche : channels et agents", ["Toujours visible. La pastille donne l'état de", "l'agent : vert prêt, orange occupé, gris arrêté."]), | |
| 192 | - (2, "Centre : la conversation", ["Le seul panel indispensable. Pleine largeur", "quand les docks sont repliés."]), | |
| 193 | - (3, "Dock droit : Settings", ["Éditeur YAML (CodeMirror) avec validation", "en direct. Fermé par défaut ; s'ouvre", "par ⚙︎ ou ⌘,."]), | |
| 194 | - (4, "Dock bas : terminal et fichiers", ["Replié par défaut : utile aux curieux,", "jamais imposé au citizen user."]), | |
| 195 | - (5, "Barre d'état", ["Rappelle la limite d'agents simultanés", "(mémoire) et la configuration ouverte."]), | |
| 191 | + (1, "Left dock: channels and agents", ["Always visible. The dot gives the agent's", "state: green ready, orange busy, grey stopped."]), | |
| 192 | + (2, "Centre: the conversation", ["The only panel you cannot do without.", "Full width when the docks are folded."]), | |
| 193 | + (3, "Right dock: Settings", ["YAML editor (CodeMirror) with live", "validation. Closed by default; opens", "with ⚙︎ or ⌘,."]), | |
| 194 | + (4, "Bottom dock: terminal and files", ["Folded by default: there for the curious,", "never forced on the citizen user."]), | |
| 195 | + (5, "Status bar", ["Shows the limit of agents running at once", "(memory) and the open configuration."]), | |
| 196 | 196 | ]) |
| 197 | 197 | return s |
| 198 | 198 | |
| 199 | 199 | |
| 200 | 200 | def screen_conversation(): |
| 201 | - s = Screen("02-conversation", "2 · Conversation multi-agents", "Chaque agent a sa couleur ; les outils sont repliés ; on peut toujours arrêter") | |
| 201 | + s = Screen("02-conversation", "2 · Multi-agent conversation", "Each agent has its colour; tools are folded; you can always stop") | |
| 202 | 202 | s.window() |
| 203 | 203 | s.left_dock() |
| 204 | 204 | s.rect(CENTER_X, FRAME_Y + 36, CENTER_W, 44, PANEL, BORDER) |
| 205 | - s.text(CENTER_X + 16, FRAME_Y + 64, "# général", 15, bold=True) | |
| 205 | + s.text(CENTER_X + 16, FRAME_Y + 64, "# general", 15, bold=True) | |
| 206 | 206 | s.text(CENTER_X + CENTER_W - 16, FRAME_Y + 64, "👩 Alice · 🧔 Bob · 🧑🚀 Riker", 13, MUTED, anchor="end") |
| 207 | 207 | x = CENTER_X + 24 |
| 208 | - y = s.message(x, FRAME_Y + 116, "", "", ["— Riker a rejoint le channel —"], system=True) | |
| 209 | - y = s.message(x, y + 6, "Vous", TEXT, ["@alice propose un nom pour un script qui sauvegarde mes photos"]) | |
| 210 | - y = s.message(x, y, "👩 Alice", AGENT_COLOURS["alice"], ["Je propose « photo-backup.sh » : court, explicite, et l'extension dit que", "c'est un script shell."]) | |
| 211 | - y = s.message(x, y, "Vous", TEXT, ["@bob tu valides ? @riker crée le fichier vide"]) | |
| 212 | - y = s.message(x, y, "🧔 Bob", AGENT_COLOURS["bob"], ["Bon choix. Alice a raison : un nom en minuscules, sans espace."]) | |
| 208 | + y = s.message(x, FRAME_Y + 116, "", "", ["— Riker joined the channel —"], system=True) | |
| 209 | + y = s.message(x, y + 6, "You", TEXT, ["@alice suggest a name for a script that backs up my photos"]) | |
| 210 | + y = s.message(x, y, "👩 Alice", AGENT_COLOURS["alice"], ["I suggest \"photo-backup.sh\": short, clear, and the extension says", "it is a shell script."]) | |
| 211 | + y = s.message(x, y, "You", TEXT, ["@bob do you agree? @riker create the empty file"]) | |
| 212 | + y = s.message(x, y, "🧔 Bob", AGENT_COLOURS["bob"], ["Good choice. Alice is right: a lowercase name, no spaces."]) | |
| 213 | 213 | s.text(x, y, "🧑🚀 Riker", 13.5, AGENT_COLOURS["riker"], bold=True) |
| 214 | - s.text(x + 90, y, "travaille…", 12.5, MUTED, italic=True) | |
| 214 | + s.text(x + 90, y, "working…", 12.5, MUTED, italic=True) | |
| 215 | 215 | s.rect(x, y + 12, 560, 40, PANEL2, BORDER, rx=8) |
| 216 | - s.text(x + 14, y + 37, "▸ 🛠 write_file : photo-backup.sh (0 octet) ✓ terminé", 12.5, TEXT) | |
| 216 | + s.text(x + 14, y + 37, "▸ 🛠 write_file: photo-backup.sh (0 bytes) ✓ done", 12.5, TEXT) | |
| 217 | 217 | s.rect(x, y + 60, 560, 40, PANEL2, BORDER, rx=8) |
| 218 | - s.text(x + 14, y + 85, "▸ 🛠 bash : ls -la … en cours", 12.5, TEXT) | |
| 218 | + s.text(x + 14, y + 85, "▸ 🛠 bash: ls -la … running", 12.5, TEXT) | |
| 219 | 219 | s.composer(CENTER_X + 20, FRAME_Y + FRAME_H - 106, CENTER_W - 160, "") |
| 220 | - s.button(CENTER_X + CENTER_W - 128, FRAME_Y + FRAME_H - 90, 108, "■ Arrêter", danger=True) | |
| 220 | + s.button(CENTER_X + CENTER_W - 128, FRAME_Y + FRAME_H - 90, 108, "■ Stop", danger=True) | |
| 221 | 221 | s.rect(CENTER_X + CENTER_W - 220, FRAME_Y + 96, 200, 30, PANEL2, BORDER, rx=15) |
| 222 | - s.text(CENTER_X + CENTER_W - 120, FRAME_Y + 116, "contexte Riker : 41 %", 11.5, MUTED, anchor="middle") | |
| 222 | + s.text(CENTER_X + CENTER_W - 120, FRAME_Y + 116, "Riker's context: 41%", 11.5, MUTED, anchor="middle") | |
| 223 | 223 | s.badge(x + 300, FRAME_Y + 111, 1) |
| 224 | 224 | s.badge(x + 80, FRAME_Y + 194, 2) |
| 225 | 225 | s.badge(x + 580, y + 32, 3) |
| 226 | 226 | s.badge(CENTER_X + CENTER_W - 140, FRAME_Y + FRAME_H - 90, 4) |
| 227 | 227 | s.badge(CENTER_X + CENTER_W - 232, FRAME_Y + 111, 5) |
| 228 | 228 | s.notes([ |
| 229 | - (1, "Arrivée visible", ["La 1re mention invite l'agent : un message", "système le dit. On sait qui « écoute »."]), | |
| 230 | - (2, "Une couleur par agent", ["Avatar + nom colorés, réponses en Markdown", "avec code coloré (ADR 0002)."]), | |
| 231 | - (3, "Outils repliés", ["Une ligne par tool call : titre lisible et", "statut. Déplier montre la commande, le", "diff ou la sortie."]), | |
| 232 | - (4, "Toujours un bouton Arrêter", ["Envoie session/cancel aux agents qui", "répondent dans ce channel (ADR 0001)."]), | |
| 233 | - (5, "Jauge de contexte", ["usage_update : prévient avant que la", "conversation ne dépasse la mémoire de", "l'agent."]), | |
| 229 | + (1, "A visible arrival", ["The first mention invites the agent: a system", "message says so. You know who is listening."]), | |
| 230 | + (2, "One colour per agent", ["Coloured avatar and name, answers in", "Markdown with highlighted code (ADR 0002)."]), | |
| 231 | + (3, "Folded tools", ["One line per tool call: a readable title", "and its status. Unfolding shows the", "command, the diff or the output."]), | |
| 232 | + (4, "Always a Stop button", ["Sends session/cancel to the agents", "answering in this channel (ADR 0001)."]), | |
| 233 | + (5, "Context gauge", ["usage_update: warns before the", "conversation outgrows the agent's", "memory."]), | |
| 234 | 234 | ]) |
| 235 | 235 | return s |
| 236 | 236 | |
| 237 | 237 | |
| 238 | 238 | def screen_popups(): |
| 239 | - s = Screen("03-mentions-commands", "3 · Invoquer un agent (@) et une commande (/)", "Tab choisit la suggestion ; continuer à écrire filtre la liste") | |
| 239 | + s = Screen("03-mentions-commands", "3 · Calling an agent (@) and a command (/)", "Tab picks the suggestion; typing on filters the list") | |
| 240 | 240 | s.window() |
| 241 | 241 | s.left_dock() |
| 242 | 242 | x, w = CENTER_X + 20, CENTER_W - 40 |
| 243 | 243 | # @ popup (top half). |
| 244 | - s.text(x, FRAME_Y + 70, "Mention d'un agent", 14, MUTED, bold=True) | |
| 244 | + s.text(x, FRAME_Y + 70, "Mentioning an agent", 14, MUTED, bold=True) | |
| 245 | 245 | s.rect(x, FRAME_Y + 84, 420, 150, PANEL, BORDER, rx=10, shadow=True) |
| 246 | - rows = [("🐮 garfield", "Garfield (traducteur) — traduit FR ⇄ EN", True), ("🧑🚀 riker", "Riker (outils) — commandes et fichiers", False), ("👩 alice", "Alice (assistante) — questions simples", False)] | |
| 246 | + rows = [("🐮 garfield", "Garfield (translator) — translates FR ⇄ EN", True), ("🧑🚀 riker", "Riker (tools) — commands and files", False), ("👩 alice", "Alice (assistant) — simple questions", False)] | |
| 247 | 247 | for index, (name, description, selected) in enumerate(rows): |
| 248 | 248 | top = FRAME_Y + 92 + index * 44 |
| 249 | 249 | if selected: |
| 250 | 250 | s.rect(x + 6, top, 408, 40, "#E8EFFD", None, rx=6) |
| 251 | 251 | s.text(x + 18, top + 18, name, 13.5, TEXT, bold=True) |
| 252 | 252 | s.text(x + 18, top + 34, description, 11.5, MUTED) |
| 253 | - s.composer(x, FRAME_Y + 244, w, "@ga", "Tab : @garfield · ↑↓ naviguer · Échap fermer") | |
| 253 | + s.composer(x, FRAME_Y + 244, w, "@ga", "Tab: @garfield · ↑↓ move · Esc close") | |
| 254 | 254 | # / popup (bottom half). |
| 255 | - s.text(x, FRAME_Y + 360, "Commande d'un agent (plusieurs agents dans le channel)", 14, MUTED, bold=True) | |
| 255 | + s.text(x, FRAME_Y + 360, "An agent's command (several agents in the channel)", 14, MUTED, bold=True) | |
| 256 | 256 | s.rect(x, FRAME_Y + 374, 520, 196, PANEL, BORDER, rx=10, shadow=True) |
| 257 | - commands = [("/garfield:idioms", "Expressions idiomatiques et faux amis", "[texte]", True), ("/garfield:styles", "Plusieurs versions d'une traduction", "[texte]", False), ("/garfield:email-letter", "E-mails et lettres : formules, tu ou vous", "[texte]", False), ("/alice:compact", "Résumer l'historique maintenant", "", False)] | |
| 257 | + commands = [("/garfield:idioms", "Idioms and false friends", "[text]", True), ("/garfield:styles", "Several versions of a translation", "[text]", False), ("/garfield:email-letter", "E-mails and letters: greetings, tu or vous", "[text]", False), ("/alice:compact", "Summarise the history now", "", False)] | |
| 258 | 258 | for index, (name, description, hint, selected) in enumerate(commands): |
| 259 | 259 | top = FRAME_Y + 382 + index * 46 |
| 260 | 260 | if selected: |
| @@ -262,90 +262,90 @@ def screen_popups(): | ||
| 262 | 262 | s.text(x + 18, top + 19, name, 13.5, TEXT, bold=True, mono=True) |
| 263 | 263 | s.text(x + 500, top + 19, hint, 11.5, MUTED, anchor="end", mono=True) |
| 264 | 264 | s.text(x + 18, top + 36, description, 11.5, MUTED) |
| 265 | - s.composer(x, FRAME_Y + 580, w, "/gar", "Tab : /garfield:idioms · le texte après la commande est son argument") | |
| 265 | + s.composer(x, FRAME_Y + 580, w, "/gar", "Tab: /garfield:idioms · the text after the command is its argument") | |
| 266 | 266 | s.badge(x + 434, FRAME_Y + 100, 1) |
| 267 | 267 | s.badge(x + 300, FRAME_Y + 276, 2) |
| 268 | 268 | s.badge(x + 534, FRAME_Y + 390, 3) |
| 269 | 269 | s.badge(x + 534, FRAME_Y + 530, 4) |
| 270 | 270 | s.badge(x + w - 20, FRAME_Y + 612, 5) |
| 271 | 271 | s.notes([ |
| 272 | - (1, "@ liste les agents de la config", ["Nom technique + titre + description.", "Filtrage flou sur nom et titre (« gar »)."]), | |
| 273 | - (2, "Tab sélectionne, sinon on écrit", ["Comportement demandé dans le draft (#1).", "Échap ferme sans rien insérer."]), | |
| 274 | - (3, "/agent:commande en multi-agents", ["Avec un seul agent : /commande. Sidekicks", "envoie « /idioms … » au seul Garfield."]), | |
| 275 | - (4, "Skills et commandes intégrées", ["mm annonce compact, new, unload et ses", "skills (available_commands_update)."]), | |
| 276 | - (5, "Indice d'argument", ["input.hint de la commande ACP, affiché", "tant que l'argument n'est pas saisi."]), | |
| 272 | + (1, "@ lists the configured agents", ["Technical name + title + description.", "Fuzzy filter on name and title (\"gar\")."]), | |
| 273 | + (2, "Tab picks, otherwise you type", ["Behaviour asked for in the draft (#1).", "Esc closes without inserting anything."]), | |
| 274 | + (3, "/agent:command with several agents", ["With one agent: /command. Sidekicks", "sends \"/idioms …\" to Garfield only."]), | |
| 275 | + (4, "Skills and built-in commands", ["mm announces compact, new, unload and", "its skills (available_commands_update)."]), | |
| 276 | + (5, "Argument hint", ["The ACP command's input.hint, shown", "until the argument is typed."]), | |
| 277 | 277 | ]) |
| 278 | 278 | return s |
| 279 | 279 | |
| 280 | 280 | |
| 281 | 281 | def screen_permission(): |
| 282 | - s = Screen("04-permission", "4 · Demande de permission", "En langage clair, sur la conversation concernée, avec une sortie de secours") | |
| 282 | + s = Screen("04-permission", "4 · Permission request", "In plain words, on the conversation concerned, with a way out") | |
| 283 | 283 | s.window() |
| 284 | 284 | s.left_dock(active="code") |
| 285 | 285 | s.rect(CENTER_X, FRAME_Y + 36, CENTER_W, 44, PANEL, BORDER) |
| 286 | 286 | s.text(CENTER_X + 16, FRAME_Y + 64, "# code", 15, bold=True) |
| 287 | 287 | x = CENTER_X + 24 |
| 288 | - y = s.message(x, FRAME_Y + 116, "Vous", TEXT, ["@riker supprime les fichiers temporaires du dossier"]) | |
| 288 | + y = s.message(x, FRAME_Y + 116, "You", TEXT, ["@riker delete the temporary files in the folder"]) | |
| 289 | 289 | s.text(x, y, "🧑🚀 Riker", 13.5, AGENT_COLOURS["riker"], bold=True) |
| 290 | - s.text(x + 90, y, "attend votre réponse", 12.5, WARN, italic=True) | |
| 290 | + s.text(x + 90, y, "waiting for your answer", 12.5, WARN, italic=True) | |
| 291 | 291 | # The dialog, attached to the conversation (not a global modal). |
| 292 | 292 | dx, dy, dw = x, y + 18, 720 |
| 293 | 293 | s.rect(dx, dy, dw, 330, PANEL, WARN, rx=12, width=2, shadow=True) |
| 294 | - s.text(dx + 20, dy + 34, "🧑🚀 Riker veut exécuter une commande sur votre ordinateur", 16, TEXT, bold=True) | |
| 294 | + s.text(dx + 20, dy + 34, "🧑🚀 Riker wants to run a command on your computer", 16, TEXT, bold=True) | |
| 295 | 295 | s.rect(dx + 20, dy + 52, dw - 40, 40, CODE, BORDER, rx=6) |
| 296 | 296 | s.text(dx + 34, dy + 77, "rm -f *.tmp", 14, TEXT, mono=True) |
| 297 | - s.lines(dx + 20, dy + 118, ["Ce que cela fait : supprime définitivement les fichiers se terminant par .tmp", "dans agents/riker . Ils ne passent pas par la corbeille."], 13, TEXT, gap=20) | |
| 298 | - s.text(dx + 20, dy + 168, "⚠ Action irréversible", 13, DANGER, bold=True) | |
| 299 | - s.button(dx + 20, dy + 190, 170, "Autoriser une fois", primary=True) | |
| 300 | - s.button(dx + 200, dy + 190, 300, "Toujours autoriser bash ici") | |
| 301 | - s.button(dx + 20, dy + 234, 170, "Refuser") | |
| 302 | - s.button(dx + 200, dy + 234, 300, "Ne plus jamais proposer bash ici") | |
| 303 | - s.button(dx + 520, dy + 234, 180, "■ Arrêter Riker", danger=True) | |
| 304 | - s.text(dx + 20, dy + 300, "▸ Détails techniques (tool call bash, rawInput)", 12, MUTED) | |
| 297 | + s.lines(dx + 20, dy + 118, ["What it does: permanently deletes the files ending in .tmp", "in agents/riker . They do not go to the trash."], 13, TEXT, gap=20) | |
| 298 | + s.text(dx + 20, dy + 168, "⚠ Cannot be undone", 13, DANGER, bold=True) | |
| 299 | + s.button(dx + 20, dy + 190, 170, "Allow once", primary=True) | |
| 300 | + s.button(dx + 200, dy + 190, 300, "Always allow bash here") | |
| 301 | + s.button(dx + 20, dy + 234, 170, "Reject") | |
| 302 | + s.button(dx + 200, dy + 234, 300, "Never offer bash here again") | |
| 303 | + s.button(dx + 520, dy + 234, 180, "■ Stop Riker", danger=True) | |
| 304 | + s.text(dx + 20, dy + 300, "▸ Technical details (bash tool call, rawInput)", 12, MUTED) | |
| 305 | 305 | s.badge(dx + dw - 16, dy + 30, 1) |
| 306 | 306 | s.badge(dx + 680, dy + 128, 2) |
| 307 | 307 | s.badge(dx + 512, dy + 206, 3) |
| 308 | 308 | s.badge(dx + 712, dy + 250, 4) |
| 309 | 309 | s.badge(dx + 380, dy + 296, 5) |
| 310 | 310 | s.notes([ |
| 311 | - (1, "Attaché à la conversation", ["Bloque seulement la session de Riker ; les", "autres channels continuent (#17)."]), | |
| 312 | - (2, "Expliquer, pas montrer du JSON", ["Titre ACP + kind + rawInput traduits en", "phrase. Les actions destructives sont", "signalées."]), | |
| 313 | - (3, "Les 4 options ACP, par ids", ["allow · allow_always · reject · never.", "« Ne plus jamais » est mis en avant au", "lieu de « Refuser une fois »."]), | |
| 314 | - (4, "Toujours une sortie de secours", ["Spike ACP : après un refus, un petit modèle", "a réessayé 40 fois. Arrêter = session/cancel."]), | |
| 315 | - (5, "Détails pour les curieux", ["Repliés par défaut."]), | |
| 311 | + (1, "Attached to the conversation", ["Blocks only Riker's session; the other", "channels go on (#17)."]), | |
| 312 | + (2, "Explain, do not show JSON", ["ACP title + kind + rawInput turned into", "a sentence. Destructive actions are", "flagged."]), | |
| 313 | + (3, "The 4 ACP options, by id", ["allow · allow_always · reject · never.", "\"Never again\" is put forward rather", "than \"Reject once\"."]), | |
| 314 | + (4, "Always a way out", ["ACP spike: after a rejection, a small model", "retried 40 times. Stop = session/cancel."]), | |
| 315 | + (5, "Details for the curious", ["Folded by default."]), | |
| 316 | 316 | ]) |
| 317 | 317 | return s |
| 318 | 318 | |
| 319 | 319 | |
| 320 | 320 | def screen_agents(): |
| 321 | - s = Screen("05-agents-panel", "5 · Panel Agents : fichiers, éditeur, terminal", "Le workspace de l'agent, qu'il tourne en local, dans un conteneur ou une sandbox sbx") | |
| 321 | + s = Screen("05-agents-panel", "5 · Agents panel: files, editor, terminal", "The agent's workspace, whether it runs locally, in a container or in an sbx sandbox") | |
| 322 | 322 | s.window() |
| 323 | 323 | s.left_dock(active="") |
| 324 | 324 | x, y = CENTER_X, FRAME_Y + 36 |
| 325 | 325 | s.rect(x, y, CENTER_W, 56, PANEL, BORDER) |
| 326 | - s.text(x + 16, y + 26, "🐮 Garfield (traducteur)", 16, bold=True) | |
| 327 | - s.text(x + 16, y + 46, "● occupé · local · agents/garfield · gemma-4-E4B", 12, WARN) | |
| 328 | - s.button(x + CENTER_W - 250, y + 12, 110, "Redémarrer") | |
| 329 | - s.button(x + CENTER_W - 130, y + 12, 110, "Arrêter", danger=True) | |
| 330 | - tabs = ["Fichiers", "Terminal", "Journal"] | |
| 326 | + s.text(x + 16, y + 26, "🐮 Garfield (translator)", 16, bold=True) | |
| 327 | + s.text(x + 16, y + 46, "● busy · local · agents/garfield · gemma-4-E4B", 12, WARN) | |
| 328 | + s.button(x + CENTER_W - 250, y + 12, 110, "Restart") | |
| 329 | + s.button(x + CENTER_W - 130, y + 12, 110, "Stop", danger=True) | |
| 330 | + tabs = ["Files", "Terminal", "Log"] | |
| 331 | 331 | for index, tab in enumerate(tabs): |
| 332 | 332 | s.text(x + 24 + index * 100, y + 82, tab, 13.5, ACCENT if index == 0 else MUTED, bold=index == 0) |
| 333 | 333 | s.rect(x + 16, y + 90, 70, 2, ACCENT, None) |
| 334 | 334 | # Tree. |
| 335 | 335 | s.rect(x, y + 100, 260, 420, PANEL, BORDER) |
| 336 | - tree = ["▾ garfield", " AGENTS.md", " README.md", " agent.yaml", " ▾ skills", " ▸ email-letter", " ▸ idioms", " ▸ styles", " ▸ technical-text", " traduction.md"] | |
| 336 | + tree = ["▾ garfield", " AGENTS.md", " README.md", " agent.yaml", " ▾ skills", " ▸ email-letter", " ▸ idioms", " ▸ styles", " ▸ technical-text", " translation.md"] | |
| 337 | 337 | for index, item in enumerate(tree): |
| 338 | 338 | if item.strip() == "AGENTS.md": |
| 339 | 339 | s.rect(x + 6, y + 112 + index * 26, 248, 24, "#E8EFFD", None, rx=4) |
| 340 | 340 | s.text(x + 14, y + 129 + index * 26, item, 12.5, TEXT, mono=True) |
| 341 | - s.text(x + 14, y + 400, "+ Nouveau fichier", 12.5, ACCENT) | |
| 341 | + s.text(x + 14, y + 400, "+ New file", 12.5, ACCENT) | |
| 342 | 342 | # Editor. |
| 343 | 343 | ex = x + 270 |
| 344 | 344 | s.rect(ex, y + 100, CENTER_W - 280, 420, CODE, BORDER) |
| 345 | 345 | s.text(ex + 14, y + 124, "AGENTS.md", 13, MUTED, bold=True) |
| 346 | - s.lines(ex + 14, y + 154, ["# Style de traduction", "", "- Registre : celui du texte source.", "- Typographie française : espaces insécables", " avant ; : ! ? et entre « guillemets ».", "- Ne jamais traduire le code ni les noms propres."], 12.5, TEXT, gap=22, mono=True) | |
| 347 | - s.button(ex + CENTER_W - 280 - 240, y + 474, 110, "Enregistrer", primary=True) | |
| 348 | - s.button(ex + CENTER_W - 280 - 120, y + 474, 110, "Supprimer", danger=True) | |
| 346 | + s.lines(ex + 14, y + 154, ["# Translation style", "", "- Register: the one of the source text.", "- French typography: non-breaking spaces", " before ; : ! ? and inside « quotes ».", "- Never translate code or proper names."], 12.5, TEXT, gap=22, mono=True) | |
| 347 | + s.button(ex + CENTER_W - 280 - 240, y + 474, 110, "Save", primary=True) | |
| 348 | + s.button(ex + CENTER_W - 280 - 120, y + 474, 110, "Delete", danger=True) | |
| 349 | 349 | # Terminal (bottom). |
| 350 | 350 | s.rect(x, y + 530, CENTER_W, FRAME_H - 26 - 36 - 530, "#111317", BORDER) |
| 351 | 351 | s.lines(x + 14, y + 556, ["garfield $ ls skills", "email-letter idioms styles technical-text", "garfield $ █"], 12.5, "#D7DAE0", gap=20, mono=True) |
| @@ -355,24 +355,24 @@ def screen_agents(): | ||
| 355 | 355 | s.badge(x + CENTER_W - 20, y + 552, 4) |
| 356 | 356 | s.badge(x + 330, y + 82, 5) |
| 357 | 357 | s.notes([ |
| 358 | - (1, "État et emplacement de l'agent", ["Statut temps réel (#11), runtime (local,", "container, sbx), dossier et modèle."]), | |
| 359 | - (2, "Arbre du workspace", ["Chargement paresseux, rafraîchi quand", "l'agent modifie un fichier (#29)."]), | |
| 360 | - (3, "Éditer, supprimer avec confirmation", ["Même éditeur que Settings. Conflit signalé", "si l'agent modifie le fichier (#30)."]), | |
| 361 | - (4, "Terminal sur le workspace", ["PTY local, docker exec ou sbx selon le", "runtime (#28, #31). Replié par défaut."]), | |
| 362 | - (5, "Journal", ["stderr de l'agent, pour comprendre", "une erreur sans ouvrir un terminal."]), | |
| 358 | + (1, "The agent's state and location", ["Live status (#11), runtime (local,", "container, sbx), folder and model."]), | |
| 359 | + (2, "Workspace tree", ["Loaded lazily, refreshed when the", "agent changes a file (#29)."]), | |
| 360 | + (3, "Edit, delete with confirmation", ["Same editor as Settings. A conflict is", "flagged if the agent changes the file (#30)."]), | |
| 361 | + (4, "Terminal in the workspace", ["Local PTY, docker exec or sbx depending on", "the runtime (#28, #31). Folded by default."]), | |
| 362 | + (5, "Log", ["The agent's stderr, to understand", "an error without opening a terminal."]), | |
| 363 | 363 | ]) |
| 364 | 364 | return s |
| 365 | 365 | |
| 366 | 366 | |
| 367 | 367 | def screen_first_launch(): |
| 368 | - s = Screen("06-first-launch", "6 · Premier lancement", "Moins d'une minute pour savoir quoi faire, sans lire de documentation") | |
| 369 | - s.window(status="○ aucun agent configuré · config : créée à l'emplacement par défaut") | |
| 368 | + s = Screen("06-first-launch", "6 · First launch", "Less than a minute to know what to do, without reading any documentation") | |
| 369 | + s.window(status="○ no agent configured · config: created at the default location") | |
| 370 | 370 | x, y = FRAME_X + 220, FRAME_Y + 120 |
| 371 | - s.text(FRAME_X + FRAME_W / 2, y, "👋 Bienvenue dans Sidekicks", 26, TEXT, bold=True, anchor="middle") | |
| 372 | - s.text(FRAME_X + FRAME_W / 2, y + 34, "Discutez avec des agents d'IA dans des channels, comme avec des collègues.", 15, MUTED, anchor="middle") | |
| 373 | - steps = [("1", "Ajoutez un agent", "Un assistant qui tourne sur votre ordinateur, par exemple avec mm."), | |
| 374 | - ("2", "Ouvrez un channel", "#général est déjà prêt. Créez-en d'autres par sujet."), | |
| 375 | - ("3", "Appelez-le avec @", "« @alice bonjour » : Alice rejoint le channel et vous répond.")] | |
| 371 | + s.text(FRAME_X + FRAME_W / 2, y, "👋 Welcome to Sidekicks", 26, TEXT, bold=True, anchor="middle") | |
| 372 | + s.text(FRAME_X + FRAME_W / 2, y + 34, "Talk with AI agents in channels, as you would with colleagues.", 15, MUTED, anchor="middle") | |
| 373 | + steps = [("1", "Add an agent", "An assistant that runs on your computer, for example with mm."), | |
| 374 | + ("2", "Open a channel", "#general is ready. Create others, one per topic."), | |
| 375 | + ("3", "Call it with @", "\"@alice hello\": Alice joins the channel and answers you.")] | |
| 376 | 376 | for index, (number, title, body) in enumerate(steps): |
| 377 | 377 | top = y + 80 + index * 92 |
| 378 | 378 | s.rect(x, top, 800, 76, PANEL, BORDER, rx=12) |
| @@ -381,21 +381,21 @@ def screen_first_launch(): | ||
| 381 | 381 | s.text(x + 40, top + 44, number, 16, "#FFFFFF", bold=True, anchor="middle") |
| 382 | 382 | s.text(x + 76, top + 32, title, 16, TEXT, bold=True) |
| 383 | 383 | s.text(x + 76, top + 56, body, 13.5, MUTED) |
| 384 | - s.button(x + 180, y + 370, 240, "+ Ajouter mon premier agent", primary=True, h=40) | |
| 385 | - s.button(x + 440, y + 370, 200, "Ouvrir une configuration…", h=40) | |
| 386 | - s.text(FRAME_X + FRAME_W / 2, y + 450, "Configuration : ~/Library/Application Support/sidekicks/config.yaml (créée pour vous, commentée)", 12, MUTED, anchor="middle") | |
| 384 | + s.button(x + 180, y + 370, 240, "+ Add my first agent", primary=True, h=40) | |
| 385 | + s.button(x + 440, y + 370, 200, "Open a configuration…", h=40) | |
| 386 | + s.text(FRAME_X + FRAME_W / 2, y + 450, "Configuration: ~/Library/Application Support/sidekicks/config.yaml (created for you, with comments)", 12, MUTED, anchor="middle") | |
| 387 | 387 | s.rect(x, y + 480, 800, 70, "#FDECEF", DANGER, rx=10) |
| 388 | - s.text(x + 20, y + 508, "La commande « mm » est introuvable.", 14, DANGER, bold=True) | |
| 389 | - s.text(x + 20, y + 532, "Installez-la (lien vers le guide) ou choisissez un autre programme pour cet agent.", 13, TEXT) | |
| 388 | + s.text(x + 20, y + 508, "The command \"mm\" cannot be found.", 14, DANGER, bold=True) | |
| 389 | + s.text(x + 20, y + 532, "Install it (link to the guide) or choose another program for this agent.", 13, TEXT) | |
| 390 | 390 | s.badge(x + 812, y + 112, 1) |
| 391 | 391 | s.badge(x + 652, y + 390, 2) |
| 392 | 392 | s.badge(FRAME_X + FRAME_W / 2 + 390, y + 446, 3) |
| 393 | 393 | s.badge(x + 812, y + 500, 4) |
| 394 | 394 | s.notes([ |
| 395 | - (1, "Trois étapes, pas plus", ["L'état vide explique le modèle mental :", "agents, channels, @ (#33)."]), | |
| 396 | - (2, "Un assistant plutôt que du YAML", ["Le formulaire écrit le YAML à la place de", "l'utilisateur ; Settings reste accessible."]), | |
| 397 | - (3, "Rien à créer à la main", ["Le fichier par défaut existe déjà, avec des", "commentaires (#9)."]), | |
| 398 | - (4, "Erreurs humaines", ["Dire ce qui ne va pas et quoi faire ;", "jamais de trace technique (#33)."]), | |
| 395 | + (1, "Three steps, no more", ["The empty state explains the mental model:", "agents, channels, @ (#33)."]), | |
| 396 | + (2, "An assistant rather than YAML", ["The form writes the YAML for the user;", "Settings stays at hand."]), | |
| 397 | + (3, "Nothing to create by hand", ["The default file already exists, with", "comments (#9)."]), | |
| 398 | + (4, "Human errors", ["Say what is wrong and what to do;", "never a technical trace (#33)."]), | |
| 399 | 399 | ]) |
| 400 | 400 | return s |
| 401 | 401 | |
| @@ -98,7 +98,7 @@ class Screen: | |||
| 98 | 98 | ||
| 99 | # -- common pieces of the window ------------------------------------------------- | 99 | # -- common pieces of the window ------------------------------------------------- |
| 100 | 100 | ||
| 101 | - def window(self, status="● 2 agents actifs sur 2 · config : ~/agents/equipe.yaml"): | 101 | + def window(self, status="● 2 of 2 agents running · config: ~/agents/team.yaml"): |
| 102 | """The window chrome: title bar, left dock, status bar.""" | 102 | """The window chrome: title bar, left dock, status bar.""" |
| 103 | self.rect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, BG, "#C9CBD1", rx=12, shadow=True) | 103 | self.rect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, BG, "#C9CBD1", rx=12, shadow=True) |
| 104 | self.rect(FRAME_X, FRAME_Y, FRAME_W, 36, PANEL2, None, rx=12) | 104 | self.rect(FRAME_X, FRAME_Y, FRAME_W, 36, PANEL2, None, rx=12) |
| @@ -111,12 +111,12 @@ class Screen: | |||
| 111 | self.text(FRAME_X + 12, FRAME_Y + FRAME_H - 9, status, 11.5, MUTED) | 111 | self.text(FRAME_X + 12, FRAME_Y + FRAME_H - 9, status, 11.5, MUTED) |
| 112 | self.text(FRAME_X + FRAME_W - 12, FRAME_Y + FRAME_H - 9, "⚙︎ Settings ⌘K", 11.5, MUTED, anchor="end") | 112 | self.text(FRAME_X + FRAME_W - 12, FRAME_Y + FRAME_H - 9, "⚙︎ Settings ⌘K", 11.5, MUTED, anchor="end") |
| 113 | 113 | ||
| 114 | - def left_dock(self, active="général", agents=(("alice", "👩 Alice", OK), ("bob", "🧔 Bob", OK), ("riker", "🧑🚀 Riker", MUTED), ("garfield", "🐮 Garfield", WARN))): | 114 | + def left_dock(self, active="general", agents=(("alice", "👩 Alice", OK), ("bob", "🧔 Bob", OK), ("riker", "🧑🚀 Riker", MUTED), ("garfield", "🐮 Garfield", WARN))): |
| 115 | x, y = FRAME_X, FRAME_Y + 36 | 115 | x, y = FRAME_X, FRAME_Y + 36 |
| 116 | self.rect(x, y, 230, FRAME_H - 62, PANEL, BORDER) | 116 | self.rect(x, y, 230, FRAME_H - 62, PANEL, BORDER) |
| 117 | self.text(x + 16, y + 28, "CHANNELS", 11, MUTED, bold=True) | 117 | self.text(x + 16, y + 28, "CHANNELS", 11, MUTED, bold=True) |
| 118 | self.text(x + 214, y + 28, "+", 16, MUTED, bold=True, anchor="end") | 118 | self.text(x + 214, y + 28, "+", 16, MUTED, bold=True, anchor="end") |
| 119 | - for index, name in enumerate(("général", "traductions", "code")): | 119 | + for index, name in enumerate(("general", "translations", "code")): |
| 120 | top = y + 42 + index * 30 | 120 | top = y + 42 + index * 30 |
| 121 | if name == active: | 121 | if name == active: |
| 122 | self.rect(x + 8, top, 214, 26, PANEL2, None, rx=6) | 122 | self.rect(x + 8, top, 214, 26, PANEL2, None, rx=6) |
| @@ -136,7 +136,7 @@ class Screen: | |||
| 136 | self.lines(x, y + 22, lines, 13.5) | 136 | self.lines(x, y + 22, lines, 13.5) |
| 137 | return y + 22 + 20 * len(lines) + 14 | 137 | return y + 22 + 20 * len(lines) + 14 |
| 138 | 138 | ||
| 139 | - def composer(self, x, y, w, value, hint="Entrée pour envoyer · Maj+Entrée nouvelle ligne"): | 139 | + def composer(self, x, y, w, value, hint="Enter to send · Shift+Enter for a new line"): |
| 140 | self.rect(x, y, w, 64, PANEL, ACCENT, rx=10, width=1.5) | 140 | self.rect(x, y, w, 64, PANEL, ACCENT, rx=10, width=1.5) |
| 141 | self.text(x + 14, y + 26, value, 14) | 141 | self.text(x + 14, y + 26, value, 14) |
| 142 | self.text(x + 14, y + 50, hint, 11, MUTED) | 142 | self.text(x + 14, y + 50, hint, 11, MUTED) |
| @@ -163,98 +163,98 @@ CENTER_W = FRAME_W - 231 | |||
| 163 | 163 | ||
| 164 | 164 | ||
| 165 | def screen_layout(): | 165 | def screen_layout(): |
| 166 | - s = Screen("01-layout", "1 · Layout global", "Docks façon Zed, mais seul l'essentiel est visible par défaut") | 166 | + s = Screen("01-layout", "1 · Overall layout", "Zed-like docks, but only the essentials are visible by default") |
| 167 | s.window() | 167 | s.window() |
| 168 | s.left_dock() | 168 | s.left_dock() |
| 169 | s.rect(CENTER_X, FRAME_Y + 36, CENTER_W - 300, 44, PANEL, BORDER) | 169 | s.rect(CENTER_X, FRAME_Y + 36, CENTER_W - 300, 44, PANEL, BORDER) |
| 170 | - s.text(CENTER_X + 16, FRAME_Y + 64, "# général", 15, bold=True) | 170 | + s.text(CENTER_X + 16, FRAME_Y + 64, "# general", 15, bold=True) |
| 171 | s.text(CENTER_X + CENTER_W - 316, FRAME_Y + 64, "👩 Alice · 🧔 Bob", 13, MUTED, anchor="end") | 171 | s.text(CENTER_X + CENTER_W - 316, FRAME_Y + 64, "👩 Alice · 🧔 Bob", 13, MUTED, anchor="end") |
| 172 | - y = s.message(CENTER_X + 24, FRAME_Y + 116, "Vous", TEXT, ["@alice résume-moi ce que fait ACP en deux phrases"]) | 172 | + y = s.message(CENTER_X + 24, FRAME_Y + 116, "You", TEXT, ["@alice sum up what ACP does in two sentences"]) |
| 173 | - y = s.message(CENTER_X + 24, y, "👩 Alice", AGENT_COLOURS["alice"], ["ACP est un protocole qui permet à une application de dialoguer avec", "n'importe quel agent d'IA. Sidekicks l'utilise pour rester agnostique."]) | 173 | + y = s.message(CENTER_X + 24, y, "👩 Alice", AGENT_COLOURS["alice"], ["ACP is a protocol that lets an application talk with any AI agent.", "Sidekicks uses it to stay agent-agnostic."]) |
| 174 | - s.composer(CENTER_X + 20, FRAME_Y + FRAME_H - 136, CENTER_W - 340, "Écrivez un message… (@ pour un agent, / pour une commande)") | 174 | + s.composer(CENTER_X + 20, FRAME_Y + FRAME_H - 136, CENTER_W - 340, "Write a message… (@ for an agent, / for a command)") |
| 175 | # Right dock (Settings), shown here opened. | 175 | # Right dock (Settings), shown here opened. |
| 176 | s.rect(FRAME_X + FRAME_W - 300, FRAME_Y + 36, 300, FRAME_H - 62, PANEL, BORDER) | 176 | s.rect(FRAME_X + FRAME_W - 300, FRAME_Y + 36, 300, FRAME_H - 62, PANEL, BORDER) |
| 177 | - s.text(FRAME_X + FRAME_W - 284, FRAME_Y + 64, "⚙︎ Settings — equipe.yaml", 13, MUTED, bold=True) | 177 | + s.text(FRAME_X + FRAME_W - 284, FRAME_Y + 64, "⚙︎ Settings — team.yaml", 13, MUTED, bold=True) |
| 178 | s.rect(FRAME_X + FRAME_W - 290, FRAME_Y + 80, 280, 300, CODE, BORDER, rx=6) | 178 | s.rect(FRAME_X + FRAME_W - 290, FRAME_Y + 80, 280, 300, CODE, BORDER, rx=6) |
| 179 | - s.lines(FRAME_X + FRAME_W - 280, FRAME_Y + 104, ["version: 1", "agents:", " - name: alice", " title: Alice", " command: mm", " args: [-acp, ...]", "channels:", " - name: général", " agents: [alice, bob]"], 12, TEXT, gap=19, mono=True) | 179 | + s.lines(FRAME_X + FRAME_W - 280, FRAME_Y + 104, ["version: 1", "agents:", " - name: alice", " title: Alice", " command: mm", " args: [-acp, ...]", "channels:", " - name: general", " agents: [alice, bob]"], 12, TEXT, gap=19, mono=True) |
| 180 | - s.text(FRAME_X + FRAME_W - 284, FRAME_Y + 410, "✓ Configuration valide", 12.5, OK, bold=True) | 180 | + s.text(FRAME_X + FRAME_W - 284, FRAME_Y + 410, "✓ Valid configuration", 12.5, OK, bold=True) |
| 181 | - s.button(FRAME_X + FRAME_W - 290, FRAME_Y + 428, 120, "Enregistrer", primary=True) | 181 | + s.button(FRAME_X + FRAME_W - 290, FRAME_Y + 428, 120, "Save", primary=True) |
| 182 | # Collapsed bottom dock. | 182 | # Collapsed bottom dock. |
| 183 | s.rect(CENTER_X, FRAME_Y + FRAME_H - 26 - 30, CENTER_W - 300, 30, PANEL2, BORDER) | 183 | s.rect(CENTER_X, FRAME_Y + FRAME_H - 26 - 30, CENTER_W - 300, 30, PANEL2, BORDER) |
| 184 | - s.text(CENTER_X + 14, FRAME_Y + FRAME_H - 36, "▸ Terminal · Fichiers (repliés)", 12, MUTED) | 184 | + s.text(CENTER_X + 14, FRAME_Y + FRAME_H - 36, "▸ Terminal · Files (folded)", 12, MUTED) |
| 185 | s.badge(FRAME_X + 200, FRAME_Y + 62, 1) | 185 | s.badge(FRAME_X + 200, FRAME_Y + 62, 1) |
| 186 | s.badge(CENTER_X + 120, FRAME_Y + 160, 2) | 186 | s.badge(CENTER_X + 120, FRAME_Y + 160, 2) |
| 187 | s.badge(FRAME_X + FRAME_W - 30, FRAME_Y + 60, 3) | 187 | s.badge(FRAME_X + FRAME_W - 30, FRAME_Y + 60, 3) |
| 188 | s.badge(CENTER_X + 330, FRAME_Y + FRAME_H - 41, 4) | 188 | s.badge(CENTER_X + 330, FRAME_Y + FRAME_H - 41, 4) |
| 189 | s.badge(FRAME_X + 420, FRAME_Y + FRAME_H - 13, 5) | 189 | s.badge(FRAME_X + 420, FRAME_Y + FRAME_H - 13, 5) |
| 190 | s.notes([ | 190 | s.notes([ |
| 191 | - (1, "Dock gauche : channels et agents", ["Toujours visible. La pastille donne l'état de", "l'agent : vert prêt, orange occupé, gris arrêté."]), | 191 | + (1, "Left dock: channels and agents", ["Always visible. The dot gives the agent's", "state: green ready, orange busy, grey stopped."]), |
| 192 | - (2, "Centre : la conversation", ["Le seul panel indispensable. Pleine largeur", "quand les docks sont repliés."]), | 192 | + (2, "Centre: the conversation", ["The only panel you cannot do without.", "Full width when the docks are folded."]), |
| 193 | - (3, "Dock droit : Settings", ["Éditeur YAML (CodeMirror) avec validation", "en direct. Fermé par défaut ; s'ouvre", "par ⚙︎ ou ⌘,."]), | 193 | + (3, "Right dock: Settings", ["YAML editor (CodeMirror) with live", "validation. Closed by default; opens", "with ⚙︎ or ⌘,."]), |
| 194 | - (4, "Dock bas : terminal et fichiers", ["Replié par défaut : utile aux curieux,", "jamais imposé au citizen user."]), | 194 | + (4, "Bottom dock: terminal and files", ["Folded by default: there for the curious,", "never forced on the citizen user."]), |
| 195 | - (5, "Barre d'état", ["Rappelle la limite d'agents simultanés", "(mémoire) et la configuration ouverte."]), | 195 | + (5, "Status bar", ["Shows the limit of agents running at once", "(memory) and the open configuration."]), |
| 196 | ]) | 196 | ]) |
| 197 | return s | 197 | return s |
| 198 | 198 | ||
| 199 | 199 | ||
| 200 | def screen_conversation(): | 200 | def screen_conversation(): |
| 201 | - s = Screen("02-conversation", "2 · Conversation multi-agents", "Chaque agent a sa couleur ; les outils sont repliés ; on peut toujours arrêter") | 201 | + s = Screen("02-conversation", "2 · Multi-agent conversation", "Each agent has its colour; tools are folded; you can always stop") |
| 202 | s.window() | 202 | s.window() |
| 203 | s.left_dock() | 203 | s.left_dock() |
| 204 | s.rect(CENTER_X, FRAME_Y + 36, CENTER_W, 44, PANEL, BORDER) | 204 | s.rect(CENTER_X, FRAME_Y + 36, CENTER_W, 44, PANEL, BORDER) |
| 205 | - s.text(CENTER_X + 16, FRAME_Y + 64, "# général", 15, bold=True) | 205 | + s.text(CENTER_X + 16, FRAME_Y + 64, "# general", 15, bold=True) |
| 206 | s.text(CENTER_X + CENTER_W - 16, FRAME_Y + 64, "👩 Alice · 🧔 Bob · 🧑🚀 Riker", 13, MUTED, anchor="end") | 206 | s.text(CENTER_X + CENTER_W - 16, FRAME_Y + 64, "👩 Alice · 🧔 Bob · 🧑🚀 Riker", 13, MUTED, anchor="end") |
| 207 | x = CENTER_X + 24 | 207 | x = CENTER_X + 24 |
| 208 | - y = s.message(x, FRAME_Y + 116, "", "", ["— Riker a rejoint le channel —"], system=True) | 208 | + y = s.message(x, FRAME_Y + 116, "", "", ["— Riker joined the channel —"], system=True) |
| 209 | - y = s.message(x, y + 6, "Vous", TEXT, ["@alice propose un nom pour un script qui sauvegarde mes photos"]) | 209 | + y = s.message(x, y + 6, "You", TEXT, ["@alice suggest a name for a script that backs up my photos"]) |
| 210 | - y = s.message(x, y, "👩 Alice", AGENT_COLOURS["alice"], ["Je propose « photo-backup.sh » : court, explicite, et l'extension dit que", "c'est un script shell."]) | 210 | + y = s.message(x, y, "👩 Alice", AGENT_COLOURS["alice"], ["I suggest \"photo-backup.sh\": short, clear, and the extension says", "it is a shell script."]) |
| 211 | - y = s.message(x, y, "Vous", TEXT, ["@bob tu valides ? @riker crée le fichier vide"]) | 211 | + y = s.message(x, y, "You", TEXT, ["@bob do you agree? @riker create the empty file"]) |
| 212 | - y = s.message(x, y, "🧔 Bob", AGENT_COLOURS["bob"], ["Bon choix. Alice a raison : un nom en minuscules, sans espace."]) | 212 | + y = s.message(x, y, "🧔 Bob", AGENT_COLOURS["bob"], ["Good choice. Alice is right: a lowercase name, no spaces."]) |
| 213 | s.text(x, y, "🧑🚀 Riker", 13.5, AGENT_COLOURS["riker"], bold=True) | 213 | s.text(x, y, "🧑🚀 Riker", 13.5, AGENT_COLOURS["riker"], bold=True) |
| 214 | - s.text(x + 90, y, "travaille…", 12.5, MUTED, italic=True) | 214 | + s.text(x + 90, y, "working…", 12.5, MUTED, italic=True) |
| 215 | s.rect(x, y + 12, 560, 40, PANEL2, BORDER, rx=8) | 215 | s.rect(x, y + 12, 560, 40, PANEL2, BORDER, rx=8) |
| 216 | - s.text(x + 14, y + 37, "▸ 🛠 write_file : photo-backup.sh (0 octet) ✓ terminé", 12.5, TEXT) | 216 | + s.text(x + 14, y + 37, "▸ 🛠 write_file: photo-backup.sh (0 bytes) ✓ done", 12.5, TEXT) |
| 217 | s.rect(x, y + 60, 560, 40, PANEL2, BORDER, rx=8) | 217 | s.rect(x, y + 60, 560, 40, PANEL2, BORDER, rx=8) |
| 218 | - s.text(x + 14, y + 85, "▸ 🛠 bash : ls -la … en cours", 12.5, TEXT) | 218 | + s.text(x + 14, y + 85, "▸ 🛠 bash: ls -la … running", 12.5, TEXT) |
| 219 | s.composer(CENTER_X + 20, FRAME_Y + FRAME_H - 106, CENTER_W - 160, "") | 219 | s.composer(CENTER_X + 20, FRAME_Y + FRAME_H - 106, CENTER_W - 160, "") |
| 220 | - s.button(CENTER_X + CENTER_W - 128, FRAME_Y + FRAME_H - 90, 108, "■ Arrêter", danger=True) | 220 | + s.button(CENTER_X + CENTER_W - 128, FRAME_Y + FRAME_H - 90, 108, "■ Stop", danger=True) |
| 221 | s.rect(CENTER_X + CENTER_W - 220, FRAME_Y + 96, 200, 30, PANEL2, BORDER, rx=15) | 221 | s.rect(CENTER_X + CENTER_W - 220, FRAME_Y + 96, 200, 30, PANEL2, BORDER, rx=15) |
| 222 | - s.text(CENTER_X + CENTER_W - 120, FRAME_Y + 116, "contexte Riker : 41 %", 11.5, MUTED, anchor="middle") | 222 | + s.text(CENTER_X + CENTER_W - 120, FRAME_Y + 116, "Riker's context: 41%", 11.5, MUTED, anchor="middle") |
| 223 | s.badge(x + 300, FRAME_Y + 111, 1) | 223 | s.badge(x + 300, FRAME_Y + 111, 1) |
| 224 | s.badge(x + 80, FRAME_Y + 194, 2) | 224 | s.badge(x + 80, FRAME_Y + 194, 2) |
| 225 | s.badge(x + 580, y + 32, 3) | 225 | s.badge(x + 580, y + 32, 3) |
| 226 | s.badge(CENTER_X + CENTER_W - 140, FRAME_Y + FRAME_H - 90, 4) | 226 | s.badge(CENTER_X + CENTER_W - 140, FRAME_Y + FRAME_H - 90, 4) |
| 227 | s.badge(CENTER_X + CENTER_W - 232, FRAME_Y + 111, 5) | 227 | s.badge(CENTER_X + CENTER_W - 232, FRAME_Y + 111, 5) |
| 228 | s.notes([ | 228 | s.notes([ |
| 229 | - (1, "Arrivée visible", ["La 1re mention invite l'agent : un message", "système le dit. On sait qui « écoute »."]), | 229 | + (1, "A visible arrival", ["The first mention invites the agent: a system", "message says so. You know who is listening."]), |
| 230 | - (2, "Une couleur par agent", ["Avatar + nom colorés, réponses en Markdown", "avec code coloré (ADR 0002)."]), | 230 | + (2, "One colour per agent", ["Coloured avatar and name, answers in", "Markdown with highlighted code (ADR 0002)."]), |
| 231 | - (3, "Outils repliés", ["Une ligne par tool call : titre lisible et", "statut. Déplier montre la commande, le", "diff ou la sortie."]), | 231 | + (3, "Folded tools", ["One line per tool call: a readable title", "and its status. Unfolding shows the", "command, the diff or the output."]), |
| 232 | - (4, "Toujours un bouton Arrêter", ["Envoie session/cancel aux agents qui", "répondent dans ce channel (ADR 0001)."]), | 232 | + (4, "Always a Stop button", ["Sends session/cancel to the agents", "answering in this channel (ADR 0001)."]), |
| 233 | - (5, "Jauge de contexte", ["usage_update : prévient avant que la", "conversation ne dépasse la mémoire de", "l'agent."]), | 233 | + (5, "Context gauge", ["usage_update: warns before the", "conversation outgrows the agent's", "memory."]), |
| 234 | ]) | 234 | ]) |
| 235 | return s | 235 | return s |
| 236 | 236 | ||
| 237 | 237 | ||
| 238 | def screen_popups(): | 238 | def screen_popups(): |
| 239 | - s = Screen("03-mentions-commands", "3 · Invoquer un agent (@) et une commande (/)", "Tab choisit la suggestion ; continuer à écrire filtre la liste") | 239 | + s = Screen("03-mentions-commands", "3 · Calling an agent (@) and a command (/)", "Tab picks the suggestion; typing on filters the list") |
| 240 | s.window() | 240 | s.window() |
| 241 | s.left_dock() | 241 | s.left_dock() |
| 242 | x, w = CENTER_X + 20, CENTER_W - 40 | 242 | x, w = CENTER_X + 20, CENTER_W - 40 |
| 243 | # @ popup (top half). | 243 | # @ popup (top half). |
| 244 | - s.text(x, FRAME_Y + 70, "Mention d'un agent", 14, MUTED, bold=True) | 244 | + s.text(x, FRAME_Y + 70, "Mentioning an agent", 14, MUTED, bold=True) |
| 245 | s.rect(x, FRAME_Y + 84, 420, 150, PANEL, BORDER, rx=10, shadow=True) | 245 | s.rect(x, FRAME_Y + 84, 420, 150, PANEL, BORDER, rx=10, shadow=True) |
| 246 | - rows = [("🐮 garfield", "Garfield (traducteur) — traduit FR ⇄ EN", True), ("🧑🚀 riker", "Riker (outils) — commandes et fichiers", False), ("👩 alice", "Alice (assistante) — questions simples", False)] | 246 | + rows = [("🐮 garfield", "Garfield (translator) — translates FR ⇄ EN", True), ("🧑🚀 riker", "Riker (tools) — commands and files", False), ("👩 alice", "Alice (assistant) — simple questions", False)] |
| 247 | for index, (name, description, selected) in enumerate(rows): | 247 | for index, (name, description, selected) in enumerate(rows): |
| 248 | top = FRAME_Y + 92 + index * 44 | 248 | top = FRAME_Y + 92 + index * 44 |
| 249 | if selected: | 249 | if selected: |
| 250 | s.rect(x + 6, top, 408, 40, "#E8EFFD", None, rx=6) | 250 | s.rect(x + 6, top, 408, 40, "#E8EFFD", None, rx=6) |
| 251 | s.text(x + 18, top + 18, name, 13.5, TEXT, bold=True) | 251 | s.text(x + 18, top + 18, name, 13.5, TEXT, bold=True) |
| 252 | s.text(x + 18, top + 34, description, 11.5, MUTED) | 252 | s.text(x + 18, top + 34, description, 11.5, MUTED) |
| 253 | - s.composer(x, FRAME_Y + 244, w, "@ga", "Tab : @garfield · ↑↓ naviguer · Échap fermer") | 253 | + s.composer(x, FRAME_Y + 244, w, "@ga", "Tab: @garfield · ↑↓ move · Esc close") |
| 254 | # / popup (bottom half). | 254 | # / popup (bottom half). |
| 255 | - s.text(x, FRAME_Y + 360, "Commande d'un agent (plusieurs agents dans le channel)", 14, MUTED, bold=True) | 255 | + s.text(x, FRAME_Y + 360, "An agent's command (several agents in the channel)", 14, MUTED, bold=True) |
| 256 | s.rect(x, FRAME_Y + 374, 520, 196, PANEL, BORDER, rx=10, shadow=True) | 256 | s.rect(x, FRAME_Y + 374, 520, 196, PANEL, BORDER, rx=10, shadow=True) |
| 257 | - commands = [("/garfield:idioms", "Expressions idiomatiques et faux amis", "[texte]", True), ("/garfield:styles", "Plusieurs versions d'une traduction", "[texte]", False), ("/garfield:email-letter", "E-mails et lettres : formules, tu ou vous", "[texte]", False), ("/alice:compact", "Résumer l'historique maintenant", "", False)] | 257 | + commands = [("/garfield:idioms", "Idioms and false friends", "[text]", True), ("/garfield:styles", "Several versions of a translation", "[text]", False), ("/garfield:email-letter", "E-mails and letters: greetings, tu or vous", "[text]", False), ("/alice:compact", "Summarise the history now", "", False)] |
| 258 | for index, (name, description, hint, selected) in enumerate(commands): | 258 | for index, (name, description, hint, selected) in enumerate(commands): |
| 259 | top = FRAME_Y + 382 + index * 46 | 259 | top = FRAME_Y + 382 + index * 46 |
| 260 | if selected: | 260 | if selected: |
| @@ -262,90 +262,90 @@ def screen_popups(): | |||
| 262 | s.text(x + 18, top + 19, name, 13.5, TEXT, bold=True, mono=True) | 262 | s.text(x + 18, top + 19, name, 13.5, TEXT, bold=True, mono=True) |
| 263 | s.text(x + 500, top + 19, hint, 11.5, MUTED, anchor="end", mono=True) | 263 | s.text(x + 500, top + 19, hint, 11.5, MUTED, anchor="end", mono=True) |
| 264 | s.text(x + 18, top + 36, description, 11.5, MUTED) | 264 | s.text(x + 18, top + 36, description, 11.5, MUTED) |
| 265 | - s.composer(x, FRAME_Y + 580, w, "/gar", "Tab : /garfield:idioms · le texte après la commande est son argument") | 265 | + s.composer(x, FRAME_Y + 580, w, "/gar", "Tab: /garfield:idioms · the text after the command is its argument") |
| 266 | s.badge(x + 434, FRAME_Y + 100, 1) | 266 | s.badge(x + 434, FRAME_Y + 100, 1) |
| 267 | s.badge(x + 300, FRAME_Y + 276, 2) | 267 | s.badge(x + 300, FRAME_Y + 276, 2) |
| 268 | s.badge(x + 534, FRAME_Y + 390, 3) | 268 | s.badge(x + 534, FRAME_Y + 390, 3) |
| 269 | s.badge(x + 534, FRAME_Y + 530, 4) | 269 | s.badge(x + 534, FRAME_Y + 530, 4) |
| 270 | s.badge(x + w - 20, FRAME_Y + 612, 5) | 270 | s.badge(x + w - 20, FRAME_Y + 612, 5) |
| 271 | s.notes([ | 271 | s.notes([ |
| 272 | - (1, "@ liste les agents de la config", ["Nom technique + titre + description.", "Filtrage flou sur nom et titre (« gar »)."]), | 272 | + (1, "@ lists the configured agents", ["Technical name + title + description.", "Fuzzy filter on name and title (\"gar\")."]), |
| 273 | - (2, "Tab sélectionne, sinon on écrit", ["Comportement demandé dans le draft (#1).", "Échap ferme sans rien insérer."]), | 273 | + (2, "Tab picks, otherwise you type", ["Behaviour asked for in the draft (#1).", "Esc closes without inserting anything."]), |
| 274 | - (3, "/agent:commande en multi-agents", ["Avec un seul agent : /commande. Sidekicks", "envoie « /idioms … » au seul Garfield."]), | 274 | + (3, "/agent:command with several agents", ["With one agent: /command. Sidekicks", "sends \"/idioms …\" to Garfield only."]), |
| 275 | - (4, "Skills et commandes intégrées", ["mm annonce compact, new, unload et ses", "skills (available_commands_update)."]), | 275 | + (4, "Skills and built-in commands", ["mm announces compact, new, unload and", "its skills (available_commands_update)."]), |
| 276 | - (5, "Indice d'argument", ["input.hint de la commande ACP, affiché", "tant que l'argument n'est pas saisi."]), | 276 | + (5, "Argument hint", ["The ACP command's input.hint, shown", "until the argument is typed."]), |
| 277 | ]) | 277 | ]) |
| 278 | return s | 278 | return s |
| 279 | 279 | ||
| 280 | 280 | ||
| 281 | def screen_permission(): | 281 | def screen_permission(): |
| 282 | - s = Screen("04-permission", "4 · Demande de permission", "En langage clair, sur la conversation concernée, avec une sortie de secours") | 282 | + s = Screen("04-permission", "4 · Permission request", "In plain words, on the conversation concerned, with a way out") |
| 283 | s.window() | 283 | s.window() |
| 284 | s.left_dock(active="code") | 284 | s.left_dock(active="code") |
| 285 | s.rect(CENTER_X, FRAME_Y + 36, CENTER_W, 44, PANEL, BORDER) | 285 | s.rect(CENTER_X, FRAME_Y + 36, CENTER_W, 44, PANEL, BORDER) |
| 286 | s.text(CENTER_X + 16, FRAME_Y + 64, "# code", 15, bold=True) | 286 | s.text(CENTER_X + 16, FRAME_Y + 64, "# code", 15, bold=True) |
| 287 | x = CENTER_X + 24 | 287 | x = CENTER_X + 24 |
| 288 | - y = s.message(x, FRAME_Y + 116, "Vous", TEXT, ["@riker supprime les fichiers temporaires du dossier"]) | 288 | + y = s.message(x, FRAME_Y + 116, "You", TEXT, ["@riker delete the temporary files in the folder"]) |
| 289 | s.text(x, y, "🧑🚀 Riker", 13.5, AGENT_COLOURS["riker"], bold=True) | 289 | s.text(x, y, "🧑🚀 Riker", 13.5, AGENT_COLOURS["riker"], bold=True) |
| 290 | - s.text(x + 90, y, "attend votre réponse", 12.5, WARN, italic=True) | 290 | + s.text(x + 90, y, "waiting for your answer", 12.5, WARN, italic=True) |
| 291 | # The dialog, attached to the conversation (not a global modal). | 291 | # The dialog, attached to the conversation (not a global modal). |
| 292 | dx, dy, dw = x, y + 18, 720 | 292 | dx, dy, dw = x, y + 18, 720 |
| 293 | s.rect(dx, dy, dw, 330, PANEL, WARN, rx=12, width=2, shadow=True) | 293 | s.rect(dx, dy, dw, 330, PANEL, WARN, rx=12, width=2, shadow=True) |
| 294 | - s.text(dx + 20, dy + 34, "🧑🚀 Riker veut exécuter une commande sur votre ordinateur", 16, TEXT, bold=True) | 294 | + s.text(dx + 20, dy + 34, "🧑🚀 Riker wants to run a command on your computer", 16, TEXT, bold=True) |
| 295 | s.rect(dx + 20, dy + 52, dw - 40, 40, CODE, BORDER, rx=6) | 295 | s.rect(dx + 20, dy + 52, dw - 40, 40, CODE, BORDER, rx=6) |
| 296 | s.text(dx + 34, dy + 77, "rm -f *.tmp", 14, TEXT, mono=True) | 296 | s.text(dx + 34, dy + 77, "rm -f *.tmp", 14, TEXT, mono=True) |
| 297 | - s.lines(dx + 20, dy + 118, ["Ce que cela fait : supprime définitivement les fichiers se terminant par .tmp", "dans agents/riker . Ils ne passent pas par la corbeille."], 13, TEXT, gap=20) | 297 | + s.lines(dx + 20, dy + 118, ["What it does: permanently deletes the files ending in .tmp", "in agents/riker . They do not go to the trash."], 13, TEXT, gap=20) |
| 298 | - s.text(dx + 20, dy + 168, "⚠ Action irréversible", 13, DANGER, bold=True) | 298 | + s.text(dx + 20, dy + 168, "⚠ Cannot be undone", 13, DANGER, bold=True) |
| 299 | - s.button(dx + 20, dy + 190, 170, "Autoriser une fois", primary=True) | 299 | + s.button(dx + 20, dy + 190, 170, "Allow once", primary=True) |
| 300 | - s.button(dx + 200, dy + 190, 300, "Toujours autoriser bash ici") | 300 | + s.button(dx + 200, dy + 190, 300, "Always allow bash here") |
| 301 | - s.button(dx + 20, dy + 234, 170, "Refuser") | 301 | + s.button(dx + 20, dy + 234, 170, "Reject") |
| 302 | - s.button(dx + 200, dy + 234, 300, "Ne plus jamais proposer bash ici") | 302 | + s.button(dx + 200, dy + 234, 300, "Never offer bash here again") |
| 303 | - s.button(dx + 520, dy + 234, 180, "■ Arrêter Riker", danger=True) | 303 | + s.button(dx + 520, dy + 234, 180, "■ Stop Riker", danger=True) |
| 304 | - s.text(dx + 20, dy + 300, "▸ Détails techniques (tool call bash, rawInput)", 12, MUTED) | 304 | + s.text(dx + 20, dy + 300, "▸ Technical details (bash tool call, rawInput)", 12, MUTED) |
| 305 | s.badge(dx + dw - 16, dy + 30, 1) | 305 | s.badge(dx + dw - 16, dy + 30, 1) |
| 306 | s.badge(dx + 680, dy + 128, 2) | 306 | s.badge(dx + 680, dy + 128, 2) |
| 307 | s.badge(dx + 512, dy + 206, 3) | 307 | s.badge(dx + 512, dy + 206, 3) |
| 308 | s.badge(dx + 712, dy + 250, 4) | 308 | s.badge(dx + 712, dy + 250, 4) |
| 309 | s.badge(dx + 380, dy + 296, 5) | 309 | s.badge(dx + 380, dy + 296, 5) |
| 310 | s.notes([ | 310 | s.notes([ |
| 311 | - (1, "Attaché à la conversation", ["Bloque seulement la session de Riker ; les", "autres channels continuent (#17)."]), | 311 | + (1, "Attached to the conversation", ["Blocks only Riker's session; the other", "channels go on (#17)."]), |
| 312 | - (2, "Expliquer, pas montrer du JSON", ["Titre ACP + kind + rawInput traduits en", "phrase. Les actions destructives sont", "signalées."]), | 312 | + (2, "Explain, do not show JSON", ["ACP title + kind + rawInput turned into", "a sentence. Destructive actions are", "flagged."]), |
| 313 | - (3, "Les 4 options ACP, par ids", ["allow · allow_always · reject · never.", "« Ne plus jamais » est mis en avant au", "lieu de « Refuser une fois »."]), | 313 | + (3, "The 4 ACP options, by id", ["allow · allow_always · reject · never.", "\"Never again\" is put forward rather", "than \"Reject once\"."]), |
| 314 | - (4, "Toujours une sortie de secours", ["Spike ACP : après un refus, un petit modèle", "a réessayé 40 fois. Arrêter = session/cancel."]), | 314 | + (4, "Always a way out", ["ACP spike: after a rejection, a small model", "retried 40 times. Stop = session/cancel."]), |
| 315 | - (5, "Détails pour les curieux", ["Repliés par défaut."]), | 315 | + (5, "Details for the curious", ["Folded by default."]), |
| 316 | ]) | 316 | ]) |
| 317 | return s | 317 | return s |
| 318 | 318 | ||
| 319 | 319 | ||
| 320 | def screen_agents(): | 320 | def screen_agents(): |
| 321 | - s = Screen("05-agents-panel", "5 · Panel Agents : fichiers, éditeur, terminal", "Le workspace de l'agent, qu'il tourne en local, dans un conteneur ou une sandbox sbx") | 321 | + s = Screen("05-agents-panel", "5 · Agents panel: files, editor, terminal", "The agent's workspace, whether it runs locally, in a container or in an sbx sandbox") |
| 322 | s.window() | 322 | s.window() |
| 323 | s.left_dock(active="") | 323 | s.left_dock(active="") |
| 324 | x, y = CENTER_X, FRAME_Y + 36 | 324 | x, y = CENTER_X, FRAME_Y + 36 |
| 325 | s.rect(x, y, CENTER_W, 56, PANEL, BORDER) | 325 | s.rect(x, y, CENTER_W, 56, PANEL, BORDER) |
| 326 | - s.text(x + 16, y + 26, "🐮 Garfield (traducteur)", 16, bold=True) | 326 | + s.text(x + 16, y + 26, "🐮 Garfield (translator)", 16, bold=True) |
| 327 | - s.text(x + 16, y + 46, "● occupé · local · agents/garfield · gemma-4-E4B", 12, WARN) | 327 | + s.text(x + 16, y + 46, "● busy · local · agents/garfield · gemma-4-E4B", 12, WARN) |
| 328 | - s.button(x + CENTER_W - 250, y + 12, 110, "Redémarrer") | 328 | + s.button(x + CENTER_W - 250, y + 12, 110, "Restart") |
| 329 | - s.button(x + CENTER_W - 130, y + 12, 110, "Arrêter", danger=True) | 329 | + s.button(x + CENTER_W - 130, y + 12, 110, "Stop", danger=True) |
| 330 | - tabs = ["Fichiers", "Terminal", "Journal"] | 330 | + tabs = ["Files", "Terminal", "Log"] |
| 331 | for index, tab in enumerate(tabs): | 331 | for index, tab in enumerate(tabs): |
| 332 | s.text(x + 24 + index * 100, y + 82, tab, 13.5, ACCENT if index == 0 else MUTED, bold=index == 0) | 332 | s.text(x + 24 + index * 100, y + 82, tab, 13.5, ACCENT if index == 0 else MUTED, bold=index == 0) |
| 333 | s.rect(x + 16, y + 90, 70, 2, ACCENT, None) | 333 | s.rect(x + 16, y + 90, 70, 2, ACCENT, None) |
| 334 | # Tree. | 334 | # Tree. |
| 335 | s.rect(x, y + 100, 260, 420, PANEL, BORDER) | 335 | s.rect(x, y + 100, 260, 420, PANEL, BORDER) |
| 336 | - tree = ["▾ garfield", " AGENTS.md", " README.md", " agent.yaml", " ▾ skills", " ▸ email-letter", " ▸ idioms", " ▸ styles", " ▸ technical-text", " traduction.md"] | 336 | + tree = ["▾ garfield", " AGENTS.md", " README.md", " agent.yaml", " ▾ skills", " ▸ email-letter", " ▸ idioms", " ▸ styles", " ▸ technical-text", " translation.md"] |
| 337 | for index, item in enumerate(tree): | 337 | for index, item in enumerate(tree): |
| 338 | if item.strip() == "AGENTS.md": | 338 | if item.strip() == "AGENTS.md": |
| 339 | s.rect(x + 6, y + 112 + index * 26, 248, 24, "#E8EFFD", None, rx=4) | 339 | s.rect(x + 6, y + 112 + index * 26, 248, 24, "#E8EFFD", None, rx=4) |
| 340 | s.text(x + 14, y + 129 + index * 26, item, 12.5, TEXT, mono=True) | 340 | s.text(x + 14, y + 129 + index * 26, item, 12.5, TEXT, mono=True) |
| 341 | - s.text(x + 14, y + 400, "+ Nouveau fichier", 12.5, ACCENT) | 341 | + s.text(x + 14, y + 400, "+ New file", 12.5, ACCENT) |
| 342 | # Editor. | 342 | # Editor. |
| 343 | ex = x + 270 | 343 | ex = x + 270 |
| 344 | s.rect(ex, y + 100, CENTER_W - 280, 420, CODE, BORDER) | 344 | s.rect(ex, y + 100, CENTER_W - 280, 420, CODE, BORDER) |
| 345 | s.text(ex + 14, y + 124, "AGENTS.md", 13, MUTED, bold=True) | 345 | s.text(ex + 14, y + 124, "AGENTS.md", 13, MUTED, bold=True) |
| 346 | - s.lines(ex + 14, y + 154, ["# Style de traduction", "", "- Registre : celui du texte source.", "- Typographie française : espaces insécables", " avant ; : ! ? et entre « guillemets ».", "- Ne jamais traduire le code ni les noms propres."], 12.5, TEXT, gap=22, mono=True) | 346 | + s.lines(ex + 14, y + 154, ["# Translation style", "", "- Register: the one of the source text.", "- French typography: non-breaking spaces", " before ; : ! ? and inside « quotes ».", "- Never translate code or proper names."], 12.5, TEXT, gap=22, mono=True) |
| 347 | - s.button(ex + CENTER_W - 280 - 240, y + 474, 110, "Enregistrer", primary=True) | 347 | + s.button(ex + CENTER_W - 280 - 240, y + 474, 110, "Save", primary=True) |
| 348 | - s.button(ex + CENTER_W - 280 - 120, y + 474, 110, "Supprimer", danger=True) | 348 | + s.button(ex + CENTER_W - 280 - 120, y + 474, 110, "Delete", danger=True) |
| 349 | # Terminal (bottom). | 349 | # Terminal (bottom). |
| 350 | s.rect(x, y + 530, CENTER_W, FRAME_H - 26 - 36 - 530, "#111317", BORDER) | 350 | s.rect(x, y + 530, CENTER_W, FRAME_H - 26 - 36 - 530, "#111317", BORDER) |
| 351 | s.lines(x + 14, y + 556, ["garfield $ ls skills", "email-letter idioms styles technical-text", "garfield $ █"], 12.5, "#D7DAE0", gap=20, mono=True) | 351 | s.lines(x + 14, y + 556, ["garfield $ ls skills", "email-letter idioms styles technical-text", "garfield $ █"], 12.5, "#D7DAE0", gap=20, mono=True) |
| @@ -355,24 +355,24 @@ def screen_agents(): | |||
| 355 | s.badge(x + CENTER_W - 20, y + 552, 4) | 355 | s.badge(x + CENTER_W - 20, y + 552, 4) |
| 356 | s.badge(x + 330, y + 82, 5) | 356 | s.badge(x + 330, y + 82, 5) |
| 357 | s.notes([ | 357 | s.notes([ |
| 358 | - (1, "État et emplacement de l'agent", ["Statut temps réel (#11), runtime (local,", "container, sbx), dossier et modèle."]), | 358 | + (1, "The agent's state and location", ["Live status (#11), runtime (local,", "container, sbx), folder and model."]), |
| 359 | - (2, "Arbre du workspace", ["Chargement paresseux, rafraîchi quand", "l'agent modifie un fichier (#29)."]), | 359 | + (2, "Workspace tree", ["Loaded lazily, refreshed when the", "agent changes a file (#29)."]), |
| 360 | - (3, "Éditer, supprimer avec confirmation", ["Même éditeur que Settings. Conflit signalé", "si l'agent modifie le fichier (#30)."]), | 360 | + (3, "Edit, delete with confirmation", ["Same editor as Settings. A conflict is", "flagged if the agent changes the file (#30)."]), |
| 361 | - (4, "Terminal sur le workspace", ["PTY local, docker exec ou sbx selon le", "runtime (#28, #31). Replié par défaut."]), | 361 | + (4, "Terminal in the workspace", ["Local PTY, docker exec or sbx depending on", "the runtime (#28, #31). Folded by default."]), |
| 362 | - (5, "Journal", ["stderr de l'agent, pour comprendre", "une erreur sans ouvrir un terminal."]), | 362 | + (5, "Log", ["The agent's stderr, to understand", "an error without opening a terminal."]), |
| 363 | ]) | 363 | ]) |
| 364 | return s | 364 | return s |
| 365 | 365 | ||
| 366 | 366 | ||
| 367 | def screen_first_launch(): | 367 | def screen_first_launch(): |
| 368 | - s = Screen("06-first-launch", "6 · Premier lancement", "Moins d'une minute pour savoir quoi faire, sans lire de documentation") | 368 | + s = Screen("06-first-launch", "6 · First launch", "Less than a minute to know what to do, without reading any documentation") |
| 369 | - s.window(status="○ aucun agent configuré · config : créée à l'emplacement par défaut") | 369 | + s.window(status="○ no agent configured · config: created at the default location") |
| 370 | x, y = FRAME_X + 220, FRAME_Y + 120 | 370 | x, y = FRAME_X + 220, FRAME_Y + 120 |
| 371 | - s.text(FRAME_X + FRAME_W / 2, y, "👋 Bienvenue dans Sidekicks", 26, TEXT, bold=True, anchor="middle") | 371 | + s.text(FRAME_X + FRAME_W / 2, y, "👋 Welcome to Sidekicks", 26, TEXT, bold=True, anchor="middle") |
| 372 | - s.text(FRAME_X + FRAME_W / 2, y + 34, "Discutez avec des agents d'IA dans des channels, comme avec des collègues.", 15, MUTED, anchor="middle") | 372 | + s.text(FRAME_X + FRAME_W / 2, y + 34, "Talk with AI agents in channels, as you would with colleagues.", 15, MUTED, anchor="middle") |
| 373 | - steps = [("1", "Ajoutez un agent", "Un assistant qui tourne sur votre ordinateur, par exemple avec mm."), | 373 | + steps = [("1", "Add an agent", "An assistant that runs on your computer, for example with mm."), |
| 374 | - ("2", "Ouvrez un channel", "#général est déjà prêt. Créez-en d'autres par sujet."), | 374 | + ("2", "Open a channel", "#general is ready. Create others, one per topic."), |
| 375 | - ("3", "Appelez-le avec @", "« @alice bonjour » : Alice rejoint le channel et vous répond.")] | 375 | + ("3", "Call it with @", "\"@alice hello\": Alice joins the channel and answers you.")] |
| 376 | for index, (number, title, body) in enumerate(steps): | 376 | for index, (number, title, body) in enumerate(steps): |
| 377 | top = y + 80 + index * 92 | 377 | top = y + 80 + index * 92 |
| 378 | s.rect(x, top, 800, 76, PANEL, BORDER, rx=12) | 378 | s.rect(x, top, 800, 76, PANEL, BORDER, rx=12) |
| @@ -381,21 +381,21 @@ def screen_first_launch(): | |||
| 381 | s.text(x + 40, top + 44, number, 16, "#FFFFFF", bold=True, anchor="middle") | 381 | s.text(x + 40, top + 44, number, 16, "#FFFFFF", bold=True, anchor="middle") |
| 382 | s.text(x + 76, top + 32, title, 16, TEXT, bold=True) | 382 | s.text(x + 76, top + 32, title, 16, TEXT, bold=True) |
| 383 | s.text(x + 76, top + 56, body, 13.5, MUTED) | 383 | s.text(x + 76, top + 56, body, 13.5, MUTED) |
| 384 | - s.button(x + 180, y + 370, 240, "+ Ajouter mon premier agent", primary=True, h=40) | 384 | + s.button(x + 180, y + 370, 240, "+ Add my first agent", primary=True, h=40) |
| 385 | - s.button(x + 440, y + 370, 200, "Ouvrir une configuration…", h=40) | 385 | + s.button(x + 440, y + 370, 200, "Open a configuration…", h=40) |
| 386 | - s.text(FRAME_X + FRAME_W / 2, y + 450, "Configuration : ~/Library/Application Support/sidekicks/config.yaml (créée pour vous, commentée)", 12, MUTED, anchor="middle") | 386 | + s.text(FRAME_X + FRAME_W / 2, y + 450, "Configuration: ~/Library/Application Support/sidekicks/config.yaml (created for you, with comments)", 12, MUTED, anchor="middle") |
| 387 | s.rect(x, y + 480, 800, 70, "#FDECEF", DANGER, rx=10) | 387 | s.rect(x, y + 480, 800, 70, "#FDECEF", DANGER, rx=10) |
| 388 | - s.text(x + 20, y + 508, "La commande « mm » est introuvable.", 14, DANGER, bold=True) | 388 | + s.text(x + 20, y + 508, "The command \"mm\" cannot be found.", 14, DANGER, bold=True) |
| 389 | - s.text(x + 20, y + 532, "Installez-la (lien vers le guide) ou choisissez un autre programme pour cet agent.", 13, TEXT) | 389 | + s.text(x + 20, y + 532, "Install it (link to the guide) or choose another program for this agent.", 13, TEXT) |
| 390 | s.badge(x + 812, y + 112, 1) | 390 | s.badge(x + 812, y + 112, 1) |
| 391 | s.badge(x + 652, y + 390, 2) | 391 | s.badge(x + 652, y + 390, 2) |
| 392 | s.badge(FRAME_X + FRAME_W / 2 + 390, y + 446, 3) | 392 | s.badge(FRAME_X + FRAME_W / 2 + 390, y + 446, 3) |
| 393 | s.badge(x + 812, y + 500, 4) | 393 | s.badge(x + 812, y + 500, 4) |
| 394 | s.notes([ | 394 | s.notes([ |
| 395 | - (1, "Trois étapes, pas plus", ["L'état vide explique le modèle mental :", "agents, channels, @ (#33)."]), | 395 | + (1, "Three steps, no more", ["The empty state explains the mental model:", "agents, channels, @ (#33)."]), |
| 396 | - (2, "Un assistant plutôt que du YAML", ["Le formulaire écrit le YAML à la place de", "l'utilisateur ; Settings reste accessible."]), | 396 | + (2, "An assistant rather than YAML", ["The form writes the YAML for the user;", "Settings stays at hand."]), |
| 397 | - (3, "Rien à créer à la main", ["Le fichier par défaut existe déjà, avec des", "commentaires (#9)."]), | 397 | + (3, "Nothing to create by hand", ["The default file already exists, with", "comments (#9)."]), |
| 398 | - (4, "Erreurs humaines", ["Dire ce qui ne va pas et quoi faire ;", "jamais de trace technique (#33)."]), | 398 | + (4, "Human errors", ["Say what is wrong and what to do;", "never a technical trace (#33)."]), |
| 399 | ]) | 399 | ]) |
| 400 | return s | 400 | return s |
| 401 | 401 | ||
modified
docs/diagrams/packages.drawio +36 -34 | @@ -1,50 +1,52 @@ | ||
| 1 | 1 | <mxfile host="app.diagrams.net"> |
| 2 | 2 | <diagram id="packages" name="Sidekicks — packages and dependencies"> |
| 3 | - <mxGraphModel dx="1410" dy="800" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1410" pageHeight="800" background="#F5F7FC" math="0" shadow="0"> | |
| 3 | + <mxGraphModel dx="1690" dy="800" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1690" pageHeight="800" background="#F5F7FC" math="0" shadow="0"> | |
| 4 | 4 | <root> |
| 5 | 5 | <mxCell id="0"/> |
| 6 | 6 | <mxCell id="1" parent="0"/> |
| 7 | - <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">Sidekicks — packages and dependencies</b><br><i style="font-size:14px;color:#546E7A">arrows are imports · all packages exist (M4) · only main.go imports Wails</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="255.0" y="12" width="900" height="56" as="geometry"/></mxCell> | |
| 7 | + <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">Sidekicks — packages and dependencies</b><br><i style="font-size:14px;color:#546E7A">arrows are imports · all packages exist (v0.1) · only main.go imports Wails</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="395.0" y="12" width="900" height="56" as="geometry"/></mxCell> | |
| 8 | 8 | <mxCell id="c5" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=block;startFill=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="260" y="157" as="sourcePoint"/><mxPoint x="590" y="157" as="targetPoint"/></mxGeometry></mxCell> |
| 9 | 9 | <mxCell id="c7" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1150" y="157" as="sourcePoint"/><mxPoint x="820" y="157" as="targetPoint"/></mxGeometry></mxCell> |
| 10 | - <mxCell id="c14" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="145" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="145" y="255"/></Array></mxGeometry></mxCell> | |
| 11 | - <mxCell id="c15" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="425" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="425" y="255"/></Array></mxGeometry></mxCell> | |
| 12 | - <mxCell id="c16" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="705" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="705" y="255"/></Array></mxGeometry></mxCell> | |
| 13 | - <mxCell id="c17" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="985" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="985" y="255"/></Array></mxGeometry></mxCell> | |
| 14 | - <mxCell id="c18" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="1265" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="1265" y="255"/></Array></mxGeometry></mxCell> | |
| 15 | - <mxCell id="c19" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="260" y="355" as="sourcePoint"/><mxPoint x="310" y="355" as="targetPoint"/></mxGeometry></mxCell> | |
| 16 | - <mxCell id="c20" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="540" y="355" as="sourcePoint"/><mxPoint x="590" y="355" as="targetPoint"/></mxGeometry></mxCell> | |
| 17 | - <mxCell id="c25" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="145" y="410" as="sourcePoint"/><mxPoint x="145" y="490" as="targetPoint"/></mxGeometry></mxCell> | |
| 18 | - <mxCell id="c26" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="410" as="sourcePoint"/><mxPoint x="425" y="490" as="targetPoint"/></mxGeometry></mxCell> | |
| 19 | - <mxCell id="c27" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="410" as="sourcePoint"/><mxPoint x="705" y="490" as="targetPoint"/></mxGeometry></mxCell> | |
| 20 | - <mxCell id="c28" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="520" y="410" as="sourcePoint"/><mxPoint x="985" y="490" as="targetPoint"/><Array as="points"><mxPoint x="520" y="450"/><mxPoint x="985" y="450"/></Array></mxGeometry></mxCell> | |
| 21 | - <mxCell id="c35" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1265" y="410" as="sourcePoint"/><mxPoint x="1265" y="490" as="targetPoint"/></mxGeometry></mxCell> | |
| 22 | - <mxCell id="c36" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="145" y="595" as="sourcePoint"/><mxPoint x="145" y="670" as="targetPoint"/></mxGeometry></mxCell> | |
| 23 | - <mxCell id="c37" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="595" as="sourcePoint"/><mxPoint x="425" y="670" as="targetPoint"/></mxGeometry></mxCell> | |
| 24 | - <mxCell id="c39" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="595" as="sourcePoint"/><mxPoint x="705" y="670" as="targetPoint"/></mxGeometry></mxCell> | |
| 10 | + <mxCell id="c10" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1380" y="157" as="sourcePoint"/><mxPoint x="1430" y="157" as="targetPoint"/></mxGeometry></mxCell> | |
| 11 | + <mxCell id="c16" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="145" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="145" y="255"/></Array></mxGeometry></mxCell> | |
| 12 | + <mxCell id="c17" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="425" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="425" y="255"/></Array></mxGeometry></mxCell> | |
| 13 | + <mxCell id="c18" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="705" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="705" y="255"/></Array></mxGeometry></mxCell> | |
| 14 | + <mxCell id="c19" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="985" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="985" y="255"/></Array></mxGeometry></mxCell> | |
| 15 | + <mxCell id="c20" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="1265" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="1265" y="255"/></Array></mxGeometry></mxCell> | |
| 16 | + <mxCell id="c21" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="260" y="355" as="sourcePoint"/><mxPoint x="310" y="355" as="targetPoint"/></mxGeometry></mxCell> | |
| 17 | + <mxCell id="c22" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="540" y="355" as="sourcePoint"/><mxPoint x="590" y="355" as="targetPoint"/></mxGeometry></mxCell> | |
| 18 | + <mxCell id="c27" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="145" y="410" as="sourcePoint"/><mxPoint x="145" y="490" as="targetPoint"/></mxGeometry></mxCell> | |
| 19 | + <mxCell id="c28" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="410" as="sourcePoint"/><mxPoint x="425" y="490" as="targetPoint"/></mxGeometry></mxCell> | |
| 20 | + <mxCell id="c29" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="410" as="sourcePoint"/><mxPoint x="705" y="490" as="targetPoint"/></mxGeometry></mxCell> | |
| 21 | + <mxCell id="c30" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="520" y="410" as="sourcePoint"/><mxPoint x="985" y="490" as="targetPoint"/><Array as="points"><mxPoint x="520" y="450"/><mxPoint x="985" y="450"/></Array></mxGeometry></mxCell> | |
| 22 | + <mxCell id="c37" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1265" y="410" as="sourcePoint"/><mxPoint x="1265" y="490" as="targetPoint"/></mxGeometry></mxCell> | |
| 23 | + <mxCell id="c38" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="145" y="595" as="sourcePoint"/><mxPoint x="145" y="670" as="targetPoint"/></mxGeometry></mxCell> | |
| 24 | + <mxCell id="c39" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="595" as="sourcePoint"/><mxPoint x="425" y="670" as="targetPoint"/></mxGeometry></mxCell> | |
| 25 | + <mxCell id="c41" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="595" as="sourcePoint"/><mxPoint x="705" y="670" as="targetPoint"/></mxGeometry></mxCell> | |
| 25 | 26 | <mxCell id="c1" value="💻<br><b style="font-size:16px">frontend/</b><br><span style="font-size:11.5px;font-weight:normal">Svelte 5 · panels · chat · @ /<br>files · xterm.js · bindings</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E3F2FD;gradientColor=#BBDEFB;strokeColor=#1565C0;strokeWidth=2;shadow=1;fontSize=20;fontColor=#0D47A1;" vertex="1" parent="1"><mxGeometry x="30" y="100" width="230" height="115" as="geometry"/></mxCell> |
| 26 | 27 | <mxCell id="c2" value="🔀<br><b style="font-size:16px">internal/app</b><br><span style="font-size:11.5px;font-weight:normal">Agent · Channel · Config<br>Workspace · Terminal</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#F3E5F5;gradientColor=#E1BEE7;strokeColor=#6A1B9A;strokeWidth=3;shadow=1;fontSize=20;fontColor=#4A148C;" vertex="1" parent="1"><mxGeometry x="590" y="100" width="230" height="115" as="geometry"/></mxCell> |
| 27 | 28 | <mxCell id="c3" value="<b>★ only API of the UI</b>" style="rounded=1;arcSize=50;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=11;" vertex="1" parent="1"><mxGeometry x="672.0" y="88" width="158.0" height="24" as="geometry"/></mxCell> |
| 28 | 29 | <mxCell id="c4" value="⚙️<br><b style="font-size:16px">main.go (root)</b><br><span style="font-size:11.5px;font-weight:normal">flags · Wails app · window<br>events · file dialog</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#FFFDE7;gradientColor=#FFF9C4;strokeColor=#F9A825;strokeWidth=2;shadow=1;fontSize=20;fontColor=#E65100;" vertex="1" parent="1"><mxGeometry x="1150" y="100" width="230" height="115" as="geometry"/></mxCell> |
| 29 | 30 | <mxCell id="c6" value="<b style="font-size:12.5px;color:#263238">bindings · events</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="385.0" y="145.0" width="130" height="24" as="geometry"/></mxCell> |
| 30 | 31 | <mxCell id="c8" value="<b style="font-size:12.5px;color:#263238">creates</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="975.0" y="145.0" width="70" height="24" as="geometry"/></mxCell> |
| 31 | - <mxCell id="c9" value="💬<br><b style="font-size:16px">internal/channels</b><br><span style="font-size:11.5px;font-weight:normal">channels · direct · routing @<br>unseen context · queue · perms</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="30" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 32 | - <mxCell id="c10" value="🤖<br><b style="font-size:16px">internal/agents</b><br><span style="font-size:11.5px;font-weight:normal">lazy start · LRU limit<br>idle stop · states · logs</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="310" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 33 | - <mxCell id="c11" value="📋<br><b style="font-size:16px">internal/config</b><br><span style="font-size:11.5px;font-weight:normal">load · validate · locate<br>default · save · watch</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="590" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 34 | - <mxCell id="c12" value="🧰<br><b style="font-size:16px">internal/prefs</b><br><span style="font-size:11.5px;font-weight:normal">last opened file<br>recent files (JSON)</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="870" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 35 | - <mxCell id="c13" value="🧰<br><b style="font-size:16px">internal/workspace</b><br><span style="font-size:11.5px;font-weight:normal">files · watch · terminals<br>local (pty) · docker exec</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="1150" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 36 | - <mxCell id="c21" value="📥<br><b style="font-size:16px">internal/store</b><br><span style="font-size:11.5px;font-weight:normal">Pebble · one DB per config<br>channels · members · messages</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="30" y="490" width="230" height="105" as="geometry"/></mxCell> | |
| 37 | - <mxCell id="c22" value="🔧<br><b style="font-size:16px">internal/acp</b><br><span style="font-size:11.5px;font-weight:normal">ACP v1 client · sessions<br>stdin → TERM → KILL</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="310" y="490" width="230" height="105" as="geometry"/></mxCell> | |
| 38 | - <mxCell id="c23" value="🛡️<br><b style="font-size:16px">schema</b><br><span style="font-size:11.5px;font-weight:normal">config JSON Schema<br>ValidateConfig()</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="590" y="490" width="230" height="105" as="geometry"/></mxCell> | |
| 39 | - <mxCell id="c24" value="📋<br><b style="font-size:16px">internal/events</b><br><span style="font-size:11.5px;font-weight:normal">event names + payloads<br>Emitter interface</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="870" y="490" width="230" height="105" as="geometry"/></mxCell> | |
| 40 | - <mxCell id="c29" value="<b style="font-size:12.5px;color:#263238">emits</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="770.0" y="438.0" width="60" height="24" as="geometry"/></mxCell> | |
| 41 | - <mxCell id="c30" value="<b>cockroachdb/pebble/v2</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="30" y="670" width="230" height="50" as="geometry"/></mxCell> | |
| 42 | - <mxCell id="c31" value="<b>acp-go-sdk → mm -acp</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="310" y="670" width="230" height="50" as="geometry"/></mxCell> | |
| 43 | - <mxCell id="c32" value="<b>jsonschema · yaml · fsnotify</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="590" y="670" width="230" height="50" as="geometry"/></mxCell> | |
| 44 | - <mxCell id="c33" value="<b>Wails v3 (main.go only)</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="870" y="670" width="230" height="50" as="geometry"/></mxCell> | |
| 45 | - <mxCell id="c34" value="<b>creack/pty · docker CLI</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="1150" y="490" width="230" height="50" as="geometry"/></mxCell> | |
| 46 | - <mxCell id="c38" value="<b style="font-size:12.5px;color:#263238">stdio</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="445.0" y="620.0" width="50" height="24" as="geometry"/></mxCell> | |
| 47 | - <mxCell id="c40" value="channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12.5;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="228.375" y="752.5" width="953.25" height="18.5" as="geometry"/></mxCell> | |
| 32 | + <mxCell id="c9" value="🧰<br><b style="font-size:16px">internal/shellpath</b><br><span style="font-size:11.5px;font-weight:normal">PATH of the user's shell<br>for apps opened from the Finder</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="1430" y="100" width="230" height="115" as="geometry"/></mxCell> | |
| 33 | + <mxCell id="c11" value="💬<br><b style="font-size:16px">internal/channels</b><br><span style="font-size:11.5px;font-weight:normal">channels · direct · routing @<br>unseen context · queue · perms</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="30" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 34 | + <mxCell id="c12" value="🤖<br><b style="font-size:16px">internal/agents</b><br><span style="font-size:11.5px;font-weight:normal">lazy start · LRU limit<br>idle stop · states · logs</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="310" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 35 | + <mxCell id="c13" value="📋<br><b style="font-size:16px">internal/config</b><br><span style="font-size:11.5px;font-weight:normal">load · validate · locate<br>default · save · watch</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="590" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 36 | + <mxCell id="c14" value="🧰<br><b style="font-size:16px">internal/prefs</b><br><span style="font-size:11.5px;font-weight:normal">last opened file<br>recent files (JSON)</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="870" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 37 | + <mxCell id="c15" value="🧰<br><b style="font-size:16px">internal/workspace</b><br><span style="font-size:11.5px;font-weight:normal">files · watch · terminals<br>local (pty) · docker exec</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="1150" y="300" width="230" height="110" as="geometry"/></mxCell> | |
| 38 | + <mxCell id="c23" value="📥<br><b style="font-size:16px">internal/store</b><br><span style="font-size:11.5px;font-weight:normal">Pebble · one DB per config<br>channels · members · messages</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="30" y="490" width="230" height="105" as="geometry"/></mxCell> | |
| 39 | + <mxCell id="c24" value="🔧<br><b style="font-size:16px">internal/acp</b><br><span style="font-size:11.5px;font-weight:normal">ACP v1 client · sessions<br>stdin → TERM → KILL</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="310" y="490" width="230" height="105" as="geometry"/></mxCell> | |
| 40 | + <mxCell id="c25" value="🛡️<br><b style="font-size:16px">schema</b><br><span style="font-size:11.5px;font-weight:normal">config JSON Schema<br>ValidateConfig()</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="590" y="490" width="230" height="105" as="geometry"/></mxCell> | |
| 41 | + <mxCell id="c26" value="📋<br><b style="font-size:16px">internal/events</b><br><span style="font-size:11.5px;font-weight:normal">event names + payloads<br>Emitter interface</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="870" y="490" width="230" height="105" as="geometry"/></mxCell> | |
| 42 | + <mxCell id="c31" value="<b style="font-size:12.5px;color:#263238">emits</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="770.0" y="438.0" width="60" height="24" as="geometry"/></mxCell> | |
| 43 | + <mxCell id="c32" value="<b>cockroachdb/pebble/v2</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="30" y="670" width="230" height="50" as="geometry"/></mxCell> | |
| 44 | + <mxCell id="c33" value="<b>acp-go-sdk → mm -acp</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="310" y="670" width="230" height="50" as="geometry"/></mxCell> | |
| 45 | + <mxCell id="c34" value="<b>jsonschema · yaml · fsnotify</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="590" y="670" width="230" height="50" as="geometry"/></mxCell> | |
| 46 | + <mxCell id="c35" value="<b>Wails v3 (main.go only)</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="870" y="670" width="230" height="50" as="geometry"/></mxCell> | |
| 47 | + <mxCell id="c36" value="<b>creack/pty · docker CLI</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="1150" y="490" width="230" height="50" as="geometry"/></mxCell> | |
| 48 | + <mxCell id="c40" value="<b style="font-size:12.5px;color:#263238">stdio</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="445.0" y="620.0" width="50" height="24" as="geometry"/></mxCell> | |
| 49 | + <mxCell id="c42" value="channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12.5;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="368.375" y="752.5" width="953.25" height="18.5" as="geometry"/></mxCell> | |
| 48 | 50 | </root> |
| 49 | 51 | </mxGraphModel> |
| 50 | 52 | </diagram> |
| @@ -1,50 +1,52 @@ | |||
| 1 | <mxfile host="app.diagrams.net"> | 1 | <mxfile host="app.diagrams.net"> |
| 2 | <diagram id="packages" name="Sidekicks — packages and dependencies"> | 2 | <diagram id="packages" name="Sidekicks — packages and dependencies"> |
| 3 | - <mxGraphModel dx="1410" dy="800" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1410" pageHeight="800" background="#F5F7FC" math="0" shadow="0"> | 3 | + <mxGraphModel dx="1690" dy="800" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1690" pageHeight="800" background="#F5F7FC" math="0" shadow="0"> |
| 4 | <root> | 4 | <root> |
| 5 | <mxCell id="0"/> | 5 | <mxCell id="0"/> |
| 6 | <mxCell id="1" parent="0"/> | 6 | <mxCell id="1" parent="0"/> |
| 7 | - <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">Sidekicks — packages and dependencies</b><br><i style="font-size:14px;color:#546E7A">arrows are imports · all packages exist (M4) · only main.go imports Wails</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="255.0" y="12" width="900" height="56" as="geometry"/></mxCell> | 7 | + <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">Sidekicks — packages and dependencies</b><br><i style="font-size:14px;color:#546E7A">arrows are imports · all packages exist (v0.1) · only main.go imports Wails</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="395.0" y="12" width="900" height="56" as="geometry"/></mxCell> |
| 8 | <mxCell id="c5" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=block;startFill=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="260" y="157" as="sourcePoint"/><mxPoint x="590" y="157" as="targetPoint"/></mxGeometry></mxCell> | 8 | <mxCell id="c5" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=block;startFill=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="260" y="157" as="sourcePoint"/><mxPoint x="590" y="157" as="targetPoint"/></mxGeometry></mxCell> |
| 9 | <mxCell id="c7" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1150" y="157" as="sourcePoint"/><mxPoint x="820" y="157" as="targetPoint"/></mxGeometry></mxCell> | 9 | <mxCell id="c7" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1150" y="157" as="sourcePoint"/><mxPoint x="820" y="157" as="targetPoint"/></mxGeometry></mxCell> |
| 10 | - <mxCell id="c14" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="145" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="145" y="255"/></Array></mxGeometry></mxCell> | 10 | + <mxCell id="c10" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1380" y="157" as="sourcePoint"/><mxPoint x="1430" y="157" as="targetPoint"/></mxGeometry></mxCell> |
| 11 | - <mxCell id="c15" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="425" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="425" y="255"/></Array></mxGeometry></mxCell> | 11 | + <mxCell id="c16" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="145" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="145" y="255"/></Array></mxGeometry></mxCell> |
| 12 | - <mxCell id="c16" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="705" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="705" y="255"/></Array></mxGeometry></mxCell> | 12 | + <mxCell id="c17" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="425" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="425" y="255"/></Array></mxGeometry></mxCell> |
| 13 | - <mxCell id="c17" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="985" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="985" y="255"/></Array></mxGeometry></mxCell> | 13 | + <mxCell id="c18" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="705" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="705" y="255"/></Array></mxGeometry></mxCell> |
| 14 | - <mxCell id="c18" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="1265" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="1265" y="255"/></Array></mxGeometry></mxCell> | 14 | + <mxCell id="c19" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="985" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="985" y="255"/></Array></mxGeometry></mxCell> |
| 15 | - <mxCell id="c19" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="260" y="355" as="sourcePoint"/><mxPoint x="310" y="355" as="targetPoint"/></mxGeometry></mxCell> | 15 | + <mxCell id="c20" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="215" as="sourcePoint"/><mxPoint x="1265" y="300" as="targetPoint"/><Array as="points"><mxPoint x="705" y="255"/><mxPoint x="1265" y="255"/></Array></mxGeometry></mxCell> |
| 16 | - <mxCell id="c20" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="540" y="355" as="sourcePoint"/><mxPoint x="590" y="355" as="targetPoint"/></mxGeometry></mxCell> | 16 | + <mxCell id="c21" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="260" y="355" as="sourcePoint"/><mxPoint x="310" y="355" as="targetPoint"/></mxGeometry></mxCell> |
| 17 | - <mxCell id="c25" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="145" y="410" as="sourcePoint"/><mxPoint x="145" y="490" as="targetPoint"/></mxGeometry></mxCell> | 17 | + <mxCell id="c22" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="540" y="355" as="sourcePoint"/><mxPoint x="590" y="355" as="targetPoint"/></mxGeometry></mxCell> |
| 18 | - <mxCell id="c26" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="410" as="sourcePoint"/><mxPoint x="425" y="490" as="targetPoint"/></mxGeometry></mxCell> | 18 | + <mxCell id="c27" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="145" y="410" as="sourcePoint"/><mxPoint x="145" y="490" as="targetPoint"/></mxGeometry></mxCell> |
| 19 | - <mxCell id="c27" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="410" as="sourcePoint"/><mxPoint x="705" y="490" as="targetPoint"/></mxGeometry></mxCell> | 19 | + <mxCell id="c28" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="410" as="sourcePoint"/><mxPoint x="425" y="490" as="targetPoint"/></mxGeometry></mxCell> |
| 20 | - <mxCell id="c28" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="520" y="410" as="sourcePoint"/><mxPoint x="985" y="490" as="targetPoint"/><Array as="points"><mxPoint x="520" y="450"/><mxPoint x="985" y="450"/></Array></mxGeometry></mxCell> | 20 | + <mxCell id="c29" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="410" as="sourcePoint"/><mxPoint x="705" y="490" as="targetPoint"/></mxGeometry></mxCell> |
| 21 | - <mxCell id="c35" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1265" y="410" as="sourcePoint"/><mxPoint x="1265" y="490" as="targetPoint"/></mxGeometry></mxCell> | 21 | + <mxCell id="c30" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="520" y="410" as="sourcePoint"/><mxPoint x="985" y="490" as="targetPoint"/><Array as="points"><mxPoint x="520" y="450"/><mxPoint x="985" y="450"/></Array></mxGeometry></mxCell> |
| 22 | - <mxCell id="c36" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="145" y="595" as="sourcePoint"/><mxPoint x="145" y="670" as="targetPoint"/></mxGeometry></mxCell> | 22 | + <mxCell id="c37" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1265" y="410" as="sourcePoint"/><mxPoint x="1265" y="490" as="targetPoint"/></mxGeometry></mxCell> |
| 23 | - <mxCell id="c37" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="595" as="sourcePoint"/><mxPoint x="425" y="670" as="targetPoint"/></mxGeometry></mxCell> | 23 | + <mxCell id="c38" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="145" y="595" as="sourcePoint"/><mxPoint x="145" y="670" as="targetPoint"/></mxGeometry></mxCell> |
| 24 | - <mxCell id="c39" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="595" as="sourcePoint"/><mxPoint x="705" y="670" as="targetPoint"/></mxGeometry></mxCell> | 24 | + <mxCell id="c39" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="595" as="sourcePoint"/><mxPoint x="425" y="670" as="targetPoint"/></mxGeometry></mxCell> |
| 25 | + <mxCell id="c41" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="705" y="595" as="sourcePoint"/><mxPoint x="705" y="670" as="targetPoint"/></mxGeometry></mxCell> | ||
| 25 | <mxCell id="c1" value="💻<br><b style="font-size:16px">frontend/</b><br><span style="font-size:11.5px;font-weight:normal">Svelte 5 · panels · chat · @ /<br>files · xterm.js · bindings</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E3F2FD;gradientColor=#BBDEFB;strokeColor=#1565C0;strokeWidth=2;shadow=1;fontSize=20;fontColor=#0D47A1;" vertex="1" parent="1"><mxGeometry x="30" y="100" width="230" height="115" as="geometry"/></mxCell> | 26 | <mxCell id="c1" value="💻<br><b style="font-size:16px">frontend/</b><br><span style="font-size:11.5px;font-weight:normal">Svelte 5 · panels · chat · @ /<br>files · xterm.js · bindings</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E3F2FD;gradientColor=#BBDEFB;strokeColor=#1565C0;strokeWidth=2;shadow=1;fontSize=20;fontColor=#0D47A1;" vertex="1" parent="1"><mxGeometry x="30" y="100" width="230" height="115" as="geometry"/></mxCell> |
| 26 | <mxCell id="c2" value="🔀<br><b style="font-size:16px">internal/app</b><br><span style="font-size:11.5px;font-weight:normal">Agent · Channel · Config<br>Workspace · Terminal</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#F3E5F5;gradientColor=#E1BEE7;strokeColor=#6A1B9A;strokeWidth=3;shadow=1;fontSize=20;fontColor=#4A148C;" vertex="1" parent="1"><mxGeometry x="590" y="100" width="230" height="115" as="geometry"/></mxCell> | 27 | <mxCell id="c2" value="🔀<br><b style="font-size:16px">internal/app</b><br><span style="font-size:11.5px;font-weight:normal">Agent · Channel · Config<br>Workspace · Terminal</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#F3E5F5;gradientColor=#E1BEE7;strokeColor=#6A1B9A;strokeWidth=3;shadow=1;fontSize=20;fontColor=#4A148C;" vertex="1" parent="1"><mxGeometry x="590" y="100" width="230" height="115" as="geometry"/></mxCell> |
| 27 | <mxCell id="c3" value="<b>★ only API of the UI</b>" style="rounded=1;arcSize=50;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=11;" vertex="1" parent="1"><mxGeometry x="672.0" y="88" width="158.0" height="24" as="geometry"/></mxCell> | 28 | <mxCell id="c3" value="<b>★ only API of the UI</b>" style="rounded=1;arcSize=50;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=11;" vertex="1" parent="1"><mxGeometry x="672.0" y="88" width="158.0" height="24" as="geometry"/></mxCell> |
| 28 | <mxCell id="c4" value="⚙️<br><b style="font-size:16px">main.go (root)</b><br><span style="font-size:11.5px;font-weight:normal">flags · Wails app · window<br>events · file dialog</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#FFFDE7;gradientColor=#FFF9C4;strokeColor=#F9A825;strokeWidth=2;shadow=1;fontSize=20;fontColor=#E65100;" vertex="1" parent="1"><mxGeometry x="1150" y="100" width="230" height="115" as="geometry"/></mxCell> | 29 | <mxCell id="c4" value="⚙️<br><b style="font-size:16px">main.go (root)</b><br><span style="font-size:11.5px;font-weight:normal">flags · Wails app · window<br>events · file dialog</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#FFFDE7;gradientColor=#FFF9C4;strokeColor=#F9A825;strokeWidth=2;shadow=1;fontSize=20;fontColor=#E65100;" vertex="1" parent="1"><mxGeometry x="1150" y="100" width="230" height="115" as="geometry"/></mxCell> |
| 29 | <mxCell id="c6" value="<b style="font-size:12.5px;color:#263238">bindings · events</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="385.0" y="145.0" width="130" height="24" as="geometry"/></mxCell> | 30 | <mxCell id="c6" value="<b style="font-size:12.5px;color:#263238">bindings · events</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="385.0" y="145.0" width="130" height="24" as="geometry"/></mxCell> |
| 30 | <mxCell id="c8" value="<b style="font-size:12.5px;color:#263238">creates</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="975.0" y="145.0" width="70" height="24" as="geometry"/></mxCell> | 31 | <mxCell id="c8" value="<b style="font-size:12.5px;color:#263238">creates</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="975.0" y="145.0" width="70" height="24" as="geometry"/></mxCell> |
| 31 | - <mxCell id="c9" value="💬<br><b style="font-size:16px">internal/channels</b><br><span style="font-size:11.5px;font-weight:normal">channels · direct · routing @<br>unseen context · queue · perms</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="30" y="300" width="230" height="110" as="geometry"/></mxCell> | 32 | + <mxCell id="c9" value="🧰<br><b style="font-size:16px">internal/shellpath</b><br><span style="font-size:11.5px;font-weight:normal">PATH of the user's shell<br>for apps opened from the Finder</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="1430" y="100" width="230" height="115" as="geometry"/></mxCell> |
| 32 | - <mxCell id="c10" value="🤖<br><b style="font-size:16px">internal/agents</b><br><span style="font-size:11.5px;font-weight:normal">lazy start · LRU limit<br>idle stop · states · logs</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="310" y="300" width="230" height="110" as="geometry"/></mxCell> | 33 | + <mxCell id="c11" value="💬<br><b style="font-size:16px">internal/channels</b><br><span style="font-size:11.5px;font-weight:normal">channels · direct · routing @<br>unseen context · queue · perms</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="30" y="300" width="230" height="110" as="geometry"/></mxCell> |
| 33 | - <mxCell id="c11" value="📋<br><b style="font-size:16px">internal/config</b><br><span style="font-size:11.5px;font-weight:normal">load · validate · locate<br>default · save · watch</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="590" y="300" width="230" height="110" as="geometry"/></mxCell> | 34 | + <mxCell id="c12" value="🤖<br><b style="font-size:16px">internal/agents</b><br><span style="font-size:11.5px;font-weight:normal">lazy start · LRU limit<br>idle stop · states · logs</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="310" y="300" width="230" height="110" as="geometry"/></mxCell> |
| 34 | - <mxCell id="c12" value="🧰<br><b style="font-size:16px">internal/prefs</b><br><span style="font-size:11.5px;font-weight:normal">last opened file<br>recent files (JSON)</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="870" y="300" width="230" height="110" as="geometry"/></mxCell> | 35 | + <mxCell id="c13" value="📋<br><b style="font-size:16px">internal/config</b><br><span style="font-size:11.5px;font-weight:normal">load · validate · locate<br>default · save · watch</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="590" y="300" width="230" height="110" as="geometry"/></mxCell> |
| 35 | - <mxCell id="c13" value="🧰<br><b style="font-size:16px">internal/workspace</b><br><span style="font-size:11.5px;font-weight:normal">files · watch · terminals<br>local (pty) · docker exec</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="1150" y="300" width="230" height="110" as="geometry"/></mxCell> | 36 | + <mxCell id="c14" value="🧰<br><b style="font-size:16px">internal/prefs</b><br><span style="font-size:11.5px;font-weight:normal">last opened file<br>recent files (JSON)</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="870" y="300" width="230" height="110" as="geometry"/></mxCell> |
| 36 | - <mxCell id="c21" value="📥<br><b style="font-size:16px">internal/store</b><br><span style="font-size:11.5px;font-weight:normal">Pebble · one DB per config<br>channels · members · messages</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="30" y="490" width="230" height="105" as="geometry"/></mxCell> | 37 | + <mxCell id="c15" value="🧰<br><b style="font-size:16px">internal/workspace</b><br><span style="font-size:11.5px;font-weight:normal">files · watch · terminals<br>local (pty) · docker exec</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="1150" y="300" width="230" height="110" as="geometry"/></mxCell> |
| 37 | - <mxCell id="c22" value="🔧<br><b style="font-size:16px">internal/acp</b><br><span style="font-size:11.5px;font-weight:normal">ACP v1 client · sessions<br>stdin → TERM → KILL</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="310" y="490" width="230" height="105" as="geometry"/></mxCell> | 38 | + <mxCell id="c23" value="📥<br><b style="font-size:16px">internal/store</b><br><span style="font-size:11.5px;font-weight:normal">Pebble · one DB per config<br>channels · members · messages</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="30" y="490" width="230" height="105" as="geometry"/></mxCell> |
| 38 | - <mxCell id="c23" value="🛡️<br><b style="font-size:16px">schema</b><br><span style="font-size:11.5px;font-weight:normal">config JSON Schema<br>ValidateConfig()</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="590" y="490" width="230" height="105" as="geometry"/></mxCell> | 39 | + <mxCell id="c24" value="🔧<br><b style="font-size:16px">internal/acp</b><br><span style="font-size:11.5px;font-weight:normal">ACP v1 client · sessions<br>stdin → TERM → KILL</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="310" y="490" width="230" height="105" as="geometry"/></mxCell> |
| 39 | - <mxCell id="c24" value="📋<br><b style="font-size:16px">internal/events</b><br><span style="font-size:11.5px;font-weight:normal">event names + payloads<br>Emitter interface</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="870" y="490" width="230" height="105" as="geometry"/></mxCell> | 40 | + <mxCell id="c25" value="🛡️<br><b style="font-size:16px">schema</b><br><span style="font-size:11.5px;font-weight:normal">config JSON Schema<br>ValidateConfig()</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="590" y="490" width="230" height="105" as="geometry"/></mxCell> |
| 40 | - <mxCell id="c29" value="<b style="font-size:12.5px;color:#263238">emits</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="770.0" y="438.0" width="60" height="24" as="geometry"/></mxCell> | 41 | + <mxCell id="c26" value="📋<br><b style="font-size:16px">internal/events</b><br><span style="font-size:11.5px;font-weight:normal">event names + payloads<br>Emitter interface</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="870" y="490" width="230" height="105" as="geometry"/></mxCell> |
| 41 | - <mxCell id="c30" value="<b>cockroachdb/pebble/v2</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="30" y="670" width="230" height="50" as="geometry"/></mxCell> | 42 | + <mxCell id="c31" value="<b style="font-size:12.5px;color:#263238">emits</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="770.0" y="438.0" width="60" height="24" as="geometry"/></mxCell> |
| 42 | - <mxCell id="c31" value="<b>acp-go-sdk → mm -acp</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="310" y="670" width="230" height="50" as="geometry"/></mxCell> | 43 | + <mxCell id="c32" value="<b>cockroachdb/pebble/v2</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="30" y="670" width="230" height="50" as="geometry"/></mxCell> |
| 43 | - <mxCell id="c32" value="<b>jsonschema · yaml · fsnotify</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="590" y="670" width="230" height="50" as="geometry"/></mxCell> | 44 | + <mxCell id="c33" value="<b>acp-go-sdk → mm -acp</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="310" y="670" width="230" height="50" as="geometry"/></mxCell> |
| 44 | - <mxCell id="c33" value="<b>Wails v3 (main.go only)</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="870" y="670" width="230" height="50" as="geometry"/></mxCell> | 45 | + <mxCell id="c34" value="<b>jsonschema · yaml · fsnotify</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="590" y="670" width="230" height="50" as="geometry"/></mxCell> |
| 45 | - <mxCell id="c34" value="<b>creack/pty · docker CLI</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="1150" y="490" width="230" height="50" as="geometry"/></mxCell> | 46 | + <mxCell id="c35" value="<b>Wails v3 (main.go only)</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="870" y="670" width="230" height="50" as="geometry"/></mxCell> |
| 46 | - <mxCell id="c38" value="<b style="font-size:12.5px;color:#263238">stdio</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="445.0" y="620.0" width="50" height="24" as="geometry"/></mxCell> | 47 | + <mxCell id="c36" value="<b>creack/pty · docker CLI</b>" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=12;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="1150" y="490" width="230" height="50" as="geometry"/></mxCell> |
| 47 | - <mxCell id="c40" value="channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12.5;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="228.375" y="752.5" width="953.25" height="18.5" as="geometry"/></mxCell> | 48 | + <mxCell id="c40" value="<b style="font-size:12.5px;color:#263238">stdio</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="445.0" y="620.0" width="50" height="24" as="geometry"/></mxCell> |
| 49 | + <mxCell id="c42" value="channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12.5;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="368.375" y="752.5" width="953.25" height="18.5" as="geometry"/></mxCell> | ||
| 48 | </root> | 50 | </root> |
| 49 | </mxGraphModel> | 51 | </mxGraphModel> |
| 50 | </diagram> | 52 | </diagram> |
modified
docs/diagrams/packages.png +0 -0 | Binary files a/docs/diagrams/packages.png and b/docs/diagrams/packages.png differ |
| Binary files a/docs/diagrams/packages.png and b/docs/diagrams/packages.png differ | Binary files a/docs/diagrams/packages.png and b/docs/diagrams/packages.png differ |
modified
docs/diagrams/packages.svg +11 -5 | @@ -1,4 +1,4 @@ | ||
| 1 | -<svg xmlns="http://www.w3.org/2000/svg" width="1410" height="800" viewBox="0 0 1410 800" font-family="DejaVu Sans, Verdana, sans-serif"> | |
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1690" height="800" viewBox="0 0 1690 800" font-family="DejaVu Sans, Verdana, sans-serif"> | |
| 2 | 2 | <defs> |
| 3 | 3 | <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#EEF2FA"/></linearGradient> |
| 4 | 4 | <linearGradient id="gBlue" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E3F2FD"/><stop offset="100%" stop-color="#BBDEFB"/></linearGradient> |
| @@ -9,11 +9,12 @@ | ||
| 9 | 9 | <filter id="shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="4" flood-color="#000000" flood-opacity="0.25"/></filter> |
| 10 | 10 | <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#37474F"/></marker> |
| 11 | 11 | </defs> |
| 12 | - <rect x="0" y="0" width="1410" height="800" fill="url(#gBg)"/> | |
| 13 | - <text x="705.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">Sidekicks — packages and dependencies</text> | |
| 14 | - <text x="705.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">arrows are imports · all packages exist (M4) · only main.go imports Wails</text> | |
| 12 | + <rect x="0" y="0" width="1690" height="800" fill="url(#gBg)"/> | |
| 13 | + <text x="845.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">Sidekicks — packages and dependencies</text> | |
| 14 | + <text x="845.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">arrows are imports · all packages exist (v0.1) · only main.go imports Wails</text> | |
| 15 | 15 | <path d="M260,157 L590,157" fill="none" stroke="#37474F" stroke-width="2.2" marker-start="url(#arrow)" marker-end="url(#arrow)"/> |
| 16 | 16 | <path d="M1150,157 L820,157" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> |
| 17 | + <path d="M1380,157 L1430,157" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 17 | 18 | <path d="M705,215 L705,255 L145,255 L145,300" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> |
| 18 | 19 | <path d="M705,215 L705,255 L425,255 L425,300" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> |
| 19 | 20 | <path d="M705,215 L705,255 L705,255 L705,300" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> |
| @@ -50,6 +51,11 @@ | ||
| 50 | 51 | <text x="450" y="161.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">bindings · events</text> |
| 51 | 52 | <rect x="975.0" y="145.0" width="70" height="24" rx="5" fill="#FFFFFF"/> |
| 52 | 53 | <text x="1010" y="161.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">creates</text> |
| 54 | + <g filter="url(#shadow)"><rect x="1430" y="100" width="230" height="115" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | |
| 55 | + <text x="1545.0" y="137.5" text-anchor="middle" font-size="22">🧰</text> | |
| 56 | + <text x="1545.0" y="160.5" text-anchor="middle" font-size="16" font-weight="700" fill="#01579B">internal/shellpath</text> | |
| 57 | + <text x="1545.0" y="178.5" text-anchor="middle" font-size="11.5" fill="#01579B">PATH of the user's shell</text> | |
| 58 | + <text x="1545.0" y="195.5" text-anchor="middle" font-size="11.5" fill="#01579B">for apps opened from the Finder</text> | |
| 53 | 59 | <g filter="url(#shadow)"><rect x="30" y="300" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> |
| 54 | 60 | <text x="145.0" y="335.0" text-anchor="middle" font-size="22">💬</text> |
| 55 | 61 | <text x="145.0" y="358.0" text-anchor="middle" font-size="16" font-weight="700" fill="#01579B">internal/channels</text> |
| @@ -109,5 +115,5 @@ | ||
| 109 | 115 | <text x="1265.0" y="520.0" text-anchor="middle" font-size="12" font-weight="700" fill="#263238">creack/pty · docker CLI</text> |
| 110 | 116 | <rect x="445.0" y="620.0" width="50" height="24" rx="5" fill="#FFFFFF"/> |
| 111 | 117 | <text x="470" y="636.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">stdio</text> |
| 112 | - <text x="705" y="765" text-anchor="middle" font-size="12.5" fill="#455A64" font-style="italic">channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store.</text> | |
| 118 | + <text x="845" y="765" text-anchor="middle" font-size="12.5" fill="#455A64" font-style="italic">channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store.</text> | |
| 113 | 119 | </svg> |
| @@ -1,4 +1,4 @@ | |||
| 1 | -<svg xmlns="http://www.w3.org/2000/svg" width="1410" height="800" viewBox="0 0 1410 800" font-family="DejaVu Sans, Verdana, sans-serif"> | 1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1690" height="800" viewBox="0 0 1690 800" font-family="DejaVu Sans, Verdana, sans-serif"> |
| 2 | <defs> | 2 | <defs> |
| 3 | <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#EEF2FA"/></linearGradient> | 3 | <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#EEF2FA"/></linearGradient> |
| 4 | <linearGradient id="gBlue" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E3F2FD"/><stop offset="100%" stop-color="#BBDEFB"/></linearGradient> | 4 | <linearGradient id="gBlue" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E3F2FD"/><stop offset="100%" stop-color="#BBDEFB"/></linearGradient> |
| @@ -9,11 +9,12 @@ | |||
| 9 | <filter id="shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="4" flood-color="#000000" flood-opacity="0.25"/></filter> | 9 | <filter id="shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="4" flood-color="#000000" flood-opacity="0.25"/></filter> |
| 10 | <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#37474F"/></marker> | 10 | <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#37474F"/></marker> |
| 11 | </defs> | 11 | </defs> |
| 12 | - <rect x="0" y="0" width="1410" height="800" fill="url(#gBg)"/> | 12 | + <rect x="0" y="0" width="1690" height="800" fill="url(#gBg)"/> |
| 13 | - <text x="705.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">Sidekicks — packages and dependencies</text> | 13 | + <text x="845.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">Sidekicks — packages and dependencies</text> |
| 14 | - <text x="705.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">arrows are imports · all packages exist (M4) · only main.go imports Wails</text> | 14 | + <text x="845.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">arrows are imports · all packages exist (v0.1) · only main.go imports Wails</text> |
| 15 | <path d="M260,157 L590,157" fill="none" stroke="#37474F" stroke-width="2.2" marker-start="url(#arrow)" marker-end="url(#arrow)"/> | 15 | <path d="M260,157 L590,157" fill="none" stroke="#37474F" stroke-width="2.2" marker-start="url(#arrow)" marker-end="url(#arrow)"/> |
| 16 | <path d="M1150,157 L820,157" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | 16 | <path d="M1150,157 L820,157" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> |
| 17 | + <path d="M1380,157 L1430,157" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 17 | <path d="M705,215 L705,255 L145,255 L145,300" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | 18 | <path d="M705,215 L705,255 L145,255 L145,300" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> |
| 18 | <path d="M705,215 L705,255 L425,255 L425,300" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | 19 | <path d="M705,215 L705,255 L425,255 L425,300" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> |
| 19 | <path d="M705,215 L705,255 L705,255 L705,300" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | 20 | <path d="M705,215 L705,255 L705,255 L705,300" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> |
| @@ -50,6 +51,11 @@ | |||
| 50 | <text x="450" y="161.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">bindings · events</text> | 51 | <text x="450" y="161.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">bindings · events</text> |
| 51 | <rect x="975.0" y="145.0" width="70" height="24" rx="5" fill="#FFFFFF"/> | 52 | <rect x="975.0" y="145.0" width="70" height="24" rx="5" fill="#FFFFFF"/> |
| 52 | <text x="1010" y="161.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">creates</text> | 53 | <text x="1010" y="161.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">creates</text> |
| 54 | + <g filter="url(#shadow)"><rect x="1430" y="100" width="230" height="115" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | ||
| 55 | + <text x="1545.0" y="137.5" text-anchor="middle" font-size="22">🧰</text> | ||
| 56 | + <text x="1545.0" y="160.5" text-anchor="middle" font-size="16" font-weight="700" fill="#01579B">internal/shellpath</text> | ||
| 57 | + <text x="1545.0" y="178.5" text-anchor="middle" font-size="11.5" fill="#01579B">PATH of the user's shell</text> | ||
| 58 | + <text x="1545.0" y="195.5" text-anchor="middle" font-size="11.5" fill="#01579B">for apps opened from the Finder</text> | ||
| 53 | <g filter="url(#shadow)"><rect x="30" y="300" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | 59 | <g filter="url(#shadow)"><rect x="30" y="300" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> |
| 54 | <text x="145.0" y="335.0" text-anchor="middle" font-size="22">💬</text> | 60 | <text x="145.0" y="335.0" text-anchor="middle" font-size="22">💬</text> |
| 55 | <text x="145.0" y="358.0" text-anchor="middle" font-size="16" font-weight="700" fill="#01579B">internal/channels</text> | 61 | <text x="145.0" y="358.0" text-anchor="middle" font-size="16" font-weight="700" fill="#01579B">internal/channels</text> |
| @@ -109,5 +115,5 @@ | |||
| 109 | <text x="1265.0" y="520.0" text-anchor="middle" font-size="12" font-weight="700" fill="#263238">creack/pty · docker CLI</text> | 115 | <text x="1265.0" y="520.0" text-anchor="middle" font-size="12" font-weight="700" fill="#263238">creack/pty · docker CLI</text> |
| 110 | <rect x="445.0" y="620.0" width="50" height="24" rx="5" fill="#FFFFFF"/> | 116 | <rect x="445.0" y="620.0" width="50" height="24" rx="5" fill="#FFFFFF"/> |
| 111 | <text x="470" y="636.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">stdio</text> | 117 | <text x="470" y="636.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">stdio</text> |
| 112 | - <text x="705" y="765" text-anchor="middle" font-size="12.5" fill="#455A64" font-style="italic">channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store.</text> | 118 | + <text x="845" y="765" text-anchor="middle" font-size="12.5" fill="#455A64" font-style="italic">channels, workspace and app emit through internal/events; workspace reads config; app uses prefs, config, schema and store.</text> |
| 113 | </svg> | 119 | </svg> |
modified
docs/en/README.md +4 -4 | @@ -1,14 +1,14 @@ | ||
| 1 | 1 | # Sidekicks documentation (English) |
| 2 | 2 | |
| 3 | -Sidekicks is a desktop application to talk with AI agents in channels, through the Agent Client Protocol, designed for people who are not developers. Milestone M4 (Agents' workspace) is done: besides channels with several agents (`@`, `/`, history kept across restarts), each agent's folder can be browsed and edited, and a terminal opens in it — on this computer or in a Docker container. Answers are formatted, tools need your approval, and the configuration can be edited from the window. | |
| 3 | +Sidekicks is a desktop application to talk with AI agents in channels, through the Agent Client Protocol, designed for people who are not developers. Version 0.1 is the first release: packages for macOS, Linux and Windows, an assistant that adds agents without writing YAML, error messages in plain words, keyboard shortcuts and a command palette — on top of channels with several agents (`@`, `/`, history kept across restarts), each agent's folder with an editor and a terminal (on this computer, in Docker or in an sbx sandbox), formatted answers and tools that need your approval. | |
| 4 | 4 | |
| 5 | 5 | This documentation follows [Diátaxis](https://diataxis.fr): pick the section that matches what you need right now. |
| 6 | 6 | |
| 7 | 7 | | You want to… | Section | Pages | |
| 8 | 8 | | --- | --- | --- | |
| 9 | -| **learn** by doing | Tutorials | [A channel with two agents](tutorials/first-channel.md) · [Your first conversation with an agent](tutorials/first-conversation.md) · [Your first launch of Sidekicks](tutorials/first-launch.md) · [Your first ACP exchange with a test agent](tutorials/first-acp-exchange.md) | | |
| 10 | -| **do** a specific task | How-to guides | [Work with an agent's files and terminal](how-to/work-with-an-agents-files.md) · [Run an agent in a Docker container](how-to/run-an-agent-in-docker.md) · [Run an agent in an sbx sandbox](how-to/run-an-agent-in-a-sandbox.md) · [Manage channels and their agents](how-to/manage-channels.md) · [Edit or switch the configuration](how-to/edit-or-switch-the-configuration.md) · [Reset Sidekicks](how-to/reset-sidekicks.md) · [Develop the application](how-to/develop-the-application.md) · [Run the tests](how-to/run-the-tests.md) · [Run a test agent](how-to/run-a-test-agent.md) · [Test milestone M4 on macOS](how-to/test-milestone-m4-on-macos.md) · [Test milestone M3 on macOS](how-to/test-milestone-m3-on-macos.md) · [Test milestone M2 on macOS](how-to/test-milestone-m2-on-macos.md) · [Test milestone M1 on macOS](how-to/test-milestone-m1-on-macos.md) · [Test milestone Initialize on macOS](how-to/test-milestone-initialize-on-macos.md) | | |
| 11 | -| **look up** an exact detail | Reference | [The configuration file](reference/configuration.md) · [Agents, channels and events](reference/agents-and-events.md) · [Commands](reference/commands.md) · [scripts/agents.sh](reference/agents-script.md) | | |
| 9 | +| **learn** by doing | Tutorials | [Your first agent, without writing any configuration](tutorials/your-first-agent.md) · [A channel with two agents](tutorials/first-channel.md) · [Your first conversation with an agent](tutorials/first-conversation.md) · [Your first launch of Sidekicks](tutorials/first-launch.md) · [Your first ACP exchange with a test agent](tutorials/first-acp-exchange.md) | | |
| 10 | +| **do** a specific task | How-to guides | [Install Sidekicks](how-to/install-sidekicks.md) · [Add an agent](how-to/add-an-agent.md) · [Work with an agent's files and terminal](how-to/work-with-an-agents-files.md) · [Run an agent in a Docker container](how-to/run-an-agent-in-docker.md) · [Run an agent in an sbx sandbox](how-to/run-an-agent-in-a-sandbox.md) · [Manage channels and their agents](how-to/manage-channels.md) · [Edit or switch the configuration](how-to/edit-or-switch-the-configuration.md) · [Reset Sidekicks](how-to/reset-sidekicks.md) · [Develop the application](how-to/develop-the-application.md) · [Run the tests](how-to/run-the-tests.md) · [Run a test agent](how-to/run-a-test-agent.md) · [Run the end-to-end scenarios (v0.1)](how-to/run-the-end-to-end-scenarios.md) · [Publish a release](how-to/publish-a-release.md) · [Test milestone M4 on macOS](how-to/test-milestone-m4-on-macos.md) · [Test milestone M3 on macOS](how-to/test-milestone-m3-on-macos.md) · [Test milestone M2 on macOS](how-to/test-milestone-m2-on-macos.md) · [Test milestone M1 on macOS](how-to/test-milestone-m1-on-macos.md) · [Test milestone Initialize on macOS](how-to/test-milestone-initialize-on-macos.md) | | |
| 11 | +| **look up** an exact detail | Reference | [The configuration file](reference/configuration.md) · [Keyboard shortcuts](reference/keyboard-shortcuts.md) · [Agents, channels and events](reference/agents-and-events.md) · [Commands](reference/commands.md) · [scripts/agents.sh](reference/agents-script.md) | | |
| 12 | 12 | | **understand** why | Explanation | [Workspaces and terminals](explanation/workspaces-and-terminals.md) · [Channels and what each agent knows](explanation/channels-and-context.md) · [Permissions and trust](explanation/permissions.md) · [Why ACP](explanation/why-acp.md) · [The interface stack](explanation/ui-stack.md) · [Architecture](explanation/architecture.md) · [Memory and local models](explanation/memory-and-local-models.md) | |
| 13 | 13 | |
| 14 | 14 | ## Design records |
| @@ -1,14 +1,14 @@ | |||
| 1 | # Sidekicks documentation (English) | 1 | # Sidekicks documentation (English) |
| 2 | 2 | ||
| 3 | -Sidekicks is a desktop application to talk with AI agents in channels, through the Agent Client Protocol, designed for people who are not developers. Milestone M4 (Agents' workspace) is done: besides channels with several agents (`@`, `/`, history kept across restarts), each agent's folder can be browsed and edited, and a terminal opens in it — on this computer or in a Docker container. Answers are formatted, tools need your approval, and the configuration can be edited from the window. | 3 | +Sidekicks is a desktop application to talk with AI agents in channels, through the Agent Client Protocol, designed for people who are not developers. Version 0.1 is the first release: packages for macOS, Linux and Windows, an assistant that adds agents without writing YAML, error messages in plain words, keyboard shortcuts and a command palette — on top of channels with several agents (`@`, `/`, history kept across restarts), each agent's folder with an editor and a terminal (on this computer, in Docker or in an sbx sandbox), formatted answers and tools that need your approval. |
| 4 | 4 | ||
| 5 | This documentation follows [Diátaxis](https://diataxis.fr): pick the section that matches what you need right now. | 5 | This documentation follows [Diátaxis](https://diataxis.fr): pick the section that matches what you need right now. |
| 6 | 6 | ||
| 7 | | You want to… | Section | Pages | | 7 | | You want to… | Section | Pages | |
| 8 | | --- | --- | --- | | 8 | | --- | --- | --- | |
| 9 | -| **learn** by doing | Tutorials | [A channel with two agents](tutorials/first-channel.md) · [Your first conversation with an agent](tutorials/first-conversation.md) · [Your first launch of Sidekicks](tutorials/first-launch.md) · [Your first ACP exchange with a test agent](tutorials/first-acp-exchange.md) | | 9 | +| **learn** by doing | Tutorials | [Your first agent, without writing any configuration](tutorials/your-first-agent.md) · [A channel with two agents](tutorials/first-channel.md) · [Your first conversation with an agent](tutorials/first-conversation.md) · [Your first launch of Sidekicks](tutorials/first-launch.md) · [Your first ACP exchange with a test agent](tutorials/first-acp-exchange.md) | |
| 10 | -| **do** a specific task | How-to guides | [Work with an agent's files and terminal](how-to/work-with-an-agents-files.md) · [Run an agent in a Docker container](how-to/run-an-agent-in-docker.md) · [Run an agent in an sbx sandbox](how-to/run-an-agent-in-a-sandbox.md) · [Manage channels and their agents](how-to/manage-channels.md) · [Edit or switch the configuration](how-to/edit-or-switch-the-configuration.md) · [Reset Sidekicks](how-to/reset-sidekicks.md) · [Develop the application](how-to/develop-the-application.md) · [Run the tests](how-to/run-the-tests.md) · [Run a test agent](how-to/run-a-test-agent.md) · [Test milestone M4 on macOS](how-to/test-milestone-m4-on-macos.md) · [Test milestone M3 on macOS](how-to/test-milestone-m3-on-macos.md) · [Test milestone M2 on macOS](how-to/test-milestone-m2-on-macos.md) · [Test milestone M1 on macOS](how-to/test-milestone-m1-on-macos.md) · [Test milestone Initialize on macOS](how-to/test-milestone-initialize-on-macos.md) | | 10 | +| **do** a specific task | How-to guides | [Install Sidekicks](how-to/install-sidekicks.md) · [Add an agent](how-to/add-an-agent.md) · [Work with an agent's files and terminal](how-to/work-with-an-agents-files.md) · [Run an agent in a Docker container](how-to/run-an-agent-in-docker.md) · [Run an agent in an sbx sandbox](how-to/run-an-agent-in-a-sandbox.md) · [Manage channels and their agents](how-to/manage-channels.md) · [Edit or switch the configuration](how-to/edit-or-switch-the-configuration.md) · [Reset Sidekicks](how-to/reset-sidekicks.md) · [Develop the application](how-to/develop-the-application.md) · [Run the tests](how-to/run-the-tests.md) · [Run a test agent](how-to/run-a-test-agent.md) · [Run the end-to-end scenarios (v0.1)](how-to/run-the-end-to-end-scenarios.md) · [Publish a release](how-to/publish-a-release.md) · [Test milestone M4 on macOS](how-to/test-milestone-m4-on-macos.md) · [Test milestone M3 on macOS](how-to/test-milestone-m3-on-macos.md) · [Test milestone M2 on macOS](how-to/test-milestone-m2-on-macos.md) · [Test milestone M1 on macOS](how-to/test-milestone-m1-on-macos.md) · [Test milestone Initialize on macOS](how-to/test-milestone-initialize-on-macos.md) | |
| 11 | -| **look up** an exact detail | Reference | [The configuration file](reference/configuration.md) · [Agents, channels and events](reference/agents-and-events.md) · [Commands](reference/commands.md) · [scripts/agents.sh](reference/agents-script.md) | | 11 | +| **look up** an exact detail | Reference | [The configuration file](reference/configuration.md) · [Keyboard shortcuts](reference/keyboard-shortcuts.md) · [Agents, channels and events](reference/agents-and-events.md) · [Commands](reference/commands.md) · [scripts/agents.sh](reference/agents-script.md) | |
| 12 | | **understand** why | Explanation | [Workspaces and terminals](explanation/workspaces-and-terminals.md) · [Channels and what each agent knows](explanation/channels-and-context.md) · [Permissions and trust](explanation/permissions.md) · [Why ACP](explanation/why-acp.md) · [The interface stack](explanation/ui-stack.md) · [Architecture](explanation/architecture.md) · [Memory and local models](explanation/memory-and-local-models.md) | | 12 | | **understand** why | Explanation | [Workspaces and terminals](explanation/workspaces-and-terminals.md) · [Channels and what each agent knows](explanation/channels-and-context.md) · [Permissions and trust](explanation/permissions.md) · [Why ACP](explanation/why-acp.md) · [The interface stack](explanation/ui-stack.md) · [Architecture](explanation/architecture.md) · [Memory and local models](explanation/memory-and-local-models.md) | |
| 13 | 13 | ||
| 14 | ## Design records | 14 | ## Design records |
modified
docs/en/explanation/architecture.md +9 -1 | @@ -6,7 +6,7 @@ Before writing the application, the project fixed how its code is divided, what | ||
| 6 | 6 | |
| 7 | 7 |  |
| 8 | 8 | |
| 9 | -The diagram's source is [packages.drawio](../../diagrams/packages.drawio). Blue boxes exist since milestone M1; grey ones are planned. | |
| 9 | +The diagram's source is [packages.drawio](../../diagrams/packages.drawio). Every box exists (v0.1). | |
| 10 | 10 | |
| 11 | 11 | ## Why this split |
| 12 | 12 | |
| @@ -30,6 +30,14 @@ Each configuration file gets its own database: switching from "my work agents" t | ||
| 30 | 30 | |
| 31 | 31 | While an agent answers, the answer lives in memory and the interface receives each fragment. It is written to disk when the turn ends. Writing fifty times a second would wear the disk for nothing; the price is losing an unfinished answer if the application crashes, which is acceptable. |
| 32 | 32 | |
| 33 | +## Programs are found as in a terminal | |
| 34 | + | |
| 35 | +An application opened from the Finder does not inherit the `PATH` of the user's terminal: macOS gives it `/usr/bin:/bin:/usr/sbin:/sbin`, so `mm`, `docker` or `sbx` installed with Homebrew or in `~/.local/bin` are "not found", although the user just ran them in a terminal. Asking a non-developer to write full paths would be the wrong answer. At startup, before the configuration is read, `main.go` asks the user's shell for its `PATH` (`internal/shellpath`: an interactive login shell, so that it reads the same files as a terminal, with a five-second limit) and puts it in front of its own. The agents inherit it, and the warnings of the configuration ("program not found") are computed with it. When the shell cannot be read, nothing changes and the full path remains the way out. | |
| 36 | + | |
| 37 | +## Errors in plain words | |
| 38 | + | |
| 39 | +Go, the agents, Docker and sbx report errors for developers (`exec: "mm": executable file not found in $PATH`). The Go side keeps them as they are: they are precise, the tests check them, and they are what a developer needs in the log. The interface translates the common ones (`frontend/src/lib/errors.ts`) into a sentence that says what is wrong and what to do, in the interface's language, and keeps the original text folded under **Technical details**. An unknown error is shown as it is rather than hidden behind a vague sentence. | |
| 40 | + | |
| 33 | 41 | ## Rejected alternatives |
| 34 | 42 | |
| 35 | 43 | - **Storing conversations in the YAML file**: it would turn a file people edit into a database, and conflict with the application writing to it. |
| @@ -6,7 +6,7 @@ Before writing the application, the project fixed how its code is divided, what | |||
| 6 | 6 | ||
| 7 |  | 7 |  |
| 8 | 8 | ||
| 9 | -The diagram's source is [packages.drawio](../../diagrams/packages.drawio). Blue boxes exist since milestone M1; grey ones are planned. | 9 | +The diagram's source is [packages.drawio](../../diagrams/packages.drawio). Every box exists (v0.1). |
| 10 | 10 | ||
| 11 | ## Why this split | 11 | ## Why this split |
| 12 | 12 | ||
| @@ -30,6 +30,14 @@ Each configuration file gets its own database: switching from "my work agents" t | |||
| 30 | 30 | ||
| 31 | While an agent answers, the answer lives in memory and the interface receives each fragment. It is written to disk when the turn ends. Writing fifty times a second would wear the disk for nothing; the price is losing an unfinished answer if the application crashes, which is acceptable. | 31 | While an agent answers, the answer lives in memory and the interface receives each fragment. It is written to disk when the turn ends. Writing fifty times a second would wear the disk for nothing; the price is losing an unfinished answer if the application crashes, which is acceptable. |
| 32 | 32 | ||
| 33 | +## Programs are found as in a terminal | ||
| 34 | + | ||
| 35 | +An application opened from the Finder does not inherit the `PATH` of the user's terminal: macOS gives it `/usr/bin:/bin:/usr/sbin:/sbin`, so `mm`, `docker` or `sbx` installed with Homebrew or in `~/.local/bin` are "not found", although the user just ran them in a terminal. Asking a non-developer to write full paths would be the wrong answer. At startup, before the configuration is read, `main.go` asks the user's shell for its `PATH` (`internal/shellpath`: an interactive login shell, so that it reads the same files as a terminal, with a five-second limit) and puts it in front of its own. The agents inherit it, and the warnings of the configuration ("program not found") are computed with it. When the shell cannot be read, nothing changes and the full path remains the way out. | ||
| 36 | + | ||
| 37 | +## Errors in plain words | ||
| 38 | + | ||
| 39 | +Go, the agents, Docker and sbx report errors for developers (`exec: "mm": executable file not found in $PATH`). The Go side keeps them as they are: they are precise, the tests check them, and they are what a developer needs in the log. The interface translates the common ones (`frontend/src/lib/errors.ts`) into a sentence that says what is wrong and what to do, in the interface's language, and keeps the original text folded under **Technical details**. An unknown error is shown as it is rather than hidden behind a vague sentence. | ||
| 40 | + | ||
| 33 | ## Rejected alternatives | 41 | ## Rejected alternatives |
| 34 | 42 | ||
| 35 | - **Storing conversations in the YAML file**: it would turn a file people edit into a database, and conflict with the application writing to it. | 43 | - **Storing conversations in the YAML file**: it would turn a file people edit into a database, and conflict with the application writing to it. |
added
docs/en/how-to/add-an-agent.md +26 -0 | new file mode 100644 | ||
| @@ -0,0 +1,26 @@ | ||
| 1 | +# How to add an agent | |
| 2 | + | |
| 3 | +This guide shows how to add an agent from the Sidekicks window, with the "Add an agent" assistant, wherever the agent runs: on this computer, in a Docker container or in an sbx sandbox. It assumes the agent's program speaks ACP (for `mm`: the `-acp` argument). | |
| 4 | + | |
| 5 | +## Steps | |
| 6 | + | |
| 7 | +1. Open the assistant: **+ Add my first agent** on the welcome screen, **+ Add an agent** under the agents list, or **⇧⌘N** (Ctrl+Shift+N on Linux and Windows). | |
| 8 | +2. **Who is it?** Fill in **Name shown** (e.g. `Garfield (translator)`). **Name used with @** follows it; change it if you want a shorter one (lowercase letters, digits, `-` and `_`, starting with a letter). The icon and the description are optional. | |
| 9 | +3. **Where does it run?** Choose the environment, then fill in what it asks for (see below). | |
| 10 | +4. **How is it started?** Fill in **Program**, **Arguments** (on one line, as in a terminal; quotes group words) and **Agent's folder**. The folder is created when it does not exist. | |
| 11 | +5. Click **Add the agent**. Its direct conversation opens once the configuration is reloaded. | |
| 12 | + | |
| 13 | +When the agent cannot be added (a name already used, for instance), the assistant says why and writes nothing. | |
| 14 | + | |
| 15 | +## Variants | |
| 16 | + | |
| 17 | +- **On this computer**: the program runs here, in the agent's folder. If Sidekicks was opened from the Finder and does not find the program, write its full path (`which mm` in a terminal gives it). Sidekicks reads your shell's `PATH` at startup, so this is rarely needed. | |
| 18 | +- **In a Docker container**: give the **Container name**. The container must be running, with the agent's folder mounted at the same path, and contain the program: see [How to run an agent in a Docker container](run-an-agent-in-docker.md). Sidekicks starts the agent with `docker exec -i <container> <program> <arguments>`. | |
| 19 | +- **In an sbx sandbox**: give the **Sandbox name**. The sandbox must exist, with the agent's folder at the same path: see [How to run an agent in an sbx sandbox](run-an-agent-in-a-sandbox.md). Sidekicks starts the agent with `sbx exec -i <sandbox> <program> <arguments>`. | |
| 20 | +- **Options the assistant does not ask for** (`env`, `afterStop`, a different `workspacePath`): add the agent with the assistant, then complete its entry in **Settings**. | |
| 21 | + | |
| 22 | +## See also | |
| 23 | + | |
| 24 | +- What the assistant writes: [The configuration file](../reference/configuration.md) | |
| 25 | +- [How to edit or switch the configuration](edit-or-switch-the-configuration.md) | |
| 26 | +- [Tutorial: your first agent, without writing any configuration](../tutorials/your-first-agent.md) | |
| new file mode 100644 | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | +# How to add an agent | ||
| 2 | + | ||
| 3 | +This guide shows how to add an agent from the Sidekicks window, with the "Add an agent" assistant, wherever the agent runs: on this computer, in a Docker container or in an sbx sandbox. It assumes the agent's program speaks ACP (for `mm`: the `-acp` argument). | ||
| 4 | + | ||
| 5 | +## Steps | ||
| 6 | + | ||
| 7 | +1. Open the assistant: **+ Add my first agent** on the welcome screen, **+ Add an agent** under the agents list, or **⇧⌘N** (Ctrl+Shift+N on Linux and Windows). | ||
| 8 | +2. **Who is it?** Fill in **Name shown** (e.g. `Garfield (translator)`). **Name used with @** follows it; change it if you want a shorter one (lowercase letters, digits, `-` and `_`, starting with a letter). The icon and the description are optional. | ||
| 9 | +3. **Where does it run?** Choose the environment, then fill in what it asks for (see below). | ||
| 10 | +4. **How is it started?** Fill in **Program**, **Arguments** (on one line, as in a terminal; quotes group words) and **Agent's folder**. The folder is created when it does not exist. | ||
| 11 | +5. Click **Add the agent**. Its direct conversation opens once the configuration is reloaded. | ||
| 12 | + | ||
| 13 | +When the agent cannot be added (a name already used, for instance), the assistant says why and writes nothing. | ||
| 14 | + | ||
| 15 | +## Variants | ||
| 16 | + | ||
| 17 | +- **On this computer**: the program runs here, in the agent's folder. If Sidekicks was opened from the Finder and does not find the program, write its full path (`which mm` in a terminal gives it). Sidekicks reads your shell's `PATH` at startup, so this is rarely needed. | ||
| 18 | +- **In a Docker container**: give the **Container name**. The container must be running, with the agent's folder mounted at the same path, and contain the program: see [How to run an agent in a Docker container](run-an-agent-in-docker.md). Sidekicks starts the agent with `docker exec -i <container> <program> <arguments>`. | ||
| 19 | +- **In an sbx sandbox**: give the **Sandbox name**. The sandbox must exist, with the agent's folder at the same path: see [How to run an agent in an sbx sandbox](run-an-agent-in-a-sandbox.md). Sidekicks starts the agent with `sbx exec -i <sandbox> <program> <arguments>`. | ||
| 20 | +- **Options the assistant does not ask for** (`env`, `afterStop`, a different `workspacePath`): add the agent with the assistant, then complete its entry in **Settings**. | ||
| 21 | + | ||
| 22 | +## See also | ||
| 23 | + | ||
| 24 | +- What the assistant writes: [The configuration file](../reference/configuration.md) | ||
| 25 | +- [How to edit or switch the configuration](edit-or-switch-the-configuration.md) | ||
| 26 | +- [Tutorial: your first agent, without writing any configuration](../tutorials/your-first-agent.md) | ||
modified
docs/en/how-to/develop-the-application.md +2 -0 | @@ -30,6 +30,8 @@ make build # bin/sidekicks | ||
| 30 | 30 | make package # macOS: bin/sidekicks.app, signed ad hoc |
| 31 | 31 | ``` |
| 32 | 32 | |
| 33 | +Release packages go to `dist/`: `make package-macos`, `make package-linux`, `make package-windows` (see [How to publish a release](publish-a-release.md)). | |
| 34 | + | |
| 33 | 35 | ## When you change… |
| 34 | 36 | |
| 35 | 37 | - **a Go service or an event payload** (`internal/app`, `internal/events`, `main.go`): run `make bindings` and commit `frontend/bindings` — the CI fails when they are stale. |
| @@ -30,6 +30,8 @@ make build # bin/sidekicks | |||
| 30 | make package # macOS: bin/sidekicks.app, signed ad hoc | 30 | make package # macOS: bin/sidekicks.app, signed ad hoc |
| 31 | ``` | 31 | ``` |
| 32 | 32 | ||
| 33 | +Release packages go to `dist/`: `make package-macos`, `make package-linux`, `make package-windows` (see [How to publish a release](publish-a-release.md)). | ||
| 34 | + | ||
| 33 | ## When you change… | 35 | ## When you change… |
| 34 | 36 | ||
| 35 | - **a Go service or an event payload** (`internal/app`, `internal/events`, `main.go`): run `make bindings` and commit `frontend/bindings` — the CI fails when they are stale. | 37 | - **a Go service or an event payload** (`internal/app`, `internal/events`, `main.go`): run `make bindings` and commit `frontend/bindings` — the CI fails when they are stale. |
added
docs/en/how-to/install-sidekicks.md +48 -0 | new file mode 100644 | ||
| @@ -0,0 +1,48 @@ | ||
| 1 | +# How to install Sidekicks | |
| 2 | + | |
| 3 | +This guide shows how to install Sidekicks from the packages of a release, on macOS, Linux or Windows. The packages are on the project's releases page, `https://rickub.com/bots-garden/sidekicks/releases`; `SHA256SUMS` lists their checksums. | |
| 4 | + | |
| 5 | +Sidekicks talks with agents; it does not contain one. Install your agent's program too (for instance `mm`). | |
| 6 | + | |
| 7 | +## macOS (Apple Silicon and Intel) | |
| 8 | + | |
| 9 | +Sidekicks needs macOS 13 (Ventura) or later. | |
| 10 | + | |
| 11 | +1. Download `Sidekicks-<version>-macos-universal.dmg` and open it. | |
| 12 | +2. Drag **sidekicks** into **Applications**. | |
| 13 | +3. Open it once from **Applications**. The application is not signed by an Apple developer account, so macOS refuses it the first time ("Apple could not verify…"). | |
| 14 | +4. Open **System Settings → Privacy & Security**, scroll to the message about Sidekicks and click **Open Anyway**, then confirm. | |
| 15 | + | |
| 16 | +From then on, Sidekicks opens normally. | |
| 17 | + | |
| 18 | +## Linux (x86-64) | |
| 19 | + | |
| 20 | +Sidekicks needs GTK 4 and WebKitGTK 6 (Ubuntu 24.04 or later, Debian 13, Fedora 40 or later). | |
| 21 | + | |
| 22 | +- **Debian, Ubuntu**: `sudo apt install ./sidekicks_<version>_linux_amd64.deb` | |
| 23 | +- **Fedora**: `sudo dnf install ./sidekicks_<version>_linux_amd64.rpm` | |
| 24 | +- **Any distribution, without installing**: `chmod +x Sidekicks-<version>-x86_64.AppImage`, then run it. If it complains about FUSE, run it with `--appimage-extract-and-run`. | |
| 25 | +- **The bare program**: `sidekicks_<version>_linux_amd64.tar.gz` holds `sidekicks`; the GTK 4 and WebKitGTK 6 libraries must be installed. | |
| 26 | + | |
| 27 | +The `.deb` and `.rpm` add Sidekicks to the applications menu. | |
| 28 | + | |
| 29 | +## Windows (x86-64) | |
| 30 | + | |
| 31 | +1. Download `Sidekicks-<version>-windows-amd64-installer.exe` and run it. | |
| 32 | +2. The installer is not signed: Windows SmartScreen may say "Windows protected your PC". Click **More info**, then **Run anyway**. | |
| 33 | +3. The installer adds Microsoft Edge WebView2 when it is missing, then a Sidekicks shortcut. | |
| 34 | + | |
| 35 | +`sidekicks_<version>_windows_amd64.zip` holds the bare `sidekicks.exe`, for a machine where WebView2 is already present. | |
| 36 | + | |
| 37 | +On Windows, the **Terminal** tab of an agent is not available yet; files, conversations and agents in Docker work. | |
| 38 | + | |
| 39 | +## Variants | |
| 40 | + | |
| 41 | +- **Check a download**: `shasum -a 256 <file>` (macOS) or `sha256sum <file>` (Linux), and compare with `SHA256SUMS`. | |
| 42 | +- **macOS, from a terminal**: `xattr -dr com.apple.quarantine /Applications/sidekicks.app` lifts the quarantine instead of step 4. | |
| 43 | +- **Build it yourself**: `make package-macos`, `make package-linux` or `make package-windows` (see [How to publish a release](publish-a-release.md)). | |
| 44 | + | |
| 45 | +## See also | |
| 46 | + | |
| 47 | +- [Tutorial: your first agent, without writing any configuration](../tutorials/your-first-agent.md) | |
| 48 | +- [How to reset Sidekicks](reset-sidekicks.md) | |
| new file mode 100644 | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | +# How to install Sidekicks | ||
| 2 | + | ||
| 3 | +This guide shows how to install Sidekicks from the packages of a release, on macOS, Linux or Windows. The packages are on the project's releases page, `https://rickub.com/bots-garden/sidekicks/releases`; `SHA256SUMS` lists their checksums. | ||
| 4 | + | ||
| 5 | +Sidekicks talks with agents; it does not contain one. Install your agent's program too (for instance `mm`). | ||
| 6 | + | ||
| 7 | +## macOS (Apple Silicon and Intel) | ||
| 8 | + | ||
| 9 | +Sidekicks needs macOS 13 (Ventura) or later. | ||
| 10 | + | ||
| 11 | +1. Download `Sidekicks-<version>-macos-universal.dmg` and open it. | ||
| 12 | +2. Drag **sidekicks** into **Applications**. | ||
| 13 | +3. Open it once from **Applications**. The application is not signed by an Apple developer account, so macOS refuses it the first time ("Apple could not verify…"). | ||
| 14 | +4. Open **System Settings → Privacy & Security**, scroll to the message about Sidekicks and click **Open Anyway**, then confirm. | ||
| 15 | + | ||
| 16 | +From then on, Sidekicks opens normally. | ||
| 17 | + | ||
| 18 | +## Linux (x86-64) | ||
| 19 | + | ||
| 20 | +Sidekicks needs GTK 4 and WebKitGTK 6 (Ubuntu 24.04 or later, Debian 13, Fedora 40 or later). | ||
| 21 | + | ||
| 22 | +- **Debian, Ubuntu**: `sudo apt install ./sidekicks_<version>_linux_amd64.deb` | ||
| 23 | +- **Fedora**: `sudo dnf install ./sidekicks_<version>_linux_amd64.rpm` | ||
| 24 | +- **Any distribution, without installing**: `chmod +x Sidekicks-<version>-x86_64.AppImage`, then run it. If it complains about FUSE, run it with `--appimage-extract-and-run`. | ||
| 25 | +- **The bare program**: `sidekicks_<version>_linux_amd64.tar.gz` holds `sidekicks`; the GTK 4 and WebKitGTK 6 libraries must be installed. | ||
| 26 | + | ||
| 27 | +The `.deb` and `.rpm` add Sidekicks to the applications menu. | ||
| 28 | + | ||
| 29 | +## Windows (x86-64) | ||
| 30 | + | ||
| 31 | +1. Download `Sidekicks-<version>-windows-amd64-installer.exe` and run it. | ||
| 32 | +2. The installer is not signed: Windows SmartScreen may say "Windows protected your PC". Click **More info**, then **Run anyway**. | ||
| 33 | +3. The installer adds Microsoft Edge WebView2 when it is missing, then a Sidekicks shortcut. | ||
| 34 | + | ||
| 35 | +`sidekicks_<version>_windows_amd64.zip` holds the bare `sidekicks.exe`, for a machine where WebView2 is already present. | ||
| 36 | + | ||
| 37 | +On Windows, the **Terminal** tab of an agent is not available yet; files, conversations and agents in Docker work. | ||
| 38 | + | ||
| 39 | +## Variants | ||
| 40 | + | ||
| 41 | +- **Check a download**: `shasum -a 256 <file>` (macOS) or `sha256sum <file>` (Linux), and compare with `SHA256SUMS`. | ||
| 42 | +- **macOS, from a terminal**: `xattr -dr com.apple.quarantine /Applications/sidekicks.app` lifts the quarantine instead of step 4. | ||
| 43 | +- **Build it yourself**: `make package-macos`, `make package-linux` or `make package-windows` (see [How to publish a release](publish-a-release.md)). | ||
| 44 | + | ||
| 45 | +## See also | ||
| 46 | + | ||
| 47 | +- [Tutorial: your first agent, without writing any configuration](../tutorials/your-first-agent.md) | ||
| 48 | +- [How to reset Sidekicks](reset-sidekicks.md) | ||
added
docs/en/how-to/publish-a-release.md +23 -0 | new file mode 100644 | ||
| @@ -0,0 +1,23 @@ | ||
| 1 | +# How to publish a release | |
| 2 | + | |
| 3 | +This guide shows how to publish a Sidekicks release from a Mac: build every package, tag, attach the files to the release that Rickub creates. It assumes the development tools of [How to develop the application](develop-the-application.md), Docker Desktop running, `brew install makensis zip`, and the right to push tags. [RELEASING.md](../../../RELEASING.md) is the same procedure as a checklist. | |
| 4 | + | |
| 5 | +## Steps | |
| 6 | + | |
| 7 | +1. **Set the version** in `build/config.yml` (`info.version`), run `wails3 task common:update:build-assets`, put `LSMinimumSystemVersion` back to `13.0.0` in `build/darwin/Info.plist` and `Info.dev.plist`, then commit, merge into `main` and `git checkout main && git pull`. | |
| 8 | +2. **Build everything**: `make release-build`. `dist/` then holds the macOS packages (universal `.dmg` and `.zip`), the Windows ones (installer and `.zip`), the Linux amd64 ones (`.deb`, `.rpm`, `.AppImage`, `.tar.gz`, built in Docker) and `SHA256SUMS`. | |
| 9 | +3. **Tag**: `make release-tag`. The tag `v<version>` is pushed, and the **Release** workflow creates the release on Rickub with notes listing the files. | |
| 10 | +4. **Attach the files**: on Rickub, open **Releases → v<version>** and attach every file of `dist/`. | |
| 11 | + | |
| 12 | +## Variants | |
| 13 | + | |
| 14 | +- **Linux arm64 too**: `LINUX_ARCHES="amd64 arm64" make release-build`. | |
| 15 | +- **Leave a system out**: `SKIP="linux"` (or `macos`, `windows`, several separated by spaces) before `make release-build`. | |
| 16 | +- **Tag without pushing**: `scripts/tag-release.sh --no-push`, then `git push origin v<version>` when ready. | |
| 17 | +- **Wrong tag**: `git push origin :refs/tags/v<version>` and `git tag -d v<version>`, delete the release if it was created, fix the version and tag again. | |
| 18 | +- **One package only**: `make package-macos`, `make package-windows` or `make package-linux` (Linux only, for the machine's architecture). | |
| 19 | + | |
| 20 | +## See also | |
| 21 | + | |
| 22 | +- [How to install Sidekicks](install-sidekicks.md) | |
| 23 | +- [Reference: commands](../reference/commands.md) — `make release-*`, `scripts/build-release.sh`, `scripts/tag-release.sh`, the Release workflow | |
| new file mode 100644 | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | +# How to publish a release | ||
| 2 | + | ||
| 3 | +This guide shows how to publish a Sidekicks release from a Mac: build every package, tag, attach the files to the release that Rickub creates. It assumes the development tools of [How to develop the application](develop-the-application.md), Docker Desktop running, `brew install makensis zip`, and the right to push tags. [RELEASING.md](../../../RELEASING.md) is the same procedure as a checklist. | ||
| 4 | + | ||
| 5 | +## Steps | ||
| 6 | + | ||
| 7 | +1. **Set the version** in `build/config.yml` (`info.version`), run `wails3 task common:update:build-assets`, put `LSMinimumSystemVersion` back to `13.0.0` in `build/darwin/Info.plist` and `Info.dev.plist`, then commit, merge into `main` and `git checkout main && git pull`. | ||
| 8 | +2. **Build everything**: `make release-build`. `dist/` then holds the macOS packages (universal `.dmg` and `.zip`), the Windows ones (installer and `.zip`), the Linux amd64 ones (`.deb`, `.rpm`, `.AppImage`, `.tar.gz`, built in Docker) and `SHA256SUMS`. | ||
| 9 | +3. **Tag**: `make release-tag`. The tag `v<version>` is pushed, and the **Release** workflow creates the release on Rickub with notes listing the files. | ||
| 10 | +4. **Attach the files**: on Rickub, open **Releases → v<version>** and attach every file of `dist/`. | ||
| 11 | + | ||
| 12 | +## Variants | ||
| 13 | + | ||
| 14 | +- **Linux arm64 too**: `LINUX_ARCHES="amd64 arm64" make release-build`. | ||
| 15 | +- **Leave a system out**: `SKIP="linux"` (or `macos`, `windows`, several separated by spaces) before `make release-build`. | ||
| 16 | +- **Tag without pushing**: `scripts/tag-release.sh --no-push`, then `git push origin v<version>` when ready. | ||
| 17 | +- **Wrong tag**: `git push origin :refs/tags/v<version>` and `git tag -d v<version>`, delete the release if it was created, fix the version and tag again. | ||
| 18 | +- **One package only**: `make package-macos`, `make package-windows` or `make package-linux` (Linux only, for the machine's architecture). | ||
| 19 | + | ||
| 20 | +## See also | ||
| 21 | + | ||
| 22 | +- [How to install Sidekicks](install-sidekicks.md) | ||
| 23 | +- [Reference: commands](../reference/commands.md) — `make release-*`, `scripts/build-release.sh`, `scripts/tag-release.sh`, the Release workflow | ||
added
docs/en/how-to/run-the-end-to-end-scenarios.md +100 -0 | new file mode 100644 | ||
| @@ -0,0 +1,100 @@ | ||
| 1 | +# How to run the end-to-end scenarios (v0.1) | |
| 2 | + | |
| 3 | +This guide runs the six scenarios that validate a release with the real test agents (issue #34), then the checks of what v0.1 added. It assumes a Mac with `mm`, llmman running, the models of the four test agents pulled, and Sidekicks built from the release's tag (`make package-macos`, or `make dev`). | |
| 4 | + | |
| 5 | +Two agents at most run at once (`limits.maxRunningAgents: 2`). Between two scenarios, unload every model, so each scenario starts cold: | |
| 6 | + | |
| 7 | +```bash | |
| 8 | +scripts/agents.sh unload --all | |
| 9 | +scripts/agents.sh ps # no model loaded | |
| 10 | +``` | |
| 11 | + | |
| 12 | +## 0. Prepare | |
| 13 | + | |
| 14 | +1. `make install-test-config` (the four test agents at the default location; the previous file is kept as a backup). | |
| 15 | +2. Open Sidekicks. Under **AGENTS**: Alice, Bob, Riker, Garfield, all "stopped". | |
| 16 | +3. Open the [report](#report) below in a text editor, to fill it in as you go. | |
| 17 | + | |
| 18 | +## 1. Alice — a simple conversation, Markdown, cancelling | |
| 19 | + | |
| 20 | +1. Click **Alice (assistant)**, send: `Donne un tableau markdown de 2 lignes (nom, rôle) puis un bloc de code Go qui affiche hello.` | |
| 21 | +2. Expected: the answer streams; a table and coloured Go code with **Copy** appear. | |
| 22 | +3. Send: `Écris un poème de 40 vers sur la mer.` and click **■ Stop** after a few lines. | |
| 23 | +4. Expected: the answer stops and ends with "Answer stopped."; Alice goes back to "ready". | |
| 24 | + | |
| 25 | +## 2. Alice + Bob — a multi-agent channel, routing, shared context | |
| 26 | + | |
| 27 | +1. Create a channel `#e2e` (**⌘N**). Send: `@alice donne un prénom pour un chat roux.` | |
| 28 | +2. Expected: "Alice (assistant) joined the channel." then her answer with a name. | |
| 29 | +3. Send: `@bob que penses-tu du prénom proposé par Alice ?` | |
| 30 | +4. Expected: Bob joins and quotes the name Alice gave: he received the messages he had not seen. | |
| 31 | +5. Send a message without any mention: expected, the last agent who spoke (Bob) answers. | |
| 32 | + | |
| 33 | +## 3. Riker — tool calls, permissions | |
| 34 | + | |
| 35 | +1. Unload the models. Click **Riker (tools)**, send: `Crée le fichier e2e.txt contenant "ok", puis liste le dossier.` | |
| 36 | +2. Expected: a permission card in plain words. Click **Allow once**: the tool card turns ✓, `e2e.txt` is listed. | |
| 37 | +3. Send: `Supprime e2e.txt.` Click **Reject once**. | |
| 38 | +4. Expected: Riker says it could not; the file is still there (📂 → Files). | |
| 39 | + | |
| 40 | +## 4. Garfield — slash commands and skills | |
| 41 | + | |
| 42 | +1. Unload the models. Click **Garfield (translator)**, type `/`. | |
| 43 | +2. Expected: "Asking Garfield (translator) for their commands…" then Garfield's commands and skills (`idioms`, `styles`…). | |
| 44 | +3. Pick `/idioms` (Tab), add `il pleut des cordes`, send. | |
| 45 | +4. Expected: the answer explains the idiom with an English equivalent. | |
| 46 | + | |
| 47 | +## 5. Garfield + Bob — `/garfield:command` in a channel | |
| 48 | + | |
| 49 | +1. Unload the models. In `#e2e`, invite Garfield (**+ Invite**), then type `/gar`. | |
| 50 | +2. Expected: `/garfield:idioms`, `/garfield:styles`… listed with their agent. | |
| 51 | +3. Send `/garfield:styles Bonjour à tous`. Expected: only Garfield answers. | |
| 52 | +4. Send `@bob traduis la première version de Garfield en espagnol.` Expected: Bob answers from Garfield's text. | |
| 53 | + | |
| 54 | +## 6. Alice — restart and resume | |
| 55 | + | |
| 56 | +1. Quit Sidekicks (⌘Q) while nothing is answering. Reopen it. | |
| 57 | +2. Expected: `#e2e` and the direct conversations are there with their messages; the agents are "stopped". | |
| 58 | +3. In Alice's conversation, send: `Quelle était ma première question ?` | |
| 59 | +4. Expected: Alice answers from the earlier exchange (her session was resumed, or the history was given back to her). | |
| 60 | + | |
| 61 | +## 7. What v0.1 added | |
| 62 | + | |
| 63 | +| # | Check | Expected | | |
| 64 | +| --- | --- | --- | | |
| 65 | +| 7.1 | `mv ~/Library/Application\ Support/sidekicks ~/sidekicks-backup`, open Sidekicks | Welcome screen: logo, three steps, **+ Add my first agent** | | |
| 66 | +| 7.2 | Add Alice with the assistant (program `mm`, arguments `-acp -config agent.yaml`, folder `agents/alice`) | Her conversation opens; Settings shows her entry, the file's comments are kept | | |
| 67 | +| 7.3 | Add an agent whose program is `nothere`, start it (▶) | "The program "nothere" cannot be found…", with **Technical details** folded | | |
| 68 | +| 7.4 | Add an agent in a container that does not exist, start it | A sentence about the missing container | | |
| 69 | +| 7.5 | ⌘K, type `ali`, Enter; ⌘N; ⌘L; ⌘,; ⌘J; ⌘B; ⇧⌘N | Each does what [Keyboard shortcuts](../reference/keyboard-shortcuts.md) says | | |
| 70 | +| 7.6 | Tab through the window | The focused element is always outlined | | |
| 71 | +| 7.7 | Open the `.app` installed from the `.dmg` **from the Finder**, start Alice | It starts: `mm` is found without a full path (the shell's PATH) | | |
| 72 | +| 7.8 | Put the backup back: `rm -r ~/Library/Application\ Support/sidekicks && mv ~/sidekicks-backup ~/Library/Application\ Support/sidekicks` | Your agents and history are back | | |
| 73 | + | |
| 74 | +## Report | |
| 75 | + | |
| 76 | +Copy this into a comment of issue #34 and fill it in: | |
| 77 | + | |
| 78 | +```markdown | |
| 79 | +## End-to-end report — Sidekicks <version>, <date> | |
| 80 | + | |
| 81 | +Mac: <model, RAM>, macOS <version> · mm <version> · build: <dmg | make dev> | |
| 82 | + | |
| 83 | +| # | Scenario | Result | Notes | | |
| 84 | +| --- | --- | --- | --- | | |
| 85 | +| 1 | Alice: conversation, Markdown, cancel | ✅ / ❌ | | | |
| 86 | +| 2 | Alice + Bob: channel, routing, shared context | ✅ / ❌ | | | |
| 87 | +| 3 | Riker: tools, allow / reject | ✅ / ❌ | | | |
| 88 | +| 4 | Garfield: / commands and skills | ✅ / ❌ | | | |
| 89 | +| 5 | Garfield + Bob: /garfield:command in a channel | ✅ / ❌ | | | |
| 90 | +| 6 | Alice: restart and resume | ✅ / ❌ | | | |
| 91 | +| 7 | v0.1 checks (7.1–7.8) | ✅ / ❌ | | | |
| 92 | + | |
| 93 | +Models unloaded between scenarios: yes / no | |
| 94 | +``` | |
| 95 | + | |
| 96 | +## See also | |
| 97 | + | |
| 98 | +- [How to run the tests](run-the-tests.md) — the automated tests, with and without real agents | |
| 99 | +- [scripts/agents.sh](../reference/agents-script.md) | |
| 100 | +- [How to publish a release](publish-a-release.md) | |
| new file mode 100644 | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | +# How to run the end-to-end scenarios (v0.1) | ||
| 2 | + | ||
| 3 | +This guide runs the six scenarios that validate a release with the real test agents (issue #34), then the checks of what v0.1 added. It assumes a Mac with `mm`, llmman running, the models of the four test agents pulled, and Sidekicks built from the release's tag (`make package-macos`, or `make dev`). | ||
| 4 | + | ||
| 5 | +Two agents at most run at once (`limits.maxRunningAgents: 2`). Between two scenarios, unload every model, so each scenario starts cold: | ||
| 6 | + | ||
| 7 | +```bash | ||
| 8 | +scripts/agents.sh unload --all | ||
| 9 | +scripts/agents.sh ps # no model loaded | ||
| 10 | +``` | ||
| 11 | + | ||
| 12 | +## 0. Prepare | ||
| 13 | + | ||
| 14 | +1. `make install-test-config` (the four test agents at the default location; the previous file is kept as a backup). | ||
| 15 | +2. Open Sidekicks. Under **AGENTS**: Alice, Bob, Riker, Garfield, all "stopped". | ||
| 16 | +3. Open the [report](#report) below in a text editor, to fill it in as you go. | ||
| 17 | + | ||
| 18 | +## 1. Alice — a simple conversation, Markdown, cancelling | ||
| 19 | + | ||
| 20 | +1. Click **Alice (assistant)**, send: `Donne un tableau markdown de 2 lignes (nom, rôle) puis un bloc de code Go qui affiche hello.` | ||
| 21 | +2. Expected: the answer streams; a table and coloured Go code with **Copy** appear. | ||
| 22 | +3. Send: `Écris un poème de 40 vers sur la mer.` and click **■ Stop** after a few lines. | ||
| 23 | +4. Expected: the answer stops and ends with "Answer stopped."; Alice goes back to "ready". | ||
| 24 | + | ||
| 25 | +## 2. Alice + Bob — a multi-agent channel, routing, shared context | ||
| 26 | + | ||
| 27 | +1. Create a channel `#e2e` (**⌘N**). Send: `@alice donne un prénom pour un chat roux.` | ||
| 28 | +2. Expected: "Alice (assistant) joined the channel." then her answer with a name. | ||
| 29 | +3. Send: `@bob que penses-tu du prénom proposé par Alice ?` | ||
| 30 | +4. Expected: Bob joins and quotes the name Alice gave: he received the messages he had not seen. | ||
| 31 | +5. Send a message without any mention: expected, the last agent who spoke (Bob) answers. | ||
| 32 | + | ||
| 33 | +## 3. Riker — tool calls, permissions | ||
| 34 | + | ||
| 35 | +1. Unload the models. Click **Riker (tools)**, send: `Crée le fichier e2e.txt contenant "ok", puis liste le dossier.` | ||
| 36 | +2. Expected: a permission card in plain words. Click **Allow once**: the tool card turns ✓, `e2e.txt` is listed. | ||
| 37 | +3. Send: `Supprime e2e.txt.` Click **Reject once**. | ||
| 38 | +4. Expected: Riker says it could not; the file is still there (📂 → Files). | ||
| 39 | + | ||
| 40 | +## 4. Garfield — slash commands and skills | ||
| 41 | + | ||
| 42 | +1. Unload the models. Click **Garfield (translator)**, type `/`. | ||
| 43 | +2. Expected: "Asking Garfield (translator) for their commands…" then Garfield's commands and skills (`idioms`, `styles`…). | ||
| 44 | +3. Pick `/idioms` (Tab), add `il pleut des cordes`, send. | ||
| 45 | +4. Expected: the answer explains the idiom with an English equivalent. | ||
| 46 | + | ||
| 47 | +## 5. Garfield + Bob — `/garfield:command` in a channel | ||
| 48 | + | ||
| 49 | +1. Unload the models. In `#e2e`, invite Garfield (**+ Invite**), then type `/gar`. | ||
| 50 | +2. Expected: `/garfield:idioms`, `/garfield:styles`… listed with their agent. | ||
| 51 | +3. Send `/garfield:styles Bonjour à tous`. Expected: only Garfield answers. | ||
| 52 | +4. Send `@bob traduis la première version de Garfield en espagnol.` Expected: Bob answers from Garfield's text. | ||
| 53 | + | ||
| 54 | +## 6. Alice — restart and resume | ||
| 55 | + | ||
| 56 | +1. Quit Sidekicks (⌘Q) while nothing is answering. Reopen it. | ||
| 57 | +2. Expected: `#e2e` and the direct conversations are there with their messages; the agents are "stopped". | ||
| 58 | +3. In Alice's conversation, send: `Quelle était ma première question ?` | ||
| 59 | +4. Expected: Alice answers from the earlier exchange (her session was resumed, or the history was given back to her). | ||
| 60 | + | ||
| 61 | +## 7. What v0.1 added | ||
| 62 | + | ||
| 63 | +| # | Check | Expected | | ||
| 64 | +| --- | --- | --- | | ||
| 65 | +| 7.1 | `mv ~/Library/Application\ Support/sidekicks ~/sidekicks-backup`, open Sidekicks | Welcome screen: logo, three steps, **+ Add my first agent** | | ||
| 66 | +| 7.2 | Add Alice with the assistant (program `mm`, arguments `-acp -config agent.yaml`, folder `agents/alice`) | Her conversation opens; Settings shows her entry, the file's comments are kept | | ||
| 67 | +| 7.3 | Add an agent whose program is `nothere`, start it (▶) | "The program "nothere" cannot be found…", with **Technical details** folded | | ||
| 68 | +| 7.4 | Add an agent in a container that does not exist, start it | A sentence about the missing container | | ||
| 69 | +| 7.5 | ⌘K, type `ali`, Enter; ⌘N; ⌘L; ⌘,; ⌘J; ⌘B; ⇧⌘N | Each does what [Keyboard shortcuts](../reference/keyboard-shortcuts.md) says | | ||
| 70 | +| 7.6 | Tab through the window | The focused element is always outlined | | ||
| 71 | +| 7.7 | Open the `.app` installed from the `.dmg` **from the Finder**, start Alice | It starts: `mm` is found without a full path (the shell's PATH) | | ||
| 72 | +| 7.8 | Put the backup back: `rm -r ~/Library/Application\ Support/sidekicks && mv ~/sidekicks-backup ~/Library/Application\ Support/sidekicks` | Your agents and history are back | | ||
| 73 | + | ||
| 74 | +## Report | ||
| 75 | + | ||
| 76 | +Copy this into a comment of issue #34 and fill it in: | ||
| 77 | + | ||
| 78 | +```markdown | ||
| 79 | +## End-to-end report — Sidekicks <version>, <date> | ||
| 80 | + | ||
| 81 | +Mac: <model, RAM>, macOS <version> · mm <version> · build: <dmg | make dev> | ||
| 82 | + | ||
| 83 | +| # | Scenario | Result | Notes | | ||
| 84 | +| --- | --- | --- | --- | | ||
| 85 | +| 1 | Alice: conversation, Markdown, cancel | ✅ / ❌ | | | ||
| 86 | +| 2 | Alice + Bob: channel, routing, shared context | ✅ / ❌ | | | ||
| 87 | +| 3 | Riker: tools, allow / reject | ✅ / ❌ | | | ||
| 88 | +| 4 | Garfield: / commands and skills | ✅ / ❌ | | | ||
| 89 | +| 5 | Garfield + Bob: /garfield:command in a channel | ✅ / ❌ | | | ||
| 90 | +| 6 | Alice: restart and resume | ✅ / ❌ | | | ||
| 91 | +| 7 | v0.1 checks (7.1–7.8) | ✅ / ❌ | | | ||
| 92 | + | ||
| 93 | +Models unloaded between scenarios: yes / no | ||
| 94 | +``` | ||
| 95 | + | ||
| 96 | +## See also | ||
| 97 | + | ||
| 98 | +- [How to run the tests](run-the-tests.md) — the automated tests, with and without real agents | ||
| 99 | +- [scripts/agents.sh](../reference/agents-script.md) | ||
| 100 | +- [How to publish a release](publish-a-release.md) | ||
modified
docs/en/how-to/run-the-tests.md +2 -2 | @@ -22,8 +22,8 @@ The CI (`.github/workflows/ci.yml`) runs the same command, plus `make bindings-c | ||
| 22 | 22 | | To check | Command | |
| 23 | 23 | | --- | --- | |
| 24 | 24 | | Go packages | `make test-go`, or `go test -race ./internal/agents -run Limit -v` for one test | |
| 25 | -| Frontend (vitest) | `make test-frontend` | | |
| 26 | -| Shell tooling | `make test-scripts` | | |
| 25 | +| Frontend (vitest), including the WCAG contrast of the theme's colours | `make test-frontend` | | |
| 26 | +| Shell tooling (agents.sh, licence headers, package names, release tag) | `make test-scripts` | | |
| 27 | 27 | | Go lint (golangci-lint, pinned in `tools/go.mod`) | `make lint-go` | |
| 28 | 28 | | Frontend types and Svelte warnings | `make lint-frontend` | |
| 29 | 29 | | Licence headers | `make lint-headers` | |
| @@ -22,8 +22,8 @@ The CI (`.github/workflows/ci.yml`) runs the same command, plus `make bindings-c | |||
| 22 | | To check | Command | | 22 | | To check | Command | |
| 23 | | --- | --- | | 23 | | --- | --- | |
| 24 | | Go packages | `make test-go`, or `go test -race ./internal/agents -run Limit -v` for one test | | 24 | | Go packages | `make test-go`, or `go test -race ./internal/agents -run Limit -v` for one test | |
| 25 | -| Frontend (vitest) | `make test-frontend` | | 25 | +| Frontend (vitest), including the WCAG contrast of the theme's colours | `make test-frontend` | |
| 26 | -| Shell tooling | `make test-scripts` | | 26 | +| Shell tooling (agents.sh, licence headers, package names, release tag) | `make test-scripts` | |
| 27 | | Go lint (golangci-lint, pinned in `tools/go.mod`) | `make lint-go` | | 27 | | Go lint (golangci-lint, pinned in `tools/go.mod`) | `make lint-go` | |
| 28 | | Frontend types and Svelte warnings | `make lint-frontend` | | 28 | | Frontend types and Svelte warnings | `make lint-frontend` | |
| 29 | | Licence headers | `make lint-headers` | | 29 | | Licence headers | `make lint-headers` | |
modified
docs/en/reference/commands.md +47 -2 | @@ -25,12 +25,17 @@ The order is detailed in the [configuration reference](configuration.md#location | ||
| 25 | 25 | | `dev` | `wails3 dev`: the application with hot reload. | |
| 26 | 26 | | `build` | `wails3 build`: `bin/sidekicks`. | |
| 27 | 27 | | `package` | `wails3 package`: on macOS `bin/sidekicks.app`. | |
| 28 | +| `package-linux` | `scripts/package.sh linux`: `.deb`, `.rpm`, `.AppImage` and `.tar.gz` for the machine's architecture, into `dist/`. Needs `file` (AppImage) and `rpm`. | | |
| 29 | +| `package-windows` | `scripts/package.sh windows`: NSIS installer and `.zip` for Windows amd64, cross-built, into `dist/`. Needs `makensis` and `zip`. | | |
| 30 | +| `release-build` | `scripts/build-release.sh`: on the Mac, every release package into `dist/` and `SHA256SUMS`. | | |
| 31 | +| `release-tag` | `scripts/tag-release.sh`: tags `v<version>` on `main` and pushes it. | | |
| 32 | +| `package-macos` | `scripts/package.sh macos`: universal `.dmg` and `.zip` (arm64 + amd64, signed ad hoc), into `dist/`. macOS only. | | |
| 28 | 33 | | `install-test-config` | `scripts/install-test-config.sh`: writes `examples/test-agents.yaml` at the default configuration location with absolute paths to the repository: each agent is `mm -acp -config agent.yaml` started in its folder, with `afterStop: [<repo>/scripts/agents.sh, unload, <agent>]` to unload its model when it stops, `mm` written with its absolute path (`MM_BIN`, or the one in `PATH`), and the current `PATH` in each agent's `env`; an existing file is kept as `config.yaml.<date>.bak`. | |
| 29 | 34 | | `check` | `lint` then `test`. | |
| 30 | 35 | | `test` | `test-go`, `test-frontend`, `test-scripts`. | |
| 31 | 36 | | `test-go` | `go test ./...` (builds `frontend/dist` first if missing). | |
| 32 | 37 | | `test-frontend` | `vitest run` in `frontend/`. | |
| 33 | -| `test-scripts` | `scripts/agents_test.sh` and `scripts/check-license-headers_test.sh`. | | |
| 38 | +| `test-scripts` | `scripts/agents_test.sh`, `scripts/check-license-headers_test.sh`, `scripts/package_test.sh` and `scripts/tag-release_test.sh`. | | |
| 34 | 39 | | `test-real` | `go test -tags realagents -count=1 ./...` — needs `mm` and llmman. | |
| 35 | 40 | | `lint` | `lint-go`, `lint-frontend`, `lint-headers`. | |
| 36 | 41 | | `lint-go` | golangci-lint v2.14.0 (`tools/go.mod`), configuration `.golangci.yml`. | |
| @@ -46,6 +51,46 @@ scripts/check-license-headers.sh [repository root] | ||
| 46 | 51 | |
| 47 | 52 | Lists the source files (`.go .ts .js .svelte .css .html .sh .py .yml .yaml`, `Makefile`) known to git whose first three lines do not contain `Sidekicks Source-Available License`, and exits 1 if there is one. Not checked: `frontend/bindings`, Wails' `build/` and `Taskfile.yml`, `*.d.ts`, `pnpm-lock.yaml`, `vite.config.ts`, `svelte.config.js`, `agents/`, `*/testdata/*`, `git.sh`, `new.*.sh`, `tag-step.sh`, `.claude/`, `.tickets/`. |
| 48 | 53 | |
| 54 | +## `scripts/package.sh` | |
| 55 | + | |
| 56 | +```text | |
| 57 | +scripts/package.sh linux | windows | macos | |
| 58 | +scripts/package.sh names <system> <arch> | |
| 59 | +scripts/package.sh version | |
| 60 | +``` | |
| 61 | + | |
| 62 | +| Command | Effect | | |
| 63 | +| --- | --- | | |
| 64 | +| `linux`, `windows`, `macos` | Builds the packages of that system into `dist/` (see the `package-*` targets), then lists `dist/`. | | |
| 65 | +| `names <system> <arch>` | Prints the file names a build produces, one per line; builds nothing. | | |
| 66 | +| `version` | Prints `info.version` of `build/config.yml`. | | |
| 67 | + | |
| 68 | +| System | Files (`<v>` = version) | | |
| 69 | +| --- | --- | | |
| 70 | +| `linux` | `sidekicks_<v>_linux_<arch>.deb`, `.rpm`, `.tar.gz`, `Sidekicks-<v>-<x86_64\|aarch64>.AppImage` | | |
| 71 | +| `windows` | `Sidekicks-<v>-windows-amd64-installer.exe`, `sidekicks_<v>_windows_amd64.zip` | | |
| 72 | +| `macos` | `Sidekicks-<v>-macos-universal.dmg`, `Sidekicks-<v>-macos-universal.zip` | | |
| 73 | + | |
| 74 | +## `scripts/build-release.sh` | |
| 75 | + | |
| 76 | +```text | |
| 77 | +[LINUX_ARCHES="amd64 arm64"] [SKIP="macos windows linux"] scripts/build-release.sh | |
| 78 | +``` | |
| 79 | + | |
| 80 | +Empties `dist/`, then builds: macOS with `scripts/package.sh macos` (macOS only), Windows with `scripts/package.sh windows` (needs `makensis`), Linux with `scripts/package.sh linux` in a container per architecture of `LINUX_ARCHES` (default `amd64`), built from `scripts/linux-packages.Dockerfile` (`ubuntu:26.04`, Go of `go.mod`, pnpm of `frontend/package.json`, Wails CLI) with the repository mounted at `/src` and the Go module cache in the volume `sidekicks-gomod-<arch>`. Finally writes `dist/SHA256SUMS`. `SKIP` leaves the systems it names out. Fails when `makensis` is missing or Docker is not running, naming the system to skip. | |
| 81 | + | |
| 82 | +## `scripts/tag-release.sh` | |
| 83 | + | |
| 84 | +```text | |
| 85 | +scripts/tag-release.sh [--remote <name>] [--no-push] | |
| 86 | +``` | |
| 87 | + | |
| 88 | +Creates the annotated tag `v<version>` (`info.version` of `build/config.yml`, message `Sidekicks <version>`) and pushes it to `--remote` (default `origin`). Refuses when tracked files have changes, when the current branch is not `main`, when `main` differs from `<remote>/main` after a fetch, or when the tag exists locally. Warns, without refusing, when `dist/` misses a package of the version or `SHA256SUMS`. `--no-push` tags locally only. | |
| 89 | + | |
| 49 | 90 | ## CI |
| 50 | 91 | |
| 51 | -`.github/workflows/ci.yml`, on every push and merge request: installs Go (from `go.mod`), Node 22, pnpm (from `frontend/package.json`), the GTK 4 / WebKitGTK 6 build packages and the Wails CLI, then runs `make bindings-check` and `make check`. | |
| 92 | +`.github/workflows/ci.yml`, on every push and merge request, in an `ubuntu:26.04` container (GTK ≥ 4.10): installs git, a C compiler, the GTK 4 / WebKitGTK 6 build packages, Node and npm from apt, Go from go.dev (version of `go.mod`), pnpm (version of `frontend/package.json`) and the Wails CLI, then runs `make bindings-check` and `make check`. | |
| 93 | + | |
| 94 | +## Release workflow | |
| 95 | + | |
| 96 | +`.github/workflows/release.yml`, on the push of a tag `v*`, with `permissions: contents: write`: fails when the tag is not `v` + `info.version` of `build/config.yml`, then creates the release `<tag>` named `Sidekicks <tag>` (`softprops/action-gh-release@v2`, through Rickub's GitHub-compatible API behind `GITHUB_API_URL`), with notes giving the commit, the install guides and the table of the files to expect (from `scripts/package.sh names`). It attaches no file: the packages are attached by hand. | |
| @@ -25,12 +25,17 @@ The order is detailed in the [configuration reference](configuration.md#location | |||
| 25 | | `dev` | `wails3 dev`: the application with hot reload. | | 25 | | `dev` | `wails3 dev`: the application with hot reload. | |
| 26 | | `build` | `wails3 build`: `bin/sidekicks`. | | 26 | | `build` | `wails3 build`: `bin/sidekicks`. | |
| 27 | | `package` | `wails3 package`: on macOS `bin/sidekicks.app`. | | 27 | | `package` | `wails3 package`: on macOS `bin/sidekicks.app`. | |
| 28 | +| `package-linux` | `scripts/package.sh linux`: `.deb`, `.rpm`, `.AppImage` and `.tar.gz` for the machine's architecture, into `dist/`. Needs `file` (AppImage) and `rpm`. | | ||
| 29 | +| `package-windows` | `scripts/package.sh windows`: NSIS installer and `.zip` for Windows amd64, cross-built, into `dist/`. Needs `makensis` and `zip`. | | ||
| 30 | +| `release-build` | `scripts/build-release.sh`: on the Mac, every release package into `dist/` and `SHA256SUMS`. | | ||
| 31 | +| `release-tag` | `scripts/tag-release.sh`: tags `v<version>` on `main` and pushes it. | | ||
| 32 | +| `package-macos` | `scripts/package.sh macos`: universal `.dmg` and `.zip` (arm64 + amd64, signed ad hoc), into `dist/`. macOS only. | | ||
| 28 | | `install-test-config` | `scripts/install-test-config.sh`: writes `examples/test-agents.yaml` at the default configuration location with absolute paths to the repository: each agent is `mm -acp -config agent.yaml` started in its folder, with `afterStop: [<repo>/scripts/agents.sh, unload, <agent>]` to unload its model when it stops, `mm` written with its absolute path (`MM_BIN`, or the one in `PATH`), and the current `PATH` in each agent's `env`; an existing file is kept as `config.yaml.<date>.bak`. | | 33 | | `install-test-config` | `scripts/install-test-config.sh`: writes `examples/test-agents.yaml` at the default configuration location with absolute paths to the repository: each agent is `mm -acp -config agent.yaml` started in its folder, with `afterStop: [<repo>/scripts/agents.sh, unload, <agent>]` to unload its model when it stops, `mm` written with its absolute path (`MM_BIN`, or the one in `PATH`), and the current `PATH` in each agent's `env`; an existing file is kept as `config.yaml.<date>.bak`. | |
| 29 | | `check` | `lint` then `test`. | | 34 | | `check` | `lint` then `test`. | |
| 30 | | `test` | `test-go`, `test-frontend`, `test-scripts`. | | 35 | | `test` | `test-go`, `test-frontend`, `test-scripts`. | |
| 31 | | `test-go` | `go test ./...` (builds `frontend/dist` first if missing). | | 36 | | `test-go` | `go test ./...` (builds `frontend/dist` first if missing). | |
| 32 | | `test-frontend` | `vitest run` in `frontend/`. | | 37 | | `test-frontend` | `vitest run` in `frontend/`. | |
| 33 | -| `test-scripts` | `scripts/agents_test.sh` and `scripts/check-license-headers_test.sh`. | | 38 | +| `test-scripts` | `scripts/agents_test.sh`, `scripts/check-license-headers_test.sh`, `scripts/package_test.sh` and `scripts/tag-release_test.sh`. | |
| 34 | | `test-real` | `go test -tags realagents -count=1 ./...` — needs `mm` and llmman. | | 39 | | `test-real` | `go test -tags realagents -count=1 ./...` — needs `mm` and llmman. | |
| 35 | | `lint` | `lint-go`, `lint-frontend`, `lint-headers`. | | 40 | | `lint` | `lint-go`, `lint-frontend`, `lint-headers`. | |
| 36 | | `lint-go` | golangci-lint v2.14.0 (`tools/go.mod`), configuration `.golangci.yml`. | | 41 | | `lint-go` | golangci-lint v2.14.0 (`tools/go.mod`), configuration `.golangci.yml`. | |
| @@ -46,6 +51,46 @@ scripts/check-license-headers.sh [repository root] | |||
| 46 | 51 | ||
| 47 | Lists the source files (`.go .ts .js .svelte .css .html .sh .py .yml .yaml`, `Makefile`) known to git whose first three lines do not contain `Sidekicks Source-Available License`, and exits 1 if there is one. Not checked: `frontend/bindings`, Wails' `build/` and `Taskfile.yml`, `*.d.ts`, `pnpm-lock.yaml`, `vite.config.ts`, `svelte.config.js`, `agents/`, `*/testdata/*`, `git.sh`, `new.*.sh`, `tag-step.sh`, `.claude/`, `.tickets/`. | 52 | Lists the source files (`.go .ts .js .svelte .css .html .sh .py .yml .yaml`, `Makefile`) known to git whose first three lines do not contain `Sidekicks Source-Available License`, and exits 1 if there is one. Not checked: `frontend/bindings`, Wails' `build/` and `Taskfile.yml`, `*.d.ts`, `pnpm-lock.yaml`, `vite.config.ts`, `svelte.config.js`, `agents/`, `*/testdata/*`, `git.sh`, `new.*.sh`, `tag-step.sh`, `.claude/`, `.tickets/`. |
| 48 | 53 | ||
| 54 | +## `scripts/package.sh` | ||
| 55 | + | ||
| 56 | +```text | ||
| 57 | +scripts/package.sh linux | windows | macos | ||
| 58 | +scripts/package.sh names <system> <arch> | ||
| 59 | +scripts/package.sh version | ||
| 60 | +``` | ||
| 61 | + | ||
| 62 | +| Command | Effect | | ||
| 63 | +| --- | --- | | ||
| 64 | +| `linux`, `windows`, `macos` | Builds the packages of that system into `dist/` (see the `package-*` targets), then lists `dist/`. | | ||
| 65 | +| `names <system> <arch>` | Prints the file names a build produces, one per line; builds nothing. | | ||
| 66 | +| `version` | Prints `info.version` of `build/config.yml`. | | ||
| 67 | + | ||
| 68 | +| System | Files (`<v>` = version) | | ||
| 69 | +| --- | --- | | ||
| 70 | +| `linux` | `sidekicks_<v>_linux_<arch>.deb`, `.rpm`, `.tar.gz`, `Sidekicks-<v>-<x86_64\|aarch64>.AppImage` | | ||
| 71 | +| `windows` | `Sidekicks-<v>-windows-amd64-installer.exe`, `sidekicks_<v>_windows_amd64.zip` | | ||
| 72 | +| `macos` | `Sidekicks-<v>-macos-universal.dmg`, `Sidekicks-<v>-macos-universal.zip` | | ||
| 73 | + | ||
| 74 | +## `scripts/build-release.sh` | ||
| 75 | + | ||
| 76 | +```text | ||
| 77 | +[LINUX_ARCHES="amd64 arm64"] [SKIP="macos windows linux"] scripts/build-release.sh | ||
| 78 | +``` | ||
| 79 | + | ||
| 80 | +Empties `dist/`, then builds: macOS with `scripts/package.sh macos` (macOS only), Windows with `scripts/package.sh windows` (needs `makensis`), Linux with `scripts/package.sh linux` in a container per architecture of `LINUX_ARCHES` (default `amd64`), built from `scripts/linux-packages.Dockerfile` (`ubuntu:26.04`, Go of `go.mod`, pnpm of `frontend/package.json`, Wails CLI) with the repository mounted at `/src` and the Go module cache in the volume `sidekicks-gomod-<arch>`. Finally writes `dist/SHA256SUMS`. `SKIP` leaves the systems it names out. Fails when `makensis` is missing or Docker is not running, naming the system to skip. | ||
| 81 | + | ||
| 82 | +## `scripts/tag-release.sh` | ||
| 83 | + | ||
| 84 | +```text | ||
| 85 | +scripts/tag-release.sh [--remote <name>] [--no-push] | ||
| 86 | +``` | ||
| 87 | + | ||
| 88 | +Creates the annotated tag `v<version>` (`info.version` of `build/config.yml`, message `Sidekicks <version>`) and pushes it to `--remote` (default `origin`). Refuses when tracked files have changes, when the current branch is not `main`, when `main` differs from `<remote>/main` after a fetch, or when the tag exists locally. Warns, without refusing, when `dist/` misses a package of the version or `SHA256SUMS`. `--no-push` tags locally only. | ||
| 89 | + | ||
| 49 | ## CI | 90 | ## CI |
| 50 | 91 | ||
| 51 | -`.github/workflows/ci.yml`, on every push and merge request: installs Go (from `go.mod`), Node 22, pnpm (from `frontend/package.json`), the GTK 4 / WebKitGTK 6 build packages and the Wails CLI, then runs `make bindings-check` and `make check`. | 92 | +`.github/workflows/ci.yml`, on every push and merge request, in an `ubuntu:26.04` container (GTK ≥ 4.10): installs git, a C compiler, the GTK 4 / WebKitGTK 6 build packages, Node and npm from apt, Go from go.dev (version of `go.mod`), pnpm (version of `frontend/package.json`) and the Wails CLI, then runs `make bindings-check` and `make check`. |
| 93 | + | ||
| 94 | +## Release workflow | ||
| 95 | + | ||
| 96 | +`.github/workflows/release.yml`, on the push of a tag `v*`, with `permissions: contents: write`: fails when the tag is not `v` + `info.version` of `build/config.yml`, then creates the release `<tag>` named `Sidekicks <tag>` (`softprops/action-gh-release@v2`, through Rickub's GitHub-compatible API behind `GITHUB_API_URL`), with notes giving the commit, the install guides and the table of the files to expect (from `scripts/package.sh names`). It attaches no file: the packages are attached by hand. | ||
modified
docs/en/reference/configuration.md +14 -0 | @@ -94,6 +94,20 @@ The runtime tells Sidekicks how to reach the agent's **files and terminal** (Age | ||
| 94 | 94 | |
| 95 | 95 | A channel declared here is created at startup, or when the file is reloaded, **if no channel has this name yet** (whatever the case); after that it lives in the application like any other channel, and can be renamed or deleted there. Removing it from the file does not delete it (deleting history must be an explicit user action). Each configuration file has its own channels and history ([where it is kept](agents-and-events.md#history)). |
| 96 | 96 | |
| 97 | +## What the "Add an agent" assistant writes | |
| 98 | + | |
| 99 | +The assistant appends one entry at the end of `agents`; the rest of the file, comments included, is kept. Nothing is written when the result would not be valid. | |
| 100 | + | |
| 101 | +| Field of the assistant | Written as | | |
| 102 | +| --- | --- | | |
| 103 | +| Name used with @, Name shown, Icon, What it does | `name`, `title`, `icon`, `description` (empty fields left out) | | |
| 104 | +| Agent's folder | `workspace`, as typed (`~` and relative paths are resolved like any `workspace`) | | |
| 105 | +| On this computer | `command: <program>`, `args: [<arguments>]` | | |
| 106 | +| In a Docker container | `command: docker`, `args: [exec, -i, <container>, <program>, <arguments>]`, `runtime: {type: container, container: <container>}` | | |
| 107 | +| In an sbx sandbox | `command: sbx`, `args: [exec, -i, <sandbox>, <program>, <arguments>]`, `runtime: {type: sbx, sandbox: <sandbox>}` | | |
| 108 | + | |
| 109 | +The arguments are split like a shell does for simple cases: spaces separate, single or double quotes group. | |
| 110 | + | |
| 97 | 111 | ## Rules checked by the loader, not by the schema |
| 98 | 112 | |
| 99 | 113 | JSON Schema cannot express them; the configuration loader (issue #9) checks them and reports them like schema errors: |
| @@ -94,6 +94,20 @@ The runtime tells Sidekicks how to reach the agent's **files and terminal** (Age | |||
| 94 | 94 | ||
| 95 | A channel declared here is created at startup, or when the file is reloaded, **if no channel has this name yet** (whatever the case); after that it lives in the application like any other channel, and can be renamed or deleted there. Removing it from the file does not delete it (deleting history must be an explicit user action). Each configuration file has its own channels and history ([where it is kept](agents-and-events.md#history)). | 95 | A channel declared here is created at startup, or when the file is reloaded, **if no channel has this name yet** (whatever the case); after that it lives in the application like any other channel, and can be renamed or deleted there. Removing it from the file does not delete it (deleting history must be an explicit user action). Each configuration file has its own channels and history ([where it is kept](agents-and-events.md#history)). |
| 96 | 96 | ||
| 97 | +## What the "Add an agent" assistant writes | ||
| 98 | + | ||
| 99 | +The assistant appends one entry at the end of `agents`; the rest of the file, comments included, is kept. Nothing is written when the result would not be valid. | ||
| 100 | + | ||
| 101 | +| Field of the assistant | Written as | | ||
| 102 | +| --- | --- | | ||
| 103 | +| Name used with @, Name shown, Icon, What it does | `name`, `title`, `icon`, `description` (empty fields left out) | | ||
| 104 | +| Agent's folder | `workspace`, as typed (`~` and relative paths are resolved like any `workspace`) | | ||
| 105 | +| On this computer | `command: <program>`, `args: [<arguments>]` | | ||
| 106 | +| In a Docker container | `command: docker`, `args: [exec, -i, <container>, <program>, <arguments>]`, `runtime: {type: container, container: <container>}` | | ||
| 107 | +| In an sbx sandbox | `command: sbx`, `args: [exec, -i, <sandbox>, <program>, <arguments>]`, `runtime: {type: sbx, sandbox: <sandbox>}` | | ||
| 108 | + | ||
| 109 | +The arguments are split like a shell does for simple cases: spaces separate, single or double quotes group. | ||
| 110 | + | ||
| 97 | ## Rules checked by the loader, not by the schema | 111 | ## Rules checked by the loader, not by the schema |
| 98 | 112 | ||
| 99 | JSON Schema cannot express them; the configuration loader (issue #9) checks them and reports them like schema errors: | 113 | JSON Schema cannot express them; the configuration loader (issue #9) checks them and reports them like schema errors: |
added
docs/en/reference/keyboard-shortcuts.md +51 -0 | new file mode 100644 | ||
| @@ -0,0 +1,51 @@ | ||
| 1 | +# Reference: keyboard shortcuts | |
| 2 | + | |
| 3 | +On macOS the shortcuts use **⌘**; on Linux and Windows, **Ctrl**. The table is `frontend/src/lib/shortcuts.ts`. | |
| 4 | + | |
| 5 | +## Application | |
| 6 | + | |
| 7 | +| macOS | Linux, Windows | Action | | |
| 8 | +| --- | --- | --- | | |
| 9 | +| ⌘K | Ctrl+K | Opens or closes the command palette | | |
| 10 | +| ⌘N | Ctrl+N | New channel (opens the channels dock when folded) | | |
| 11 | +| ⇧⌘N | Ctrl+Shift+N | Add an agent (the assistant) | | |
| 12 | +| ⌘L | Ctrl+L | Puts the cursor in the message box | | |
| 13 | +| ⌘B | Ctrl+B | Shows or hides the channels and agents dock | | |
| 14 | +| ⌘, | Ctrl+, | Shows or hides Settings | | |
| 15 | +| ⌘J | Ctrl+J | Shows or hides the log | | |
| 16 | + | |
| 17 | +On Linux and Windows, when the cursor is in an agent's terminal, the terminal keeps the Ctrl shortcuts (Ctrl+L clears the screen, Ctrl+K cuts the line…). | |
| 18 | + | |
| 19 | +## Command palette | |
| 20 | + | |
| 21 | +| Key | Action | | |
| 22 | +| --- | --- | | |
| 23 | +| letters | Filters: channels (`#` optional), agents' conversations, agents' files, actions | | |
| 24 | +| ↑ ↓ | Moves the selection | | |
| 25 | +| Enter | Runs the selection | | |
| 26 | +| Escape, or a click outside | Closes the palette | | |
| 27 | + | |
| 28 | +The palette lists, in order: the channels, a conversation per agent, the files of each agent, the actions of the table above, and **Open a configuration…**. | |
| 29 | + | |
| 30 | +## Message box | |
| 31 | + | |
| 32 | +| Key | Action | | |
| 33 | +| --- | --- | | |
| 34 | +| Enter | Sends | | |
| 35 | +| Shift+Enter | New line | | |
| 36 | +| ↑ (empty box) | Previous messages | | |
| 37 | +| `@`, `/` | Agent and command lists; Tab or Enter picks, ↑ ↓ move, Escape closes | | |
| 38 | + | |
| 39 | +## Editors (Settings, agents' files) | |
| 40 | + | |
| 41 | +| macOS | Linux, Windows | Action | | |
| 42 | +| --- | --- | --- | | |
| 43 | +| ⌘S | Ctrl+S | Saves | | |
| 44 | + | |
| 45 | +## Assistant, channels list | |
| 46 | + | |
| 47 | +| Key | Action | | |
| 48 | +| --- | --- | | |
| 49 | +| Enter | Validates the name of a new or renamed channel | | |
| 50 | +| Escape | Cancels it | | |
| 51 | +| Tab | Moves from field to field; every button is reachable, and the focused element is outlined | | |
| new file mode 100644 | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | +# Reference: keyboard shortcuts | ||
| 2 | + | ||
| 3 | +On macOS the shortcuts use **⌘**; on Linux and Windows, **Ctrl**. The table is `frontend/src/lib/shortcuts.ts`. | ||
| 4 | + | ||
| 5 | +## Application | ||
| 6 | + | ||
| 7 | +| macOS | Linux, Windows | Action | | ||
| 8 | +| --- | --- | --- | | ||
| 9 | +| ⌘K | Ctrl+K | Opens or closes the command palette | | ||
| 10 | +| ⌘N | Ctrl+N | New channel (opens the channels dock when folded) | | ||
| 11 | +| ⇧⌘N | Ctrl+Shift+N | Add an agent (the assistant) | | ||
| 12 | +| ⌘L | Ctrl+L | Puts the cursor in the message box | | ||
| 13 | +| ⌘B | Ctrl+B | Shows or hides the channels and agents dock | | ||
| 14 | +| ⌘, | Ctrl+, | Shows or hides Settings | | ||
| 15 | +| ⌘J | Ctrl+J | Shows or hides the log | | ||
| 16 | + | ||
| 17 | +On Linux and Windows, when the cursor is in an agent's terminal, the terminal keeps the Ctrl shortcuts (Ctrl+L clears the screen, Ctrl+K cuts the line…). | ||
| 18 | + | ||
| 19 | +## Command palette | ||
| 20 | + | ||
| 21 | +| Key | Action | | ||
| 22 | +| --- | --- | | ||
| 23 | +| letters | Filters: channels (`#` optional), agents' conversations, agents' files, actions | | ||
| 24 | +| ↑ ↓ | Moves the selection | | ||
| 25 | +| Enter | Runs the selection | | ||
| 26 | +| Escape, or a click outside | Closes the palette | | ||
| 27 | + | ||
| 28 | +The palette lists, in order: the channels, a conversation per agent, the files of each agent, the actions of the table above, and **Open a configuration…**. | ||
| 29 | + | ||
| 30 | +## Message box | ||
| 31 | + | ||
| 32 | +| Key | Action | | ||
| 33 | +| --- | --- | | ||
| 34 | +| Enter | Sends | | ||
| 35 | +| Shift+Enter | New line | | ||
| 36 | +| ↑ (empty box) | Previous messages | | ||
| 37 | +| `@`, `/` | Agent and command lists; Tab or Enter picks, ↑ ↓ move, Escape closes | | ||
| 38 | + | ||
| 39 | +## Editors (Settings, agents' files) | ||
| 40 | + | ||
| 41 | +| macOS | Linux, Windows | Action | | ||
| 42 | +| --- | --- | --- | | ||
| 43 | +| ⌘S | Ctrl+S | Saves | | ||
| 44 | + | ||
| 45 | +## Assistant, channels list | ||
| 46 | + | ||
| 47 | +| Key | Action | | ||
| 48 | +| --- | --- | | ||
| 49 | +| Enter | Validates the name of a new or renamed channel | | ||
| 50 | +| Escape | Cancels it | | ||
| 51 | +| Tab | Moves from field to field; every button is reachable, and the focused element is outlined | | ||
modified
docs/en/tutorials/first-conversation.md +2 -0 | @@ -25,6 +25,8 @@ You should see your message, then "Alice … writing…": the answer appears wor | ||
| 25 | 25 | |
| 26 | 26 | Click **Copy**: it says "Copied ✓" — the code is in your clipboard. |
| 27 | 27 | |
| 28 | +Now move the pointer over Alice's answer: **⧉ Copy** appears next to her name. Click it: the whole answer is in your clipboard, as Markdown (table and code included). | |
| 29 | + | |
| 28 | 30 | ## Step 3 — Let Riker run a command |
| 29 | 31 | |
| 30 | 32 | Click **Riker (tools)** and send: |
| @@ -25,6 +25,8 @@ You should see your message, then "Alice … writing…": the answer appears wor | |||
| 25 | 25 | ||
| 26 | Click **Copy**: it says "Copied ✓" — the code is in your clipboard. | 26 | Click **Copy**: it says "Copied ✓" — the code is in your clipboard. |
| 27 | 27 | ||
| 28 | +Now move the pointer over Alice's answer: **⧉ Copy** appears next to her name. Click it: the whole answer is in your clipboard, as Markdown (table and code included). | ||
| 29 | + | ||
| 28 | ## Step 3 — Let Riker run a command | 30 | ## Step 3 — Let Riker run a command |
| 29 | 31 | ||
| 30 | Click **Riker (tools)** and send: | 32 | Click **Riker (tools)** and send: |
added
docs/en/tutorials/your-first-agent.md +64 -0 | new file mode 100644 | ||
| @@ -0,0 +1,64 @@ | ||
| 1 | +# Tutorial: your first agent, without writing any configuration | |
| 2 | + | |
| 3 | +By the end of this tutorial, you will have added an agent to Sidekicks with the "Add an agent" assistant, talked with it, and found it again with the command palette. You will not open the configuration file once. | |
| 4 | + | |
| 5 | +## Prerequisites | |
| 6 | + | |
| 7 | +- Sidekicks installed: see [How to install Sidekicks](../how-to/install-sidekicks.md). | |
| 8 | +- `mm` installed, and llmman running with the model of Alice pulled (see [Your first ACP exchange with a test agent](first-acp-exchange.md)). | |
| 9 | +- The Sidekicks repository on your computer: Alice's folder, `agents/alice`, holds her `agent.yaml`. Below, it is `~/sidekicks/agents/alice`; use your own path. | |
| 10 | + | |
| 11 | +## Step 1 — Open Sidekicks | |
| 12 | + | |
| 13 | +Open Sidekicks from your Applications folder (or your applications menu). | |
| 14 | + | |
| 15 | +You should see the Sidekicks logo, "Welcome to Sidekicks", three numbered steps and a blue **+ Add my first agent** button. If agents are already listed on the left, use **+ Add an agent** under them instead: the rest is the same. | |
| 16 | + | |
| 17 | +## Step 2 — Say who the agent is | |
| 18 | + | |
| 19 | +Click **+ Add my first agent**. In **Name shown**, type: | |
| 20 | + | |
| 21 | +```text | |
| 22 | +Alice (assistant) | |
| 23 | +``` | |
| 24 | + | |
| 25 | +You should see **Name used with @** fill itself in with `alice-assistant`. Replace it with `alice`: that is the name you will use to call her. | |
| 26 | + | |
| 27 | +## Step 3 — Say how to start it | |
| 28 | + | |
| 29 | +Leave **On this computer** selected. Fill in: | |
| 30 | + | |
| 31 | +| Field | Value | | |
| 32 | +| --- | --- | | |
| 33 | +| Program | `mm` | | |
| 34 | +| Arguments | `-acp -config agent.yaml` | | |
| 35 | +| Agent's folder | `~/sidekicks/agents/alice` (or **Choose…** and pick the folder) | | |
| 36 | + | |
| 37 | +Click **Add the agent**. | |
| 38 | + | |
| 39 | +You should see the assistant close, **🤖 Alice (assistant)** appear under **AGENTS** and under **DIRECT MESSAGES**, and her conversation open in the centre with "Write your first message to Alice (assistant)." | |
| 40 | + | |
| 41 | +## Step 4 — Talk with Alice | |
| 42 | + | |
| 43 | +Click the text box at the bottom, type the following and press Enter: | |
| 44 | + | |
| 45 | +```text | |
| 46 | +Bonjour Alice, présente-toi en une phrase. | |
| 47 | +``` | |
| 48 | + | |
| 49 | +You should see Alice's dot turn orange while she starts and answers, then her sentence appear word by word. | |
| 50 | + | |
| 51 | +## Step 5 — Find her again with the keyboard | |
| 52 | + | |
| 53 | +Click **# general** on the left. Then press **⌘K** (Ctrl+K on Linux and Windows) and type `ali`. | |
| 54 | + | |
| 55 | +You should see a list with **Alice (assistant)** first. Press Enter: her conversation is back in the centre. | |
| 56 | + | |
| 57 | +## What now? | |
| 58 | + | |
| 59 | +You have added an agent without touching any YAML, talked with it and moved around with the keyboard. To go further: | |
| 60 | + | |
| 61 | +- To add an agent that runs in Docker or in an sbx sandbox → [How to add an agent](../how-to/add-an-agent.md) | |
| 62 | +- To bring several agents into one channel → [A channel with two agents](first-channel.md) | |
| 63 | +- Every shortcut → [Keyboard shortcuts](../reference/keyboard-shortcuts.md) | |
| 64 | +- What the assistant wrote → [The configuration file](../reference/configuration.md) | |
| new file mode 100644 | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | +# Tutorial: your first agent, without writing any configuration | ||
| 2 | + | ||
| 3 | +By the end of this tutorial, you will have added an agent to Sidekicks with the "Add an agent" assistant, talked with it, and found it again with the command palette. You will not open the configuration file once. | ||
| 4 | + | ||
| 5 | +## Prerequisites | ||
| 6 | + | ||
| 7 | +- Sidekicks installed: see [How to install Sidekicks](../how-to/install-sidekicks.md). | ||
| 8 | +- `mm` installed, and llmman running with the model of Alice pulled (see [Your first ACP exchange with a test agent](first-acp-exchange.md)). | ||
| 9 | +- The Sidekicks repository on your computer: Alice's folder, `agents/alice`, holds her `agent.yaml`. Below, it is `~/sidekicks/agents/alice`; use your own path. | ||
| 10 | + | ||
| 11 | +## Step 1 — Open Sidekicks | ||
| 12 | + | ||
| 13 | +Open Sidekicks from your Applications folder (or your applications menu). | ||
| 14 | + | ||
| 15 | +You should see the Sidekicks logo, "Welcome to Sidekicks", three numbered steps and a blue **+ Add my first agent** button. If agents are already listed on the left, use **+ Add an agent** under them instead: the rest is the same. | ||
| 16 | + | ||
| 17 | +## Step 2 — Say who the agent is | ||
| 18 | + | ||
| 19 | +Click **+ Add my first agent**. In **Name shown**, type: | ||
| 20 | + | ||
| 21 | +```text | ||
| 22 | +Alice (assistant) | ||
| 23 | +``` | ||
| 24 | + | ||
| 25 | +You should see **Name used with @** fill itself in with `alice-assistant`. Replace it with `alice`: that is the name you will use to call her. | ||
| 26 | + | ||
| 27 | +## Step 3 — Say how to start it | ||
| 28 | + | ||
| 29 | +Leave **On this computer** selected. Fill in: | ||
| 30 | + | ||
| 31 | +| Field | Value | | ||
| 32 | +| --- | --- | | ||
| 33 | +| Program | `mm` | | ||
| 34 | +| Arguments | `-acp -config agent.yaml` | | ||
| 35 | +| Agent's folder | `~/sidekicks/agents/alice` (or **Choose…** and pick the folder) | | ||
| 36 | + | ||
| 37 | +Click **Add the agent**. | ||
| 38 | + | ||
| 39 | +You should see the assistant close, **🤖 Alice (assistant)** appear under **AGENTS** and under **DIRECT MESSAGES**, and her conversation open in the centre with "Write your first message to Alice (assistant)." | ||
| 40 | + | ||
| 41 | +## Step 4 — Talk with Alice | ||
| 42 | + | ||
| 43 | +Click the text box at the bottom, type the following and press Enter: | ||
| 44 | + | ||
| 45 | +```text | ||
| 46 | +Bonjour Alice, présente-toi en une phrase. | ||
| 47 | +``` | ||
| 48 | + | ||
| 49 | +You should see Alice's dot turn orange while she starts and answers, then her sentence appear word by word. | ||
| 50 | + | ||
| 51 | +## Step 5 — Find her again with the keyboard | ||
| 52 | + | ||
| 53 | +Click **# general** on the left. Then press **⌘K** (Ctrl+K on Linux and Windows) and type `ali`. | ||
| 54 | + | ||
| 55 | +You should see a list with **Alice (assistant)** first. Press Enter: her conversation is back in the centre. | ||
| 56 | + | ||
| 57 | +## What now? | ||
| 58 | + | ||
| 59 | +You have added an agent without touching any YAML, talked with it and moved around with the keyboard. To go further: | ||
| 60 | + | ||
| 61 | +- To add an agent that runs in Docker or in an sbx sandbox → [How to add an agent](../how-to/add-an-agent.md) | ||
| 62 | +- To bring several agents into one channel → [A channel with two agents](first-channel.md) | ||
| 63 | +- Every shortcut → [Keyboard shortcuts](../reference/keyboard-shortcuts.md) | ||
| 64 | +- What the assistant wrote → [The configuration file](../reference/configuration.md) | ||
modified
docs/fr/README.md +5 -5 | @@ -1,14 +1,14 @@ | ||
| 1 | 1 | # Documentation de Sidekicks (français) |
| 2 | 2 | |
| 3 | -Sidekicks est une application de bureau pour converser avec des agents d'IA dans des channels, grâce à l'Agent Client Protocol, pensée pour des personnes qui ne sont pas développeuses. La milestone M4 (Workspace des agents) est terminée : en plus des channels à plusieurs agents (`@`, `/`, historique gardé d'un lancement à l'autre), on parcourt et on modifie le dossier de chaque agent, et on y ouvre un terminal — sur cet ordinateur ou dans un conteneur Docker. Les réponses sont mises en forme, les outils demandent votre accord, et la configuration se modifie depuis la fenêtre. | |
| 3 | +Sidekicks est une application de bureau pour converser avec des agents d'IA dans des channels, grâce à l'Agent Client Protocol, pensée pour des personnes qui ne sont pas développeuses. La version 0.1 est la première release : des paquets pour macOS, Linux et Windows, un assistant qui ajoute des agents sans écrire de YAML, des messages d'erreur en phrases claires, des raccourcis clavier et une palette de commandes — en plus des channels à plusieurs agents (`@`, `/`, historique gardé d'un lancement à l'autre), du dossier de chaque agent avec un éditeur et un terminal (sur cet ordinateur, dans Docker ou dans une sandbox sbx), des réponses mises en forme et des outils qui demandent votre accord. | |
| 4 | 4 | |
| 5 | 5 | Cette documentation suit la méthode [Diátaxis](https://diataxis.fr) : choisissez la section qui correspond à votre besoin du moment. |
| 6 | 6 | |
| 7 | 7 | | Vous voulez… | Section | Pages | |
| 8 | 8 | | --- | --- | --- | |
| 9 | -| **apprendre** en pratiquant | Tutoriels | [Un channel avec deux agents](tutorials/premier-channel.md) · [Votre première conversation avec un agent](tutorials/premiere-conversation.md) · [Votre premier lancement de Sidekicks](tutorials/premier-lancement.md) · [Votre premier échange ACP avec un agent de test](tutorials/premier-echange-acp.md) | | |
| 10 | -| **réaliser** une tâche précise | Guides pratiques | [Travailler avec les fichiers et le terminal d'un agent](how-to/fichiers-et-terminal-d-un-agent.md) · [Lancer un agent dans un conteneur Docker](how-to/lancer-un-agent-dans-docker.md) · [Lancer un agent dans une sandbox sbx](how-to/lancer-un-agent-dans-une-sandbox.md) · [Gérer les channels et leurs agents](how-to/gerer-les-channels.md) · [Modifier ou changer la configuration](how-to/modifier-ou-changer-la-configuration.md) · [Repartir de zéro](how-to/repartir-de-zero.md) · [Développer l'application](how-to/developper-l-application.md) · [Lancer les tests](how-to/lancer-les-tests.md) · [Lancer un agent de test](how-to/lancer-un-agent-de-test.md) · [Tester la milestone M4 sous macOS](how-to/tester-la-milestone-m4-sous-macos.md) · [Tester la milestone M3 sous macOS](how-to/tester-la-milestone-m3-sous-macos.md) · [Tester la milestone M2 sous macOS](how-to/tester-la-milestone-m2-sous-macos.md) · [Tester la milestone M1 sous macOS](how-to/tester-la-milestone-m1-sous-macos.md) · [Tester la milestone Initialize sous macOS](how-to/tester-la-milestone-initialize-sous-macos.md) | | |
| 11 | -| **consulter** un détail exact | Référence | [Le fichier de configuration](reference/configuration.md) · [Agents, channels et événements](reference/agents-et-evenements.md) · [Commandes](reference/commandes.md) · [scripts/agents.sh](reference/script-agents.md) | | |
| 9 | +| **apprendre** en pratiquant | Tutoriels | [Votre premier agent, sans écrire de configuration](tutorials/premier-agent.md) · [Un channel avec deux agents](tutorials/premier-channel.md) · [Votre première conversation avec un agent](tutorials/premiere-conversation.md) · [Votre premier lancement de Sidekicks](tutorials/premier-lancement.md) · [Votre premier échange ACP avec un agent de test](tutorials/premier-echange-acp.md) | | |
| 10 | +| **réaliser** une tâche précise | Guides pratiques | [Installer Sidekicks](how-to/installer-sidekicks.md) · [Ajouter un agent](how-to/ajouter-un-agent.md) · [Travailler avec les fichiers et le terminal d'un agent](how-to/fichiers-et-terminal-d-un-agent.md) · [Lancer un agent dans un conteneur Docker](how-to/lancer-un-agent-dans-docker.md) · [Lancer un agent dans une sandbox sbx](how-to/lancer-un-agent-dans-une-sandbox.md) · [Gérer les channels et leurs agents](how-to/gerer-les-channels.md) · [Modifier ou changer la configuration](how-to/modifier-ou-changer-la-configuration.md) · [Repartir de zéro](how-to/repartir-de-zero.md) · [Développer l'application](how-to/developper-l-application.md) · [Lancer les tests](how-to/lancer-les-tests.md) · [Lancer un agent de test](how-to/lancer-un-agent-de-test.md) · [Dérouler les scénarios de bout en bout (v0.1)](how-to/derouler-les-scenarios-de-bout-en-bout.md) · [Publier une release](how-to/publier-une-release.md) · [Tester la milestone M4 sous macOS](how-to/tester-la-milestone-m4-sous-macos.md) · [Tester la milestone M3 sous macOS](how-to/tester-la-milestone-m3-sous-macos.md) · [Tester la milestone M2 sous macOS](how-to/tester-la-milestone-m2-sous-macos.md) · [Tester la milestone M1 sous macOS](how-to/tester-la-milestone-m1-sous-macos.md) · [Tester la milestone Initialize sous macOS](how-to/tester-la-milestone-initialize-sous-macos.md) | | |
| 11 | +| **consulter** un détail exact | Référence | [Le fichier de configuration](reference/configuration.md) · [Raccourcis clavier](reference/raccourcis-clavier.md) · [Agents, channels et événements](reference/agents-et-evenements.md) · [Commandes](reference/commandes.md) · [scripts/agents.sh](reference/script-agents.md) | | |
| 12 | 12 | | **comprendre** le pourquoi | Explications | [Workspaces et terminaux](explanation/workspaces-et-terminaux.md) · [Les channels et ce que sait chaque agent](explanation/channels-et-contexte.md) · [Permissions et confiance](explanation/permissions-et-confiance.md) · [Pourquoi ACP](explanation/pourquoi-acp.md) · [La stack de l'interface](explanation/stack-interface.md) · [Architecture](explanation/architecture.md) · [Mémoire et modèles locaux](explanation/memoire-et-modeles-locaux.md) | |
| 13 | 13 | |
| 14 | 14 | ## Documents de conception |
| @@ -16,6 +16,6 @@ Cette documentation suit la méthode [Diátaxis](https://diataxis.fr) : choisiss | ||
| 16 | 16 | Communs aux deux langues et rédigés en anglais : |
| 17 | 17 | |
| 18 | 18 | - [Décisions d'architecture (ADR)](../adr/) — ACP, stack de l'interface, architecture, conversations, langue de l'interface, channels, workspaces des agents |
| 19 | -- [Maquettes](../design/README.md) — les six écrans principaux (textes d'interface en français) | |
| 19 | +- [Maquettes](../design/README.md) — les six écrans principaux (textes d'interface en anglais, la langue par défaut) | |
| 20 | 20 | - [Schéma des packages](../diagrams/packages.drawio) |
| 21 | 21 | - [Traces ACP](../spikes/acp/README.md) enregistrées avec les vrais agents |
| @@ -1,14 +1,14 @@ | |||
| 1 | # Documentation de Sidekicks (français) | 1 | # Documentation de Sidekicks (français) |
| 2 | 2 | ||
| 3 | -Sidekicks est une application de bureau pour converser avec des agents d'IA dans des channels, grâce à l'Agent Client Protocol, pensée pour des personnes qui ne sont pas développeuses. La milestone M4 (Workspace des agents) est terminée : en plus des channels à plusieurs agents (`@`, `/`, historique gardé d'un lancement à l'autre), on parcourt et on modifie le dossier de chaque agent, et on y ouvre un terminal — sur cet ordinateur ou dans un conteneur Docker. Les réponses sont mises en forme, les outils demandent votre accord, et la configuration se modifie depuis la fenêtre. | 3 | +Sidekicks est une application de bureau pour converser avec des agents d'IA dans des channels, grâce à l'Agent Client Protocol, pensée pour des personnes qui ne sont pas développeuses. La version 0.1 est la première release : des paquets pour macOS, Linux et Windows, un assistant qui ajoute des agents sans écrire de YAML, des messages d'erreur en phrases claires, des raccourcis clavier et une palette de commandes — en plus des channels à plusieurs agents (`@`, `/`, historique gardé d'un lancement à l'autre), du dossier de chaque agent avec un éditeur et un terminal (sur cet ordinateur, dans Docker ou dans une sandbox sbx), des réponses mises en forme et des outils qui demandent votre accord. |
| 4 | 4 | ||
| 5 | Cette documentation suit la méthode [Diátaxis](https://diataxis.fr) : choisissez la section qui correspond à votre besoin du moment. | 5 | Cette documentation suit la méthode [Diátaxis](https://diataxis.fr) : choisissez la section qui correspond à votre besoin du moment. |
| 6 | 6 | ||
| 7 | | Vous voulez… | Section | Pages | | 7 | | Vous voulez… | Section | Pages | |
| 8 | | --- | --- | --- | | 8 | | --- | --- | --- | |
| 9 | -| **apprendre** en pratiquant | Tutoriels | [Un channel avec deux agents](tutorials/premier-channel.md) · [Votre première conversation avec un agent](tutorials/premiere-conversation.md) · [Votre premier lancement de Sidekicks](tutorials/premier-lancement.md) · [Votre premier échange ACP avec un agent de test](tutorials/premier-echange-acp.md) | | 9 | +| **apprendre** en pratiquant | Tutoriels | [Votre premier agent, sans écrire de configuration](tutorials/premier-agent.md) · [Un channel avec deux agents](tutorials/premier-channel.md) · [Votre première conversation avec un agent](tutorials/premiere-conversation.md) · [Votre premier lancement de Sidekicks](tutorials/premier-lancement.md) · [Votre premier échange ACP avec un agent de test](tutorials/premier-echange-acp.md) | |
| 10 | -| **réaliser** une tâche précise | Guides pratiques | [Travailler avec les fichiers et le terminal d'un agent](how-to/fichiers-et-terminal-d-un-agent.md) · [Lancer un agent dans un conteneur Docker](how-to/lancer-un-agent-dans-docker.md) · [Lancer un agent dans une sandbox sbx](how-to/lancer-un-agent-dans-une-sandbox.md) · [Gérer les channels et leurs agents](how-to/gerer-les-channels.md) · [Modifier ou changer la configuration](how-to/modifier-ou-changer-la-configuration.md) · [Repartir de zéro](how-to/repartir-de-zero.md) · [Développer l'application](how-to/developper-l-application.md) · [Lancer les tests](how-to/lancer-les-tests.md) · [Lancer un agent de test](how-to/lancer-un-agent-de-test.md) · [Tester la milestone M4 sous macOS](how-to/tester-la-milestone-m4-sous-macos.md) · [Tester la milestone M3 sous macOS](how-to/tester-la-milestone-m3-sous-macos.md) · [Tester la milestone M2 sous macOS](how-to/tester-la-milestone-m2-sous-macos.md) · [Tester la milestone M1 sous macOS](how-to/tester-la-milestone-m1-sous-macos.md) · [Tester la milestone Initialize sous macOS](how-to/tester-la-milestone-initialize-sous-macos.md) | | 10 | +| **réaliser** une tâche précise | Guides pratiques | [Installer Sidekicks](how-to/installer-sidekicks.md) · [Ajouter un agent](how-to/ajouter-un-agent.md) · [Travailler avec les fichiers et le terminal d'un agent](how-to/fichiers-et-terminal-d-un-agent.md) · [Lancer un agent dans un conteneur Docker](how-to/lancer-un-agent-dans-docker.md) · [Lancer un agent dans une sandbox sbx](how-to/lancer-un-agent-dans-une-sandbox.md) · [Gérer les channels et leurs agents](how-to/gerer-les-channels.md) · [Modifier ou changer la configuration](how-to/modifier-ou-changer-la-configuration.md) · [Repartir de zéro](how-to/repartir-de-zero.md) · [Développer l'application](how-to/developper-l-application.md) · [Lancer les tests](how-to/lancer-les-tests.md) · [Lancer un agent de test](how-to/lancer-un-agent-de-test.md) · [Dérouler les scénarios de bout en bout (v0.1)](how-to/derouler-les-scenarios-de-bout-en-bout.md) · [Publier une release](how-to/publier-une-release.md) · [Tester la milestone M4 sous macOS](how-to/tester-la-milestone-m4-sous-macos.md) · [Tester la milestone M3 sous macOS](how-to/tester-la-milestone-m3-sous-macos.md) · [Tester la milestone M2 sous macOS](how-to/tester-la-milestone-m2-sous-macos.md) · [Tester la milestone M1 sous macOS](how-to/tester-la-milestone-m1-sous-macos.md) · [Tester la milestone Initialize sous macOS](how-to/tester-la-milestone-initialize-sous-macos.md) | |
| 11 | -| **consulter** un détail exact | Référence | [Le fichier de configuration](reference/configuration.md) · [Agents, channels et événements](reference/agents-et-evenements.md) · [Commandes](reference/commandes.md) · [scripts/agents.sh](reference/script-agents.md) | | 11 | +| **consulter** un détail exact | Référence | [Le fichier de configuration](reference/configuration.md) · [Raccourcis clavier](reference/raccourcis-clavier.md) · [Agents, channels et événements](reference/agents-et-evenements.md) · [Commandes](reference/commandes.md) · [scripts/agents.sh](reference/script-agents.md) | |
| 12 | | **comprendre** le pourquoi | Explications | [Workspaces et terminaux](explanation/workspaces-et-terminaux.md) · [Les channels et ce que sait chaque agent](explanation/channels-et-contexte.md) · [Permissions et confiance](explanation/permissions-et-confiance.md) · [Pourquoi ACP](explanation/pourquoi-acp.md) · [La stack de l'interface](explanation/stack-interface.md) · [Architecture](explanation/architecture.md) · [Mémoire et modèles locaux](explanation/memoire-et-modeles-locaux.md) | | 12 | | **comprendre** le pourquoi | Explications | [Workspaces et terminaux](explanation/workspaces-et-terminaux.md) · [Les channels et ce que sait chaque agent](explanation/channels-et-contexte.md) · [Permissions et confiance](explanation/permissions-et-confiance.md) · [Pourquoi ACP](explanation/pourquoi-acp.md) · [La stack de l'interface](explanation/stack-interface.md) · [Architecture](explanation/architecture.md) · [Mémoire et modèles locaux](explanation/memoire-et-modeles-locaux.md) | |
| 13 | 13 | ||
| 14 | ## Documents de conception | 14 | ## Documents de conception |
| @@ -16,6 +16,6 @@ Cette documentation suit la méthode [Diátaxis](https://diataxis.fr) : choisiss | |||
| 16 | Communs aux deux langues et rédigés en anglais : | 16 | Communs aux deux langues et rédigés en anglais : |
| 17 | 17 | ||
| 18 | - [Décisions d'architecture (ADR)](../adr/) — ACP, stack de l'interface, architecture, conversations, langue de l'interface, channels, workspaces des agents | 18 | - [Décisions d'architecture (ADR)](../adr/) — ACP, stack de l'interface, architecture, conversations, langue de l'interface, channels, workspaces des agents |
| 19 | -- [Maquettes](../design/README.md) — les six écrans principaux (textes d'interface en français) | 19 | +- [Maquettes](../design/README.md) — les six écrans principaux (textes d'interface en anglais, la langue par défaut) |
| 20 | - [Schéma des packages](../diagrams/packages.drawio) | 20 | - [Schéma des packages](../diagrams/packages.drawio) |
| 21 | - [Traces ACP](../spikes/acp/README.md) enregistrées avec les vrais agents | 21 | - [Traces ACP](../spikes/acp/README.md) enregistrées avec les vrais agents |
modified
docs/fr/explanation/architecture.md +9 -1 | @@ -6,7 +6,7 @@ Avant d'écrire l'application, le projet a fixé le découpage du code, ce qui e | ||
| 6 | 6 | |
| 7 | 7 |  |
| 8 | 8 | |
| 9 | -La source du schéma est [packages.drawio](../../diagrams/packages.drawio). Les boîtes bleues existent depuis la milestone M1 ; les grises sont prévues. | |
| 9 | +La source du schéma est [packages.drawio](../../diagrams/packages.drawio). Toutes les boîtes existent (v0.1). | |
| 10 | 10 | |
| 11 | 11 | ## Pourquoi ce découpage |
| 12 | 12 | |
| @@ -30,6 +30,14 @@ Chaque fichier de configuration a sa propre base : passer de « mes agents de tr | ||
| 30 | 30 | |
| 31 | 31 | Pendant qu'un agent répond, la réponse vit en mémoire et l'interface reçoit chaque fragment. Elle est écrite sur disque à la fin du tour. Écrire cinquante fois par seconde userait le disque pour rien ; le prix est de perdre une réponse inachevée si l'application plante, ce qui est acceptable. |
| 32 | 32 | |
| 33 | +## Les programmes sont trouvés comme dans un terminal | |
| 34 | + | |
| 35 | +Une application ouverte depuis le Finder n'hérite pas du `PATH` du terminal de l'utilisateur : macOS lui donne `/usr/bin:/bin:/usr/sbin:/sbin`, si bien que `mm`, `docker` ou `sbx` installés avec Homebrew ou dans `~/.local/bin` sont « introuvables », alors que l'utilisateur vient de les lancer dans un terminal. Demander à une personne qui n'est pas développeuse d'écrire des chemins complets serait la mauvaise réponse. Au démarrage, avant de lire la configuration, `main.go` demande son `PATH` au shell de l'utilisateur (`internal/shellpath` : un shell de connexion interactif, pour qu'il lise les mêmes fichiers qu'un terminal, avec une limite de cinq secondes) et le place devant le sien. Les agents en héritent, et les avertissements de la configuration (« programme introuvable ») sont calculés avec lui. Quand le shell ne peut pas être lu, rien ne change et le chemin complet reste la solution. | |
| 36 | + | |
| 37 | +## Des erreurs en phrases claires | |
| 38 | + | |
| 39 | +Go, les agents, Docker et sbx signalent leurs erreurs pour des développeurs (`exec: "mm": executable file not found in $PATH`). Le côté Go les garde telles quelles : elles sont précises, les tests les vérifient, et c'est ce qu'il faut à un développeur dans le journal. L'interface traduit les plus courantes (`frontend/src/lib/errors.ts`) en une phrase qui dit ce qui ne va pas et quoi faire, dans la langue de l'interface, et garde le texte d'origine replié sous **Détails techniques**. Une erreur inconnue est affichée telle quelle plutôt que cachée derrière une phrase vague. | |
| 40 | + | |
| 33 | 41 | ## Alternatives écartées |
| 34 | 42 | |
| 35 | 43 | - **Stocker les conversations dans le fichier YAML** : cela transformerait un fichier que les gens modifient en base de données, en conflit avec les écritures de l'application. |
| @@ -6,7 +6,7 @@ Avant d'écrire l'application, le projet a fixé le découpage du code, ce qui e | |||
| 6 | 6 | ||
| 7 |  | 7 |  |
| 8 | 8 | ||
| 9 | -La source du schéma est [packages.drawio](../../diagrams/packages.drawio). Les boîtes bleues existent depuis la milestone M1 ; les grises sont prévues. | 9 | +La source du schéma est [packages.drawio](../../diagrams/packages.drawio). Toutes les boîtes existent (v0.1). |
| 10 | 10 | ||
| 11 | ## Pourquoi ce découpage | 11 | ## Pourquoi ce découpage |
| 12 | 12 | ||
| @@ -30,6 +30,14 @@ Chaque fichier de configuration a sa propre base : passer de « mes agents de tr | |||
| 30 | 30 | ||
| 31 | Pendant qu'un agent répond, la réponse vit en mémoire et l'interface reçoit chaque fragment. Elle est écrite sur disque à la fin du tour. Écrire cinquante fois par seconde userait le disque pour rien ; le prix est de perdre une réponse inachevée si l'application plante, ce qui est acceptable. | 31 | Pendant qu'un agent répond, la réponse vit en mémoire et l'interface reçoit chaque fragment. Elle est écrite sur disque à la fin du tour. Écrire cinquante fois par seconde userait le disque pour rien ; le prix est de perdre une réponse inachevée si l'application plante, ce qui est acceptable. |
| 32 | 32 | ||
| 33 | +## Les programmes sont trouvés comme dans un terminal | ||
| 34 | + | ||
| 35 | +Une application ouverte depuis le Finder n'hérite pas du `PATH` du terminal de l'utilisateur : macOS lui donne `/usr/bin:/bin:/usr/sbin:/sbin`, si bien que `mm`, `docker` ou `sbx` installés avec Homebrew ou dans `~/.local/bin` sont « introuvables », alors que l'utilisateur vient de les lancer dans un terminal. Demander à une personne qui n'est pas développeuse d'écrire des chemins complets serait la mauvaise réponse. Au démarrage, avant de lire la configuration, `main.go` demande son `PATH` au shell de l'utilisateur (`internal/shellpath` : un shell de connexion interactif, pour qu'il lise les mêmes fichiers qu'un terminal, avec une limite de cinq secondes) et le place devant le sien. Les agents en héritent, et les avertissements de la configuration (« programme introuvable ») sont calculés avec lui. Quand le shell ne peut pas être lu, rien ne change et le chemin complet reste la solution. | ||
| 36 | + | ||
| 37 | +## Des erreurs en phrases claires | ||
| 38 | + | ||
| 39 | +Go, les agents, Docker et sbx signalent leurs erreurs pour des développeurs (`exec: "mm": executable file not found in $PATH`). Le côté Go les garde telles quelles : elles sont précises, les tests les vérifient, et c'est ce qu'il faut à un développeur dans le journal. L'interface traduit les plus courantes (`frontend/src/lib/errors.ts`) en une phrase qui dit ce qui ne va pas et quoi faire, dans la langue de l'interface, et garde le texte d'origine replié sous **Détails techniques**. Une erreur inconnue est affichée telle quelle plutôt que cachée derrière une phrase vague. | ||
| 40 | + | ||
| 33 | ## Alternatives écartées | 41 | ## Alternatives écartées |
| 34 | 42 | ||
| 35 | - **Stocker les conversations dans le fichier YAML** : cela transformerait un fichier que les gens modifient en base de données, en conflit avec les écritures de l'application. | 43 | - **Stocker les conversations dans le fichier YAML** : cela transformerait un fichier que les gens modifient en base de données, en conflit avec les écritures de l'application. |
added
docs/fr/how-to/ajouter-un-agent.md +26 -0 | new file mode 100644 | ||
| @@ -0,0 +1,26 @@ | ||
| 1 | +# Ajouter un agent | |
| 2 | + | |
| 3 | +Ce guide montre comment ajouter un agent depuis la fenêtre de Sidekicks, avec l'assistant « Ajouter un agent », quel que soit l'endroit où il tourne : sur cet ordinateur, dans un conteneur Docker ou dans une sandbox sbx. Il suppose que le programme de l'agent parle ACP (pour `mm` : l'argument `-acp`). | |
| 4 | + | |
| 5 | +## Étapes | |
| 6 | + | |
| 7 | +1. Ouvrez l'assistant : **+ Ajouter mon premier agent** sur l'écran d'accueil, **+ Ajouter un agent** sous la liste des agents, ou **⇧⌘N** (Ctrl+Maj+N sous Linux et Windows). | |
| 8 | +2. **Qui est-ce ?** Remplissez **Nom affiché** (par exemple `Garfield (traducteur)`). **Nom utilisé avec @** le suit ; changez-le si vous en voulez un plus court (minuscules, chiffres, `-` et `_`, en commençant par une lettre). L'icône et la description sont facultatives. | |
| 9 | +3. **Où tourne-t-il ?** Choisissez l'environnement, puis remplissez ce qu'il demande (voir plus bas). | |
| 10 | +4. **Comment le démarrer ?** Remplissez **Programme**, **Arguments** (sur une ligne, comme dans un terminal ; les guillemets regroupent des mots) et **Dossier de l'agent**. Le dossier est créé s'il n'existe pas. | |
| 11 | +5. Cliquez sur **Ajouter l'agent**. Sa conversation directe s'ouvre dès que la configuration est rechargée. | |
| 12 | + | |
| 13 | +Quand l'agent ne peut pas être ajouté (un nom déjà pris, par exemple), l'assistant dit pourquoi et n'écrit rien. | |
| 14 | + | |
| 15 | +## Variantes | |
| 16 | + | |
| 17 | +- **Sur cet ordinateur** : le programme tourne ici, dans le dossier de l'agent. Si Sidekicks, ouvert depuis le Finder, ne trouve pas le programme, indiquez son chemin complet (`which mm` dans un terminal le donne). Sidekicks lit le `PATH` de votre shell au démarrage : c'est rarement nécessaire. | |
| 18 | +- **Dans un conteneur Docker** : indiquez le **Nom du conteneur**. Le conteneur doit tourner, avec le dossier de l'agent monté au même chemin, et contenir le programme : voir [Lancer un agent dans un conteneur Docker](lancer-un-agent-dans-docker.md). Sidekicks démarre l'agent avec `docker exec -i <conteneur> <programme> <arguments>`. | |
| 19 | +- **Dans une sandbox sbx** : indiquez le **Nom de la sandbox**. Elle doit exister, avec le dossier de l'agent au même chemin : voir [Lancer un agent dans une sandbox sbx](lancer-un-agent-dans-une-sandbox.md). Sidekicks démarre l'agent avec `sbx exec -i <sandbox> <programme> <arguments>`. | |
| 20 | +- **Les options que l'assistant ne demande pas** (`env`, `afterStop`, un autre `workspacePath`) : ajoutez l'agent avec l'assistant, puis complétez son entrée dans **Settings**. | |
| 21 | + | |
| 22 | +## Voir aussi | |
| 23 | + | |
| 24 | +- Ce que l'assistant écrit : [Le fichier de configuration](../reference/configuration.md) | |
| 25 | +- [Modifier ou changer la configuration](modifier-ou-changer-la-configuration.md) | |
| 26 | +- [Tutoriel : votre premier agent, sans écrire de configuration](../tutorials/premier-agent.md) | |
| new file mode 100644 | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | +# Ajouter un agent | ||
| 2 | + | ||
| 3 | +Ce guide montre comment ajouter un agent depuis la fenêtre de Sidekicks, avec l'assistant « Ajouter un agent », quel que soit l'endroit où il tourne : sur cet ordinateur, dans un conteneur Docker ou dans une sandbox sbx. Il suppose que le programme de l'agent parle ACP (pour `mm` : l'argument `-acp`). | ||
| 4 | + | ||
| 5 | +## Étapes | ||
| 6 | + | ||
| 7 | +1. Ouvrez l'assistant : **+ Ajouter mon premier agent** sur l'écran d'accueil, **+ Ajouter un agent** sous la liste des agents, ou **⇧⌘N** (Ctrl+Maj+N sous Linux et Windows). | ||
| 8 | +2. **Qui est-ce ?** Remplissez **Nom affiché** (par exemple `Garfield (traducteur)`). **Nom utilisé avec @** le suit ; changez-le si vous en voulez un plus court (minuscules, chiffres, `-` et `_`, en commençant par une lettre). L'icône et la description sont facultatives. | ||
| 9 | +3. **Où tourne-t-il ?** Choisissez l'environnement, puis remplissez ce qu'il demande (voir plus bas). | ||
| 10 | +4. **Comment le démarrer ?** Remplissez **Programme**, **Arguments** (sur une ligne, comme dans un terminal ; les guillemets regroupent des mots) et **Dossier de l'agent**. Le dossier est créé s'il n'existe pas. | ||
| 11 | +5. Cliquez sur **Ajouter l'agent**. Sa conversation directe s'ouvre dès que la configuration est rechargée. | ||
| 12 | + | ||
| 13 | +Quand l'agent ne peut pas être ajouté (un nom déjà pris, par exemple), l'assistant dit pourquoi et n'écrit rien. | ||
| 14 | + | ||
| 15 | +## Variantes | ||
| 16 | + | ||
| 17 | +- **Sur cet ordinateur** : le programme tourne ici, dans le dossier de l'agent. Si Sidekicks, ouvert depuis le Finder, ne trouve pas le programme, indiquez son chemin complet (`which mm` dans un terminal le donne). Sidekicks lit le `PATH` de votre shell au démarrage : c'est rarement nécessaire. | ||
| 18 | +- **Dans un conteneur Docker** : indiquez le **Nom du conteneur**. Le conteneur doit tourner, avec le dossier de l'agent monté au même chemin, et contenir le programme : voir [Lancer un agent dans un conteneur Docker](lancer-un-agent-dans-docker.md). Sidekicks démarre l'agent avec `docker exec -i <conteneur> <programme> <arguments>`. | ||
| 19 | +- **Dans une sandbox sbx** : indiquez le **Nom de la sandbox**. Elle doit exister, avec le dossier de l'agent au même chemin : voir [Lancer un agent dans une sandbox sbx](lancer-un-agent-dans-une-sandbox.md). Sidekicks démarre l'agent avec `sbx exec -i <sandbox> <programme> <arguments>`. | ||
| 20 | +- **Les options que l'assistant ne demande pas** (`env`, `afterStop`, un autre `workspacePath`) : ajoutez l'agent avec l'assistant, puis complétez son entrée dans **Settings**. | ||
| 21 | + | ||
| 22 | +## Voir aussi | ||
| 23 | + | ||
| 24 | +- Ce que l'assistant écrit : [Le fichier de configuration](../reference/configuration.md) | ||
| 25 | +- [Modifier ou changer la configuration](modifier-ou-changer-la-configuration.md) | ||
| 26 | +- [Tutoriel : votre premier agent, sans écrire de configuration](../tutorials/premier-agent.md) | ||
added
docs/fr/how-to/derouler-les-scenarios-de-bout-en-bout.md +102 -0 | new file mode 100644 | ||
| @@ -0,0 +1,102 @@ | ||
| 1 | +# Dérouler les scénarios de bout en bout (v0.1) | |
| 2 | + | |
| 3 | +Ce guide déroule les six scénarios qui valident une release avec les vrais agents de test (ticket #34), puis les vérifications de ce que la v0.1 a ajouté. Il suppose un Mac avec `mm`, llmman démarré, les modèles des quatre agents de test téléchargés, et Sidekicks construit depuis le tag de la release (`make package-macos`, ou `make dev`). | |
| 4 | + | |
| 5 | +Deux agents au plus tournent en même temps (`limits.maxRunningAgents: 2`). Entre deux scénarios, déchargez tous les modèles, pour que chaque scénario parte à froid : | |
| 6 | + | |
| 7 | +```bash | |
| 8 | +scripts/agents.sh unload --all | |
| 9 | +scripts/agents.sh ps # aucun modèle chargé | |
| 10 | +``` | |
| 11 | + | |
| 12 | +Les libellés cités sont ceux de l'interface en anglais (la langue par défaut). | |
| 13 | + | |
| 14 | +## 0. Préparer | |
| 15 | + | |
| 16 | +1. `make install-test-config` (les quatre agents de test à l'emplacement par défaut ; le fichier précédent est gardé en sauvegarde). | |
| 17 | +2. Ouvrez Sidekicks. Sous **AGENTS** : Alice, Bob, Riker, Garfield, tous « stopped ». | |
| 18 | +3. Ouvrez le [rapport](#rapport) ci-dessous dans un éditeur de texte, pour le remplir au fur et à mesure. | |
| 19 | + | |
| 20 | +## 1. Alice — conversation simple, Markdown, annulation | |
| 21 | + | |
| 22 | +1. Cliquez sur **Alice (assistant)**, envoyez : `Donne un tableau markdown de 2 lignes (nom, rôle) puis un bloc de code Go qui affiche hello.` | |
| 23 | +2. Attendu : la réponse s'affiche au fil de l'eau ; un tableau et du code Go en couleurs avec **Copy**. | |
| 24 | +3. Envoyez : `Écris un poème de 40 vers sur la mer.` et cliquez sur **■ Stop** après quelques lignes. | |
| 25 | +4. Attendu : la réponse s'arrête et finit par « Answer stopped. » ; Alice repasse à « ready ». | |
| 26 | + | |
| 27 | +## 2. Alice + Bob — channel multi-agents, routage, contexte partagé | |
| 28 | + | |
| 29 | +1. Créez un channel `#e2e` (**⌘N**). Envoyez : `@alice donne un prénom pour un chat roux.` | |
| 30 | +2. Attendu : « Alice (assistant) joined the channel. » puis sa réponse avec un prénom. | |
| 31 | +3. Envoyez : `@bob que penses-tu du prénom proposé par Alice ?` | |
| 32 | +4. Attendu : Bob rejoint le channel et reprend le prénom donné par Alice : il a reçu les messages qu'il n'avait pas vus. | |
| 33 | +5. Envoyez un message sans mention : attendu, le dernier agent qui a parlé (Bob) répond. | |
| 34 | + | |
| 35 | +## 3. Riker — tool calls, permissions | |
| 36 | + | |
| 37 | +1. Déchargez les modèles. Cliquez sur **Riker (tools)**, envoyez : `Crée le fichier e2e.txt contenant "ok", puis liste le dossier.` | |
| 38 | +2. Attendu : une carte de permission en phrases claires. Cliquez sur **Allow once** : la carte de l'outil passe à ✓, `e2e.txt` est listé. | |
| 39 | +3. Envoyez : `Supprime e2e.txt.` Cliquez sur **Reject once**. | |
| 40 | +4. Attendu : Riker dit qu'il n'a pas pu ; le fichier est toujours là (📂 → Files). | |
| 41 | + | |
| 42 | +## 4. Garfield — commandes slash et skills | |
| 43 | + | |
| 44 | +1. Déchargez les modèles. Cliquez sur **Garfield (translator)**, tapez `/`. | |
| 45 | +2. Attendu : « Asking Garfield (translator) for their commands… » puis les commandes et skills de Garfield (`idioms`, `styles`…). | |
| 46 | +3. Choisissez `/idioms` (Tab), ajoutez `il pleut des cordes`, envoyez. | |
| 47 | +4. Attendu : la réponse explique l'expression avec un équivalent anglais. | |
| 48 | + | |
| 49 | +## 5. Garfield + Bob — `/garfield:commande` dans un channel | |
| 50 | + | |
| 51 | +1. Déchargez les modèles. Dans `#e2e`, invitez Garfield (**+ Invite**), puis tapez `/gar`. | |
| 52 | +2. Attendu : `/garfield:idioms`, `/garfield:styles`… listés avec leur agent. | |
| 53 | +3. Envoyez `/garfield:styles Bonjour à tous`. Attendu : seul Garfield répond. | |
| 54 | +4. Envoyez `@bob traduis la première version de Garfield en espagnol.` Attendu : Bob répond à partir du texte de Garfield. | |
| 55 | + | |
| 56 | +## 6. Alice — redémarrage et reprise | |
| 57 | + | |
| 58 | +1. Quittez Sidekicks (⌘Q) pendant que rien ne répond. Rouvrez-le. | |
| 59 | +2. Attendu : `#e2e` et les conversations directes sont là avec leurs messages ; les agents sont « stopped ». | |
| 60 | +3. Dans la conversation d'Alice, envoyez : `Quelle était ma première question ?` | |
| 61 | +4. Attendu : Alice répond à partir de l'échange précédent (sa session a été reprise, ou l'historique lui a été redonné). | |
| 62 | + | |
| 63 | +## 7. Ce que la v0.1 a ajouté | |
| 64 | + | |
| 65 | +| # | Vérification | Attendu | | |
| 66 | +| --- | --- | --- | | |
| 67 | +| 7.1 | `mv ~/Library/Application\ Support/sidekicks ~/sidekicks-backup`, ouvrez Sidekicks | Écran d'accueil : logo, trois étapes, **+ Add my first agent** | | |
| 68 | +| 7.2 | Ajoutez Alice avec l'assistant (programme `mm`, arguments `-acp -config agent.yaml`, dossier `agents/alice`) | Sa conversation s'ouvre ; Settings montre son entrée, les commentaires du fichier sont gardés | | |
| 69 | +| 7.3 | Ajoutez un agent dont le programme est `nothere`, démarrez-le (▶) | « The program "nothere" cannot be found… », avec **Technical details** replié | | |
| 70 | +| 7.4 | Ajoutez un agent dans un conteneur qui n'existe pas, démarrez-le | Une phrase sur le conteneur manquant | | |
| 71 | +| 7.5 | ⌘K, tapez `ali`, Entrée ; ⌘N ; ⌘L ; ⌘, ; ⌘J ; ⌘B ; ⇧⌘N | Chacun fait ce que dit [Raccourcis clavier](../reference/raccourcis-clavier.md) | | |
| 72 | +| 7.6 | Parcourez la fenêtre avec Tab | L'élément qui a le focus est toujours entouré | | |
| 73 | +| 7.7 | Ouvrez le `.app` installé depuis le `.dmg` **depuis le Finder**, démarrez Alice | Elle démarre : `mm` est trouvé sans chemin complet (le PATH du shell) | | |
| 74 | +| 7.8 | Remettez la sauvegarde : `rm -r ~/Library/Application\ Support/sidekicks && mv ~/sidekicks-backup ~/Library/Application\ Support/sidekicks` | Vos agents et votre historique sont de retour | | |
| 75 | + | |
| 76 | +## Rapport | |
| 77 | + | |
| 78 | +Copiez ceci dans un commentaire du ticket #34 et remplissez-le : | |
| 79 | + | |
| 80 | +```markdown | |
| 81 | +## Rapport de bout en bout — Sidekicks <version>, <date> | |
| 82 | + | |
| 83 | +Mac : <modèle, RAM>, macOS <version> · mm <version> · build : <dmg | make dev> | |
| 84 | + | |
| 85 | +| # | Scénario | Résultat | Notes | | |
| 86 | +| --- | --- | --- | --- | | |
| 87 | +| 1 | Alice : conversation, Markdown, annulation | ✅ / ❌ | | | |
| 88 | +| 2 | Alice + Bob : channel, routage, contexte partagé | ✅ / ❌ | | | |
| 89 | +| 3 | Riker : outils, autoriser / refuser | ✅ / ❌ | | | |
| 90 | +| 4 | Garfield : commandes / et skills | ✅ / ❌ | | | |
| 91 | +| 5 | Garfield + Bob : /garfield:commande dans un channel | ✅ / ❌ | | | |
| 92 | +| 6 | Alice : redémarrage et reprise | ✅ / ❌ | | | |
| 93 | +| 7 | Vérifications v0.1 (7.1–7.8) | ✅ / ❌ | | | |
| 94 | + | |
| 95 | +Modèles déchargés entre les scénarios : oui / non | |
| 96 | +``` | |
| 97 | + | |
| 98 | +## Voir aussi | |
| 99 | + | |
| 100 | +- [Lancer les tests](lancer-les-tests.md) — les tests automatiques, avec et sans vrais agents | |
| 101 | +- [scripts/agents.sh](../reference/script-agents.md) | |
| 102 | +- [Publier une release](publier-une-release.md) | |
| new file mode 100644 | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | +# Dérouler les scénarios de bout en bout (v0.1) | ||
| 2 | + | ||
| 3 | +Ce guide déroule les six scénarios qui valident une release avec les vrais agents de test (ticket #34), puis les vérifications de ce que la v0.1 a ajouté. Il suppose un Mac avec `mm`, llmman démarré, les modèles des quatre agents de test téléchargés, et Sidekicks construit depuis le tag de la release (`make package-macos`, ou `make dev`). | ||
| 4 | + | ||
| 5 | +Deux agents au plus tournent en même temps (`limits.maxRunningAgents: 2`). Entre deux scénarios, déchargez tous les modèles, pour que chaque scénario parte à froid : | ||
| 6 | + | ||
| 7 | +```bash | ||
| 8 | +scripts/agents.sh unload --all | ||
| 9 | +scripts/agents.sh ps # aucun modèle chargé | ||
| 10 | +``` | ||
| 11 | + | ||
| 12 | +Les libellés cités sont ceux de l'interface en anglais (la langue par défaut). | ||
| 13 | + | ||
| 14 | +## 0. Préparer | ||
| 15 | + | ||
| 16 | +1. `make install-test-config` (les quatre agents de test à l'emplacement par défaut ; le fichier précédent est gardé en sauvegarde). | ||
| 17 | +2. Ouvrez Sidekicks. Sous **AGENTS** : Alice, Bob, Riker, Garfield, tous « stopped ». | ||
| 18 | +3. Ouvrez le [rapport](#rapport) ci-dessous dans un éditeur de texte, pour le remplir au fur et à mesure. | ||
| 19 | + | ||
| 20 | +## 1. Alice — conversation simple, Markdown, annulation | ||
| 21 | + | ||
| 22 | +1. Cliquez sur **Alice (assistant)**, envoyez : `Donne un tableau markdown de 2 lignes (nom, rôle) puis un bloc de code Go qui affiche hello.` | ||
| 23 | +2. Attendu : la réponse s'affiche au fil de l'eau ; un tableau et du code Go en couleurs avec **Copy**. | ||
| 24 | +3. Envoyez : `Écris un poème de 40 vers sur la mer.` et cliquez sur **■ Stop** après quelques lignes. | ||
| 25 | +4. Attendu : la réponse s'arrête et finit par « Answer stopped. » ; Alice repasse à « ready ». | ||
| 26 | + | ||
| 27 | +## 2. Alice + Bob — channel multi-agents, routage, contexte partagé | ||
| 28 | + | ||
| 29 | +1. Créez un channel `#e2e` (**⌘N**). Envoyez : `@alice donne un prénom pour un chat roux.` | ||
| 30 | +2. Attendu : « Alice (assistant) joined the channel. » puis sa réponse avec un prénom. | ||
| 31 | +3. Envoyez : `@bob que penses-tu du prénom proposé par Alice ?` | ||
| 32 | +4. Attendu : Bob rejoint le channel et reprend le prénom donné par Alice : il a reçu les messages qu'il n'avait pas vus. | ||
| 33 | +5. Envoyez un message sans mention : attendu, le dernier agent qui a parlé (Bob) répond. | ||
| 34 | + | ||
| 35 | +## 3. Riker — tool calls, permissions | ||
| 36 | + | ||
| 37 | +1. Déchargez les modèles. Cliquez sur **Riker (tools)**, envoyez : `Crée le fichier e2e.txt contenant "ok", puis liste le dossier.` | ||
| 38 | +2. Attendu : une carte de permission en phrases claires. Cliquez sur **Allow once** : la carte de l'outil passe à ✓, `e2e.txt` est listé. | ||
| 39 | +3. Envoyez : `Supprime e2e.txt.` Cliquez sur **Reject once**. | ||
| 40 | +4. Attendu : Riker dit qu'il n'a pas pu ; le fichier est toujours là (📂 → Files). | ||
| 41 | + | ||
| 42 | +## 4. Garfield — commandes slash et skills | ||
| 43 | + | ||
| 44 | +1. Déchargez les modèles. Cliquez sur **Garfield (translator)**, tapez `/`. | ||
| 45 | +2. Attendu : « Asking Garfield (translator) for their commands… » puis les commandes et skills de Garfield (`idioms`, `styles`…). | ||
| 46 | +3. Choisissez `/idioms` (Tab), ajoutez `il pleut des cordes`, envoyez. | ||
| 47 | +4. Attendu : la réponse explique l'expression avec un équivalent anglais. | ||
| 48 | + | ||
| 49 | +## 5. Garfield + Bob — `/garfield:commande` dans un channel | ||
| 50 | + | ||
| 51 | +1. Déchargez les modèles. Dans `#e2e`, invitez Garfield (**+ Invite**), puis tapez `/gar`. | ||
| 52 | +2. Attendu : `/garfield:idioms`, `/garfield:styles`… listés avec leur agent. | ||
| 53 | +3. Envoyez `/garfield:styles Bonjour à tous`. Attendu : seul Garfield répond. | ||
| 54 | +4. Envoyez `@bob traduis la première version de Garfield en espagnol.` Attendu : Bob répond à partir du texte de Garfield. | ||
| 55 | + | ||
| 56 | +## 6. Alice — redémarrage et reprise | ||
| 57 | + | ||
| 58 | +1. Quittez Sidekicks (⌘Q) pendant que rien ne répond. Rouvrez-le. | ||
| 59 | +2. Attendu : `#e2e` et les conversations directes sont là avec leurs messages ; les agents sont « stopped ». | ||
| 60 | +3. Dans la conversation d'Alice, envoyez : `Quelle était ma première question ?` | ||
| 61 | +4. Attendu : Alice répond à partir de l'échange précédent (sa session a été reprise, ou l'historique lui a été redonné). | ||
| 62 | + | ||
| 63 | +## 7. Ce que la v0.1 a ajouté | ||
| 64 | + | ||
| 65 | +| # | Vérification | Attendu | | ||
| 66 | +| --- | --- | --- | | ||
| 67 | +| 7.1 | `mv ~/Library/Application\ Support/sidekicks ~/sidekicks-backup`, ouvrez Sidekicks | Écran d'accueil : logo, trois étapes, **+ Add my first agent** | | ||
| 68 | +| 7.2 | Ajoutez Alice avec l'assistant (programme `mm`, arguments `-acp -config agent.yaml`, dossier `agents/alice`) | Sa conversation s'ouvre ; Settings montre son entrée, les commentaires du fichier sont gardés | | ||
| 69 | +| 7.3 | Ajoutez un agent dont le programme est `nothere`, démarrez-le (▶) | « The program "nothere" cannot be found… », avec **Technical details** replié | | ||
| 70 | +| 7.4 | Ajoutez un agent dans un conteneur qui n'existe pas, démarrez-le | Une phrase sur le conteneur manquant | | ||
| 71 | +| 7.5 | ⌘K, tapez `ali`, Entrée ; ⌘N ; ⌘L ; ⌘, ; ⌘J ; ⌘B ; ⇧⌘N | Chacun fait ce que dit [Raccourcis clavier](../reference/raccourcis-clavier.md) | | ||
| 72 | +| 7.6 | Parcourez la fenêtre avec Tab | L'élément qui a le focus est toujours entouré | | ||
| 73 | +| 7.7 | Ouvrez le `.app` installé depuis le `.dmg` **depuis le Finder**, démarrez Alice | Elle démarre : `mm` est trouvé sans chemin complet (le PATH du shell) | | ||
| 74 | +| 7.8 | Remettez la sauvegarde : `rm -r ~/Library/Application\ Support/sidekicks && mv ~/sidekicks-backup ~/Library/Application\ Support/sidekicks` | Vos agents et votre historique sont de retour | | ||
| 75 | + | ||
| 76 | +## Rapport | ||
| 77 | + | ||
| 78 | +Copiez ceci dans un commentaire du ticket #34 et remplissez-le : | ||
| 79 | + | ||
| 80 | +```markdown | ||
| 81 | +## Rapport de bout en bout — Sidekicks <version>, <date> | ||
| 82 | + | ||
| 83 | +Mac : <modèle, RAM>, macOS <version> · mm <version> · build : <dmg | make dev> | ||
| 84 | + | ||
| 85 | +| # | Scénario | Résultat | Notes | | ||
| 86 | +| --- | --- | --- | --- | | ||
| 87 | +| 1 | Alice : conversation, Markdown, annulation | ✅ / ❌ | | | ||
| 88 | +| 2 | Alice + Bob : channel, routage, contexte partagé | ✅ / ❌ | | | ||
| 89 | +| 3 | Riker : outils, autoriser / refuser | ✅ / ❌ | | | ||
| 90 | +| 4 | Garfield : commandes / et skills | ✅ / ❌ | | | ||
| 91 | +| 5 | Garfield + Bob : /garfield:commande dans un channel | ✅ / ❌ | | | ||
| 92 | +| 6 | Alice : redémarrage et reprise | ✅ / ❌ | | | ||
| 93 | +| 7 | Vérifications v0.1 (7.1–7.8) | ✅ / ❌ | | | ||
| 94 | + | ||
| 95 | +Modèles déchargés entre les scénarios : oui / non | ||
| 96 | +``` | ||
| 97 | + | ||
| 98 | +## Voir aussi | ||
| 99 | + | ||
| 100 | +- [Lancer les tests](lancer-les-tests.md) — les tests automatiques, avec et sans vrais agents | ||
| 101 | +- [scripts/agents.sh](../reference/script-agents.md) | ||
| 102 | +- [Publier une release](publier-une-release.md) | ||
modified
docs/fr/how-to/developper-l-application.md +2 -0 | @@ -30,6 +30,8 @@ make build # bin/sidekicks | ||
| 30 | 30 | make package # macOS : bin/sidekicks.app, signé ad hoc |
| 31 | 31 | ``` |
| 32 | 32 | |
| 33 | +Les paquets de release vont dans `dist/` : `make package-macos`, `make package-linux`, `make package-windows` (voir [Publier une release](publier-une-release.md)). | |
| 34 | + | |
| 33 | 35 | ## Quand vous modifiez… |
| 34 | 36 | |
| 35 | 37 | - **un service Go ou une charge d'événement** (`internal/app`, `internal/events`, `main.go`) : lancez `make bindings` et commitez `frontend/bindings` — la CI échoue s'ils ne sont pas à jour. |
| @@ -30,6 +30,8 @@ make build # bin/sidekicks | |||
| 30 | make package # macOS : bin/sidekicks.app, signé ad hoc | 30 | make package # macOS : bin/sidekicks.app, signé ad hoc |
| 31 | ``` | 31 | ``` |
| 32 | 32 | ||
| 33 | +Les paquets de release vont dans `dist/` : `make package-macos`, `make package-linux`, `make package-windows` (voir [Publier une release](publier-une-release.md)). | ||
| 34 | + | ||
| 33 | ## Quand vous modifiez… | 35 | ## Quand vous modifiez… |
| 34 | 36 | ||
| 35 | - **un service Go ou une charge d'événement** (`internal/app`, `internal/events`, `main.go`) : lancez `make bindings` et commitez `frontend/bindings` — la CI échoue s'ils ne sont pas à jour. | 37 | - **un service Go ou une charge d'événement** (`internal/app`, `internal/events`, `main.go`) : lancez `make bindings` et commitez `frontend/bindings` — la CI échoue s'ils ne sont pas à jour. |
added
docs/fr/how-to/installer-sidekicks.md +48 -0 | new file mode 100644 | ||
| @@ -0,0 +1,48 @@ | ||
| 1 | +# Installer Sidekicks | |
| 2 | + | |
| 3 | +Ce guide montre comment installer Sidekicks à partir des paquets d'une release, sous macOS, Linux ou Windows. Les paquets sont sur la page des releases du projet, `https://rickub.com/bots-garden/sidekicks/releases` ; `SHA256SUMS` donne leurs sommes de contrôle. | |
| 4 | + | |
| 5 | +Sidekicks discute avec des agents, il n'en contient pas. Installez aussi le programme de votre agent (par exemple `mm`). | |
| 6 | + | |
| 7 | +## macOS (Apple Silicon et Intel) | |
| 8 | + | |
| 9 | +Sidekicks demande macOS 13 (Ventura) ou plus récent. | |
| 10 | + | |
| 11 | +1. Téléchargez `Sidekicks-<version>-macos-universal.dmg` et ouvrez-le. | |
| 12 | +2. Glissez **sidekicks** dans **Applications**. | |
| 13 | +3. Ouvrez-le une fois depuis **Applications**. L'application n'est pas signée par un compte développeur Apple : macOS la refuse la première fois (« Apple n'a pas pu vérifier… »). | |
| 14 | +4. Ouvrez **Réglages Système → Confidentialité et sécurité**, descendez jusqu'au message sur Sidekicks, cliquez sur **Ouvrir quand même**, puis confirmez. | |
| 15 | + | |
| 16 | +Ensuite, Sidekicks s'ouvre normalement. | |
| 17 | + | |
| 18 | +## Linux (x86-64) | |
| 19 | + | |
| 20 | +Sidekicks a besoin de GTK 4 et de WebKitGTK 6 (Ubuntu 24.04 ou plus récent, Debian 13, Fedora 40 ou plus récent). | |
| 21 | + | |
| 22 | +- **Debian, Ubuntu** : `sudo apt install ./sidekicks_<version>_linux_amd64.deb` | |
| 23 | +- **Fedora** : `sudo dnf install ./sidekicks_<version>_linux_amd64.rpm` | |
| 24 | +- **Toute distribution, sans installer** : `chmod +x Sidekicks-<version>-x86_64.AppImage`, puis lancez-le. S'il se plaint de FUSE, lancez-le avec `--appimage-extract-and-run`. | |
| 25 | +- **Le programme seul** : `sidekicks_<version>_linux_amd64.tar.gz` contient `sidekicks` ; les bibliothèques GTK 4 et WebKitGTK 6 doivent être installées. | |
| 26 | + | |
| 27 | +Le `.deb` et le `.rpm` ajoutent Sidekicks au menu des applications. | |
| 28 | + | |
| 29 | +## Windows (x86-64) | |
| 30 | + | |
| 31 | +1. Téléchargez `Sidekicks-<version>-windows-amd64-installer.exe` et lancez-le. | |
| 32 | +2. L'installateur n'est pas signé : Windows SmartScreen peut afficher « Windows a protégé votre ordinateur ». Cliquez sur **Informations complémentaires**, puis **Exécuter quand même**. | |
| 33 | +3. L'installateur ajoute Microsoft Edge WebView2 s'il manque, puis un raccourci Sidekicks. | |
| 34 | + | |
| 35 | +`sidekicks_<version>_windows_amd64.zip` contient `sidekicks.exe` seul, pour une machine où WebView2 est déjà présent. | |
| 36 | + | |
| 37 | +Sous Windows, l'onglet **Terminal** d'un agent n'est pas encore disponible ; les fichiers, les conversations et les agents dans Docker fonctionnent. | |
| 38 | + | |
| 39 | +## Variantes | |
| 40 | + | |
| 41 | +- **Vérifier un téléchargement** : `shasum -a 256 <fichier>` (macOS) ou `sha256sum <fichier>` (Linux), à comparer avec `SHA256SUMS`. | |
| 42 | +- **macOS, depuis un terminal** : `xattr -dr com.apple.quarantine /Applications/sidekicks.app` lève la quarantaine, à la place de l'étape 4. | |
| 43 | +- **Le construire soi-même** : `make package-macos`, `make package-linux` ou `make package-windows` (voir [Publier une release](publier-une-release.md)). | |
| 44 | + | |
| 45 | +## Voir aussi | |
| 46 | + | |
| 47 | +- [Tutoriel : votre premier agent, sans écrire de configuration](../tutorials/premier-agent.md) | |
| 48 | +- [Repartir de zéro](repartir-de-zero.md) | |
| new file mode 100644 | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | +# Installer Sidekicks | ||
| 2 | + | ||
| 3 | +Ce guide montre comment installer Sidekicks à partir des paquets d'une release, sous macOS, Linux ou Windows. Les paquets sont sur la page des releases du projet, `https://rickub.com/bots-garden/sidekicks/releases` ; `SHA256SUMS` donne leurs sommes de contrôle. | ||
| 4 | + | ||
| 5 | +Sidekicks discute avec des agents, il n'en contient pas. Installez aussi le programme de votre agent (par exemple `mm`). | ||
| 6 | + | ||
| 7 | +## macOS (Apple Silicon et Intel) | ||
| 8 | + | ||
| 9 | +Sidekicks demande macOS 13 (Ventura) ou plus récent. | ||
| 10 | + | ||
| 11 | +1. Téléchargez `Sidekicks-<version>-macos-universal.dmg` et ouvrez-le. | ||
| 12 | +2. Glissez **sidekicks** dans **Applications**. | ||
| 13 | +3. Ouvrez-le une fois depuis **Applications**. L'application n'est pas signée par un compte développeur Apple : macOS la refuse la première fois (« Apple n'a pas pu vérifier… »). | ||
| 14 | +4. Ouvrez **Réglages Système → Confidentialité et sécurité**, descendez jusqu'au message sur Sidekicks, cliquez sur **Ouvrir quand même**, puis confirmez. | ||
| 15 | + | ||
| 16 | +Ensuite, Sidekicks s'ouvre normalement. | ||
| 17 | + | ||
| 18 | +## Linux (x86-64) | ||
| 19 | + | ||
| 20 | +Sidekicks a besoin de GTK 4 et de WebKitGTK 6 (Ubuntu 24.04 ou plus récent, Debian 13, Fedora 40 ou plus récent). | ||
| 21 | + | ||
| 22 | +- **Debian, Ubuntu** : `sudo apt install ./sidekicks_<version>_linux_amd64.deb` | ||
| 23 | +- **Fedora** : `sudo dnf install ./sidekicks_<version>_linux_amd64.rpm` | ||
| 24 | +- **Toute distribution, sans installer** : `chmod +x Sidekicks-<version>-x86_64.AppImage`, puis lancez-le. S'il se plaint de FUSE, lancez-le avec `--appimage-extract-and-run`. | ||
| 25 | +- **Le programme seul** : `sidekicks_<version>_linux_amd64.tar.gz` contient `sidekicks` ; les bibliothèques GTK 4 et WebKitGTK 6 doivent être installées. | ||
| 26 | + | ||
| 27 | +Le `.deb` et le `.rpm` ajoutent Sidekicks au menu des applications. | ||
| 28 | + | ||
| 29 | +## Windows (x86-64) | ||
| 30 | + | ||
| 31 | +1. Téléchargez `Sidekicks-<version>-windows-amd64-installer.exe` et lancez-le. | ||
| 32 | +2. L'installateur n'est pas signé : Windows SmartScreen peut afficher « Windows a protégé votre ordinateur ». Cliquez sur **Informations complémentaires**, puis **Exécuter quand même**. | ||
| 33 | +3. L'installateur ajoute Microsoft Edge WebView2 s'il manque, puis un raccourci Sidekicks. | ||
| 34 | + | ||
| 35 | +`sidekicks_<version>_windows_amd64.zip` contient `sidekicks.exe` seul, pour une machine où WebView2 est déjà présent. | ||
| 36 | + | ||
| 37 | +Sous Windows, l'onglet **Terminal** d'un agent n'est pas encore disponible ; les fichiers, les conversations et les agents dans Docker fonctionnent. | ||
| 38 | + | ||
| 39 | +## Variantes | ||
| 40 | + | ||
| 41 | +- **Vérifier un téléchargement** : `shasum -a 256 <fichier>` (macOS) ou `sha256sum <fichier>` (Linux), à comparer avec `SHA256SUMS`. | ||
| 42 | +- **macOS, depuis un terminal** : `xattr -dr com.apple.quarantine /Applications/sidekicks.app` lève la quarantaine, à la place de l'étape 4. | ||
| 43 | +- **Le construire soi-même** : `make package-macos`, `make package-linux` ou `make package-windows` (voir [Publier une release](publier-une-release.md)). | ||
| 44 | + | ||
| 45 | +## Voir aussi | ||
| 46 | + | ||
| 47 | +- [Tutoriel : votre premier agent, sans écrire de configuration](../tutorials/premier-agent.md) | ||
| 48 | +- [Repartir de zéro](repartir-de-zero.md) | ||
modified
docs/fr/how-to/lancer-les-tests.md +2 -2 | @@ -22,8 +22,8 @@ La CI (`.github/workflows/ci.yml`) lance la même commande, plus `make bindings- | ||
| 22 | 22 | | Pour vérifier | Commande | |
| 23 | 23 | | --- | --- | |
| 24 | 24 | | Les packages Go | `make test-go`, ou `go test -race ./internal/agents -run Limit -v` pour un test | |
| 25 | -| Le frontend (vitest) | `make test-frontend` | | |
| 26 | -| L'outillage shell | `make test-scripts` | | |
| 25 | +| Le frontend (vitest), dont le contraste WCAG des couleurs du thème | `make test-frontend` | | |
| 26 | +| L'outillage shell (agents.sh, en-têtes de licence, noms des paquets, tag de release) | `make test-scripts` | | |
| 27 | 27 | | Le lint Go (golangci-lint, épinglé dans `tools/go.mod`) | `make lint-go` | |
| 28 | 28 | | Les types du frontend et les avertissements Svelte | `make lint-frontend` | |
| 29 | 29 | | Les en-têtes de licence | `make lint-headers` | |
| @@ -22,8 +22,8 @@ La CI (`.github/workflows/ci.yml`) lance la même commande, plus `make bindings- | |||
| 22 | | Pour vérifier | Commande | | 22 | | Pour vérifier | Commande | |
| 23 | | --- | --- | | 23 | | --- | --- | |
| 24 | | Les packages Go | `make test-go`, ou `go test -race ./internal/agents -run Limit -v` pour un test | | 24 | | Les packages Go | `make test-go`, ou `go test -race ./internal/agents -run Limit -v` pour un test | |
| 25 | -| Le frontend (vitest) | `make test-frontend` | | 25 | +| Le frontend (vitest), dont le contraste WCAG des couleurs du thème | `make test-frontend` | |
| 26 | -| L'outillage shell | `make test-scripts` | | 26 | +| L'outillage shell (agents.sh, en-têtes de licence, noms des paquets, tag de release) | `make test-scripts` | |
| 27 | | Le lint Go (golangci-lint, épinglé dans `tools/go.mod`) | `make lint-go` | | 27 | | Le lint Go (golangci-lint, épinglé dans `tools/go.mod`) | `make lint-go` | |
| 28 | | Les types du frontend et les avertissements Svelte | `make lint-frontend` | | 28 | | Les types du frontend et les avertissements Svelte | `make lint-frontend` | |
| 29 | | Les en-têtes de licence | `make lint-headers` | | 29 | | Les en-têtes de licence | `make lint-headers` | |
added
docs/fr/how-to/publier-une-release.md +23 -0 | new file mode 100644 | ||
| @@ -0,0 +1,23 @@ | ||
| 1 | +# Publier une release | |
| 2 | + | |
| 3 | +Ce guide montre comment publier une release de Sidekicks depuis un Mac : construire tous les paquets, tagger, attacher les fichiers à la release que Rickub crée. Il suppose les outils de [Développer l'application](developper-l-application.md), Docker Desktop démarré, `brew install makensis zip`, et le droit de pousser des tags. [RELEASING.fr.md](../../../RELEASING.fr.md) donne la même procédure en liste de contrôle. | |
| 4 | + | |
| 5 | +## Étapes | |
| 6 | + | |
| 7 | +1. **Fixez la version** dans `build/config.yml` (`info.version`), lancez `wails3 task common:update:build-assets`, remettez `LSMinimumSystemVersion` à `13.0.0` dans `build/darwin/Info.plist` et `Info.dev.plist`, puis commitez, fusionnez dans `main` et `git checkout main && git pull`. | |
| 8 | +2. **Construisez tout** : `make release-build`. `dist/` contient alors les paquets macOS (`.dmg` et `.zip` universels), Windows (installateur et `.zip`), Linux amd64 (`.deb`, `.rpm`, `.AppImage`, `.tar.gz`, construits dans Docker) et `SHA256SUMS`. | |
| 9 | +3. **Taggez** : `make release-tag`. Le tag `v<version>` est poussé, et le workflow **Release** crée la release sur Rickub avec des notes qui listent les fichiers. | |
| 10 | +4. **Attachez les fichiers** : sur Rickub, ouvrez **Releases → v<version>** et attachez tous les fichiers de `dist/`. | |
| 11 | + | |
| 12 | +## Variantes | |
| 13 | + | |
| 14 | +- **Linux arm64 aussi** : `LINUX_ARCHES="amd64 arm64" make release-build`. | |
| 15 | +- **Laisser un système de côté** : `SKIP="linux"` (ou `macos`, `windows`, plusieurs séparés par des espaces) avant `make release-build`. | |
| 16 | +- **Tagger sans pousser** : `scripts/tag-release.sh --no-push`, puis `git push origin v<version>` le moment venu. | |
| 17 | +- **Mauvais tag** : `git push origin :refs/tags/v<version>` et `git tag -d v<version>`, supprimez la release si elle a été créée, corrigez la version et taggez à nouveau. | |
| 18 | +- **Un seul paquet** : `make package-macos`, `make package-windows` ou `make package-linux` (Linux seulement, pour l'architecture de la machine). | |
| 19 | + | |
| 20 | +## Voir aussi | |
| 21 | + | |
| 22 | +- [Installer Sidekicks](installer-sidekicks.md) | |
| 23 | +- [Référence : commandes](../reference/commandes.md) — `make release-*`, `scripts/build-release.sh`, `scripts/tag-release.sh`, le workflow Release | |
| new file mode 100644 | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | +# Publier une release | ||
| 2 | + | ||
| 3 | +Ce guide montre comment publier une release de Sidekicks depuis un Mac : construire tous les paquets, tagger, attacher les fichiers à la release que Rickub crée. Il suppose les outils de [Développer l'application](developper-l-application.md), Docker Desktop démarré, `brew install makensis zip`, et le droit de pousser des tags. [RELEASING.fr.md](../../../RELEASING.fr.md) donne la même procédure en liste de contrôle. | ||
| 4 | + | ||
| 5 | +## Étapes | ||
| 6 | + | ||
| 7 | +1. **Fixez la version** dans `build/config.yml` (`info.version`), lancez `wails3 task common:update:build-assets`, remettez `LSMinimumSystemVersion` à `13.0.0` dans `build/darwin/Info.plist` et `Info.dev.plist`, puis commitez, fusionnez dans `main` et `git checkout main && git pull`. | ||
| 8 | +2. **Construisez tout** : `make release-build`. `dist/` contient alors les paquets macOS (`.dmg` et `.zip` universels), Windows (installateur et `.zip`), Linux amd64 (`.deb`, `.rpm`, `.AppImage`, `.tar.gz`, construits dans Docker) et `SHA256SUMS`. | ||
| 9 | +3. **Taggez** : `make release-tag`. Le tag `v<version>` est poussé, et le workflow **Release** crée la release sur Rickub avec des notes qui listent les fichiers. | ||
| 10 | +4. **Attachez les fichiers** : sur Rickub, ouvrez **Releases → v<version>** et attachez tous les fichiers de `dist/`. | ||
| 11 | + | ||
| 12 | +## Variantes | ||
| 13 | + | ||
| 14 | +- **Linux arm64 aussi** : `LINUX_ARCHES="amd64 arm64" make release-build`. | ||
| 15 | +- **Laisser un système de côté** : `SKIP="linux"` (ou `macos`, `windows`, plusieurs séparés par des espaces) avant `make release-build`. | ||
| 16 | +- **Tagger sans pousser** : `scripts/tag-release.sh --no-push`, puis `git push origin v<version>` le moment venu. | ||
| 17 | +- **Mauvais tag** : `git push origin :refs/tags/v<version>` et `git tag -d v<version>`, supprimez la release si elle a été créée, corrigez la version et taggez à nouveau. | ||
| 18 | +- **Un seul paquet** : `make package-macos`, `make package-windows` ou `make package-linux` (Linux seulement, pour l'architecture de la machine). | ||
| 19 | + | ||
| 20 | +## Voir aussi | ||
| 21 | + | ||
| 22 | +- [Installer Sidekicks](installer-sidekicks.md) | ||
| 23 | +- [Référence : commandes](../reference/commandes.md) — `make release-*`, `scripts/build-release.sh`, `scripts/tag-release.sh`, le workflow Release | ||
modified
docs/fr/reference/commandes.md +47 -2 | @@ -25,12 +25,17 @@ L'ordre est détaillé dans la [référence de la configuration](configuration.m | ||
| 25 | 25 | | `dev` | `wails3 dev` : l'application avec rechargement à chaud. | |
| 26 | 26 | | `build` | `wails3 build` : `bin/sidekicks`. | |
| 27 | 27 | | `package` | `wails3 package` : sous macOS `bin/sidekicks.app`. | |
| 28 | +| `package-linux` | `scripts/package.sh linux` : `.deb`, `.rpm`, `.AppImage` et `.tar.gz` pour l'architecture de la machine, dans `dist/`. Demande `file` (AppImage) et `rpm`. | | |
| 29 | +| `package-windows` | `scripts/package.sh windows` : installateur NSIS et `.zip` pour Windows amd64, compilés depuis Linux ou macOS, dans `dist/`. Demande `makensis` et `zip`. | | |
| 30 | +| `release-build` | `scripts/build-release.sh` : sur le Mac, tous les paquets de release dans `dist/` et `SHA256SUMS`. | | |
| 31 | +| `release-tag` | `scripts/tag-release.sh` : tague `v<version>` sur `main` et le pousse. | | |
| 32 | +| `package-macos` | `scripts/package.sh macos` : `.dmg` et `.zip` universels (arm64 + amd64, signés ad hoc), dans `dist/`. macOS seulement. | | |
| 28 | 33 | | `install-test-config` | `scripts/install-test-config.sh` : écrit `examples/test-agents.yaml` à l'emplacement par défaut de la configuration, avec des chemins absolus vers le dépôt : chaque agent est `mm -acp -config agent.yaml` lancé dans son dossier, avec `afterStop: [<dépôt>/scripts/agents.sh, unload, <agent>]` pour décharger son modèle à l'arrêt, `mm` écrit avec son chemin absolu (`MM_BIN`, ou celui du `PATH`), et le `PATH` courant dans l'`env` de chaque agent ; un fichier existant est gardé sous `config.yaml.<date>.bak`. | |
| 29 | 34 | | `check` | `lint` puis `test`. | |
| 30 | 35 | | `test` | `test-go`, `test-frontend`, `test-scripts`. | |
| 31 | 36 | | `test-go` | `go test ./...` (construit `frontend/dist` d'abord s'il manque). | |
| 32 | 37 | | `test-frontend` | `vitest run` dans `frontend/`. | |
| 33 | -| `test-scripts` | `scripts/agents_test.sh` et `scripts/check-license-headers_test.sh`. | | |
| 38 | +| `test-scripts` | `scripts/agents_test.sh`, `scripts/check-license-headers_test.sh`, `scripts/package_test.sh` et `scripts/tag-release_test.sh`. | | |
| 34 | 39 | | `test-real` | `go test -tags realagents -count=1 ./...` — nécessite `mm` et llmman. | |
| 35 | 40 | | `lint` | `lint-go`, `lint-frontend`, `lint-headers`. | |
| 36 | 41 | | `lint-go` | golangci-lint v2.14.0 (`tools/go.mod`), configuration `.golangci.yml`. | |
| @@ -46,6 +51,46 @@ scripts/check-license-headers.sh [racine du dépôt] | ||
| 46 | 51 | |
| 47 | 52 | Liste les fichiers sources (`.go .ts .js .svelte .css .html .sh .py .yml .yaml`, `Makefile`) connus de git dont les trois premières lignes ne contiennent pas `Sidekicks Source-Available License`, et se termine avec le code 1 s'il y en a. Non vérifiés : `frontend/bindings`, `build/` et `Taskfile.yml` de Wails, `*.d.ts`, `pnpm-lock.yaml`, `vite.config.ts`, `svelte.config.js`, `agents/`, `*/testdata/*`, `git.sh`, `new.*.sh`, `tag-step.sh`, `.claude/`, `.tickets/`. |
| 48 | 53 | |
| 54 | +## `scripts/package.sh` | |
| 55 | + | |
| 56 | +```text | |
| 57 | +scripts/package.sh linux | windows | macos | |
| 58 | +scripts/package.sh names <système> <arch> | |
| 59 | +scripts/package.sh version | |
| 60 | +``` | |
| 61 | + | |
| 62 | +| Commande | Effet | | |
| 63 | +| --- | --- | | |
| 64 | +| `linux`, `windows`, `macos` | Construit les paquets de ce système dans `dist/` (voir les cibles `package-*`), puis liste `dist/`. | | |
| 65 | +| `names <système> <arch>` | Affiche les noms des fichiers qu'un build produit, un par ligne ; ne construit rien. | | |
| 66 | +| `version` | Affiche `info.version` de `build/config.yml`. | | |
| 67 | + | |
| 68 | +| Système | Fichiers (`<v>` = version) | | |
| 69 | +| --- | --- | | |
| 70 | +| `linux` | `sidekicks_<v>_linux_<arch>.deb`, `.rpm`, `.tar.gz`, `Sidekicks-<v>-<x86_64\|aarch64>.AppImage` | | |
| 71 | +| `windows` | `Sidekicks-<v>-windows-amd64-installer.exe`, `sidekicks_<v>_windows_amd64.zip` | | |
| 72 | +| `macos` | `Sidekicks-<v>-macos-universal.dmg`, `Sidekicks-<v>-macos-universal.zip` | | |
| 73 | + | |
| 74 | +## `scripts/build-release.sh` | |
| 75 | + | |
| 76 | +```text | |
| 77 | +[LINUX_ARCHES="amd64 arm64"] [SKIP="macos windows linux"] scripts/build-release.sh | |
| 78 | +``` | |
| 79 | + | |
| 80 | +Vide `dist/`, puis construit : macOS avec `scripts/package.sh macos` (macOS seulement), Windows avec `scripts/package.sh windows` (demande `makensis`), Linux avec `scripts/package.sh linux` dans un conteneur par architecture de `LINUX_ARCHES` (par défaut `amd64`), construit depuis `scripts/linux-packages.Dockerfile` (`ubuntu:26.04`, Go de `go.mod`, pnpm de `frontend/package.json`, CLI Wails) avec le dépôt monté sur `/src` et le cache des modules Go dans le volume `sidekicks-gomod-<arch>`. Écrit enfin `dist/SHA256SUMS`. `SKIP` laisse de côté les systèmes qu'il nomme. Échoue si `makensis` manque ou si Docker ne tourne pas, en nommant le système à laisser de côté. | |
| 81 | + | |
| 82 | +## `scripts/tag-release.sh` | |
| 83 | + | |
| 84 | +```text | |
| 85 | +scripts/tag-release.sh [--remote <nom>] [--no-push] | |
| 86 | +``` | |
| 87 | + | |
| 88 | +Crée le tag annoté `v<version>` (`info.version` de `build/config.yml`, message `Sidekicks <version>`) et le pousse sur `--remote` (par défaut `origin`). Refuse si des fichiers suivis sont modifiés, si la branche courante n'est pas `main`, si `main` diffère de `<remote>/main` après un fetch, ou si le tag existe en local. Avertit, sans refuser, s'il manque dans `dist/` un paquet de la version ou `SHA256SUMS`. `--no-push` tague en local seulement. | |
| 89 | + | |
| 49 | 90 | ## CI |
| 50 | 91 | |
| 51 | -`.github/workflows/ci.yml`, à chaque push et merge request : installe Go (version de `go.mod`), Node 22, pnpm (version de `frontend/package.json`), les paquets de build GTK 4 / WebKitGTK 6 et la CLI Wails, puis lance `make bindings-check` et `make check`. | |
| 92 | +`.github/workflows/ci.yml`, à chaque push et merge request, dans un conteneur `ubuntu:26.04` (GTK ≥ 4.10) : installe git, un compilateur C, les paquets de build GTK 4 / WebKitGTK 6, Node et npm depuis apt, Go depuis go.dev (version de `go.mod`), pnpm (version de `frontend/package.json`) et la CLI Wails, puis lance `make bindings-check` et `make check`. | |
| 93 | + | |
| 94 | +## Workflow de release | |
| 95 | + | |
| 96 | +`.github/workflows/release.yml`, au push d'un tag `v*`, avec `permissions: contents: write` : échoue si le tag n'est pas `v` + `info.version` de `build/config.yml`, puis crée la release `<tag>` nommée `Sidekicks <tag>` (`softprops/action-gh-release@v2`, via l'API compatible GitHub de Rickub derrière `GITHUB_API_URL`), avec des notes qui donnent le commit, les guides d'installation et le tableau des fichiers attendus (tirés de `scripts/package.sh names`). Il n'attache aucun fichier : les paquets sont attachés à la main. | |
| @@ -25,12 +25,17 @@ L'ordre est détaillé dans la [référence de la configuration](configuration.m | |||
| 25 | | `dev` | `wails3 dev` : l'application avec rechargement à chaud. | | 25 | | `dev` | `wails3 dev` : l'application avec rechargement à chaud. | |
| 26 | | `build` | `wails3 build` : `bin/sidekicks`. | | 26 | | `build` | `wails3 build` : `bin/sidekicks`. | |
| 27 | | `package` | `wails3 package` : sous macOS `bin/sidekicks.app`. | | 27 | | `package` | `wails3 package` : sous macOS `bin/sidekicks.app`. | |
| 28 | +| `package-linux` | `scripts/package.sh linux` : `.deb`, `.rpm`, `.AppImage` et `.tar.gz` pour l'architecture de la machine, dans `dist/`. Demande `file` (AppImage) et `rpm`. | | ||
| 29 | +| `package-windows` | `scripts/package.sh windows` : installateur NSIS et `.zip` pour Windows amd64, compilés depuis Linux ou macOS, dans `dist/`. Demande `makensis` et `zip`. | | ||
| 30 | +| `release-build` | `scripts/build-release.sh` : sur le Mac, tous les paquets de release dans `dist/` et `SHA256SUMS`. | | ||
| 31 | +| `release-tag` | `scripts/tag-release.sh` : tague `v<version>` sur `main` et le pousse. | | ||
| 32 | +| `package-macos` | `scripts/package.sh macos` : `.dmg` et `.zip` universels (arm64 + amd64, signés ad hoc), dans `dist/`. macOS seulement. | | ||
| 28 | | `install-test-config` | `scripts/install-test-config.sh` : écrit `examples/test-agents.yaml` à l'emplacement par défaut de la configuration, avec des chemins absolus vers le dépôt : chaque agent est `mm -acp -config agent.yaml` lancé dans son dossier, avec `afterStop: [<dépôt>/scripts/agents.sh, unload, <agent>]` pour décharger son modèle à l'arrêt, `mm` écrit avec son chemin absolu (`MM_BIN`, ou celui du `PATH`), et le `PATH` courant dans l'`env` de chaque agent ; un fichier existant est gardé sous `config.yaml.<date>.bak`. | | 33 | | `install-test-config` | `scripts/install-test-config.sh` : écrit `examples/test-agents.yaml` à l'emplacement par défaut de la configuration, avec des chemins absolus vers le dépôt : chaque agent est `mm -acp -config agent.yaml` lancé dans son dossier, avec `afterStop: [<dépôt>/scripts/agents.sh, unload, <agent>]` pour décharger son modèle à l'arrêt, `mm` écrit avec son chemin absolu (`MM_BIN`, ou celui du `PATH`), et le `PATH` courant dans l'`env` de chaque agent ; un fichier existant est gardé sous `config.yaml.<date>.bak`. | |
| 29 | | `check` | `lint` puis `test`. | | 34 | | `check` | `lint` puis `test`. | |
| 30 | | `test` | `test-go`, `test-frontend`, `test-scripts`. | | 35 | | `test` | `test-go`, `test-frontend`, `test-scripts`. | |
| 31 | | `test-go` | `go test ./...` (construit `frontend/dist` d'abord s'il manque). | | 36 | | `test-go` | `go test ./...` (construit `frontend/dist` d'abord s'il manque). | |
| 32 | | `test-frontend` | `vitest run` dans `frontend/`. | | 37 | | `test-frontend` | `vitest run` dans `frontend/`. | |
| 33 | -| `test-scripts` | `scripts/agents_test.sh` et `scripts/check-license-headers_test.sh`. | | 38 | +| `test-scripts` | `scripts/agents_test.sh`, `scripts/check-license-headers_test.sh`, `scripts/package_test.sh` et `scripts/tag-release_test.sh`. | |
| 34 | | `test-real` | `go test -tags realagents -count=1 ./...` — nécessite `mm` et llmman. | | 39 | | `test-real` | `go test -tags realagents -count=1 ./...` — nécessite `mm` et llmman. | |
| 35 | | `lint` | `lint-go`, `lint-frontend`, `lint-headers`. | | 40 | | `lint` | `lint-go`, `lint-frontend`, `lint-headers`. | |
| 36 | | `lint-go` | golangci-lint v2.14.0 (`tools/go.mod`), configuration `.golangci.yml`. | | 41 | | `lint-go` | golangci-lint v2.14.0 (`tools/go.mod`), configuration `.golangci.yml`. | |
| @@ -46,6 +51,46 @@ scripts/check-license-headers.sh [racine du dépôt] | |||
| 46 | 51 | ||
| 47 | Liste les fichiers sources (`.go .ts .js .svelte .css .html .sh .py .yml .yaml`, `Makefile`) connus de git dont les trois premières lignes ne contiennent pas `Sidekicks Source-Available License`, et se termine avec le code 1 s'il y en a. Non vérifiés : `frontend/bindings`, `build/` et `Taskfile.yml` de Wails, `*.d.ts`, `pnpm-lock.yaml`, `vite.config.ts`, `svelte.config.js`, `agents/`, `*/testdata/*`, `git.sh`, `new.*.sh`, `tag-step.sh`, `.claude/`, `.tickets/`. | 52 | Liste les fichiers sources (`.go .ts .js .svelte .css .html .sh .py .yml .yaml`, `Makefile`) connus de git dont les trois premières lignes ne contiennent pas `Sidekicks Source-Available License`, et se termine avec le code 1 s'il y en a. Non vérifiés : `frontend/bindings`, `build/` et `Taskfile.yml` de Wails, `*.d.ts`, `pnpm-lock.yaml`, `vite.config.ts`, `svelte.config.js`, `agents/`, `*/testdata/*`, `git.sh`, `new.*.sh`, `tag-step.sh`, `.claude/`, `.tickets/`. |
| 48 | 53 | ||
| 54 | +## `scripts/package.sh` | ||
| 55 | + | ||
| 56 | +```text | ||
| 57 | +scripts/package.sh linux | windows | macos | ||
| 58 | +scripts/package.sh names <système> <arch> | ||
| 59 | +scripts/package.sh version | ||
| 60 | +``` | ||
| 61 | + | ||
| 62 | +| Commande | Effet | | ||
| 63 | +| --- | --- | | ||
| 64 | +| `linux`, `windows`, `macos` | Construit les paquets de ce système dans `dist/` (voir les cibles `package-*`), puis liste `dist/`. | | ||
| 65 | +| `names <système> <arch>` | Affiche les noms des fichiers qu'un build produit, un par ligne ; ne construit rien. | | ||
| 66 | +| `version` | Affiche `info.version` de `build/config.yml`. | | ||
| 67 | + | ||
| 68 | +| Système | Fichiers (`<v>` = version) | | ||
| 69 | +| --- | --- | | ||
| 70 | +| `linux` | `sidekicks_<v>_linux_<arch>.deb`, `.rpm`, `.tar.gz`, `Sidekicks-<v>-<x86_64\|aarch64>.AppImage` | | ||
| 71 | +| `windows` | `Sidekicks-<v>-windows-amd64-installer.exe`, `sidekicks_<v>_windows_amd64.zip` | | ||
| 72 | +| `macos` | `Sidekicks-<v>-macos-universal.dmg`, `Sidekicks-<v>-macos-universal.zip` | | ||
| 73 | + | ||
| 74 | +## `scripts/build-release.sh` | ||
| 75 | + | ||
| 76 | +```text | ||
| 77 | +[LINUX_ARCHES="amd64 arm64"] [SKIP="macos windows linux"] scripts/build-release.sh | ||
| 78 | +``` | ||
| 79 | + | ||
| 80 | +Vide `dist/`, puis construit : macOS avec `scripts/package.sh macos` (macOS seulement), Windows avec `scripts/package.sh windows` (demande `makensis`), Linux avec `scripts/package.sh linux` dans un conteneur par architecture de `LINUX_ARCHES` (par défaut `amd64`), construit depuis `scripts/linux-packages.Dockerfile` (`ubuntu:26.04`, Go de `go.mod`, pnpm de `frontend/package.json`, CLI Wails) avec le dépôt monté sur `/src` et le cache des modules Go dans le volume `sidekicks-gomod-<arch>`. Écrit enfin `dist/SHA256SUMS`. `SKIP` laisse de côté les systèmes qu'il nomme. Échoue si `makensis` manque ou si Docker ne tourne pas, en nommant le système à laisser de côté. | ||
| 81 | + | ||
| 82 | +## `scripts/tag-release.sh` | ||
| 83 | + | ||
| 84 | +```text | ||
| 85 | +scripts/tag-release.sh [--remote <nom>] [--no-push] | ||
| 86 | +``` | ||
| 87 | + | ||
| 88 | +Crée le tag annoté `v<version>` (`info.version` de `build/config.yml`, message `Sidekicks <version>`) et le pousse sur `--remote` (par défaut `origin`). Refuse si des fichiers suivis sont modifiés, si la branche courante n'est pas `main`, si `main` diffère de `<remote>/main` après un fetch, ou si le tag existe en local. Avertit, sans refuser, s'il manque dans `dist/` un paquet de la version ou `SHA256SUMS`. `--no-push` tague en local seulement. | ||
| 89 | + | ||
| 49 | ## CI | 90 | ## CI |
| 50 | 91 | ||
| 51 | -`.github/workflows/ci.yml`, à chaque push et merge request : installe Go (version de `go.mod`), Node 22, pnpm (version de `frontend/package.json`), les paquets de build GTK 4 / WebKitGTK 6 et la CLI Wails, puis lance `make bindings-check` et `make check`. | 92 | +`.github/workflows/ci.yml`, à chaque push et merge request, dans un conteneur `ubuntu:26.04` (GTK ≥ 4.10) : installe git, un compilateur C, les paquets de build GTK 4 / WebKitGTK 6, Node et npm depuis apt, Go depuis go.dev (version de `go.mod`), pnpm (version de `frontend/package.json`) et la CLI Wails, puis lance `make bindings-check` et `make check`. |
| 93 | + | ||
| 94 | +## Workflow de release | ||
| 95 | + | ||
| 96 | +`.github/workflows/release.yml`, au push d'un tag `v*`, avec `permissions: contents: write` : échoue si le tag n'est pas `v` + `info.version` de `build/config.yml`, puis crée la release `<tag>` nommée `Sidekicks <tag>` (`softprops/action-gh-release@v2`, via l'API compatible GitHub de Rickub derrière `GITHUB_API_URL`), avec des notes qui donnent le commit, les guides d'installation et le tableau des fichiers attendus (tirés de `scripts/package.sh names`). Il n'attache aucun fichier : les paquets sont attachés à la main. | ||
modified
docs/fr/reference/configuration.md +14 -0 | @@ -94,6 +94,20 @@ Le runtime indique à Sidekicks comment atteindre les **fichiers et le terminal* | ||
| 94 | 94 | |
| 95 | 95 | Un channel déclaré ici est créé au démarrage, ou au rechargement du fichier, **si aucun channel ne porte encore ce nom** (sans tenir compte de la casse) ; il vit ensuite dans l'application comme n'importe quel channel, et peut y être renommé ou supprimé. Le retirer du fichier ne le supprime pas (supprimer un historique doit être une action explicite de l'utilisateur). Chaque fichier de configuration a ses propres channels et son propre historique ([où il est gardé](agents-et-evenements.md#historique)). |
| 96 | 96 | |
| 97 | +## Ce qu'écrit l'assistant « Ajouter un agent » | |
| 98 | + | |
| 99 | +L'assistant ajoute une entrée à la fin de `agents` ; le reste du fichier, commentaires compris, est gardé. Rien n'est écrit si le résultat ne serait pas valide. | |
| 100 | + | |
| 101 | +| Champ de l'assistant | Écrit comme | | |
| 102 | +| --- | --- | | |
| 103 | +| Nom utilisé avec @, Nom affiché, Icône, Ce qu'il fait | `name`, `title`, `icon`, `description` (champs vides omis) | | |
| 104 | +| Dossier de l'agent | `workspace`, tel que saisi (`~` et chemins relatifs résolus comme tout `workspace`) | | |
| 105 | +| Sur cet ordinateur | `command: <programme>`, `args: [<arguments>]` | | |
| 106 | +| Dans un conteneur Docker | `command: docker`, `args: [exec, -i, <conteneur>, <programme>, <arguments>]`, `runtime: {type: container, container: <conteneur>}` | | |
| 107 | +| Dans une sandbox sbx | `command: sbx`, `args: [exec, -i, <sandbox>, <programme>, <arguments>]`, `runtime: {type: sbx, sandbox: <sandbox>}` | | |
| 108 | + | |
| 109 | +Les arguments sont découpés comme le ferait un shell dans les cas simples : les espaces séparent, les guillemets simples ou doubles regroupent. | |
| 110 | + | |
| 97 | 111 | ## Règles vérifiées par le chargeur, pas par le schéma |
| 98 | 112 | |
| 99 | 113 | JSON Schema ne sait pas les exprimer ; le chargeur de configuration (issue #9) les vérifie et les signale comme les erreurs de schéma : |
| @@ -94,6 +94,20 @@ Le runtime indique à Sidekicks comment atteindre les **fichiers et le terminal* | |||
| 94 | 94 | ||
| 95 | Un channel déclaré ici est créé au démarrage, ou au rechargement du fichier, **si aucun channel ne porte encore ce nom** (sans tenir compte de la casse) ; il vit ensuite dans l'application comme n'importe quel channel, et peut y être renommé ou supprimé. Le retirer du fichier ne le supprime pas (supprimer un historique doit être une action explicite de l'utilisateur). Chaque fichier de configuration a ses propres channels et son propre historique ([où il est gardé](agents-et-evenements.md#historique)). | 95 | Un channel déclaré ici est créé au démarrage, ou au rechargement du fichier, **si aucun channel ne porte encore ce nom** (sans tenir compte de la casse) ; il vit ensuite dans l'application comme n'importe quel channel, et peut y être renommé ou supprimé. Le retirer du fichier ne le supprime pas (supprimer un historique doit être une action explicite de l'utilisateur). Chaque fichier de configuration a ses propres channels et son propre historique ([où il est gardé](agents-et-evenements.md#historique)). |
| 96 | 96 | ||
| 97 | +## Ce qu'écrit l'assistant « Ajouter un agent » | ||
| 98 | + | ||
| 99 | +L'assistant ajoute une entrée à la fin de `agents` ; le reste du fichier, commentaires compris, est gardé. Rien n'est écrit si le résultat ne serait pas valide. | ||
| 100 | + | ||
| 101 | +| Champ de l'assistant | Écrit comme | | ||
| 102 | +| --- | --- | | ||
| 103 | +| Nom utilisé avec @, Nom affiché, Icône, Ce qu'il fait | `name`, `title`, `icon`, `description` (champs vides omis) | | ||
| 104 | +| Dossier de l'agent | `workspace`, tel que saisi (`~` et chemins relatifs résolus comme tout `workspace`) | | ||
| 105 | +| Sur cet ordinateur | `command: <programme>`, `args: [<arguments>]` | | ||
| 106 | +| Dans un conteneur Docker | `command: docker`, `args: [exec, -i, <conteneur>, <programme>, <arguments>]`, `runtime: {type: container, container: <conteneur>}` | | ||
| 107 | +| Dans une sandbox sbx | `command: sbx`, `args: [exec, -i, <sandbox>, <programme>, <arguments>]`, `runtime: {type: sbx, sandbox: <sandbox>}` | | ||
| 108 | + | ||
| 109 | +Les arguments sont découpés comme le ferait un shell dans les cas simples : les espaces séparent, les guillemets simples ou doubles regroupent. | ||
| 110 | + | ||
| 97 | ## Règles vérifiées par le chargeur, pas par le schéma | 111 | ## Règles vérifiées par le chargeur, pas par le schéma |
| 98 | 112 | ||
| 99 | JSON Schema ne sait pas les exprimer ; le chargeur de configuration (issue #9) les vérifie et les signale comme les erreurs de schéma : | 113 | JSON Schema ne sait pas les exprimer ; le chargeur de configuration (issue #9) les vérifie et les signale comme les erreurs de schéma : |
added
docs/fr/reference/raccourcis-clavier.md +51 -0 | new file mode 100644 | ||
| @@ -0,0 +1,51 @@ | ||
| 1 | +# Référence : raccourcis clavier | |
| 2 | + | |
| 3 | +Sous macOS, les raccourcis utilisent **⌘** ; sous Linux et Windows, **Ctrl**. La table est `frontend/src/lib/shortcuts.ts`. | |
| 4 | + | |
| 5 | +## Application | |
| 6 | + | |
| 7 | +| macOS | Linux, Windows | Action | | |
| 8 | +| --- | --- | --- | | |
| 9 | +| ⌘K | Ctrl+K | Ouvre ou ferme la palette de commandes | | |
| 10 | +| ⌘N | Ctrl+N | Nouveau channel (ouvre le dock des channels s'il est replié) | | |
| 11 | +| ⇧⌘N | Ctrl+Maj+N | Ajouter un agent (l'assistant) | | |
| 12 | +| ⌘L | Ctrl+L | Place le curseur dans la zone de message | | |
| 13 | +| ⌘B | Ctrl+B | Affiche ou masque le dock des channels et des agents | | |
| 14 | +| ⌘, | Ctrl+, | Affiche ou masque Settings | | |
| 15 | +| ⌘J | Ctrl+J | Affiche ou masque le journal | | |
| 16 | + | |
| 17 | +Sous Linux et Windows, quand le curseur est dans le terminal d'un agent, le terminal garde les raccourcis Ctrl (Ctrl+L efface l'écran, Ctrl+K coupe la ligne…). | |
| 18 | + | |
| 19 | +## Palette de commandes | |
| 20 | + | |
| 21 | +| Touche | Action | | |
| 22 | +| --- | --- | | |
| 23 | +| lettres | Filtre : channels (`#` facultatif), conversations des agents, fichiers des agents, actions | | |
| 24 | +| ↑ ↓ | Déplace la sélection | | |
| 25 | +| Entrée | Lance la sélection | | |
| 26 | +| Échap, ou un clic à côté | Ferme la palette | | |
| 27 | + | |
| 28 | +La palette liste, dans l'ordre : les channels, une conversation par agent, les fichiers de chaque agent, les actions du tableau ci-dessus, et **Ouvrir une configuration…**. | |
| 29 | + | |
| 30 | +## Zone de message | |
| 31 | + | |
| 32 | +| Touche | Action | | |
| 33 | +| --- | --- | | |
| 34 | +| Entrée | Envoie | | |
| 35 | +| Maj+Entrée | Nouvelle ligne | | |
| 36 | +| ↑ (zone vide) | Messages précédents | | |
| 37 | +| `@`, `/` | Listes des agents et des commandes ; Tab ou Entrée choisit, ↑ ↓ déplacent, Échap ferme | | |
| 38 | + | |
| 39 | +## Éditeurs (Settings, fichiers des agents) | |
| 40 | + | |
| 41 | +| macOS | Linux, Windows | Action | | |
| 42 | +| --- | --- | --- | | |
| 43 | +| ⌘S | Ctrl+S | Enregistre | | |
| 44 | + | |
| 45 | +## Assistant, liste des channels | |
| 46 | + | |
| 47 | +| Touche | Action | | |
| 48 | +| --- | --- | | |
| 49 | +| Entrée | Valide le nom d'un channel nouveau ou renommé | | |
| 50 | +| Échap | L'annule | | |
| 51 | +| Tab | Passe d'un champ à l'autre ; chaque bouton est atteignable, et l'élément qui a le focus est entouré | | |
| new file mode 100644 | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | +# Référence : raccourcis clavier | ||
| 2 | + | ||
| 3 | +Sous macOS, les raccourcis utilisent **⌘** ; sous Linux et Windows, **Ctrl**. La table est `frontend/src/lib/shortcuts.ts`. | ||
| 4 | + | ||
| 5 | +## Application | ||
| 6 | + | ||
| 7 | +| macOS | Linux, Windows | Action | | ||
| 8 | +| --- | --- | --- | | ||
| 9 | +| ⌘K | Ctrl+K | Ouvre ou ferme la palette de commandes | | ||
| 10 | +| ⌘N | Ctrl+N | Nouveau channel (ouvre le dock des channels s'il est replié) | | ||
| 11 | +| ⇧⌘N | Ctrl+Maj+N | Ajouter un agent (l'assistant) | | ||
| 12 | +| ⌘L | Ctrl+L | Place le curseur dans la zone de message | | ||
| 13 | +| ⌘B | Ctrl+B | Affiche ou masque le dock des channels et des agents | | ||
| 14 | +| ⌘, | Ctrl+, | Affiche ou masque Settings | | ||
| 15 | +| ⌘J | Ctrl+J | Affiche ou masque le journal | | ||
| 16 | + | ||
| 17 | +Sous Linux et Windows, quand le curseur est dans le terminal d'un agent, le terminal garde les raccourcis Ctrl (Ctrl+L efface l'écran, Ctrl+K coupe la ligne…). | ||
| 18 | + | ||
| 19 | +## Palette de commandes | ||
| 20 | + | ||
| 21 | +| Touche | Action | | ||
| 22 | +| --- | --- | | ||
| 23 | +| lettres | Filtre : channels (`#` facultatif), conversations des agents, fichiers des agents, actions | | ||
| 24 | +| ↑ ↓ | Déplace la sélection | | ||
| 25 | +| Entrée | Lance la sélection | | ||
| 26 | +| Échap, ou un clic à côté | Ferme la palette | | ||
| 27 | + | ||
| 28 | +La palette liste, dans l'ordre : les channels, une conversation par agent, les fichiers de chaque agent, les actions du tableau ci-dessus, et **Ouvrir une configuration…**. | ||
| 29 | + | ||
| 30 | +## Zone de message | ||
| 31 | + | ||
| 32 | +| Touche | Action | | ||
| 33 | +| --- | --- | | ||
| 34 | +| Entrée | Envoie | | ||
| 35 | +| Maj+Entrée | Nouvelle ligne | | ||
| 36 | +| ↑ (zone vide) | Messages précédents | | ||
| 37 | +| `@`, `/` | Listes des agents et des commandes ; Tab ou Entrée choisit, ↑ ↓ déplacent, Échap ferme | | ||
| 38 | + | ||
| 39 | +## Éditeurs (Settings, fichiers des agents) | ||
| 40 | + | ||
| 41 | +| macOS | Linux, Windows | Action | | ||
| 42 | +| --- | --- | --- | | ||
| 43 | +| ⌘S | Ctrl+S | Enregistre | | ||
| 44 | + | ||
| 45 | +## Assistant, liste des channels | ||
| 46 | + | ||
| 47 | +| Touche | Action | | ||
| 48 | +| --- | --- | | ||
| 49 | +| Entrée | Valide le nom d'un channel nouveau ou renommé | | ||
| 50 | +| Échap | L'annule | | ||
| 51 | +| Tab | Passe d'un champ à l'autre ; chaque bouton est atteignable, et l'élément qui a le focus est entouré | | ||
added
docs/fr/tutorials/premier-agent.md +66 -0 | new file mode 100644 | ||
| @@ -0,0 +1,66 @@ | ||
| 1 | +# Tutoriel : votre premier agent, sans écrire de configuration | |
| 2 | + | |
| 3 | +À la fin de ce tutoriel, vous aurez ajouté un agent à Sidekicks avec l'assistant « Ajouter un agent », discuté avec lui, et l'aurez retrouvé avec la palette de commandes. Vous n'ouvrirez pas une seule fois le fichier de configuration. | |
| 4 | + | |
| 5 | +## Prérequis | |
| 6 | + | |
| 7 | +- Sidekicks installé : voir [Installer Sidekicks](../how-to/installer-sidekicks.md). | |
| 8 | +- `mm` installé, et llmman démarré avec le modèle d'Alice téléchargé (voir [Votre premier échange ACP avec un agent de test](premier-echange-acp.md)). | |
| 9 | +- Le dépôt de Sidekicks sur votre ordinateur : le dossier d'Alice, `agents/alice`, contient son `agent.yaml`. Ci-dessous, c'est `~/sidekicks/agents/alice` ; utilisez votre propre chemin. | |
| 10 | + | |
| 11 | +L'interface est en anglais par défaut ; avec `ui.language: fr`, elle est en français. Les libellés ci-dessous sont ceux de l'interface en français. | |
| 12 | + | |
| 13 | +## Étape 1 — Ouvrir Sidekicks | |
| 14 | + | |
| 15 | +Ouvrez Sidekicks depuis votre dossier Applications (ou votre menu d'applications). | |
| 16 | + | |
| 17 | +Vous devez voir le logo de Sidekicks, « Bienvenue dans Sidekicks », trois étapes numérotées et un bouton bleu **+ Ajouter mon premier agent**. Si des agents sont déjà listés à gauche, utilisez plutôt **+ Ajouter un agent** sous la liste : la suite est identique. | |
| 18 | + | |
| 19 | +## Étape 2 — Dire qui est l'agent | |
| 20 | + | |
| 21 | +Cliquez sur **+ Ajouter mon premier agent**. Dans **Nom affiché**, tapez : | |
| 22 | + | |
| 23 | +```text | |
| 24 | +Alice (assistante) | |
| 25 | +``` | |
| 26 | + | |
| 27 | +Vous devez voir **Nom utilisé avec @** se remplir tout seul avec `alice-assistante`. Remplacez-le par `alice` : c'est le nom avec lequel vous l'appellerez. | |
| 28 | + | |
| 29 | +## Étape 3 — Dire comment le démarrer | |
| 30 | + | |
| 31 | +Laissez **Sur cet ordinateur** sélectionné. Remplissez : | |
| 32 | + | |
| 33 | +| Champ | Valeur | | |
| 34 | +| --- | --- | | |
| 35 | +| Programme | `mm` | | |
| 36 | +| Arguments | `-acp -config agent.yaml` | | |
| 37 | +| Dossier de l'agent | `~/sidekicks/agents/alice` (ou **Choisir…** puis le dossier) | | |
| 38 | + | |
| 39 | +Cliquez sur **Ajouter l'agent**. | |
| 40 | + | |
| 41 | +Vous devez voir l'assistant se fermer, **🤖 Alice (assistante)** apparaître sous **AGENTS** et sous **MESSAGES DIRECTS**, et sa conversation s'ouvrir au centre avec « Écrivez votre premier message à Alice (assistante). » | |
| 42 | + | |
| 43 | +## Étape 4 — Discuter avec Alice | |
| 44 | + | |
| 45 | +Cliquez dans la zone de texte en bas, tapez ceci et appuyez sur Entrée : | |
| 46 | + | |
| 47 | +```text | |
| 48 | +Bonjour Alice, présente-toi en une phrase. | |
| 49 | +``` | |
| 50 | + | |
| 51 | +Vous devez voir la pastille d'Alice passer à l'orange pendant qu'elle démarre et répond, puis sa phrase s'afficher mot à mot. | |
| 52 | + | |
| 53 | +## Étape 5 — La retrouver au clavier | |
| 54 | + | |
| 55 | +Cliquez sur **# general** à gauche. Puis appuyez sur **⌘K** (Ctrl+K sous Linux et Windows) et tapez `ali`. | |
| 56 | + | |
| 57 | +Vous devez voir une liste avec **Alice (assistante)** en premier. Appuyez sur Entrée : sa conversation revient au centre. | |
| 58 | + | |
| 59 | +## Et maintenant ? | |
| 60 | + | |
| 61 | +Vous avez ajouté un agent sans toucher au YAML, discuté avec lui et circulé au clavier. Pour aller plus loin : | |
| 62 | + | |
| 63 | +- Pour ajouter un agent qui tourne dans Docker ou dans une sandbox sbx → [Ajouter un agent](../how-to/ajouter-un-agent.md) | |
| 64 | +- Pour réunir plusieurs agents dans un channel → [Un channel avec deux agents](premier-channel.md) | |
| 65 | +- Tous les raccourcis → [Raccourcis clavier](../reference/raccourcis-clavier.md) | |
| 66 | +- Ce que l'assistant a écrit → [Le fichier de configuration](../reference/configuration.md) | |
| new file mode 100644 | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | +# Tutoriel : votre premier agent, sans écrire de configuration | ||
| 2 | + | ||
| 3 | +À la fin de ce tutoriel, vous aurez ajouté un agent à Sidekicks avec l'assistant « Ajouter un agent », discuté avec lui, et l'aurez retrouvé avec la palette de commandes. Vous n'ouvrirez pas une seule fois le fichier de configuration. | ||
| 4 | + | ||
| 5 | +## Prérequis | ||
| 6 | + | ||
| 7 | +- Sidekicks installé : voir [Installer Sidekicks](../how-to/installer-sidekicks.md). | ||
| 8 | +- `mm` installé, et llmman démarré avec le modèle d'Alice téléchargé (voir [Votre premier échange ACP avec un agent de test](premier-echange-acp.md)). | ||
| 9 | +- Le dépôt de Sidekicks sur votre ordinateur : le dossier d'Alice, `agents/alice`, contient son `agent.yaml`. Ci-dessous, c'est `~/sidekicks/agents/alice` ; utilisez votre propre chemin. | ||
| 10 | + | ||
| 11 | +L'interface est en anglais par défaut ; avec `ui.language: fr`, elle est en français. Les libellés ci-dessous sont ceux de l'interface en français. | ||
| 12 | + | ||
| 13 | +## Étape 1 — Ouvrir Sidekicks | ||
| 14 | + | ||
| 15 | +Ouvrez Sidekicks depuis votre dossier Applications (ou votre menu d'applications). | ||
| 16 | + | ||
| 17 | +Vous devez voir le logo de Sidekicks, « Bienvenue dans Sidekicks », trois étapes numérotées et un bouton bleu **+ Ajouter mon premier agent**. Si des agents sont déjà listés à gauche, utilisez plutôt **+ Ajouter un agent** sous la liste : la suite est identique. | ||
| 18 | + | ||
| 19 | +## Étape 2 — Dire qui est l'agent | ||
| 20 | + | ||
| 21 | +Cliquez sur **+ Ajouter mon premier agent**. Dans **Nom affiché**, tapez : | ||
| 22 | + | ||
| 23 | +```text | ||
| 24 | +Alice (assistante) | ||
| 25 | +``` | ||
| 26 | + | ||
| 27 | +Vous devez voir **Nom utilisé avec @** se remplir tout seul avec `alice-assistante`. Remplacez-le par `alice` : c'est le nom avec lequel vous l'appellerez. | ||
| 28 | + | ||
| 29 | +## Étape 3 — Dire comment le démarrer | ||
| 30 | + | ||
| 31 | +Laissez **Sur cet ordinateur** sélectionné. Remplissez : | ||
| 32 | + | ||
| 33 | +| Champ | Valeur | | ||
| 34 | +| --- | --- | | ||
| 35 | +| Programme | `mm` | | ||
| 36 | +| Arguments | `-acp -config agent.yaml` | | ||
| 37 | +| Dossier de l'agent | `~/sidekicks/agents/alice` (ou **Choisir…** puis le dossier) | | ||
| 38 | + | ||
| 39 | +Cliquez sur **Ajouter l'agent**. | ||
| 40 | + | ||
| 41 | +Vous devez voir l'assistant se fermer, **🤖 Alice (assistante)** apparaître sous **AGENTS** et sous **MESSAGES DIRECTS**, et sa conversation s'ouvrir au centre avec « Écrivez votre premier message à Alice (assistante). » | ||
| 42 | + | ||
| 43 | +## Étape 4 — Discuter avec Alice | ||
| 44 | + | ||
| 45 | +Cliquez dans la zone de texte en bas, tapez ceci et appuyez sur Entrée : | ||
| 46 | + | ||
| 47 | +```text | ||
| 48 | +Bonjour Alice, présente-toi en une phrase. | ||
| 49 | +``` | ||
| 50 | + | ||
| 51 | +Vous devez voir la pastille d'Alice passer à l'orange pendant qu'elle démarre et répond, puis sa phrase s'afficher mot à mot. | ||
| 52 | + | ||
| 53 | +## Étape 5 — La retrouver au clavier | ||
| 54 | + | ||
| 55 | +Cliquez sur **# general** à gauche. Puis appuyez sur **⌘K** (Ctrl+K sous Linux et Windows) et tapez `ali`. | ||
| 56 | + | ||
| 57 | +Vous devez voir une liste avec **Alice (assistante)** en premier. Appuyez sur Entrée : sa conversation revient au centre. | ||
| 58 | + | ||
| 59 | +## Et maintenant ? | ||
| 60 | + | ||
| 61 | +Vous avez ajouté un agent sans toucher au YAML, discuté avec lui et circulé au clavier. Pour aller plus loin : | ||
| 62 | + | ||
| 63 | +- Pour ajouter un agent qui tourne dans Docker ou dans une sandbox sbx → [Ajouter un agent](../how-to/ajouter-un-agent.md) | ||
| 64 | +- Pour réunir plusieurs agents dans un channel → [Un channel avec deux agents](premier-channel.md) | ||
| 65 | +- Tous les raccourcis → [Raccourcis clavier](../reference/raccourcis-clavier.md) | ||
| 66 | +- Ce que l'assistant a écrit → [Le fichier de configuration](../reference/configuration.md) | ||
modified
docs/fr/tutorials/premiere-conversation.md +2 -0 | @@ -27,6 +27,8 @@ Vous devriez voir votre message, puis « Alice … writing… » : la réponse a | ||
| 27 | 27 | |
| 28 | 28 | Cliquez sur **Copy** : il affiche « Copied ✓ », le code est dans votre presse-papiers. |
| 29 | 29 | |
| 30 | +Passez maintenant le pointeur sur la réponse d'Alice : **⧉ Copy** apparaît à côté de son nom. Cliquez dessus : toute la réponse est dans votre presse-papiers, en Markdown (tableau et code compris). | |
| 31 | + | |
| 30 | 32 | ## Étape 3 — Laisser Riker exécuter une commande |
| 31 | 33 | |
| 32 | 34 | Cliquez sur **Riker (tools)** et envoyez : |
| @@ -27,6 +27,8 @@ Vous devriez voir votre message, puis « Alice … writing… » : la réponse a | |||
| 27 | 27 | ||
| 28 | Cliquez sur **Copy** : il affiche « Copied ✓ », le code est dans votre presse-papiers. | 28 | Cliquez sur **Copy** : il affiche « Copied ✓ », le code est dans votre presse-papiers. |
| 29 | 29 | ||
| 30 | +Passez maintenant le pointeur sur la réponse d'Alice : **⧉ Copy** apparaît à côté de son nom. Cliquez dessus : toute la réponse est dans votre presse-papiers, en Markdown (tableau et code compris). | ||
| 31 | + | ||
| 30 | ## Étape 3 — Laisser Riker exécuter une commande | 32 | ## Étape 3 — Laisser Riker exécuter une commande |
| 31 | 33 | ||
| 32 | Cliquez sur **Riker (tools)** et envoyez : | 34 | Cliquez sur **Riker (tools)** et envoyez : |
modified
frontend/bindings/git.rickub.com/bots-garden/sidekicks/internal/app/configservice.ts +22 -0 | @@ -16,6 +16,19 @@ import { Call as $Call, CancellablePromise as $CancellablePromise } from "@wails | ||
| 16 | 16 | // @ts-ignore: Unused imports |
| 17 | 17 | import * as $models from "./models.js"; |
| 18 | 18 | |
| 19 | +/** | |
| 20 | + * AddAgent adds the agent described by form to the configuration file, | |
| 21 | + * keeping its comments, and creates the agent's folder when it does not | |
| 22 | + * exist. When the result would not be valid (a name already used, a name | |
| 23 | + * with spaces…), nothing is written and the problems are returned. The file | |
| 24 | + * watcher then reloads the configuration, as after a save in Settings. | |
| 25 | + * | |
| 26 | + * problems, err := (&ConfigService{Core: core}).AddAgent(AgentForm{Name: "alice", Program: "mm", Workspace: "~/agents/alice"}) | |
| 27 | + */ | |
| 28 | +export function AddAgent(form: $models.AgentForm): $CancellablePromise<string[] | null> { | |
| 29 | + return $Call.ByID(698361705, form); | |
| 30 | +} | |
| 31 | + | |
| 19 | 32 | /** |
| 20 | 33 | * Choose asks the user for a configuration file and opens it. The dialog |
| 21 | 34 | * starts in the folder of the configuration in use: on macOS the default one |
| @@ -26,6 +39,15 @@ export function Choose(): $CancellablePromise<string> { | ||
| 26 | 39 | return $Call.ByID(1890400804); |
| 27 | 40 | } |
| 28 | 41 | |
| 42 | +/** | |
| 43 | + * ChooseFolder asks the user for a folder, starting in their home folder, | |
| 44 | + * for the assistant's "agent's folder" field. It returns "" when the user | |
| 45 | + * cancelled. | |
| 46 | + */ | |
| 47 | +export function ChooseFolder(): $CancellablePromise<string> { | |
| 48 | + return $Call.ByID(1715751888); | |
| 49 | +} | |
| 50 | + | |
| 29 | 51 | /** |
| 30 | 52 | * Content returns the text of the configuration file, for the editor. |
| 31 | 53 | */ |
| @@ -16,6 +16,19 @@ import { Call as $Call, CancellablePromise as $CancellablePromise } from "@wails | |||
| 16 | // @ts-ignore: Unused imports | 16 | // @ts-ignore: Unused imports |
| 17 | import * as $models from "./models.js"; | 17 | import * as $models from "./models.js"; |
| 18 | 18 | ||
| 19 | +/** | ||
| 20 | + * AddAgent adds the agent described by form to the configuration file, | ||
| 21 | + * keeping its comments, and creates the agent's folder when it does not | ||
| 22 | + * exist. When the result would not be valid (a name already used, a name | ||
| 23 | + * with spaces…), nothing is written and the problems are returned. The file | ||
| 24 | + * watcher then reloads the configuration, as after a save in Settings. | ||
| 25 | + * | ||
| 26 | + * problems, err := (&ConfigService{Core: core}).AddAgent(AgentForm{Name: "alice", Program: "mm", Workspace: "~/agents/alice"}) | ||
| 27 | + */ | ||
| 28 | +export function AddAgent(form: $models.AgentForm): $CancellablePromise<string[] | null> { | ||
| 29 | + return $Call.ByID(698361705, form); | ||
| 30 | +} | ||
| 31 | + | ||
| 19 | /** | 32 | /** |
| 20 | * Choose asks the user for a configuration file and opens it. The dialog | 33 | * Choose asks the user for a configuration file and opens it. The dialog |
| 21 | * starts in the folder of the configuration in use: on macOS the default one | 34 | * starts in the folder of the configuration in use: on macOS the default one |
| @@ -26,6 +39,15 @@ export function Choose(): $CancellablePromise<string> { | |||
| 26 | return $Call.ByID(1890400804); | 39 | return $Call.ByID(1890400804); |
| 27 | } | 40 | } |
| 28 | 41 | ||
| 42 | +/** | ||
| 43 | + * ChooseFolder asks the user for a folder, starting in their home folder, | ||
| 44 | + * for the assistant's "agent's folder" field. It returns "" when the user | ||
| 45 | + * cancelled. | ||
| 46 | + */ | ||
| 47 | +export function ChooseFolder(): $CancellablePromise<string> { | ||
| 48 | + return $Call.ByID(1715751888); | ||
| 49 | +} | ||
| 50 | + | ||
| 29 | /** | 51 | /** |
| 30 | * Content returns the text of the configuration file, for the editor. | 52 | * Content returns the text of the configuration file, for the editor. |
| 31 | */ | 53 | */ |
modified
frontend/bindings/git.rickub.com/bots-garden/sidekicks/internal/app/index.ts +1 -0 | @@ -15,6 +15,7 @@ export { | ||
| 15 | 15 | }; |
| 16 | 16 | |
| 17 | 17 | export type { |
| 18 | + AgentForm, | |
| 18 | 19 | ConfigView, |
| 19 | 20 | OlderView, |
| 20 | 21 | ProblemView, |
| @@ -15,6 +15,7 @@ export { | |||
| 15 | }; | 15 | }; |
| 16 | 16 | ||
| 17 | export type { | 17 | export type { |
| 18 | + AgentForm, | ||
| 18 | ConfigView, | 19 | ConfigView, |
| 19 | OlderView, | 20 | OlderView, |
| 20 | ProblemView, | 21 | ProblemView, |
modified
frontend/bindings/git.rickub.com/bots-garden/sidekicks/internal/app/models.ts +37 -0 | @@ -8,6 +8,43 @@ import * as channels$0 from "../channels/models.js"; | ||
| 8 | 8 | // @ts-ignore: Unused imports |
| 9 | 9 | import * as workspace$0 from "../workspace/models.js"; |
| 10 | 10 | |
| 11 | +/** | |
| 12 | + * AgentForm is what the "add an agent" assistant asks for. Sidekicks turns | |
| 13 | + * it into the agent's entry of the configuration file (see entryOf), so the | |
| 14 | + * user never writes YAML. | |
| 15 | + */ | |
| 16 | +export interface AgentForm { | |
| 17 | + "name": string; | |
| 18 | + "title": string; | |
| 19 | + "icon": string; | |
| 20 | + "description": string; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * Environment is local, container or sbx. | |
| 24 | + */ | |
| 25 | + "environment": string; | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * Box is the name of the Docker container or of the sbx sandbox. | |
| 29 | + */ | |
| 30 | + "box": string; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * Program is the agent's program, such as mm. | |
| 34 | + */ | |
| 35 | + "program": string; | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * Arguments are typed on one line, as in a terminal: quotes group words. | |
| 39 | + */ | |
| 40 | + "arguments": string; | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * Workspace is the agent's folder on this computer. It is created if needed. | |
| 44 | + */ | |
| 45 | + "workspace": string; | |
| 46 | +} | |
| 47 | + | |
| 11 | 48 | /** |
| 12 | 49 | * ConfigView is the configuration as the interface shows it. |
| 13 | 50 | */ |
| @@ -8,6 +8,43 @@ import * as channels$0 from "../channels/models.js"; | |||
| 8 | // @ts-ignore: Unused imports | 8 | // @ts-ignore: Unused imports |
| 9 | import * as workspace$0 from "../workspace/models.js"; | 9 | import * as workspace$0 from "../workspace/models.js"; |
| 10 | 10 | ||
| 11 | +/** | ||
| 12 | + * AgentForm is what the "add an agent" assistant asks for. Sidekicks turns | ||
| 13 | + * it into the agent's entry of the configuration file (see entryOf), so the | ||
| 14 | + * user never writes YAML. | ||
| 15 | + */ | ||
| 16 | +export interface AgentForm { | ||
| 17 | + "name": string; | ||
| 18 | + "title": string; | ||
| 19 | + "icon": string; | ||
| 20 | + "description": string; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * Environment is local, container or sbx. | ||
| 24 | + */ | ||
| 25 | + "environment": string; | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * Box is the name of the Docker container or of the sbx sandbox. | ||
| 29 | + */ | ||
| 30 | + "box": string; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * Program is the agent's program, such as mm. | ||
| 34 | + */ | ||
| 35 | + "program": string; | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * Arguments are typed on one line, as in a terminal: quotes group words. | ||
| 39 | + */ | ||
| 40 | + "arguments": string; | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * Workspace is the agent's folder on this computer. It is created if needed. | ||
| 44 | + */ | ||
| 45 | + "workspace": string; | ||
| 46 | +} | ||
| 47 | + | ||
| 11 | /** | 48 | /** |
| 12 | * ConfigView is the configuration as the interface shows it. | 49 | * ConfigView is the configuration as the interface shows it. |
| 13 | */ | 50 | */ |
added
frontend/src/lib/agent/AddAgentForm.svelte +165 -0 | new file mode 100644 | ||
| @@ -0,0 +1,165 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<script lang="ts"> | |
| 3 | + // The "add an agent" assistant (issue #33, wireframe 6): a form instead of | |
| 4 | + // YAML. ConfigService.AddAgent writes the entry, keeping the file's | |
| 5 | + // comments; the agent's direct conversation opens once it is loaded. | |
| 6 | + import { t, type MessageKey } from '../i18n/index.svelte' | |
| 7 | + import { ConfigService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' | |
| 8 | + import { emptyForm, nameFromTitle, problemsOf, type Environment, type Missing } from '../agentform' | |
| 9 | + import { agentAdded, appState } from '../state.svelte' | |
| 10 | + | |
| 11 | + const form = $state(emptyForm()) | |
| 12 | + // The name follows the title until the user edits it. | |
| 13 | + let nameEdited = $state(false) | |
| 14 | + let tried = $state(false) | |
| 15 | + let adding = $state(false) | |
| 16 | + let refused = $state<string[]>([]) | |
| 17 | + let failure = $state('') | |
| 18 | + | |
| 19 | + const environments: Environment[] = ['local', 'container', 'sbx'] | |
| 20 | + const missing = $derived(problemsOf(form)) | |
| 21 | + const shown = $derived(tried ? missing : []) | |
| 22 | + | |
| 23 | + function onTitle() { | |
| 24 | + if (!nameEdited) form.name = nameFromTitle(form.title) | |
| 25 | + } | |
| 26 | + | |
| 27 | + async function choose() { | |
| 28 | + try { | |
| 29 | + const folder = await ConfigService.ChooseFolder() | |
| 30 | + if (folder) form.workspace = folder | |
| 31 | + } catch (error) { | |
| 32 | + failure = error instanceof Error ? error.message : String(error) | |
| 33 | + } | |
| 34 | + } | |
| 35 | + | |
| 36 | + async function submit(event: SubmitEvent) { | |
| 37 | + event.preventDefault() | |
| 38 | + tried = true | |
| 39 | + refused = [] | |
| 40 | + failure = '' | |
| 41 | + if (missing.length > 0) return | |
| 42 | + adding = true | |
| 43 | + try { | |
| 44 | + const problems = (await ConfigService.AddAgent({ ...form, title: form.title.trim() || form.name })) ?? [] | |
| 45 | + if (problems.length > 0) refused = problems | |
| 46 | + else agentAdded(form.name.trim()) | |
| 47 | + } catch (error) { | |
| 48 | + failure = error instanceof Error ? error.message : String(error) | |
| 49 | + } finally { | |
| 50 | + adding = false | |
| 51 | + } | |
| 52 | + } | |
| 53 | + | |
| 54 | + function has(problem: Missing): boolean { | |
| 55 | + return shown.includes(problem) | |
| 56 | + } | |
| 57 | +</script> | |
| 58 | + | |
| 59 | +<form class="assistant" onsubmit={submit} novalidate> | |
| 60 | + <h1>{t('assistant.title')}</h1> | |
| 61 | + <p class="intro">{t('assistant.intro')}</p> | |
| 62 | + | |
| 63 | + <fieldset> | |
| 64 | + <legend>{t('assistant.who')}</legend> | |
| 65 | + <div class="row"> | |
| 66 | + <label class="icon"> | |
| 67 | + {t('assistant.icon')} | |
| 68 | + <input bind:value={form.icon} maxlength="8" /> | |
| 69 | + </label> | |
| 70 | + <label class="grow"> | |
| 71 | + {t('assistant.agentTitle')} | |
| 72 | + <!-- svelte-ignore a11y_autofocus --> | |
| 73 | + <input bind:value={form.title} oninput={onTitle} placeholder={t('assistant.agentTitlePlaceholder')} autofocus /> | |
| 74 | + </label> | |
| 75 | + </div> | |
| 76 | + <label> | |
| 77 | + {t('assistant.name')} | |
| 78 | + <input bind:value={form.name} oninput={() => (nameEdited = true)} placeholder="alice" aria-invalid={has('name') || has('nameFormat')} aria-describedby="name-hint" spellcheck="false" autocapitalize="off" /> | |
| 79 | + <small id="name-hint" class:problem={has('name') || has('nameFormat')}> | |
| 80 | + {has('name') ? t('assistant.missing.name') : has('nameFormat') ? t('assistant.missing.nameFormat') : t('assistant.nameHint')} | |
| 81 | + </small> | |
| 82 | + </label> | |
| 83 | + <label> | |
| 84 | + {t('assistant.description')} | |
| 85 | + <input bind:value={form.description} placeholder={t('assistant.descriptionPlaceholder')} /> | |
| 86 | + </label> | |
| 87 | + </fieldset> | |
| 88 | + | |
| 89 | + <fieldset> | |
| 90 | + <legend>{t('assistant.where')}</legend> | |
| 91 | + <div class="choices" role="radiogroup"> | |
| 92 | + {#each environments as environment (environment)} | |
| 93 | + <label class="choice" class:chosen={form.environment === environment}> | |
| 94 | + <input type="radio" name="environment" value={environment} bind:group={form.environment} /> | |
| 95 | + {t(`assistant.${environment}` as MessageKey)} | |
| 96 | + </label> | |
| 97 | + {/each} | |
| 98 | + </div> | |
| 99 | + {#if form.environment !== 'local'} | |
| 100 | + <label> | |
| 101 | + {form.environment === 'container' ? t('assistant.containerName') : t('assistant.sandboxName')} | |
| 102 | + <input bind:value={form.box} placeholder={form.environment === 'container' ? 'scout-box' : 'milo-sbx'} aria-invalid={has('box')} aria-describedby="box-hint" spellcheck="false" autocapitalize="off" /> | |
| 103 | + <small id="box-hint" class:problem={has('box')}>{has('box') ? t('assistant.missing.box') : t('assistant.boxHint')}</small> | |
| 104 | + </label> | |
| 105 | + {/if} | |
| 106 | + </fieldset> | |
| 107 | + | |
| 108 | + <fieldset> | |
| 109 | + <legend>{t('assistant.how')}</legend> | |
| 110 | + <label> | |
| 111 | + {t('assistant.program')} | |
| 112 | + <input bind:value={form.program} placeholder={t('assistant.programPlaceholder')} aria-invalid={has('program')} aria-describedby="program-hint" spellcheck="false" autocapitalize="off" /> | |
| 113 | + <small id="program-hint" class:problem={has('program')}>{has('program') ? t('assistant.missing.program') : t('assistant.programHint')}</small> | |
| 114 | + </label> | |
| 115 | + <label> | |
| 116 | + {t('assistant.arguments')} | |
| 117 | + <input bind:value={form.arguments} placeholder={t('assistant.argumentsPlaceholder')} spellcheck="false" autocapitalize="off" /> | |
| 118 | + </label> | |
| 119 | + <label for="workspace">{t('assistant.workspace')}</label> | |
| 120 | + <div class="row centered"> | |
| 121 | + <input id="workspace" class="grow" bind:value={form.workspace} placeholder="~/agents/alice" aria-invalid={has('workspace')} aria-describedby="workspace-hint" spellcheck="false" autocapitalize="off" /> | |
| 122 | + <button type="button" onclick={choose}>{t('assistant.choose')}</button> | |
| 123 | + </div> | |
| 124 | + <small id="workspace-hint" class:problem={has('workspace')}>{has('workspace') ? t('assistant.missing.workspace') : t('assistant.workspaceHint')}</small> | |
| 125 | + </fieldset> | |
| 126 | + | |
| 127 | + {#if refused.length > 0 || failure} | |
| 128 | + <div class="refused" role="alert"> | |
| 129 | + <strong>{t('assistant.refused')}</strong> | |
| 130 | + <ul> | |
| 131 | + {#each refused as problem, index (index)}<li>{problem}</li>{/each} | |
| 132 | + {#if failure}<li>{failure}</li>{/if} | |
| 133 | + </ul> | |
| 134 | + </div> | |
| 135 | + {/if} | |
| 136 | + | |
| 137 | + <div class="actions"> | |
| 138 | + <button type="button" onclick={() => (appState.assistant = false)}>{t('assistant.cancel')}</button> | |
| 139 | + <button type="submit" class="primary" disabled={adding}>{adding ? t('assistant.adding') : t('assistant.add')}</button> | |
| 140 | + </div> | |
| 141 | +</form> | |
| 142 | + | |
| 143 | +<style> | |
| 144 | + .assistant { max-width: 620px; margin: 0 auto; padding: 24px 24px 32px; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; } | |
| 145 | + h1 { font-size: 20px; margin: 0; } | |
| 146 | + .intro { color: var(--muted); margin: 0; } | |
| 147 | + fieldset { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 14px 14px; display: flex; flex-direction: column; gap: 10px; background: var(--panel); } | |
| 148 | + legend { font-weight: 600; padding: 0 4px; } | |
| 149 | + label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; } | |
| 150 | + input:not([type='radio']) { font: inherit; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); color: var(--text); } | |
| 151 | + input[aria-invalid='true'] { border-color: var(--danger); } | |
| 152 | + small { color: var(--muted); font-size: 12px; } | |
| 153 | + small.problem { color: var(--danger); } | |
| 154 | + .row { display: flex; gap: 8px; align-items: flex-end; } | |
| 155 | + .row.centered { align-items: center; } | |
| 156 | + .grow { flex: 1; min-width: 0; } | |
| 157 | + .icon input { width: 56px; text-align: center; } | |
| 158 | + .choices { display: flex; flex-wrap: wrap; gap: 8px; } | |
| 159 | + .choice { flex-direction: row; align-items: center; gap: 6px; border: 1px solid var(--border); border-radius: 6px; padding: 6px 10px; cursor: pointer; } | |
| 160 | + .choice.chosen { border-color: var(--accent); } | |
| 161 | + .refused { border: 1px solid var(--danger); border-radius: var(--radius); color: var(--danger); padding: 8px 12px; font-size: 13px; } | |
| 162 | + .refused ul { margin: 4px 0 0; padding-left: 18px; } | |
| 163 | + .actions { display: flex; justify-content: flex-end; gap: 8px; } | |
| 164 | + .primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; } | |
| 165 | +</style> | |
| new file mode 100644 | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<script lang="ts"> | ||
| 3 | + // The "add an agent" assistant (issue #33, wireframe 6): a form instead of | ||
| 4 | + // YAML. ConfigService.AddAgent writes the entry, keeping the file's | ||
| 5 | + // comments; the agent's direct conversation opens once it is loaded. | ||
| 6 | + import { t, type MessageKey } from '../i18n/index.svelte' | ||
| 7 | + import { ConfigService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' | ||
| 8 | + import { emptyForm, nameFromTitle, problemsOf, type Environment, type Missing } from '../agentform' | ||
| 9 | + import { agentAdded, appState } from '../state.svelte' | ||
| 10 | + | ||
| 11 | + const form = $state(emptyForm()) | ||
| 12 | + // The name follows the title until the user edits it. | ||
| 13 | + let nameEdited = $state(false) | ||
| 14 | + let tried = $state(false) | ||
| 15 | + let adding = $state(false) | ||
| 16 | + let refused = $state<string[]>([]) | ||
| 17 | + let failure = $state('') | ||
| 18 | + | ||
| 19 | + const environments: Environment[] = ['local', 'container', 'sbx'] | ||
| 20 | + const missing = $derived(problemsOf(form)) | ||
| 21 | + const shown = $derived(tried ? missing : []) | ||
| 22 | + | ||
| 23 | + function onTitle() { | ||
| 24 | + if (!nameEdited) form.name = nameFromTitle(form.title) | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + async function choose() { | ||
| 28 | + try { | ||
| 29 | + const folder = await ConfigService.ChooseFolder() | ||
| 30 | + if (folder) form.workspace = folder | ||
| 31 | + } catch (error) { | ||
| 32 | + failure = error instanceof Error ? error.message : String(error) | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + async function submit(event: SubmitEvent) { | ||
| 37 | + event.preventDefault() | ||
| 38 | + tried = true | ||
| 39 | + refused = [] | ||
| 40 | + failure = '' | ||
| 41 | + if (missing.length > 0) return | ||
| 42 | + adding = true | ||
| 43 | + try { | ||
| 44 | + const problems = (await ConfigService.AddAgent({ ...form, title: form.title.trim() || form.name })) ?? [] | ||
| 45 | + if (problems.length > 0) refused = problems | ||
| 46 | + else agentAdded(form.name.trim()) | ||
| 47 | + } catch (error) { | ||
| 48 | + failure = error instanceof Error ? error.message : String(error) | ||
| 49 | + } finally { | ||
| 50 | + adding = false | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + function has(problem: Missing): boolean { | ||
| 55 | + return shown.includes(problem) | ||
| 56 | + } | ||
| 57 | +</script> | ||
| 58 | + | ||
| 59 | +<form class="assistant" onsubmit={submit} novalidate> | ||
| 60 | + <h1>{t('assistant.title')}</h1> | ||
| 61 | + <p class="intro">{t('assistant.intro')}</p> | ||
| 62 | + | ||
| 63 | + <fieldset> | ||
| 64 | + <legend>{t('assistant.who')}</legend> | ||
| 65 | + <div class="row"> | ||
| 66 | + <label class="icon"> | ||
| 67 | + {t('assistant.icon')} | ||
| 68 | + <input bind:value={form.icon} maxlength="8" /> | ||
| 69 | + </label> | ||
| 70 | + <label class="grow"> | ||
| 71 | + {t('assistant.agentTitle')} | ||
| 72 | + <!-- svelte-ignore a11y_autofocus --> | ||
| 73 | + <input bind:value={form.title} oninput={onTitle} placeholder={t('assistant.agentTitlePlaceholder')} autofocus /> | ||
| 74 | + </label> | ||
| 75 | + </div> | ||
| 76 | + <label> | ||
| 77 | + {t('assistant.name')} | ||
| 78 | + <input bind:value={form.name} oninput={() => (nameEdited = true)} placeholder="alice" aria-invalid={has('name') || has('nameFormat')} aria-describedby="name-hint" spellcheck="false" autocapitalize="off" /> | ||
| 79 | + <small id="name-hint" class:problem={has('name') || has('nameFormat')}> | ||
| 80 | + {has('name') ? t('assistant.missing.name') : has('nameFormat') ? t('assistant.missing.nameFormat') : t('assistant.nameHint')} | ||
| 81 | + </small> | ||
| 82 | + </label> | ||
| 83 | + <label> | ||
| 84 | + {t('assistant.description')} | ||
| 85 | + <input bind:value={form.description} placeholder={t('assistant.descriptionPlaceholder')} /> | ||
| 86 | + </label> | ||
| 87 | + </fieldset> | ||
| 88 | + | ||
| 89 | + <fieldset> | ||
| 90 | + <legend>{t('assistant.where')}</legend> | ||
| 91 | + <div class="choices" role="radiogroup"> | ||
| 92 | + {#each environments as environment (environment)} | ||
| 93 | + <label class="choice" class:chosen={form.environment === environment}> | ||
| 94 | + <input type="radio" name="environment" value={environment} bind:group={form.environment} /> | ||
| 95 | + {t(`assistant.${environment}` as MessageKey)} | ||
| 96 | + </label> | ||
| 97 | + {/each} | ||
| 98 | + </div> | ||
| 99 | + {#if form.environment !== 'local'} | ||
| 100 | + <label> | ||
| 101 | + {form.environment === 'container' ? t('assistant.containerName') : t('assistant.sandboxName')} | ||
| 102 | + <input bind:value={form.box} placeholder={form.environment === 'container' ? 'scout-box' : 'milo-sbx'} aria-invalid={has('box')} aria-describedby="box-hint" spellcheck="false" autocapitalize="off" /> | ||
| 103 | + <small id="box-hint" class:problem={has('box')}>{has('box') ? t('assistant.missing.box') : t('assistant.boxHint')}</small> | ||
| 104 | + </label> | ||
| 105 | + {/if} | ||
| 106 | + </fieldset> | ||
| 107 | + | ||
| 108 | + <fieldset> | ||
| 109 | + <legend>{t('assistant.how')}</legend> | ||
| 110 | + <label> | ||
| 111 | + {t('assistant.program')} | ||
| 112 | + <input bind:value={form.program} placeholder={t('assistant.programPlaceholder')} aria-invalid={has('program')} aria-describedby="program-hint" spellcheck="false" autocapitalize="off" /> | ||
| 113 | + <small id="program-hint" class:problem={has('program')}>{has('program') ? t('assistant.missing.program') : t('assistant.programHint')}</small> | ||
| 114 | + </label> | ||
| 115 | + <label> | ||
| 116 | + {t('assistant.arguments')} | ||
| 117 | + <input bind:value={form.arguments} placeholder={t('assistant.argumentsPlaceholder')} spellcheck="false" autocapitalize="off" /> | ||
| 118 | + </label> | ||
| 119 | + <label for="workspace">{t('assistant.workspace')}</label> | ||
| 120 | + <div class="row centered"> | ||
| 121 | + <input id="workspace" class="grow" bind:value={form.workspace} placeholder="~/agents/alice" aria-invalid={has('workspace')} aria-describedby="workspace-hint" spellcheck="false" autocapitalize="off" /> | ||
| 122 | + <button type="button" onclick={choose}>{t('assistant.choose')}</button> | ||
| 123 | + </div> | ||
| 124 | + <small id="workspace-hint" class:problem={has('workspace')}>{has('workspace') ? t('assistant.missing.workspace') : t('assistant.workspaceHint')}</small> | ||
| 125 | + </fieldset> | ||
| 126 | + | ||
| 127 | + {#if refused.length > 0 || failure} | ||
| 128 | + <div class="refused" role="alert"> | ||
| 129 | + <strong>{t('assistant.refused')}</strong> | ||
| 130 | + <ul> | ||
| 131 | + {#each refused as problem, index (index)}<li>{problem}</li>{/each} | ||
| 132 | + {#if failure}<li>{failure}</li>{/if} | ||
| 133 | + </ul> | ||
| 134 | + </div> | ||
| 135 | + {/if} | ||
| 136 | + | ||
| 137 | + <div class="actions"> | ||
| 138 | + <button type="button" onclick={() => (appState.assistant = false)}>{t('assistant.cancel')}</button> | ||
| 139 | + <button type="submit" class="primary" disabled={adding}>{adding ? t('assistant.adding') : t('assistant.add')}</button> | ||
| 140 | + </div> | ||
| 141 | +</form> | ||
| 142 | + | ||
| 143 | +<style> | ||
| 144 | + .assistant { max-width: 620px; margin: 0 auto; padding: 24px 24px 32px; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; } | ||
| 145 | + h1 { font-size: 20px; margin: 0; } | ||
| 146 | + .intro { color: var(--muted); margin: 0; } | ||
| 147 | + fieldset { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 14px 14px; display: flex; flex-direction: column; gap: 10px; background: var(--panel); } | ||
| 148 | + legend { font-weight: 600; padding: 0 4px; } | ||
| 149 | + label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; } | ||
| 150 | + input:not([type='radio']) { font: inherit; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); color: var(--text); } | ||
| 151 | + input[aria-invalid='true'] { border-color: var(--danger); } | ||
| 152 | + small { color: var(--muted); font-size: 12px; } | ||
| 153 | + small.problem { color: var(--danger); } | ||
| 154 | + .row { display: flex; gap: 8px; align-items: flex-end; } | ||
| 155 | + .row.centered { align-items: center; } | ||
| 156 | + .grow { flex: 1; min-width: 0; } | ||
| 157 | + .icon input { width: 56px; text-align: center; } | ||
| 158 | + .choices { display: flex; flex-wrap: wrap; gap: 8px; } | ||
| 159 | + .choice { flex-direction: row; align-items: center; gap: 6px; border: 1px solid var(--border); border-radius: 6px; padding: 6px 10px; cursor: pointer; } | ||
| 160 | + .choice.chosen { border-color: var(--accent); } | ||
| 161 | + .refused { border: 1px solid var(--danger); border-radius: var(--radius); color: var(--danger); padding: 8px 12px; font-size: 13px; } | ||
| 162 | + .refused ul { margin: 4px 0 0; padding-left: 18px; } | ||
| 163 | + .actions { display: flex; justify-content: flex-end; gap: 8px; } | ||
| 164 | + .primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; } | ||
| 165 | +</style> | ||
modified
frontend/src/lib/agent/AgentView.svelte +2 -1 | @@ -10,6 +10,7 @@ | ||
| 10 | 10 | import AgentLog from './AgentLog.svelte' |
| 11 | 11 | import FilesTab from './FilesTab.svelte' |
| 12 | 12 | import TerminalView from './TerminalView.svelte' |
| 13 | + import ErrorText from '../chat/ErrorText.svelte' | |
| 13 | 14 | |
| 14 | 15 | let { agent: name }: { agent: string } = $props() |
| 15 | 16 | |
| @@ -68,7 +69,7 @@ | ||
| 68 | 69 | |
| 69 | 70 | <div class="body"> |
| 70 | 71 | {#if problem} |
| 71 | - <p class="error">{t('workspace.unavailable', { agent: agent.title, problem })}</p> | |
| 72 | + <div class="error">{t('workspace.unavailable', { agent: agent.title })} <ErrorText raw={problem} /></div> | |
| 72 | 73 | {:else} |
| 73 | 74 | <div class="pane" class:hidden={tab !== 'files'}> |
| 74 | 75 | <FilesTab agent={name} inContainer={!location.startsWith('local')} /> |
| @@ -10,6 +10,7 @@ | |||
| 10 | import AgentLog from './AgentLog.svelte' | 10 | import AgentLog from './AgentLog.svelte' |
| 11 | import FilesTab from './FilesTab.svelte' | 11 | import FilesTab from './FilesTab.svelte' |
| 12 | import TerminalView from './TerminalView.svelte' | 12 | import TerminalView from './TerminalView.svelte' |
| 13 | + import ErrorText from '../chat/ErrorText.svelte' | ||
| 13 | 14 | ||
| 14 | let { agent: name }: { agent: string } = $props() | 15 | let { agent: name }: { agent: string } = $props() |
| 15 | 16 | ||
| @@ -68,7 +69,7 @@ | |||
| 68 | 69 | ||
| 69 | <div class="body"> | 70 | <div class="body"> |
| 70 | {#if problem} | 71 | {#if problem} |
| 71 | - <p class="error">{t('workspace.unavailable', { agent: agent.title, problem })}</p> | 72 | + <div class="error">{t('workspace.unavailable', { agent: agent.title })} <ErrorText raw={problem} /></div> |
| 72 | {:else} | 73 | {:else} |
| 73 | <div class="pane" class:hidden={tab !== 'files'}> | 74 | <div class="pane" class:hidden={tab !== 'files'}> |
| 74 | <FilesTab agent={name} inContainer={!location.startsWith('local')} /> | 75 | <FilesTab agent={name} inContainer={!location.startsWith('local')} /> |
modified
frontend/src/lib/agent/TerminalView.svelte +2 -1 | @@ -10,6 +10,7 @@ | ||
| 10 | 10 | import { TerminalService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' |
| 11 | 11 | import { t } from '../i18n/index.svelte' |
| 12 | 12 | import { listenTerminal } from '../terminals' |
| 13 | + import ErrorText from '../chat/ErrorText.svelte' | |
| 13 | 14 | |
| 14 | 15 | let { agent, visible }: { agent: string; visible: boolean } = $props() |
| 15 | 16 | |
| @@ -87,7 +88,7 @@ | ||
| 87 | 88 | <div class="screen" bind:this={host}></div> |
| 88 | 89 | {#if ended || error} |
| 89 | 90 | <div class="ended"> |
| 90 | - <span>{error ? t('terminal.error', { error }) : t('terminal.ended')}</span> | |
| 91 | + <span>{#if error}{t('terminal.error')} <ErrorText raw={error} />{:else}{t('terminal.ended')}{/if}</span> | |
| 91 | 92 | <button onclick={openShell}>{t('terminal.restart')}</button> |
| 92 | 93 | </div> |
| 93 | 94 | {/if} |
| @@ -10,6 +10,7 @@ | |||
| 10 | import { TerminalService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' | 10 | import { TerminalService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' |
| 11 | import { t } from '../i18n/index.svelte' | 11 | import { t } from '../i18n/index.svelte' |
| 12 | import { listenTerminal } from '../terminals' | 12 | import { listenTerminal } from '../terminals' |
| 13 | + import ErrorText from '../chat/ErrorText.svelte' | ||
| 13 | 14 | ||
| 14 | let { agent, visible }: { agent: string; visible: boolean } = $props() | 15 | let { agent, visible }: { agent: string; visible: boolean } = $props() |
| 15 | 16 | ||
| @@ -87,7 +88,7 @@ | |||
| 87 | <div class="screen" bind:this={host}></div> | 88 | <div class="screen" bind:this={host}></div> |
| 88 | {#if ended || error} | 89 | {#if ended || error} |
| 89 | <div class="ended"> | 90 | <div class="ended"> |
| 90 | - <span>{error ? t('terminal.error', { error }) : t('terminal.ended')}</span> | 91 | + <span>{#if error}{t('terminal.error')} <ErrorText raw={error} />{:else}{t('terminal.ended')}{/if}</span> |
| 91 | <button onclick={openShell}>{t('terminal.restart')}</button> | 92 | <button onclick={openShell}>{t('terminal.restart')}</button> |
| 92 | </div> | 93 | </div> |
| 93 | {/if} | 94 | {/if} |
added
frontend/src/lib/agentform.test.ts +33 -0 | new file mode 100644 | ||
| @@ -0,0 +1,33 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +import { describe, expect, it } from 'vitest' | |
| 4 | +import { emptyForm, nameFromTitle, problemsOf } from './agentform' | |
| 5 | + | |
| 6 | +describe('nameFromTitle', () => { | |
| 7 | + it('folds accents, lowercases and joins words', () => { | |
| 8 | + expect(nameFromTitle('Hélène (traductrice)')).toBe('helene-traductrice') | |
| 9 | + expect(nameFromTitle('Bob')).toBe('bob') | |
| 10 | + expect(nameFromTitle('code_reviewer 2')).toBe('code_reviewer-2') | |
| 11 | + }) | |
| 12 | + it('starts with a letter and stays within 32 characters', () => { | |
| 13 | + expect(nameFromTitle('42 Bob')).toBe('bob') | |
| 14 | + expect(nameFromTitle('🐮 Garfield')).toBe('garfield') | |
| 15 | + expect(nameFromTitle('a'.repeat(40))).toHaveLength(32) | |
| 16 | + expect(nameFromTitle('')).toBe('') | |
| 17 | + }) | |
| 18 | +}) | |
| 19 | + | |
| 20 | +describe('problemsOf', () => { | |
| 21 | + it('lists the missing fields of a local agent', () => { | |
| 22 | + expect(problemsOf({ ...emptyForm(), title: 'Alice' })).toEqual(['name', 'program', 'workspace']) | |
| 23 | + expect(problemsOf({ ...emptyForm(), name: 'alice', program: 'mm', workspace: '/agents/alice' })).toEqual([]) | |
| 24 | + }) | |
| 25 | + it('checks the name like the configuration does', () => { | |
| 26 | + expect(problemsOf({ ...emptyForm(), name: 'Alice B', program: 'mm', workspace: '/a' })).toEqual(['nameFormat']) | |
| 27 | + }) | |
| 28 | + it('asks for the container or sandbox name outside this computer', () => { | |
| 29 | + const form = { ...emptyForm(), name: 'scout', program: 'mm', workspace: '/a', environment: 'container' as const } | |
| 30 | + expect(problemsOf(form)).toEqual(['box']) | |
| 31 | + expect(problemsOf({ ...form, environment: 'sbx', box: 'milo-sbx' })).toEqual([]) | |
| 32 | + }) | |
| 33 | +}) | |
| new file mode 100644 | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +import { describe, expect, it } from 'vitest' | ||
| 4 | +import { emptyForm, nameFromTitle, problemsOf } from './agentform' | ||
| 5 | + | ||
| 6 | +describe('nameFromTitle', () => { | ||
| 7 | + it('folds accents, lowercases and joins words', () => { | ||
| 8 | + expect(nameFromTitle('Hélène (traductrice)')).toBe('helene-traductrice') | ||
| 9 | + expect(nameFromTitle('Bob')).toBe('bob') | ||
| 10 | + expect(nameFromTitle('code_reviewer 2')).toBe('code_reviewer-2') | ||
| 11 | + }) | ||
| 12 | + it('starts with a letter and stays within 32 characters', () => { | ||
| 13 | + expect(nameFromTitle('42 Bob')).toBe('bob') | ||
| 14 | + expect(nameFromTitle('🐮 Garfield')).toBe('garfield') | ||
| 15 | + expect(nameFromTitle('a'.repeat(40))).toHaveLength(32) | ||
| 16 | + expect(nameFromTitle('')).toBe('') | ||
| 17 | + }) | ||
| 18 | +}) | ||
| 19 | + | ||
| 20 | +describe('problemsOf', () => { | ||
| 21 | + it('lists the missing fields of a local agent', () => { | ||
| 22 | + expect(problemsOf({ ...emptyForm(), title: 'Alice' })).toEqual(['name', 'program', 'workspace']) | ||
| 23 | + expect(problemsOf({ ...emptyForm(), name: 'alice', program: 'mm', workspace: '/agents/alice' })).toEqual([]) | ||
| 24 | + }) | ||
| 25 | + it('checks the name like the configuration does', () => { | ||
| 26 | + expect(problemsOf({ ...emptyForm(), name: 'Alice B', program: 'mm', workspace: '/a' })).toEqual(['nameFormat']) | ||
| 27 | + }) | ||
| 28 | + it('asks for the container or sandbox name outside this computer', () => { | ||
| 29 | + const form = { ...emptyForm(), name: 'scout', program: 'mm', workspace: '/a', environment: 'container' as const } | ||
| 30 | + expect(problemsOf(form)).toEqual(['box']) | ||
| 31 | + expect(problemsOf({ ...form, environment: 'sbx', box: 'milo-sbx' })).toEqual([]) | ||
| 32 | + }) | ||
| 33 | +}) | ||
added
frontend/src/lib/agentform.ts +64 -0 | new file mode 100644 | ||
| @@ -0,0 +1,64 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +// The "add an agent" assistant (issue #33): what it asks for, and what it | |
| 4 | +// checks before sending the form to ConfigService.AddAgent, which writes the | |
| 5 | +// YAML for the user. | |
| 6 | + | |
| 7 | +export type Environment = 'local' | 'container' | 'sbx' | |
| 8 | + | |
| 9 | +export interface AgentFormValues { | |
| 10 | + name: string | |
| 11 | + title: string | |
| 12 | + icon: string | |
| 13 | + description: string | |
| 14 | + environment: Environment | |
| 15 | + /** The container or sandbox name; unused for a local agent. */ | |
| 16 | + box: string | |
| 17 | + program: string | |
| 18 | + arguments: string | |
| 19 | + workspace: string | |
| 20 | +} | |
| 21 | + | |
| 22 | +export function emptyForm(): AgentFormValues { | |
| 23 | + return { name: '', title: '', icon: '🤖', description: '', environment: 'local', box: '', program: '', arguments: '', workspace: '' } | |
| 24 | +} | |
| 25 | + | |
| 26 | +/** The pattern of an agent name in the configuration schema. */ | |
| 27 | +export const namePattern = /^[a-z][a-z0-9_-]{0,31}$/ | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * The name used with @ derived from the title the user types: accents | |
| 31 | + * folded, lowercase, words joined by "-", starting with a letter. | |
| 32 | + * | |
| 33 | + * @example | |
| 34 | + * nameFromTitle('Hélène (traductrice)') // 'helene-traductrice' | |
| 35 | + * nameFromTitle('42 Bob') // 'bob' | |
| 36 | + */ | |
| 37 | +export function nameFromTitle(title: string): string { | |
| 38 | + const folded = title.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase() | |
| 39 | + return folded | |
| 40 | + .replace(/[^a-z0-9_-]+/g, '-') | |
| 41 | + .replace(/^[^a-z]+/, '') | |
| 42 | + .slice(0, 32) | |
| 43 | + .replace(/-+$/, '') | |
| 44 | +} | |
| 45 | + | |
| 46 | +/** The fields the user still has to fill in, by name. */ | |
| 47 | +export type Missing = 'name' | 'nameFormat' | 'program' | 'workspace' | 'box' | |
| 48 | + | |
| 49 | +/** | |
| 50 | + * What is missing or wrong before the form can be sent. | |
| 51 | + * | |
| 52 | + * @example | |
| 53 | + * problemsOf({ ...emptyForm(), title: 'Alice' }) // ['name', 'program', 'workspace'] | |
| 54 | + */ | |
| 55 | +export function problemsOf(form: AgentFormValues): Missing[] { | |
| 56 | + const problems: Missing[] = [] | |
| 57 | + const name = form.name.trim() | |
| 58 | + if (!name) problems.push('name') | |
| 59 | + else if (!namePattern.test(name)) problems.push('nameFormat') | |
| 60 | + if (!form.program.trim()) problems.push('program') | |
| 61 | + if (!form.workspace.trim()) problems.push('workspace') | |
| 62 | + if (form.environment !== 'local' && !form.box.trim()) problems.push('box') | |
| 63 | + return problems | |
| 64 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +// The "add an agent" assistant (issue #33): what it asks for, and what it | ||
| 4 | +// checks before sending the form to ConfigService.AddAgent, which writes the | ||
| 5 | +// YAML for the user. | ||
| 6 | + | ||
| 7 | +export type Environment = 'local' | 'container' | 'sbx' | ||
| 8 | + | ||
| 9 | +export interface AgentFormValues { | ||
| 10 | + name: string | ||
| 11 | + title: string | ||
| 12 | + icon: string | ||
| 13 | + description: string | ||
| 14 | + environment: Environment | ||
| 15 | + /** The container or sandbox name; unused for a local agent. */ | ||
| 16 | + box: string | ||
| 17 | + program: string | ||
| 18 | + arguments: string | ||
| 19 | + workspace: string | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +export function emptyForm(): AgentFormValues { | ||
| 23 | + return { name: '', title: '', icon: '🤖', description: '', environment: 'local', box: '', program: '', arguments: '', workspace: '' } | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +/** The pattern of an agent name in the configuration schema. */ | ||
| 27 | +export const namePattern = /^[a-z][a-z0-9_-]{0,31}$/ | ||
| 28 | + | ||
| 29 | +/** | ||
| 30 | + * The name used with @ derived from the title the user types: accents | ||
| 31 | + * folded, lowercase, words joined by "-", starting with a letter. | ||
| 32 | + * | ||
| 33 | + * @example | ||
| 34 | + * nameFromTitle('Hélène (traductrice)') // 'helene-traductrice' | ||
| 35 | + * nameFromTitle('42 Bob') // 'bob' | ||
| 36 | + */ | ||
| 37 | +export function nameFromTitle(title: string): string { | ||
| 38 | + const folded = title.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase() | ||
| 39 | + return folded | ||
| 40 | + .replace(/[^a-z0-9_-]+/g, '-') | ||
| 41 | + .replace(/^[^a-z]+/, '') | ||
| 42 | + .slice(0, 32) | ||
| 43 | + .replace(/-+$/, '') | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +/** The fields the user still has to fill in, by name. */ | ||
| 47 | +export type Missing = 'name' | 'nameFormat' | 'program' | 'workspace' | 'box' | ||
| 48 | + | ||
| 49 | +/** | ||
| 50 | + * What is missing or wrong before the form can be sent. | ||
| 51 | + * | ||
| 52 | + * @example | ||
| 53 | + * problemsOf({ ...emptyForm(), title: 'Alice' }) // ['name', 'program', 'workspace'] | ||
| 54 | + */ | ||
| 55 | +export function problemsOf(form: AgentFormValues): Missing[] { | ||
| 56 | + const problems: Missing[] = [] | ||
| 57 | + const name = form.name.trim() | ||
| 58 | + if (!name) problems.push('name') | ||
| 59 | + else if (!namePattern.test(name)) problems.push('nameFormat') | ||
| 60 | + if (!form.program.trim()) problems.push('program') | ||
| 61 | + if (!form.workspace.trim()) problems.push('workspace') | ||
| 62 | + if (form.environment !== 'local' && !form.box.trim()) problems.push('box') | ||
| 63 | + return problems | ||
| 64 | +} | ||
modified
frontend/src/lib/chat/ActionError.svelte +7 -3 | @@ -4,17 +4,21 @@ | ||
| 4 | 4 | // channel…), until the user closes it or the configuration changes. |
| 5 | 5 | import { t } from '../i18n/index.svelte' |
| 6 | 6 | import { appState } from '../state.svelte' |
| 7 | + import ErrorText from './ErrorText.svelte' | |
| 8 | + | |
| 9 | + // An agent that failed to start already shows the same error on its row. | |
| 10 | + const shown = $derived(appState.actionError !== '' && !appState.agents.some((agent) => !!agent.error && appState.actionError.includes(agent.error))) | |
| 7 | 11 | </script> |
| 8 | 12 | |
| 9 | -{#if appState.actionError} | |
| 13 | +{#if shown} | |
| 10 | 14 | <p class="error" role="alert"> |
| 11 | - <span>{appState.actionError}</span> | |
| 15 | + <span class="text"><ErrorText raw={appState.actionError} /></span> | |
| 12 | 16 | <button onclick={() => (appState.actionError = '')} aria-label={t('error.dismiss')} title={t('error.dismiss')}>×</button> |
| 13 | 17 | </p> |
| 14 | 18 | {/if} |
| 15 | 19 | |
| 16 | 20 | <style> |
| 17 | 21 | .error { display: flex; gap: 6px; align-items: flex-start; margin: 6px 8px; color: var(--danger); font-size: 12px; white-space: pre-wrap; overflow-wrap: anywhere; } |
| 18 | - span { flex: 1; } | |
| 22 | + .text { flex: 1; } | |
| 19 | 23 | button { border: none; background: none; color: var(--danger); padding: 0 4px; font-size: 14px; line-height: 1; } |
| 20 | 24 | </style> |
| @@ -4,17 +4,21 @@ | |||
| 4 | // channel…), until the user closes it or the configuration changes. | 4 | // channel…), until the user closes it or the configuration changes. |
| 5 | import { t } from '../i18n/index.svelte' | 5 | import { t } from '../i18n/index.svelte' |
| 6 | import { appState } from '../state.svelte' | 6 | import { appState } from '../state.svelte' |
| 7 | + import ErrorText from './ErrorText.svelte' | ||
| 8 | + | ||
| 9 | + // An agent that failed to start already shows the same error on its row. | ||
| 10 | + const shown = $derived(appState.actionError !== '' && !appState.agents.some((agent) => !!agent.error && appState.actionError.includes(agent.error))) | ||
| 7 | </script> | 11 | </script> |
| 8 | 12 | ||
| 9 | -{#if appState.actionError} | 13 | +{#if shown} |
| 10 | <p class="error" role="alert"> | 14 | <p class="error" role="alert"> |
| 11 | - <span>{appState.actionError}</span> | 15 | + <span class="text"><ErrorText raw={appState.actionError} /></span> |
| 12 | <button onclick={() => (appState.actionError = '')} aria-label={t('error.dismiss')} title={t('error.dismiss')}>×</button> | 16 | <button onclick={() => (appState.actionError = '')} aria-label={t('error.dismiss')} title={t('error.dismiss')}>×</button> |
| 13 | </p> | 17 | </p> |
| 14 | {/if} | 18 | {/if} |
| 15 | 19 | ||
| 16 | <style> | 20 | <style> |
| 17 | .error { display: flex; gap: 6px; align-items: flex-start; margin: 6px 8px; color: var(--danger); font-size: 12px; white-space: pre-wrap; overflow-wrap: anywhere; } | 21 | .error { display: flex; gap: 6px; align-items: flex-start; margin: 6px 8px; color: var(--danger); font-size: 12px; white-space: pre-wrap; overflow-wrap: anywhere; } |
| 18 | - span { flex: 1; } | 22 | + .text { flex: 1; } |
| 19 | button { border: none; background: none; color: var(--danger); padding: 0 4px; font-size: 14px; line-height: 1; } | 23 | button { border: none; background: none; color: var(--danger); padding: 0 4px; font-size: 14px; line-height: 1; } |
| 20 | </style> | 24 | </style> |
added
frontend/src/lib/chat/ErrorText.svelte +27 -0 | new file mode 100644 | ||
| @@ -0,0 +1,27 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<script lang="ts"> | |
| 3 | + // An error in plain words when it is a known one (lib/errors.ts), with the | |
| 4 | + // technical text folded below; otherwise the text as it is. | |
| 5 | + // Usage: <ErrorText raw={agent.error} /> | |
| 6 | + import { explain } from '../errors' | |
| 7 | + import { t } from '../i18n/index.svelte' | |
| 8 | + | |
| 9 | + let { raw }: { raw: string } = $props() | |
| 10 | + const explanation = $derived(explain(raw)) | |
| 11 | +</script> | |
| 12 | + | |
| 13 | +{#if explanation} | |
| 14 | + <span class="explained">{t(explanation.key, explanation.vars)}</span> | |
| 15 | + <details> | |
| 16 | + <summary>{t('error.details')}</summary> | |
| 17 | + <code>{raw}</code> | |
| 18 | + </details> | |
| 19 | +{:else} | |
| 20 | + <span>{raw}</span> | |
| 21 | +{/if} | |
| 22 | + | |
| 23 | +<style> | |
| 24 | + details { margin-top: 2px; font-size: 11px; opacity: 0.85; } | |
| 25 | + summary { cursor: pointer; } | |
| 26 | + code { display: block; white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--mono); } | |
| 27 | +</style> | |
| new file mode 100644 | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<script lang="ts"> | ||
| 3 | + // An error in plain words when it is a known one (lib/errors.ts), with the | ||
| 4 | + // technical text folded below; otherwise the text as it is. | ||
| 5 | + // Usage: <ErrorText raw={agent.error} /> | ||
| 6 | + import { explain } from '../errors' | ||
| 7 | + import { t } from '../i18n/index.svelte' | ||
| 8 | + | ||
| 9 | + let { raw }: { raw: string } = $props() | ||
| 10 | + const explanation = $derived(explain(raw)) | ||
| 11 | +</script> | ||
| 12 | + | ||
| 13 | +{#if explanation} | ||
| 14 | + <span class="explained">{t(explanation.key, explanation.vars)}</span> | ||
| 15 | + <details> | ||
| 16 | + <summary>{t('error.details')}</summary> | ||
| 17 | + <code>{raw}</code> | ||
| 18 | + </details> | ||
| 19 | +{:else} | ||
| 20 | + <span>{raw}</span> | ||
| 21 | +{/if} | ||
| 22 | + | ||
| 23 | +<style> | ||
| 24 | + details { margin-top: 2px; font-size: 11px; opacity: 0.85; } | ||
| 25 | + summary { cursor: pointer; } | ||
| 26 | + code { display: block; white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--mono); } | ||
| 27 | +</style> | ||
modified
frontend/src/lib/chat/MessageView.svelte +18 -3 | @@ -4,10 +4,11 @@ | ||
| 4 | 4 | import type { Message } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/channels' |
| 5 | 5 | import { agentTitle, appState } from '../state.svelte' |
| 6 | 6 | import { splitMentions } from '../suggestions' |
| 7 | - import { activityOf } from '../conversation' | |
| 7 | + import { activityOf, answerText } from '../conversation' | |
| 8 | 8 | import Markdown from './Markdown.svelte' |
| 9 | 9 | import Spinner from './Spinner.svelte' |
| 10 | 10 | import ToolCallCard from './ToolCallCard.svelte' |
| 11 | + import ErrorText from './ErrorText.svelte' | |
| 11 | 12 | |
| 12 | 13 | let { message }: { message: Message } = $props() |
| 13 | 14 | |
| @@ -21,17 +22,29 @@ | ||
| 21 | 22 | // Codes and stop reasons come from Go; their sentences live in i18n. |
| 22 | 23 | const systemKey = $derived(`system.${message.code ?? ''}`) |
| 23 | 24 | const stopKey = $derived(`message.stop.${message.stopReason ?? ''}`) |
| 25 | + // The whole answer, as Markdown, once it is complete. | |
| 26 | + const copyable = $derived(message.role === 'agent' && message.done ? answerText(message) : '') | |
| 27 | + let copied = $state(false) | |
| 28 | + async function copyAnswer() { | |
| 29 | + await navigator.clipboard.writeText(copyable) | |
| 30 | + copied = true | |
| 31 | + setTimeout(() => (copied = false), 1500) | |
| 32 | + } | |
| 33 | + | |
| 24 | 34 | const planIcons: Record<string, string> = { completed: '✓', in_progress: '⏵', pending: '○' } |
| 25 | 35 | </script> |
| 26 | 36 | |
| 27 | 37 | {#if message.role === 'system'} |
| 28 | - <p class="system">{hasMessage(systemKey) ? t(systemKey, { agent: author, example }) : author}{#if message.error}<br /><span class="detail">{message.error}</span>{/if}</p> | |
| 38 | + <p class="system">{hasMessage(systemKey) ? t(systemKey, { agent: author, example }) : author}{#if message.error}<br /><span class="detail"><ErrorText raw={message.error} /></span>{/if}</p> | |
| 29 | 39 | {:else} |
| 30 | 40 | <article class="message {message.role}"> |
| 31 | 41 | <div class="author"> |
| 32 | 42 | {message.role === 'user' ? t('message.you') : author} |
| 33 | 43 | {#if message.queued}<span class="note">{t('message.queued')}</span>{/if} |
| 34 | 44 | {#if activity}<span class="note activity"><Spinner /> {t(`message.${activity}`)}</span>{/if} |
| 45 | + {#if copyable} | |
| 46 | + <button class="copy" onclick={copyAnswer} title={t('message.copy')} aria-label={t('message.copy')}>{copied ? t('code.copied') : `⧉ ${t('code.copy')}`}</button> | |
| 47 | + {/if} | |
| 35 | 48 | </div> |
| 36 | 49 | {#each message.parts ?? [] as part, index (index)} |
| 37 | 50 | {#if part.kind === 'text' && message.role === 'user'} |
| @@ -54,7 +67,7 @@ | ||
| 54 | 67 | <p class="ending">{t(stopKey)}</p> |
| 55 | 68 | {/if} |
| 56 | 69 | {#if message.error && message.role === 'agent'} |
| 57 | - <p class="error">{t('message.error', { error: message.error })}</p> | |
| 70 | + <div class="error">{t('message.error')} <ErrorText raw={message.error} /></div> | |
| 58 | 71 | {:else if message.error === 'cancelled'} |
| 59 | 72 | <p class="ending">{t('message.notSent')}</p> |
| 60 | 73 | {/if} |
| @@ -78,4 +91,6 @@ | ||
| 78 | 91 | .plan .in_progress { font-weight: 600; } |
| 79 | 92 | .ending { color: var(--muted); font-size: 12px; margin: 6px 0 0; } |
| 80 | 93 | .error { color: var(--danger); font-size: 13px; margin: 6px 0 0; } |
| 94 | + .copy { font-size: 11px; font-weight: 400; padding: 0 6px; color: var(--muted); background: none; opacity: 0; } | |
| 95 | + .message:hover .copy, .copy:focus-visible { opacity: 1; } | |
| 81 | 96 | </style> |
| @@ -4,10 +4,11 @@ | |||
| 4 | import type { Message } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/channels' | 4 | import type { Message } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/channels' |
| 5 | import { agentTitle, appState } from '../state.svelte' | 5 | import { agentTitle, appState } from '../state.svelte' |
| 6 | import { splitMentions } from '../suggestions' | 6 | import { splitMentions } from '../suggestions' |
| 7 | - import { activityOf } from '../conversation' | 7 | + import { activityOf, answerText } from '../conversation' |
| 8 | import Markdown from './Markdown.svelte' | 8 | import Markdown from './Markdown.svelte' |
| 9 | import Spinner from './Spinner.svelte' | 9 | import Spinner from './Spinner.svelte' |
| 10 | import ToolCallCard from './ToolCallCard.svelte' | 10 | import ToolCallCard from './ToolCallCard.svelte' |
| 11 | + import ErrorText from './ErrorText.svelte' | ||
| 11 | 12 | ||
| 12 | let { message }: { message: Message } = $props() | 13 | let { message }: { message: Message } = $props() |
| 13 | 14 | ||
| @@ -21,17 +22,29 @@ | |||
| 21 | // Codes and stop reasons come from Go; their sentences live in i18n. | 22 | // Codes and stop reasons come from Go; their sentences live in i18n. |
| 22 | const systemKey = $derived(`system.${message.code ?? ''}`) | 23 | const systemKey = $derived(`system.${message.code ?? ''}`) |
| 23 | const stopKey = $derived(`message.stop.${message.stopReason ?? ''}`) | 24 | const stopKey = $derived(`message.stop.${message.stopReason ?? ''}`) |
| 25 | + // The whole answer, as Markdown, once it is complete. | ||
| 26 | + const copyable = $derived(message.role === 'agent' && message.done ? answerText(message) : '') | ||
| 27 | + let copied = $state(false) | ||
| 28 | + async function copyAnswer() { | ||
| 29 | + await navigator.clipboard.writeText(copyable) | ||
| 30 | + copied = true | ||
| 31 | + setTimeout(() => (copied = false), 1500) | ||
| 32 | + } | ||
| 33 | + | ||
| 24 | const planIcons: Record<string, string> = { completed: '✓', in_progress: '⏵', pending: '○' } | 34 | const planIcons: Record<string, string> = { completed: '✓', in_progress: '⏵', pending: '○' } |
| 25 | </script> | 35 | </script> |
| 26 | 36 | ||
| 27 | {#if message.role === 'system'} | 37 | {#if message.role === 'system'} |
| 28 | - <p class="system">{hasMessage(systemKey) ? t(systemKey, { agent: author, example }) : author}{#if message.error}<br /><span class="detail">{message.error}</span>{/if}</p> | 38 | + <p class="system">{hasMessage(systemKey) ? t(systemKey, { agent: author, example }) : author}{#if message.error}<br /><span class="detail"><ErrorText raw={message.error} /></span>{/if}</p> |
| 29 | {:else} | 39 | {:else} |
| 30 | <article class="message {message.role}"> | 40 | <article class="message {message.role}"> |
| 31 | <div class="author"> | 41 | <div class="author"> |
| 32 | {message.role === 'user' ? t('message.you') : author} | 42 | {message.role === 'user' ? t('message.you') : author} |
| 33 | {#if message.queued}<span class="note">{t('message.queued')}</span>{/if} | 43 | {#if message.queued}<span class="note">{t('message.queued')}</span>{/if} |
| 34 | {#if activity}<span class="note activity"><Spinner /> {t(`message.${activity}`)}</span>{/if} | 44 | {#if activity}<span class="note activity"><Spinner /> {t(`message.${activity}`)}</span>{/if} |
| 45 | + {#if copyable} | ||
| 46 | + <button class="copy" onclick={copyAnswer} title={t('message.copy')} aria-label={t('message.copy')}>{copied ? t('code.copied') : `⧉ ${t('code.copy')}`}</button> | ||
| 47 | + {/if} | ||
| 35 | </div> | 48 | </div> |
| 36 | {#each message.parts ?? [] as part, index (index)} | 49 | {#each message.parts ?? [] as part, index (index)} |
| 37 | {#if part.kind === 'text' && message.role === 'user'} | 50 | {#if part.kind === 'text' && message.role === 'user'} |
| @@ -54,7 +67,7 @@ | |||
| 54 | <p class="ending">{t(stopKey)}</p> | 67 | <p class="ending">{t(stopKey)}</p> |
| 55 | {/if} | 68 | {/if} |
| 56 | {#if message.error && message.role === 'agent'} | 69 | {#if message.error && message.role === 'agent'} |
| 57 | - <p class="error">{t('message.error', { error: message.error })}</p> | 70 | + <div class="error">{t('message.error')} <ErrorText raw={message.error} /></div> |
| 58 | {:else if message.error === 'cancelled'} | 71 | {:else if message.error === 'cancelled'} |
| 59 | <p class="ending">{t('message.notSent')}</p> | 72 | <p class="ending">{t('message.notSent')}</p> |
| 60 | {/if} | 73 | {/if} |
| @@ -78,4 +91,6 @@ | |||
| 78 | .plan .in_progress { font-weight: 600; } | 91 | .plan .in_progress { font-weight: 600; } |
| 79 | .ending { color: var(--muted); font-size: 12px; margin: 6px 0 0; } | 92 | .ending { color: var(--muted); font-size: 12px; margin: 6px 0 0; } |
| 80 | .error { color: var(--danger); font-size: 13px; margin: 6px 0 0; } | 93 | .error { color: var(--danger); font-size: 13px; margin: 6px 0 0; } |
| 94 | + .copy { font-size: 11px; font-weight: 400; padding: 0 6px; color: var(--muted); background: none; opacity: 0; } | ||
| 95 | + .message:hover .copy, .copy:focus-visible { opacity: 1; } | ||
| 81 | </style> | 96 | </style> |
added
frontend/src/lib/contrast.test.ts +35 -0 | new file mode 100644 | ||
| @@ -0,0 +1,35 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +import { describe, expect, it } from 'vitest' | |
| 4 | +import { contrastRatio, tokenBlocks } from './contrast' | |
| 5 | +import css from '../style.css?raw' | |
| 6 | + | |
| 7 | +describe('contrastRatio', () => { | |
| 8 | + it('goes from 1 to 21', () => { | |
| 9 | + expect(contrastRatio('#000000', '#ffffff')).toBeCloseTo(21, 5) | |
| 10 | + expect(contrastRatio('#777777', '#777777')).toBeCloseTo(1, 5) | |
| 11 | + }) | |
| 12 | +}) | |
| 13 | + | |
| 14 | +// Every text colour of the theme on every background it is used on. | |
| 15 | +describe('the theme of style.css', () => { | |
| 16 | + const [light, ...dark] = tokenBlocks(css) | |
| 17 | + const themes = { light, dark: { ...light, ...dark[0] }, 'dark (forced)': { ...light, ...dark[1] } } | |
| 18 | + | |
| 19 | + for (const [name, tokens] of Object.entries(themes)) { | |
| 20 | + it(`${name}: text colours reach WCAG AA (4.5:1) on the backgrounds`, () => { | |
| 21 | + const failures: string[] = [] | |
| 22 | + for (const text of ['text', 'muted', 'accent', 'danger', 'ok', 'warn']) { | |
| 23 | + for (const background of ['bg', 'panel', 'panel-2']) { | |
| 24 | + const ratio = contrastRatio(tokens[text], tokens[background]) | |
| 25 | + if (ratio < 4.5) failures.push(`--${text} on --${background}: ${ratio.toFixed(2)}`) | |
| 26 | + } | |
| 27 | + } | |
| 28 | + expect(failures).toEqual([]) | |
| 29 | + }) | |
| 30 | + } | |
| 31 | + | |
| 32 | + it('white text on the accent (primary buttons) reaches AA', () => { | |
| 33 | + expect(contrastRatio('#ffffff', light.accent)).toBeGreaterThanOrEqual(4.5) | |
| 34 | + }) | |
| 35 | +}) | |
| new file mode 100644 | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +import { describe, expect, it } from 'vitest' | ||
| 4 | +import { contrastRatio, tokenBlocks } from './contrast' | ||
| 5 | +import css from '../style.css?raw' | ||
| 6 | + | ||
| 7 | +describe('contrastRatio', () => { | ||
| 8 | + it('goes from 1 to 21', () => { | ||
| 9 | + expect(contrastRatio('#000000', '#ffffff')).toBeCloseTo(21, 5) | ||
| 10 | + expect(contrastRatio('#777777', '#777777')).toBeCloseTo(1, 5) | ||
| 11 | + }) | ||
| 12 | +}) | ||
| 13 | + | ||
| 14 | +// Every text colour of the theme on every background it is used on. | ||
| 15 | +describe('the theme of style.css', () => { | ||
| 16 | + const [light, ...dark] = tokenBlocks(css) | ||
| 17 | + const themes = { light, dark: { ...light, ...dark[0] }, 'dark (forced)': { ...light, ...dark[1] } } | ||
| 18 | + | ||
| 19 | + for (const [name, tokens] of Object.entries(themes)) { | ||
| 20 | + it(`${name}: text colours reach WCAG AA (4.5:1) on the backgrounds`, () => { | ||
| 21 | + const failures: string[] = [] | ||
| 22 | + for (const text of ['text', 'muted', 'accent', 'danger', 'ok', 'warn']) { | ||
| 23 | + for (const background of ['bg', 'panel', 'panel-2']) { | ||
| 24 | + const ratio = contrastRatio(tokens[text], tokens[background]) | ||
| 25 | + if (ratio < 4.5) failures.push(`--${text} on --${background}: ${ratio.toFixed(2)}`) | ||
| 26 | + } | ||
| 27 | + } | ||
| 28 | + expect(failures).toEqual([]) | ||
| 29 | + }) | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + it('white text on the accent (primary buttons) reaches AA', () => { | ||
| 33 | + expect(contrastRatio('#ffffff', light.accent)).toBeGreaterThanOrEqual(4.5) | ||
| 34 | + }) | ||
| 35 | +}) | ||
added
frontend/src/lib/contrast.ts +36 -0 | new file mode 100644 | ||
| @@ -0,0 +1,36 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +// WCAG contrast (issue #35): the colours of the theme must stay readable. | |
| 4 | +// AA asks for 4.5:1 for text, 3:1 for large text and interface parts. | |
| 5 | + | |
| 6 | +/** The relative luminance of a #rrggbb colour. */ | |
| 7 | +export function luminance(hex: string): number { | |
| 8 | + const channels = [1, 3, 5].map((start) => parseInt(hex.slice(start, start + 2), 16) / 255) | |
| 9 | + const [r, g, b] = channels.map((value) => (value <= 0.03928 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4)) | |
| 10 | + return 0.2126 * r + 0.7152 * g + 0.0722 * b | |
| 11 | +} | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * The contrast ratio of two #rrggbb colours, from 1 to 21. | |
| 15 | + * | |
| 16 | + * @example | |
| 17 | + * contrastRatio('#000000', '#ffffff') // 21 | |
| 18 | + */ | |
| 19 | +export function contrastRatio(first: string, second: string): number { | |
| 20 | + const [light, dark] = [luminance(first), luminance(second)].sort((a, b) => b - a) | |
| 21 | + return (light + 0.05) / (dark + 0.05) | |
| 22 | +} | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * The colour tokens (--name: #rrggbb) of each block of a stylesheet, by | |
| 26 | + * selector: ":root", then the dark blocks in their order. | |
| 27 | + */ | |
| 28 | +export function tokenBlocks(css: string): Record<string, string>[] { | |
| 29 | + const blocks: Record<string, string>[] = [] | |
| 30 | + for (const match of css.matchAll(/\{([^{}]*)\}/g)) { | |
| 31 | + const tokens: Record<string, string> = {} | |
| 32 | + for (const token of match[1].matchAll(/--([\w-]+):\s*(#[0-9a-fA-F]{6})\s*;/g)) tokens[token[1]] = token[2].toLowerCase() | |
| 33 | + if (Object.keys(tokens).length > 0) blocks.push(tokens) | |
| 34 | + } | |
| 35 | + return blocks | |
| 36 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +// WCAG contrast (issue #35): the colours of the theme must stay readable. | ||
| 4 | +// AA asks for 4.5:1 for text, 3:1 for large text and interface parts. | ||
| 5 | + | ||
| 6 | +/** The relative luminance of a #rrggbb colour. */ | ||
| 7 | +export function luminance(hex: string): number { | ||
| 8 | + const channels = [1, 3, 5].map((start) => parseInt(hex.slice(start, start + 2), 16) / 255) | ||
| 9 | + const [r, g, b] = channels.map((value) => (value <= 0.03928 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4)) | ||
| 10 | + return 0.2126 * r + 0.7152 * g + 0.0722 * b | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * The contrast ratio of two #rrggbb colours, from 1 to 21. | ||
| 15 | + * | ||
| 16 | + * @example | ||
| 17 | + * contrastRatio('#000000', '#ffffff') // 21 | ||
| 18 | + */ | ||
| 19 | +export function contrastRatio(first: string, second: string): number { | ||
| 20 | + const [light, dark] = [luminance(first), luminance(second)].sort((a, b) => b - a) | ||
| 21 | + return (light + 0.05) / (dark + 0.05) | ||
| 22 | +} | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * The colour tokens (--name: #rrggbb) of each block of a stylesheet, by | ||
| 26 | + * selector: ":root", then the dark blocks in their order. | ||
| 27 | + */ | ||
| 28 | +export function tokenBlocks(css: string): Record<string, string>[] { | ||
| 29 | + const blocks: Record<string, string>[] = [] | ||
| 30 | + for (const match of css.matchAll(/\{([^{}]*)\}/g)) { | ||
| 31 | + const tokens: Record<string, string> = {} | ||
| 32 | + for (const token of match[1].matchAll(/--([\w-]+):\s*(#[0-9a-fA-F]{6})\s*;/g)) tokens[token[1]] = token[2].toLowerCase() | ||
| 33 | + if (Object.keys(tokens).length > 0) blocks.push(tokens) | ||
| 34 | + } | ||
| 35 | + return blocks | ||
| 36 | +} | ||
modified
frontend/src/lib/conversation.test.ts +17 -1 | @@ -3,7 +3,7 @@ | ||
| 3 | 3 | import { describe, expect, it } from 'vitest' |
| 4 | 4 | import type { Channel, Message } from '../../bindings/git.rickub.com/bots-garden/sidekicks/internal/channels' |
| 5 | 5 | import { Role } from '../../bindings/git.rickub.com/bots-garden/sidekicks/internal/channels' |
| 6 | -import { activityOf, addPermission, visibleDirects, applyDelta, applyMessage, emptyConversation, prependMessages, removePermission, usagePercent } from './conversation' | |
| 6 | +import { activityOf, addPermission, answerText, visibleDirects, applyDelta, applyMessage, emptyConversation, prependMessages, removePermission, usagePercent } from './conversation' | |
| 7 | 7 | |
| 8 | 8 | const general: Channel = { id: 'c1', name: 'general', description: '', direct: '', members: ['alice'] } |
| 9 | 9 | |
| @@ -86,3 +86,19 @@ describe('conversation events', () => { | ||
| 86 | 86 | expect(visibleDirects(channels, ['alice', 'bob']).map((channel) => channel.direct)).toEqual(['alice']) |
| 87 | 87 | }) |
| 88 | 88 | }) |
| 89 | + | |
| 90 | +describe('answerText', () => { | |
| 91 | + it('keeps the text parts, as written, one paragraph apart', () => { | |
| 92 | + const answer = { ...message('m1', true), parts: [ | |
| 93 | + { kind: 'thought', text: 'thinking…' }, | |
| 94 | + { kind: 'text', text: 'Here is the table:\n\n| a | b |\n' }, | |
| 95 | + { kind: 'tool', text: '' }, | |
| 96 | + { kind: 'text', text: ' Done. ' }, | |
| 97 | + ] } as Message | |
| 98 | + expect(answerText(answer)).toBe('Here is the table:\n\n| a | b |\n\nDone.') | |
| 99 | + }) | |
| 100 | + it('is empty when the answer has no text', () => { | |
| 101 | + expect(answerText(message('m2', true))).toBe('') | |
| 102 | + expect(answerText({ ...message('m3', true), parts: [{ kind: 'text', text: ' ' }] } as Message)).toBe('') | |
| 103 | + }) | |
| 104 | +}) | |
| @@ -3,7 +3,7 @@ | |||
| 3 | import { describe, expect, it } from 'vitest' | 3 | import { describe, expect, it } from 'vitest' |
| 4 | import type { Channel, Message } from '../../bindings/git.rickub.com/bots-garden/sidekicks/internal/channels' | 4 | import type { Channel, Message } from '../../bindings/git.rickub.com/bots-garden/sidekicks/internal/channels' |
| 5 | import { Role } from '../../bindings/git.rickub.com/bots-garden/sidekicks/internal/channels' | 5 | import { Role } from '../../bindings/git.rickub.com/bots-garden/sidekicks/internal/channels' |
| 6 | -import { activityOf, addPermission, visibleDirects, applyDelta, applyMessage, emptyConversation, prependMessages, removePermission, usagePercent } from './conversation' | 6 | +import { activityOf, addPermission, answerText, visibleDirects, applyDelta, applyMessage, emptyConversation, prependMessages, removePermission, usagePercent } from './conversation' |
| 7 | 7 | ||
| 8 | const general: Channel = { id: 'c1', name: 'general', description: '', direct: '', members: ['alice'] } | 8 | const general: Channel = { id: 'c1', name: 'general', description: '', direct: '', members: ['alice'] } |
| 9 | 9 | ||
| @@ -86,3 +86,19 @@ describe('conversation events', () => { | |||
| 86 | expect(visibleDirects(channels, ['alice', 'bob']).map((channel) => channel.direct)).toEqual(['alice']) | 86 | expect(visibleDirects(channels, ['alice', 'bob']).map((channel) => channel.direct)).toEqual(['alice']) |
| 87 | }) | 87 | }) |
| 88 | }) | 88 | }) |
| 89 | + | ||
| 90 | +describe('answerText', () => { | ||
| 91 | + it('keeps the text parts, as written, one paragraph apart', () => { | ||
| 92 | + const answer = { ...message('m1', true), parts: [ | ||
| 93 | + { kind: 'thought', text: 'thinking…' }, | ||
| 94 | + { kind: 'text', text: 'Here is the table:\n\n| a | b |\n' }, | ||
| 95 | + { kind: 'tool', text: '' }, | ||
| 96 | + { kind: 'text', text: ' Done. ' }, | ||
| 97 | + ] } as Message | ||
| 98 | + expect(answerText(answer)).toBe('Here is the table:\n\n| a | b |\n\nDone.') | ||
| 99 | + }) | ||
| 100 | + it('is empty when the answer has no text', () => { | ||
| 101 | + expect(answerText(message('m2', true))).toBe('') | ||
| 102 | + expect(answerText({ ...message('m3', true), parts: [{ kind: 'text', text: ' ' }] } as Message)).toBe('') | ||
| 103 | + }) | ||
| 104 | +}) | ||
modified
frontend/src/lib/conversation.ts +16 -0 | @@ -100,3 +100,19 @@ export function activityOf(message: Message): Activity | null { | ||
| 100 | 100 | export function visibleDirects(channels: Channel[], agents: string[]): Channel[] { |
| 101 | 101 | return channels.filter((channel) => channel.direct && agents.includes(channel.direct)) |
| 102 | 102 | } |
| 103 | + | |
| 104 | +/** | |
| 105 | + * The text of an answer, for the "copy the answer" button: its text parts, | |
| 106 | + * as the agent wrote them (Markdown), one paragraph apart. Thoughts, tool | |
| 107 | + * calls and plans are left out. | |
| 108 | + * | |
| 109 | + * @example | |
| 110 | + * answerText(message) // "Here is the table:\n\n| name | role |…" | |
| 111 | + */ | |
| 112 | +export function answerText(message: Message): string { | |
| 113 | + return (message.parts ?? []) | |
| 114 | + .filter((part) => part.kind === 'text') | |
| 115 | + .map((part) => (part.text ?? '').trim()) | |
| 116 | + .filter((text) => text !== '') | |
| 117 | + .join('\n\n') | |
| 118 | +} | |
| @@ -100,3 +100,19 @@ export function activityOf(message: Message): Activity | null { | |||
| 100 | export function visibleDirects(channels: Channel[], agents: string[]): Channel[] { | 100 | export function visibleDirects(channels: Channel[], agents: string[]): Channel[] { |
| 101 | return channels.filter((channel) => channel.direct && agents.includes(channel.direct)) | 101 | return channels.filter((channel) => channel.direct && agents.includes(channel.direct)) |
| 102 | } | 102 | } |
| 103 | + | ||
| 104 | +/** | ||
| 105 | + * The text of an answer, for the "copy the answer" button: its text parts, | ||
| 106 | + * as the agent wrote them (Markdown), one paragraph apart. Thoughts, tool | ||
| 107 | + * calls and plans are left out. | ||
| 108 | + * | ||
| 109 | + * @example | ||
| 110 | + * answerText(message) // "Here is the table:\n\n| name | role |…" | ||
| 111 | + */ | ||
| 112 | +export function answerText(message: Message): string { | ||
| 113 | + return (message.parts ?? []) | ||
| 114 | + .filter((part) => part.kind === 'text') | ||
| 115 | + .map((part) => (part.text ?? '').trim()) | ||
| 116 | + .filter((text) => text !== '') | ||
| 117 | + .join('\n\n') | ||
| 118 | +} | ||
added
frontend/src/lib/errors.test.ts +35 -0 | new file mode 100644 | ||
| @@ -0,0 +1,35 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +import { describe, expect, it } from 'vitest' | |
| 4 | +import { explain } from './errors' | |
| 5 | + | |
| 6 | +describe('explain', () => { | |
| 7 | + it('recognises a program that cannot be found or run', () => { | |
| 8 | + expect(explain('start agent alice: exec: "mm": executable file not found in $PATH')).toEqual({ key: 'error.programNotFound', vars: { program: 'mm' } }) | |
| 9 | + expect(explain('start agent alice: fork/exec /opt/mm/bin/mm: no such file or directory')).toEqual({ key: 'error.programNotFound', vars: { program: '/opt/mm/bin/mm' } }) | |
| 10 | + expect(explain('start agent alice: fork/exec /tmp/agent.sh: permission denied')).toEqual({ key: 'error.programNotExecutable', vars: { program: '/tmp/agent.sh' } }) | |
| 11 | + }) | |
| 12 | + | |
| 13 | + it('recognises Docker and sbx problems before the agent stopping', () => { | |
| 14 | + expect(explain('the agent stopped: exit status 1\nError response from daemon: No such container: scout-box')).toEqual({ key: 'error.containerMissing', vars: { box: 'scout-box' } }) | |
| 15 | + expect(explain('Error response from daemon: container 4f2 is not running')).toEqual({ key: 'error.containerStopped', vars: { box: '4f2' } }) | |
| 16 | + expect(explain('the agent stopped: exit status 1\nCannot connect to the Docker daemon at unix:///var/run/docker.sock')).toEqual({ key: 'error.dockerNotRunning', vars: {} }) | |
| 17 | + expect(explain('sandbox "milo-sbx" not found')).toEqual({ key: 'error.sandboxMissing', vars: { box: 'milo-sbx' } }) | |
| 18 | + }) | |
| 19 | + | |
| 20 | + it('recognises the limit of running agents', () => { | |
| 21 | + expect(explain('too many agents running: 2 agent(s) busy (alice, bob), the limit is 2')).toEqual({ key: 'error.limitReached', vars: { limit: '2' } }) | |
| 22 | + }) | |
| 23 | + | |
| 24 | + it('recognises an agent that stops, does not answer or cannot reach its model', () => { | |
| 25 | + expect(explain('the agent stopped: exit status 2')?.key).toBe('error.agentStopped') | |
| 26 | + expect(explain('the agent stopped: exit status 1\ndial tcp 127.0.0.1:11434: connect: connection refused')?.key).toBe('error.modelServer') | |
| 27 | + expect(explain('no answer to initialize: context deadline exceeded')?.key).toBe('error.noAnswer') | |
| 28 | + expect(explain('unsupported ACP protocol version: the agent speaks version 2')?.key).toBe('error.protocol') | |
| 29 | + }) | |
| 30 | + | |
| 31 | + it('leaves unknown errors alone', () => { | |
| 32 | + expect(explain('something odd happened')).toBeNull() | |
| 33 | + expect(explain('')).toBeNull() | |
| 34 | + }) | |
| 35 | +}) | |
| new file mode 100644 | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +import { describe, expect, it } from 'vitest' | ||
| 4 | +import { explain } from './errors' | ||
| 5 | + | ||
| 6 | +describe('explain', () => { | ||
| 7 | + it('recognises a program that cannot be found or run', () => { | ||
| 8 | + expect(explain('start agent alice: exec: "mm": executable file not found in $PATH')).toEqual({ key: 'error.programNotFound', vars: { program: 'mm' } }) | ||
| 9 | + expect(explain('start agent alice: fork/exec /opt/mm/bin/mm: no such file or directory')).toEqual({ key: 'error.programNotFound', vars: { program: '/opt/mm/bin/mm' } }) | ||
| 10 | + expect(explain('start agent alice: fork/exec /tmp/agent.sh: permission denied')).toEqual({ key: 'error.programNotExecutable', vars: { program: '/tmp/agent.sh' } }) | ||
| 11 | + }) | ||
| 12 | + | ||
| 13 | + it('recognises Docker and sbx problems before the agent stopping', () => { | ||
| 14 | + expect(explain('the agent stopped: exit status 1\nError response from daemon: No such container: scout-box')).toEqual({ key: 'error.containerMissing', vars: { box: 'scout-box' } }) | ||
| 15 | + expect(explain('Error response from daemon: container 4f2 is not running')).toEqual({ key: 'error.containerStopped', vars: { box: '4f2' } }) | ||
| 16 | + expect(explain('the agent stopped: exit status 1\nCannot connect to the Docker daemon at unix:///var/run/docker.sock')).toEqual({ key: 'error.dockerNotRunning', vars: {} }) | ||
| 17 | + expect(explain('sandbox "milo-sbx" not found')).toEqual({ key: 'error.sandboxMissing', vars: { box: 'milo-sbx' } }) | ||
| 18 | + }) | ||
| 19 | + | ||
| 20 | + it('recognises the limit of running agents', () => { | ||
| 21 | + expect(explain('too many agents running: 2 agent(s) busy (alice, bob), the limit is 2')).toEqual({ key: 'error.limitReached', vars: { limit: '2' } }) | ||
| 22 | + }) | ||
| 23 | + | ||
| 24 | + it('recognises an agent that stops, does not answer or cannot reach its model', () => { | ||
| 25 | + expect(explain('the agent stopped: exit status 2')?.key).toBe('error.agentStopped') | ||
| 26 | + expect(explain('the agent stopped: exit status 1\ndial tcp 127.0.0.1:11434: connect: connection refused')?.key).toBe('error.modelServer') | ||
| 27 | + expect(explain('no answer to initialize: context deadline exceeded')?.key).toBe('error.noAnswer') | ||
| 28 | + expect(explain('unsupported ACP protocol version: the agent speaks version 2')?.key).toBe('error.protocol') | ||
| 29 | + }) | ||
| 30 | + | ||
| 31 | + it('leaves unknown errors alone', () => { | ||
| 32 | + expect(explain('something odd happened')).toBeNull() | ||
| 33 | + expect(explain('')).toBeNull() | ||
| 34 | + }) | ||
| 35 | +}) | ||
added
frontend/src/lib/errors.ts +58 -0 | new file mode 100644 | ||
| @@ -0,0 +1,58 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +// Human error messages (issue #33): the errors of Go, of the agents and of | |
| 4 | +// Docker or sbx are technical. explain recognises the common ones and gives | |
| 5 | +// the message key of a sentence that says what is wrong and what to do; the | |
| 6 | +// technical text stays available, folded, for the curious. | |
| 7 | + | |
| 8 | +import type { MessageKey } from './i18n/index.svelte' | |
| 9 | + | |
| 10 | +export interface Explanation { | |
| 11 | + key: MessageKey | |
| 12 | + vars: Record<string, string> | |
| 13 | +} | |
| 14 | + | |
| 15 | +interface Rule { | |
| 16 | + pattern: RegExp | |
| 17 | + key: MessageKey | |
| 18 | + /** Names of the pattern's groups, in order, used as variables. */ | |
| 19 | + groups?: string[] | |
| 20 | +} | |
| 21 | + | |
| 22 | +// The first rule that matches wins: the most specific ones come first. | |
| 23 | +const rules: Rule[] = [ | |
| 24 | + { pattern: /Cannot connect to the Docker daemon|docker daemon is not running|error during connect/i, key: 'error.dockerNotRunning' }, | |
| 25 | + { pattern: /No such container:\s*(\S+)/i, key: 'error.containerMissing', groups: ['box'] }, | |
| 26 | + { pattern: /container (\S+) is not running|Container (\S+) is not running/i, key: 'error.containerStopped', groups: ['box'] }, | |
| 27 | + { pattern: /sandbox[ "']+([\w.-]+)["']? (?:not found|does not exist)/i, key: 'error.sandboxMissing', groups: ['box'] }, | |
| 28 | + { pattern: /exec: "([^"]+)": executable file not found/, key: 'error.programNotFound', groups: ['program'] }, | |
| 29 | + { pattern: /(?:fork\/exec|exec:?) "?([^":\s]+)"?: no such file or directory/, key: 'error.programNotFound', groups: ['program'] }, | |
| 30 | + { pattern: /(?:fork\/exec|exec:?) "?([^":\s]+)"?: permission denied/, key: 'error.programNotExecutable', groups: ['program'] }, | |
| 31 | + { pattern: /too many agents running: .*the limit is (\d+)/, key: 'error.limitReached', groups: ['limit'] }, | |
| 32 | + { pattern: /connection refused|ECONNREFUSED/i, key: 'error.modelServer' }, | |
| 33 | + { pattern: /unsupported ACP protocol version/, key: 'error.protocol' }, | |
| 34 | + { pattern: /no answer to initialize/, key: 'error.noAnswer' }, | |
| 35 | + { pattern: /the agent stopped/, key: 'error.agentStopped' }, | |
| 36 | + { pattern: /unknown agent:?\s*(\S*)/, key: 'error.unknownAgent', groups: ['agent'] }, | |
| 37 | + { pattern: /the history was written by a newer Sidekicks/, key: 'error.newerHistory' }, | |
| 38 | +] | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * The human message for a technical error, or null when it is not a known one. | |
| 42 | + * | |
| 43 | + * @example | |
| 44 | + * explain('start agent alice: exec: "mm": executable file not found in $PATH') | |
| 45 | + * // { key: 'error.programNotFound', vars: { program: 'mm' } } | |
| 46 | + */ | |
| 47 | +export function explain(raw: string): Explanation | null { | |
| 48 | + for (const rule of rules) { | |
| 49 | + const match = rule.pattern.exec(raw) | |
| 50 | + if (!match) continue | |
| 51 | + const vars: Record<string, string> = {} | |
| 52 | + // Alternatives may capture into different groups: take the first non-empty one per name. | |
| 53 | + const captured = match.slice(1).filter((value) => value !== undefined) | |
| 54 | + ;(rule.groups ?? []).forEach((name, index) => (vars[name] = captured[index] ?? '')) | |
| 55 | + return { key: rule.key, vars } | |
| 56 | + } | |
| 57 | + return null | |
| 58 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +// Human error messages (issue #33): the errors of Go, of the agents and of | ||
| 4 | +// Docker or sbx are technical. explain recognises the common ones and gives | ||
| 5 | +// the message key of a sentence that says what is wrong and what to do; the | ||
| 6 | +// technical text stays available, folded, for the curious. | ||
| 7 | + | ||
| 8 | +import type { MessageKey } from './i18n/index.svelte' | ||
| 9 | + | ||
| 10 | +export interface Explanation { | ||
| 11 | + key: MessageKey | ||
| 12 | + vars: Record<string, string> | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +interface Rule { | ||
| 16 | + pattern: RegExp | ||
| 17 | + key: MessageKey | ||
| 18 | + /** Names of the pattern's groups, in order, used as variables. */ | ||
| 19 | + groups?: string[] | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +// The first rule that matches wins: the most specific ones come first. | ||
| 23 | +const rules: Rule[] = [ | ||
| 24 | + { pattern: /Cannot connect to the Docker daemon|docker daemon is not running|error during connect/i, key: 'error.dockerNotRunning' }, | ||
| 25 | + { pattern: /No such container:\s*(\S+)/i, key: 'error.containerMissing', groups: ['box'] }, | ||
| 26 | + { pattern: /container (\S+) is not running|Container (\S+) is not running/i, key: 'error.containerStopped', groups: ['box'] }, | ||
| 27 | + { pattern: /sandbox[ "']+([\w.-]+)["']? (?:not found|does not exist)/i, key: 'error.sandboxMissing', groups: ['box'] }, | ||
| 28 | + { pattern: /exec: "([^"]+)": executable file not found/, key: 'error.programNotFound', groups: ['program'] }, | ||
| 29 | + { pattern: /(?:fork\/exec|exec:?) "?([^":\s]+)"?: no such file or directory/, key: 'error.programNotFound', groups: ['program'] }, | ||
| 30 | + { pattern: /(?:fork\/exec|exec:?) "?([^":\s]+)"?: permission denied/, key: 'error.programNotExecutable', groups: ['program'] }, | ||
| 31 | + { pattern: /too many agents running: .*the limit is (\d+)/, key: 'error.limitReached', groups: ['limit'] }, | ||
| 32 | + { pattern: /connection refused|ECONNREFUSED/i, key: 'error.modelServer' }, | ||
| 33 | + { pattern: /unsupported ACP protocol version/, key: 'error.protocol' }, | ||
| 34 | + { pattern: /no answer to initialize/, key: 'error.noAnswer' }, | ||
| 35 | + { pattern: /the agent stopped/, key: 'error.agentStopped' }, | ||
| 36 | + { pattern: /unknown agent:?\s*(\S*)/, key: 'error.unknownAgent', groups: ['agent'] }, | ||
| 37 | + { pattern: /the history was written by a newer Sidekicks/, key: 'error.newerHistory' }, | ||
| 38 | +] | ||
| 39 | + | ||
| 40 | +/** | ||
| 41 | + * The human message for a technical error, or null when it is not a known one. | ||
| 42 | + * | ||
| 43 | + * @example | ||
| 44 | + * explain('start agent alice: exec: "mm": executable file not found in $PATH') | ||
| 45 | + * // { key: 'error.programNotFound', vars: { program: 'mm' } } | ||
| 46 | + */ | ||
| 47 | +export function explain(raw: string): Explanation | null { | ||
| 48 | + for (const rule of rules) { | ||
| 49 | + const match = rule.pattern.exec(raw) | ||
| 50 | + if (!match) continue | ||
| 51 | + const vars: Record<string, string> = {} | ||
| 52 | + // Alternatives may capture into different groups: take the first non-empty one per name. | ||
| 53 | + const captured = match.slice(1).filter((value) => value !== undefined) | ||
| 54 | + ;(rule.groups ?? []).forEach((name, index) => (vars[name] = captured[index] ?? '')) | ||
| 55 | + return { key: rule.key, vars } | ||
| 56 | + } | ||
| 57 | + return null | ||
| 58 | +} | ||
modified
frontend/src/lib/i18n/messages.ts +167 -12 | @@ -19,7 +19,7 @@ export const en = { | ||
| 19 | 19 | 'agent.state.busy': 'busy', |
| 20 | 20 | 'agent.state.error': 'error', |
| 21 | 21 | 'agent.outdated': ' · restart to apply changes', |
| 22 | - 'agents.empty': 'No agent yet. Add one in Settings.', | |
| 22 | + 'agents.empty': 'No agent yet.', | |
| 23 | 23 | 'agent.start': 'Start {agent}', |
| 24 | 24 | 'agent.restart': 'Restart {agent}', |
| 25 | 25 | 'agent.stop': 'Stop {agent}', |
| @@ -59,8 +59,6 @@ export const en = { | ||
| 59 | 59 | 'conversation.stuck': '{agent} is going in circles: {count} tools failed in a row.', |
| 60 | 60 | 'conversation.stop': '■ Stop {agent}', |
| 61 | 61 | 'conversation.placeholder': 'Write to {agent}…', |
| 62 | - 'conversation.noAgents': 'Start by adding an agent to the configuration (Settings panel).', | |
| 63 | - 'conversation.pickAgent': 'Pick a channel, or click an agent to talk with it directly.', | |
| 64 | 62 | 'conversation.channelEmpty': 'Mention an agent with @ to bring it into #{channel}. {description}', |
| 65 | 63 | 'conversation.channelPlaceholder': 'Write in #{channel} — @ to mention an agent, / for commands', |
| 66 | 64 | 'conversation.answeringAgent': '{agent} is answering…', |
| @@ -92,7 +90,7 @@ export const en = { | ||
| 92 | 90 | 'message.stop.max_tokens': 'Answer cut: the agent reached its length limit.', |
| 93 | 91 | 'message.stop.max_turn_requests': 'Answer cut: the agent reached its maximum number of steps.', |
| 94 | 92 | 'message.stop.refusal': 'The agent refused to answer.', |
| 95 | - 'message.error': 'The answer ended with an error: {error}', | |
| 93 | + 'message.error': 'The answer ended with an error.', | |
| 96 | 94 | 'message.notSent': 'Message not sent (answer stopped).', |
| 97 | 95 | 'system.agent-joined': '{agent} joined the channel.', |
| 98 | 96 | 'system.agent-left': '{agent} left the channel.', |
| @@ -130,8 +128,23 @@ export const en = { | ||
| 130 | 128 | |
| 131 | 129 | // code blocks |
| 132 | 130 | 'error.dismiss': 'Close this message', |
| 131 | + 'error.details': 'Technical details', | |
| 132 | + 'error.programNotFound': 'The program "{program}" cannot be found. Install it, or give its full path in the agent\'s settings (for example /opt/homebrew/bin/{program}).', | |
| 133 | + 'error.programNotExecutable': '"{program}" cannot be run: it is not executable. In a terminal: chmod +x {program}', | |
| 134 | + 'error.dockerNotRunning': 'Docker is not running. Start Docker Desktop (or the Docker service), then try again.', | |
| 135 | + 'error.containerMissing': 'The container "{box}" does not exist. Create and start it (docker run …), or correct its name in the agent\'s settings.', | |
| 136 | + 'error.containerStopped': 'The container "{box}" is stopped. Start it with: docker start {box}', | |
| 137 | + 'error.sandboxMissing': 'The sbx sandbox "{box}" does not exist. Create it, or correct its name in the agent\'s settings.', | |
| 138 | + 'error.limitReached': 'Already {limit} agents are working, the most allowed at once. Wait for one to finish, or stop one in the Agents panel.', | |
| 139 | + 'error.modelServer': 'The agent cannot reach its model server. Check that it is running (llmman, Ollama…), then try again.', | |
| 140 | + 'error.protocol': 'This agent speaks a version of ACP that Sidekicks does not know. Update the agent or Sidekicks.', | |
| 141 | + 'error.noAnswer': 'The agent did not answer when Sidekicks contacted it. Check that its program speaks ACP (for mm: the -acp argument).', | |
| 142 | + 'error.agentStopped': 'The agent stopped unexpectedly. Its log (📂, then Log) tells why.', | |
| 143 | + 'error.unknownAgent': 'The agent "{agent}" is no longer in the configuration.', | |
| 144 | + 'error.newerHistory': 'The history was written by a newer Sidekicks. Update Sidekicks to read it.', | |
| 133 | 145 | 'code.copy': 'Copy', |
| 134 | 146 | 'code.copied': 'Copied ✓', |
| 147 | + 'message.copy': 'Copy the answer', | |
| 135 | 148 | |
| 136 | 149 | // settings |
| 137 | 150 | 'settings.source.flag': '--config option', |
| @@ -182,10 +195,75 @@ export const en = { | ||
| 182 | 195 | 'workspace.reload': 'Take their version', |
| 183 | 196 | 'workspace.overwrite': 'Keep mine', |
| 184 | 197 | 'workspace.cannotOpen': 'This file cannot be opened here: {error}', |
| 185 | - 'workspace.unavailable': 'The files of {agent} cannot be shown: {problem}', | |
| 198 | + 'workspace.unavailable': 'The files of {agent} cannot be shown.', | |
| 186 | 199 | 'terminal.ended': 'The shell has ended.', |
| 187 | 200 | 'terminal.restart': 'Open a new shell', |
| 188 | - 'terminal.error': 'Cannot open a terminal: {error}', | |
| 201 | + 'terminal.error': 'Cannot open a terminal.', | |
| 202 | + | |
| 203 | + // welcome and the "add an agent" assistant | |
| 204 | + 'welcome.title': 'Welcome to Sidekicks', | |
| 205 | + 'welcome.tagline': 'Talk with AI agents in channels, as you would with colleagues.', | |
| 206 | + 'welcome.step1.title': 'Add an agent', | |
| 207 | + 'welcome.step1.body': 'An assistant that runs on your computer, in Docker or in an sbx sandbox.', | |
| 208 | + 'welcome.step2.title': 'Open a channel', | |
| 209 | + 'welcome.step2.body': '#general is ready. Create others, one per topic.', | |
| 210 | + 'welcome.step3.title': 'Call it with @', | |
| 211 | + 'welcome.step3.body': '"@alice hello": Alice joins the channel and answers you.', | |
| 212 | + 'welcome.addFirst': '+ Add my first agent', | |
| 213 | + 'welcome.openConfig': 'Open a configuration…', | |
| 214 | + 'welcome.configAt': 'Configuration: {path}', | |
| 215 | + 'welcome.pick': 'Pick a channel, or click an agent to talk with it directly.', | |
| 216 | + 'agents.add': '+ Add an agent', | |
| 217 | + 'palette.label': 'Command palette', | |
| 218 | + 'palette.placeholder': 'Go to a channel or an agent, or run an action…', | |
| 219 | + 'palette.none': 'Nothing matches.', | |
| 220 | + 'palette.channel': 'channel', | |
| 221 | + 'palette.direct': 'conversation', | |
| 222 | + 'palette.files': 'files', | |
| 223 | + 'palette.filesOf': 'Files of {agent}', | |
| 224 | + 'action.newChannel': 'New channel', | |
| 225 | + 'action.addAgent': 'Add an agent', | |
| 226 | + 'action.focusComposer': 'Write a message', | |
| 227 | + 'action.leftDock': 'Show or hide channels and agents', | |
| 228 | + 'action.settings': 'Show or hide Settings', | |
| 229 | + 'action.log': 'Show or hide the log', | |
| 230 | + 'action.openConfig': 'Open a configuration…', | |
| 231 | + 'action.palette': 'Command palette', | |
| 232 | + 'assistant.title': 'Add an agent', | |
| 233 | + 'assistant.intro': 'Sidekicks writes the agent into your configuration for you. You can change it later in Settings.', | |
| 234 | + 'assistant.who': 'Who is it?', | |
| 235 | + 'assistant.agentTitle': 'Name shown', | |
| 236 | + 'assistant.agentTitlePlaceholder': 'Alice (assistant)', | |
| 237 | + 'assistant.name': 'Name used with @', | |
| 238 | + 'assistant.nameHint': 'Lowercase letters, digits, - and _; it starts with a letter.', | |
| 239 | + 'assistant.icon': 'Icon', | |
| 240 | + 'assistant.description': 'What it does', | |
| 241 | + 'assistant.descriptionPlaceholder': 'Answers simple questions', | |
| 242 | + 'assistant.where': 'Where does it run?', | |
| 243 | + 'assistant.local': 'On this computer', | |
| 244 | + 'assistant.container': 'In a Docker container', | |
| 245 | + 'assistant.sbx': 'In an sbx sandbox', | |
| 246 | + 'assistant.containerName': 'Container name', | |
| 247 | + 'assistant.sandboxName': 'Sandbox name', | |
| 248 | + 'assistant.boxHint': 'It must be running, with the agent\'s folder mounted at the same path.', | |
| 249 | + 'assistant.how': 'How is it started?', | |
| 250 | + 'assistant.program': 'Program', | |
| 251 | + 'assistant.programPlaceholder': 'mm', | |
| 252 | + 'assistant.programHint': 'The agent\'s program, as you would type it in a terminal. It must speak ACP.', | |
| 253 | + 'assistant.arguments': 'Arguments', | |
| 254 | + 'assistant.argumentsPlaceholder': '-acp -config agent.yaml', | |
| 255 | + 'assistant.workspace': 'Agent\'s folder', | |
| 256 | + 'assistant.workspaceHint': 'The agent works there; it is created if it does not exist.', | |
| 257 | + 'assistant.choose': 'Choose…', | |
| 258 | + 'assistant.add': 'Add the agent', | |
| 259 | + 'assistant.cancel': 'Cancel', | |
| 260 | + 'assistant.adding': 'Adding…', | |
| 261 | + 'assistant.missing.name': 'Give the agent a name.', | |
| 262 | + 'assistant.missing.nameFormat': 'The name used with @ may only hold lowercase letters, digits, - and _, and starts with a letter.', | |
| 263 | + 'assistant.missing.program': 'Say which program starts the agent.', | |
| 264 | + 'assistant.missing.workspace': 'Choose the agent\'s folder.', | |
| 265 | + 'assistant.missing.box': 'Give the name of the container or sandbox.', | |
| 266 | + 'assistant.refused': 'The agent was not added:', | |
| 189 | 267 | } as const |
| 190 | 268 | |
| 191 | 269 | export type MessageKey = keyof typeof en |
| @@ -203,7 +281,7 @@ export const fr: Record<MessageKey, string> = { | ||
| 203 | 281 | 'agent.state.busy': 'occupé', |
| 204 | 282 | 'agent.state.error': 'erreur', |
| 205 | 283 | 'agent.outdated': ' · à redémarrer', |
| 206 | - 'agents.empty': 'Aucun agent. Ajoutez-en un dans Settings.', | |
| 284 | + 'agents.empty': 'Aucun agent pour le moment.', | |
| 207 | 285 | 'agent.start': 'Démarrer {agent}', |
| 208 | 286 | 'agent.restart': 'Redémarrer {agent}', |
| 209 | 287 | 'agent.stop': 'Arrêter {agent}', |
| @@ -239,8 +317,6 @@ export const fr: Record<MessageKey, string> = { | ||
| 239 | 317 | 'conversation.stuck': "{agent} tourne en rond : {count} outils ont échoué d'affilée.", |
| 240 | 318 | 'conversation.stop': '■ Arrêter {agent}', |
| 241 | 319 | 'conversation.placeholder': 'Écrivez à {agent}…', |
| 242 | - 'conversation.noAgents': 'Commencez par ajouter un agent dans la configuration (panneau Settings).', | |
| 243 | - 'conversation.pickAgent': 'Choisissez un channel, ou cliquez sur un agent pour lui parler directement.', | |
| 244 | 320 | 'conversation.channelEmpty': 'Mentionnez un agent avec @ pour le faire venir dans #{channel}. {description}', |
| 245 | 321 | 'conversation.channelPlaceholder': 'Écrivez dans #{channel} — @ pour mentionner un agent, / pour les commandes', |
| 246 | 322 | 'conversation.answeringAgent': '{agent} répond…', |
| @@ -270,7 +346,7 @@ export const fr: Record<MessageKey, string> = { | ||
| 270 | 346 | 'message.stop.max_tokens': "Réponse coupée : l'agent a atteint sa limite de longueur.", |
| 271 | 347 | 'message.stop.max_turn_requests': "Réponse coupée : l'agent a atteint son nombre maximal d'étapes.", |
| 272 | 348 | 'message.stop.refusal': "L'agent a refusé de répondre.", |
| 273 | - 'message.error': "La réponse s'est terminée sur une erreur : {error}", | |
| 349 | + 'message.error': "La réponse s'est terminée sur une erreur.", | |
| 274 | 350 | 'message.notSent': 'Message non envoyé (réponse arrêtée).', |
| 275 | 351 | 'system.agent-joined': '{agent} a rejoint le channel.', |
| 276 | 352 | 'system.agent-left': '{agent} a quitté le channel.', |
| @@ -305,8 +381,23 @@ export const fr: Record<MessageKey, string> = { | ||
| 305 | 381 | 'permission.details': 'Détails techniques', |
| 306 | 382 | |
| 307 | 383 | 'error.dismiss': 'Fermer ce message', |
| 384 | + 'error.details': 'Détails techniques', | |
| 385 | + 'error.programNotFound': "Le programme « {program} » est introuvable. Installez-le, ou indiquez son chemin complet dans les réglages de l'agent (par exemple /opt/homebrew/bin/{program}).", | |
| 386 | + 'error.programNotExecutable': "« {program} » ne peut pas être lancé : il n'est pas exécutable. Dans un terminal : chmod +x {program}", | |
| 387 | + 'error.dockerNotRunning': "Docker n'est pas démarré. Lancez Docker Desktop (ou le service Docker), puis réessayez.", | |
| 388 | + 'error.containerMissing': "Le conteneur « {box} » n'existe pas. Créez-le et démarrez-le (docker run …), ou corrigez son nom dans les réglages de l'agent.", | |
| 389 | + 'error.containerStopped': 'Le conteneur « {box} » est arrêté. Démarrez-le avec : docker start {box}', | |
| 390 | + 'error.sandboxMissing': "La sandbox sbx « {box} » n'existe pas. Créez-la, ou corrigez son nom dans les réglages de l'agent.", | |
| 391 | + 'error.limitReached': "Déjà {limit} agents travaillent, le maximum autorisé en même temps. Attendez qu'un agent ait fini, ou arrêtez-en un dans le panneau Agents.", | |
| 392 | + 'error.modelServer': "L'agent n'arrive pas à joindre son serveur de modèles. Vérifiez qu'il tourne (llmman, Ollama…), puis réessayez.", | |
| 393 | + 'error.protocol': "Cet agent parle une version d'ACP que Sidekicks ne connaît pas. Mettez à jour l'agent ou Sidekicks.", | |
| 394 | + 'error.noAnswer': "L'agent n'a pas répondu quand Sidekicks l'a contacté. Vérifiez que son programme parle ACP (pour mm : l'argument -acp).", | |
| 395 | + 'error.agentStopped': "L'agent s'est arrêté de façon inattendue. Son journal (📂, puis Journal) en donne la raison.", | |
| 396 | + 'error.unknownAgent': "L'agent « {agent} » n'est plus dans la configuration.", | |
| 397 | + 'error.newerHistory': "L'historique a été écrit par un Sidekicks plus récent. Mettez Sidekicks à jour pour le lire.", | |
| 308 | 398 | 'code.copy': 'Copier', |
| 309 | 399 | 'code.copied': 'Copié ✓', |
| 400 | + 'message.copy': 'Copier la réponse', | |
| 310 | 401 | |
| 311 | 402 | 'settings.source.flag': 'option --config', |
| 312 | 403 | 'settings.source.environment': 'variable SIDEKICKS_CONFIG', |
| @@ -356,8 +447,72 @@ export const fr: Record<MessageKey, string> = { | ||
| 356 | 447 | 'workspace.reload': 'Prendre sa version', |
| 357 | 448 | 'workspace.overwrite': 'Garder la mienne', |
| 358 | 449 | 'workspace.cannotOpen': "Ce fichier ne peut pas être ouvert ici : {error}", |
| 359 | - 'workspace.unavailable': "Les fichiers de {agent} ne peuvent pas être affichés : {problem}", | |
| 450 | + 'workspace.unavailable': 'Les fichiers de {agent} ne peuvent pas être affichés.', | |
| 360 | 451 | 'terminal.ended': 'Le shell est terminé.', |
| 361 | 452 | 'terminal.restart': 'Ouvrir un nouveau shell', |
| 362 | - 'terminal.error': "Impossible d'ouvrir un terminal : {error}", | |
| 453 | + 'terminal.error': "Impossible d'ouvrir un terminal.", | |
| 454 | + | |
| 455 | + 'welcome.title': 'Bienvenue dans Sidekicks', | |
| 456 | + 'welcome.tagline': "Discutez avec des agents d'IA dans des channels, comme avec des collègues.", | |
| 457 | + 'welcome.step1.title': 'Ajoutez un agent', | |
| 458 | + 'welcome.step1.body': 'Un assistant qui tourne sur votre ordinateur, dans Docker ou dans une sandbox sbx.', | |
| 459 | + 'welcome.step2.title': 'Ouvrez un channel', | |
| 460 | + 'welcome.step2.body': "#general est prêt. Créez-en d'autres, un par sujet.", | |
| 461 | + 'welcome.step3.title': 'Appelez-le avec @', | |
| 462 | + 'welcome.step3.body': '« @alice bonjour » : Alice rejoint le channel et vous répond.', | |
| 463 | + 'welcome.addFirst': '+ Ajouter mon premier agent', | |
| 464 | + 'welcome.openConfig': 'Ouvrir une configuration…', | |
| 465 | + 'welcome.configAt': 'Configuration : {path}', | |
| 466 | + 'welcome.pick': 'Choisissez un channel, ou cliquez sur un agent pour lui parler directement.', | |
| 467 | + 'agents.add': '+ Ajouter un agent', | |
| 468 | + 'palette.label': 'Palette de commandes', | |
| 469 | + 'palette.placeholder': 'Aller à un channel ou un agent, ou lancer une action…', | |
| 470 | + 'palette.none': 'Aucun résultat.', | |
| 471 | + 'palette.channel': 'channel', | |
| 472 | + 'palette.direct': 'conversation', | |
| 473 | + 'palette.files': 'fichiers', | |
| 474 | + 'palette.filesOf': 'Fichiers de {agent}', | |
| 475 | + 'action.newChannel': 'Nouveau channel', | |
| 476 | + 'action.addAgent': 'Ajouter un agent', | |
| 477 | + 'action.focusComposer': 'Écrire un message', | |
| 478 | + 'action.leftDock': 'Afficher ou masquer channels et agents', | |
| 479 | + 'action.settings': 'Afficher ou masquer Settings', | |
| 480 | + 'action.log': 'Afficher ou masquer le journal', | |
| 481 | + 'action.openConfig': 'Ouvrir une configuration…', | |
| 482 | + 'action.palette': 'Palette de commandes', | |
| 483 | + 'assistant.title': 'Ajouter un agent', | |
| 484 | + 'assistant.intro': "Sidekicks écrit l'agent dans votre configuration à votre place. Vous pourrez le modifier dans Settings.", | |
| 485 | + 'assistant.who': 'Qui est-ce ?', | |
| 486 | + 'assistant.agentTitle': 'Nom affiché', | |
| 487 | + 'assistant.agentTitlePlaceholder': 'Alice (assistante)', | |
| 488 | + 'assistant.name': 'Nom utilisé avec @', | |
| 489 | + 'assistant.nameHint': 'Minuscules, chiffres, - et _ ; commence par une lettre.', | |
| 490 | + 'assistant.icon': 'Icône', | |
| 491 | + 'assistant.description': 'Ce qu\'il fait', | |
| 492 | + 'assistant.descriptionPlaceholder': 'Répond aux questions simples', | |
| 493 | + 'assistant.where': 'Où tourne-t-il ?', | |
| 494 | + 'assistant.local': 'Sur cet ordinateur', | |
| 495 | + 'assistant.container': 'Dans un conteneur Docker', | |
| 496 | + 'assistant.sbx': 'Dans une sandbox sbx', | |
| 497 | + 'assistant.containerName': 'Nom du conteneur', | |
| 498 | + 'assistant.sandboxName': 'Nom de la sandbox', | |
| 499 | + 'assistant.boxHint': "Elle doit être démarrée, avec le dossier de l'agent monté au même chemin.", | |
| 500 | + 'assistant.how': 'Comment le démarrer ?', | |
| 501 | + 'assistant.program': 'Programme', | |
| 502 | + 'assistant.programPlaceholder': 'mm', | |
| 503 | + 'assistant.programHint': "Le programme de l'agent, tel que vous le taperiez dans un terminal. Il doit parler ACP.", | |
| 504 | + 'assistant.arguments': 'Arguments', | |
| 505 | + 'assistant.argumentsPlaceholder': '-acp -config agent.yaml', | |
| 506 | + 'assistant.workspace': "Dossier de l'agent", | |
| 507 | + 'assistant.workspaceHint': "L'agent y travaille ; il est créé s'il n'existe pas.", | |
| 508 | + 'assistant.choose': 'Choisir…', | |
| 509 | + 'assistant.add': "Ajouter l'agent", | |
| 510 | + 'assistant.cancel': 'Annuler', | |
| 511 | + 'assistant.adding': 'Ajout…', | |
| 512 | + 'assistant.missing.name': "Donnez un nom à l'agent.", | |
| 513 | + 'assistant.missing.nameFormat': 'Le nom utilisé avec @ ne contient que des minuscules, des chiffres, - et _, et commence par une lettre.', | |
| 514 | + 'assistant.missing.program': "Indiquez le programme qui démarre l'agent.", | |
| 515 | + 'assistant.missing.workspace': "Choisissez le dossier de l'agent.", | |
| 516 | + 'assistant.missing.box': 'Donnez le nom du conteneur ou de la sandbox.', | |
| 517 | + 'assistant.refused': "L'agent n'a pas été ajouté :", | |
| 363 | 518 | } |
| @@ -19,7 +19,7 @@ export const en = { | |||
| 19 | 'agent.state.busy': 'busy', | 19 | 'agent.state.busy': 'busy', |
| 20 | 'agent.state.error': 'error', | 20 | 'agent.state.error': 'error', |
| 21 | 'agent.outdated': ' · restart to apply changes', | 21 | 'agent.outdated': ' · restart to apply changes', |
| 22 | - 'agents.empty': 'No agent yet. Add one in Settings.', | 22 | + 'agents.empty': 'No agent yet.', |
| 23 | 'agent.start': 'Start {agent}', | 23 | 'agent.start': 'Start {agent}', |
| 24 | 'agent.restart': 'Restart {agent}', | 24 | 'agent.restart': 'Restart {agent}', |
| 25 | 'agent.stop': 'Stop {agent}', | 25 | 'agent.stop': 'Stop {agent}', |
| @@ -59,8 +59,6 @@ export const en = { | |||
| 59 | 'conversation.stuck': '{agent} is going in circles: {count} tools failed in a row.', | 59 | 'conversation.stuck': '{agent} is going in circles: {count} tools failed in a row.', |
| 60 | 'conversation.stop': '■ Stop {agent}', | 60 | 'conversation.stop': '■ Stop {agent}', |
| 61 | 'conversation.placeholder': 'Write to {agent}…', | 61 | 'conversation.placeholder': 'Write to {agent}…', |
| 62 | - 'conversation.noAgents': 'Start by adding an agent to the configuration (Settings panel).', | ||
| 63 | - 'conversation.pickAgent': 'Pick a channel, or click an agent to talk with it directly.', | ||
| 64 | 'conversation.channelEmpty': 'Mention an agent with @ to bring it into #{channel}. {description}', | 62 | 'conversation.channelEmpty': 'Mention an agent with @ to bring it into #{channel}. {description}', |
| 65 | 'conversation.channelPlaceholder': 'Write in #{channel} — @ to mention an agent, / for commands', | 63 | 'conversation.channelPlaceholder': 'Write in #{channel} — @ to mention an agent, / for commands', |
| 66 | 'conversation.answeringAgent': '{agent} is answering…', | 64 | 'conversation.answeringAgent': '{agent} is answering…', |
| @@ -92,7 +90,7 @@ export const en = { | |||
| 92 | 'message.stop.max_tokens': 'Answer cut: the agent reached its length limit.', | 90 | 'message.stop.max_tokens': 'Answer cut: the agent reached its length limit.', |
| 93 | 'message.stop.max_turn_requests': 'Answer cut: the agent reached its maximum number of steps.', | 91 | 'message.stop.max_turn_requests': 'Answer cut: the agent reached its maximum number of steps.', |
| 94 | 'message.stop.refusal': 'The agent refused to answer.', | 92 | 'message.stop.refusal': 'The agent refused to answer.', |
| 95 | - 'message.error': 'The answer ended with an error: {error}', | 93 | + 'message.error': 'The answer ended with an error.', |
| 96 | 'message.notSent': 'Message not sent (answer stopped).', | 94 | 'message.notSent': 'Message not sent (answer stopped).', |
| 97 | 'system.agent-joined': '{agent} joined the channel.', | 95 | 'system.agent-joined': '{agent} joined the channel.', |
| 98 | 'system.agent-left': '{agent} left the channel.', | 96 | 'system.agent-left': '{agent} left the channel.', |
| @@ -130,8 +128,23 @@ export const en = { | |||
| 130 | 128 | ||
| 131 | // code blocks | 129 | // code blocks |
| 132 | 'error.dismiss': 'Close this message', | 130 | 'error.dismiss': 'Close this message', |
| 131 | + 'error.details': 'Technical details', | ||
| 132 | + 'error.programNotFound': 'The program "{program}" cannot be found. Install it, or give its full path in the agent\'s settings (for example /opt/homebrew/bin/{program}).', | ||
| 133 | + 'error.programNotExecutable': '"{program}" cannot be run: it is not executable. In a terminal: chmod +x {program}', | ||
| 134 | + 'error.dockerNotRunning': 'Docker is not running. Start Docker Desktop (or the Docker service), then try again.', | ||
| 135 | + 'error.containerMissing': 'The container "{box}" does not exist. Create and start it (docker run …), or correct its name in the agent\'s settings.', | ||
| 136 | + 'error.containerStopped': 'The container "{box}" is stopped. Start it with: docker start {box}', | ||
| 137 | + 'error.sandboxMissing': 'The sbx sandbox "{box}" does not exist. Create it, or correct its name in the agent\'s settings.', | ||
| 138 | + 'error.limitReached': 'Already {limit} agents are working, the most allowed at once. Wait for one to finish, or stop one in the Agents panel.', | ||
| 139 | + 'error.modelServer': 'The agent cannot reach its model server. Check that it is running (llmman, Ollama…), then try again.', | ||
| 140 | + 'error.protocol': 'This agent speaks a version of ACP that Sidekicks does not know. Update the agent or Sidekicks.', | ||
| 141 | + 'error.noAnswer': 'The agent did not answer when Sidekicks contacted it. Check that its program speaks ACP (for mm: the -acp argument).', | ||
| 142 | + 'error.agentStopped': 'The agent stopped unexpectedly. Its log (📂, then Log) tells why.', | ||
| 143 | + 'error.unknownAgent': 'The agent "{agent}" is no longer in the configuration.', | ||
| 144 | + 'error.newerHistory': 'The history was written by a newer Sidekicks. Update Sidekicks to read it.', | ||
| 133 | 'code.copy': 'Copy', | 145 | 'code.copy': 'Copy', |
| 134 | 'code.copied': 'Copied ✓', | 146 | 'code.copied': 'Copied ✓', |
| 147 | + 'message.copy': 'Copy the answer', | ||
| 135 | 148 | ||
| 136 | // settings | 149 | // settings |
| 137 | 'settings.source.flag': '--config option', | 150 | 'settings.source.flag': '--config option', |
| @@ -182,10 +195,75 @@ export const en = { | |||
| 182 | 'workspace.reload': 'Take their version', | 195 | 'workspace.reload': 'Take their version', |
| 183 | 'workspace.overwrite': 'Keep mine', | 196 | 'workspace.overwrite': 'Keep mine', |
| 184 | 'workspace.cannotOpen': 'This file cannot be opened here: {error}', | 197 | 'workspace.cannotOpen': 'This file cannot be opened here: {error}', |
| 185 | - 'workspace.unavailable': 'The files of {agent} cannot be shown: {problem}', | 198 | + 'workspace.unavailable': 'The files of {agent} cannot be shown.', |
| 186 | 'terminal.ended': 'The shell has ended.', | 199 | 'terminal.ended': 'The shell has ended.', |
| 187 | 'terminal.restart': 'Open a new shell', | 200 | 'terminal.restart': 'Open a new shell', |
| 188 | - 'terminal.error': 'Cannot open a terminal: {error}', | 201 | + 'terminal.error': 'Cannot open a terminal.', |
| 202 | + | ||
| 203 | + // welcome and the "add an agent" assistant | ||
| 204 | + 'welcome.title': 'Welcome to Sidekicks', | ||
| 205 | + 'welcome.tagline': 'Talk with AI agents in channels, as you would with colleagues.', | ||
| 206 | + 'welcome.step1.title': 'Add an agent', | ||
| 207 | + 'welcome.step1.body': 'An assistant that runs on your computer, in Docker or in an sbx sandbox.', | ||
| 208 | + 'welcome.step2.title': 'Open a channel', | ||
| 209 | + 'welcome.step2.body': '#general is ready. Create others, one per topic.', | ||
| 210 | + 'welcome.step3.title': 'Call it with @', | ||
| 211 | + 'welcome.step3.body': '"@alice hello": Alice joins the channel and answers you.', | ||
| 212 | + 'welcome.addFirst': '+ Add my first agent', | ||
| 213 | + 'welcome.openConfig': 'Open a configuration…', | ||
| 214 | + 'welcome.configAt': 'Configuration: {path}', | ||
| 215 | + 'welcome.pick': 'Pick a channel, or click an agent to talk with it directly.', | ||
| 216 | + 'agents.add': '+ Add an agent', | ||
| 217 | + 'palette.label': 'Command palette', | ||
| 218 | + 'palette.placeholder': 'Go to a channel or an agent, or run an action…', | ||
| 219 | + 'palette.none': 'Nothing matches.', | ||
| 220 | + 'palette.channel': 'channel', | ||
| 221 | + 'palette.direct': 'conversation', | ||
| 222 | + 'palette.files': 'files', | ||
| 223 | + 'palette.filesOf': 'Files of {agent}', | ||
| 224 | + 'action.newChannel': 'New channel', | ||
| 225 | + 'action.addAgent': 'Add an agent', | ||
| 226 | + 'action.focusComposer': 'Write a message', | ||
| 227 | + 'action.leftDock': 'Show or hide channels and agents', | ||
| 228 | + 'action.settings': 'Show or hide Settings', | ||
| 229 | + 'action.log': 'Show or hide the log', | ||
| 230 | + 'action.openConfig': 'Open a configuration…', | ||
| 231 | + 'action.palette': 'Command palette', | ||
| 232 | + 'assistant.title': 'Add an agent', | ||
| 233 | + 'assistant.intro': 'Sidekicks writes the agent into your configuration for you. You can change it later in Settings.', | ||
| 234 | + 'assistant.who': 'Who is it?', | ||
| 235 | + 'assistant.agentTitle': 'Name shown', | ||
| 236 | + 'assistant.agentTitlePlaceholder': 'Alice (assistant)', | ||
| 237 | + 'assistant.name': 'Name used with @', | ||
| 238 | + 'assistant.nameHint': 'Lowercase letters, digits, - and _; it starts with a letter.', | ||
| 239 | + 'assistant.icon': 'Icon', | ||
| 240 | + 'assistant.description': 'What it does', | ||
| 241 | + 'assistant.descriptionPlaceholder': 'Answers simple questions', | ||
| 242 | + 'assistant.where': 'Where does it run?', | ||
| 243 | + 'assistant.local': 'On this computer', | ||
| 244 | + 'assistant.container': 'In a Docker container', | ||
| 245 | + 'assistant.sbx': 'In an sbx sandbox', | ||
| 246 | + 'assistant.containerName': 'Container name', | ||
| 247 | + 'assistant.sandboxName': 'Sandbox name', | ||
| 248 | + 'assistant.boxHint': 'It must be running, with the agent\'s folder mounted at the same path.', | ||
| 249 | + 'assistant.how': 'How is it started?', | ||
| 250 | + 'assistant.program': 'Program', | ||
| 251 | + 'assistant.programPlaceholder': 'mm', | ||
| 252 | + 'assistant.programHint': 'The agent\'s program, as you would type it in a terminal. It must speak ACP.', | ||
| 253 | + 'assistant.arguments': 'Arguments', | ||
| 254 | + 'assistant.argumentsPlaceholder': '-acp -config agent.yaml', | ||
| 255 | + 'assistant.workspace': 'Agent\'s folder', | ||
| 256 | + 'assistant.workspaceHint': 'The agent works there; it is created if it does not exist.', | ||
| 257 | + 'assistant.choose': 'Choose…', | ||
| 258 | + 'assistant.add': 'Add the agent', | ||
| 259 | + 'assistant.cancel': 'Cancel', | ||
| 260 | + 'assistant.adding': 'Adding…', | ||
| 261 | + 'assistant.missing.name': 'Give the agent a name.', | ||
| 262 | + 'assistant.missing.nameFormat': 'The name used with @ may only hold lowercase letters, digits, - and _, and starts with a letter.', | ||
| 263 | + 'assistant.missing.program': 'Say which program starts the agent.', | ||
| 264 | + 'assistant.missing.workspace': 'Choose the agent\'s folder.', | ||
| 265 | + 'assistant.missing.box': 'Give the name of the container or sandbox.', | ||
| 266 | + 'assistant.refused': 'The agent was not added:', | ||
| 189 | } as const | 267 | } as const |
| 190 | 268 | ||
| 191 | export type MessageKey = keyof typeof en | 269 | export type MessageKey = keyof typeof en |
| @@ -203,7 +281,7 @@ export const fr: Record<MessageKey, string> = { | |||
| 203 | 'agent.state.busy': 'occupé', | 281 | 'agent.state.busy': 'occupé', |
| 204 | 'agent.state.error': 'erreur', | 282 | 'agent.state.error': 'erreur', |
| 205 | 'agent.outdated': ' · à redémarrer', | 283 | 'agent.outdated': ' · à redémarrer', |
| 206 | - 'agents.empty': 'Aucun agent. Ajoutez-en un dans Settings.', | 284 | + 'agents.empty': 'Aucun agent pour le moment.', |
| 207 | 'agent.start': 'Démarrer {agent}', | 285 | 'agent.start': 'Démarrer {agent}', |
| 208 | 'agent.restart': 'Redémarrer {agent}', | 286 | 'agent.restart': 'Redémarrer {agent}', |
| 209 | 'agent.stop': 'Arrêter {agent}', | 287 | 'agent.stop': 'Arrêter {agent}', |
| @@ -239,8 +317,6 @@ export const fr: Record<MessageKey, string> = { | |||
| 239 | 'conversation.stuck': "{agent} tourne en rond : {count} outils ont échoué d'affilée.", | 317 | 'conversation.stuck': "{agent} tourne en rond : {count} outils ont échoué d'affilée.", |
| 240 | 'conversation.stop': '■ Arrêter {agent}', | 318 | 'conversation.stop': '■ Arrêter {agent}', |
| 241 | 'conversation.placeholder': 'Écrivez à {agent}…', | 319 | 'conversation.placeholder': 'Écrivez à {agent}…', |
| 242 | - 'conversation.noAgents': 'Commencez par ajouter un agent dans la configuration (panneau Settings).', | ||
| 243 | - 'conversation.pickAgent': 'Choisissez un channel, ou cliquez sur un agent pour lui parler directement.', | ||
| 244 | 'conversation.channelEmpty': 'Mentionnez un agent avec @ pour le faire venir dans #{channel}. {description}', | 320 | 'conversation.channelEmpty': 'Mentionnez un agent avec @ pour le faire venir dans #{channel}. {description}', |
| 245 | 'conversation.channelPlaceholder': 'Écrivez dans #{channel} — @ pour mentionner un agent, / pour les commandes', | 321 | 'conversation.channelPlaceholder': 'Écrivez dans #{channel} — @ pour mentionner un agent, / pour les commandes', |
| 246 | 'conversation.answeringAgent': '{agent} répond…', | 322 | 'conversation.answeringAgent': '{agent} répond…', |
| @@ -270,7 +346,7 @@ export const fr: Record<MessageKey, string> = { | |||
| 270 | 'message.stop.max_tokens': "Réponse coupée : l'agent a atteint sa limite de longueur.", | 346 | 'message.stop.max_tokens': "Réponse coupée : l'agent a atteint sa limite de longueur.", |
| 271 | 'message.stop.max_turn_requests': "Réponse coupée : l'agent a atteint son nombre maximal d'étapes.", | 347 | 'message.stop.max_turn_requests': "Réponse coupée : l'agent a atteint son nombre maximal d'étapes.", |
| 272 | 'message.stop.refusal': "L'agent a refusé de répondre.", | 348 | 'message.stop.refusal': "L'agent a refusé de répondre.", |
| 273 | - 'message.error': "La réponse s'est terminée sur une erreur : {error}", | 349 | + 'message.error': "La réponse s'est terminée sur une erreur.", |
| 274 | 'message.notSent': 'Message non envoyé (réponse arrêtée).', | 350 | 'message.notSent': 'Message non envoyé (réponse arrêtée).', |
| 275 | 'system.agent-joined': '{agent} a rejoint le channel.', | 351 | 'system.agent-joined': '{agent} a rejoint le channel.', |
| 276 | 'system.agent-left': '{agent} a quitté le channel.', | 352 | 'system.agent-left': '{agent} a quitté le channel.', |
| @@ -305,8 +381,23 @@ export const fr: Record<MessageKey, string> = { | |||
| 305 | 'permission.details': 'Détails techniques', | 381 | 'permission.details': 'Détails techniques', |
| 306 | 382 | ||
| 307 | 'error.dismiss': 'Fermer ce message', | 383 | 'error.dismiss': 'Fermer ce message', |
| 384 | + 'error.details': 'Détails techniques', | ||
| 385 | + 'error.programNotFound': "Le programme « {program} » est introuvable. Installez-le, ou indiquez son chemin complet dans les réglages de l'agent (par exemple /opt/homebrew/bin/{program}).", | ||
| 386 | + 'error.programNotExecutable': "« {program} » ne peut pas être lancé : il n'est pas exécutable. Dans un terminal : chmod +x {program}", | ||
| 387 | + 'error.dockerNotRunning': "Docker n'est pas démarré. Lancez Docker Desktop (ou le service Docker), puis réessayez.", | ||
| 388 | + 'error.containerMissing': "Le conteneur « {box} » n'existe pas. Créez-le et démarrez-le (docker run …), ou corrigez son nom dans les réglages de l'agent.", | ||
| 389 | + 'error.containerStopped': 'Le conteneur « {box} » est arrêté. Démarrez-le avec : docker start {box}', | ||
| 390 | + 'error.sandboxMissing': "La sandbox sbx « {box} » n'existe pas. Créez-la, ou corrigez son nom dans les réglages de l'agent.", | ||
| 391 | + 'error.limitReached': "Déjà {limit} agents travaillent, le maximum autorisé en même temps. Attendez qu'un agent ait fini, ou arrêtez-en un dans le panneau Agents.", | ||
| 392 | + 'error.modelServer': "L'agent n'arrive pas à joindre son serveur de modèles. Vérifiez qu'il tourne (llmman, Ollama…), puis réessayez.", | ||
| 393 | + 'error.protocol': "Cet agent parle une version d'ACP que Sidekicks ne connaît pas. Mettez à jour l'agent ou Sidekicks.", | ||
| 394 | + 'error.noAnswer': "L'agent n'a pas répondu quand Sidekicks l'a contacté. Vérifiez que son programme parle ACP (pour mm : l'argument -acp).", | ||
| 395 | + 'error.agentStopped': "L'agent s'est arrêté de façon inattendue. Son journal (📂, puis Journal) en donne la raison.", | ||
| 396 | + 'error.unknownAgent': "L'agent « {agent} » n'est plus dans la configuration.", | ||
| 397 | + 'error.newerHistory': "L'historique a été écrit par un Sidekicks plus récent. Mettez Sidekicks à jour pour le lire.", | ||
| 308 | 'code.copy': 'Copier', | 398 | 'code.copy': 'Copier', |
| 309 | 'code.copied': 'Copié ✓', | 399 | 'code.copied': 'Copié ✓', |
| 400 | + 'message.copy': 'Copier la réponse', | ||
| 310 | 401 | ||
| 311 | 'settings.source.flag': 'option --config', | 402 | 'settings.source.flag': 'option --config', |
| 312 | 'settings.source.environment': 'variable SIDEKICKS_CONFIG', | 403 | 'settings.source.environment': 'variable SIDEKICKS_CONFIG', |
| @@ -356,8 +447,72 @@ export const fr: Record<MessageKey, string> = { | |||
| 356 | 'workspace.reload': 'Prendre sa version', | 447 | 'workspace.reload': 'Prendre sa version', |
| 357 | 'workspace.overwrite': 'Garder la mienne', | 448 | 'workspace.overwrite': 'Garder la mienne', |
| 358 | 'workspace.cannotOpen': "Ce fichier ne peut pas être ouvert ici : {error}", | 449 | 'workspace.cannotOpen': "Ce fichier ne peut pas être ouvert ici : {error}", |
| 359 | - 'workspace.unavailable': "Les fichiers de {agent} ne peuvent pas être affichés : {problem}", | 450 | + 'workspace.unavailable': 'Les fichiers de {agent} ne peuvent pas être affichés.', |
| 360 | 'terminal.ended': 'Le shell est terminé.', | 451 | 'terminal.ended': 'Le shell est terminé.', |
| 361 | 'terminal.restart': 'Ouvrir un nouveau shell', | 452 | 'terminal.restart': 'Ouvrir un nouveau shell', |
| 362 | - 'terminal.error': "Impossible d'ouvrir un terminal : {error}", | 453 | + 'terminal.error': "Impossible d'ouvrir un terminal.", |
| 454 | + | ||
| 455 | + 'welcome.title': 'Bienvenue dans Sidekicks', | ||
| 456 | + 'welcome.tagline': "Discutez avec des agents d'IA dans des channels, comme avec des collègues.", | ||
| 457 | + 'welcome.step1.title': 'Ajoutez un agent', | ||
| 458 | + 'welcome.step1.body': 'Un assistant qui tourne sur votre ordinateur, dans Docker ou dans une sandbox sbx.', | ||
| 459 | + 'welcome.step2.title': 'Ouvrez un channel', | ||
| 460 | + 'welcome.step2.body': "#general est prêt. Créez-en d'autres, un par sujet.", | ||
| 461 | + 'welcome.step3.title': 'Appelez-le avec @', | ||
| 462 | + 'welcome.step3.body': '« @alice bonjour » : Alice rejoint le channel et vous répond.', | ||
| 463 | + 'welcome.addFirst': '+ Ajouter mon premier agent', | ||
| 464 | + 'welcome.openConfig': 'Ouvrir une configuration…', | ||
| 465 | + 'welcome.configAt': 'Configuration : {path}', | ||
| 466 | + 'welcome.pick': 'Choisissez un channel, ou cliquez sur un agent pour lui parler directement.', | ||
| 467 | + 'agents.add': '+ Ajouter un agent', | ||
| 468 | + 'palette.label': 'Palette de commandes', | ||
| 469 | + 'palette.placeholder': 'Aller à un channel ou un agent, ou lancer une action…', | ||
| 470 | + 'palette.none': 'Aucun résultat.', | ||
| 471 | + 'palette.channel': 'channel', | ||
| 472 | + 'palette.direct': 'conversation', | ||
| 473 | + 'palette.files': 'fichiers', | ||
| 474 | + 'palette.filesOf': 'Fichiers de {agent}', | ||
| 475 | + 'action.newChannel': 'Nouveau channel', | ||
| 476 | + 'action.addAgent': 'Ajouter un agent', | ||
| 477 | + 'action.focusComposer': 'Écrire un message', | ||
| 478 | + 'action.leftDock': 'Afficher ou masquer channels et agents', | ||
| 479 | + 'action.settings': 'Afficher ou masquer Settings', | ||
| 480 | + 'action.log': 'Afficher ou masquer le journal', | ||
| 481 | + 'action.openConfig': 'Ouvrir une configuration…', | ||
| 482 | + 'action.palette': 'Palette de commandes', | ||
| 483 | + 'assistant.title': 'Ajouter un agent', | ||
| 484 | + 'assistant.intro': "Sidekicks écrit l'agent dans votre configuration à votre place. Vous pourrez le modifier dans Settings.", | ||
| 485 | + 'assistant.who': 'Qui est-ce ?', | ||
| 486 | + 'assistant.agentTitle': 'Nom affiché', | ||
| 487 | + 'assistant.agentTitlePlaceholder': 'Alice (assistante)', | ||
| 488 | + 'assistant.name': 'Nom utilisé avec @', | ||
| 489 | + 'assistant.nameHint': 'Minuscules, chiffres, - et _ ; commence par une lettre.', | ||
| 490 | + 'assistant.icon': 'Icône', | ||
| 491 | + 'assistant.description': 'Ce qu\'il fait', | ||
| 492 | + 'assistant.descriptionPlaceholder': 'Répond aux questions simples', | ||
| 493 | + 'assistant.where': 'Où tourne-t-il ?', | ||
| 494 | + 'assistant.local': 'Sur cet ordinateur', | ||
| 495 | + 'assistant.container': 'Dans un conteneur Docker', | ||
| 496 | + 'assistant.sbx': 'Dans une sandbox sbx', | ||
| 497 | + 'assistant.containerName': 'Nom du conteneur', | ||
| 498 | + 'assistant.sandboxName': 'Nom de la sandbox', | ||
| 499 | + 'assistant.boxHint': "Elle doit être démarrée, avec le dossier de l'agent monté au même chemin.", | ||
| 500 | + 'assistant.how': 'Comment le démarrer ?', | ||
| 501 | + 'assistant.program': 'Programme', | ||
| 502 | + 'assistant.programPlaceholder': 'mm', | ||
| 503 | + 'assistant.programHint': "Le programme de l'agent, tel que vous le taperiez dans un terminal. Il doit parler ACP.", | ||
| 504 | + 'assistant.arguments': 'Arguments', | ||
| 505 | + 'assistant.argumentsPlaceholder': '-acp -config agent.yaml', | ||
| 506 | + 'assistant.workspace': "Dossier de l'agent", | ||
| 507 | + 'assistant.workspaceHint': "L'agent y travaille ; il est créé s'il n'existe pas.", | ||
| 508 | + 'assistant.choose': 'Choisir…', | ||
| 509 | + 'assistant.add': "Ajouter l'agent", | ||
| 510 | + 'assistant.cancel': 'Annuler', | ||
| 511 | + 'assistant.adding': 'Ajout…', | ||
| 512 | + 'assistant.missing.name': "Donnez un nom à l'agent.", | ||
| 513 | + 'assistant.missing.nameFormat': 'Le nom utilisé avec @ ne contient que des minuscules, des chiffres, - et _, et commence par une lettre.', | ||
| 514 | + 'assistant.missing.program': "Indiquez le programme qui démarre l'agent.", | ||
| 515 | + 'assistant.missing.workspace': "Choisissez le dossier de l'agent.", | ||
| 516 | + 'assistant.missing.box': 'Donnez le nom du conteneur ou de la sandbox.', | ||
| 517 | + 'assistant.refused': "L'agent n'a pas été ajouté :", | ||
| 363 | } | 518 | } |
added
frontend/src/lib/layout/CommandPalette.svelte +102 -0 | new file mode 100644 | ||
| @@ -0,0 +1,102 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<script lang="ts"> | |
| 3 | + // The command palette (⌘K, issue #35): go to a channel, an agent's | |
| 4 | + // conversation or files, or run an action, without the mouse. | |
| 5 | + // ↑↓ choose, Enter runs, Escape closes. | |
| 6 | + import { t } from '../i18n/index.svelte' | |
| 7 | + import { filterEntries, isMac, shortcutLabel, type Action, type PaletteEntry } from '../shortcuts' | |
| 8 | + import { act, appState, openDirect, openWorkspace, selectChannel } from '../state.svelte' | |
| 9 | + import { ConfigService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' | |
| 10 | + | |
| 11 | + let { run }: { run: (action: Action) => void } = $props() | |
| 12 | + | |
| 13 | + let query = $state('') | |
| 14 | + let selected = $state(0) | |
| 15 | + let input: HTMLInputElement | undefined = $state() | |
| 16 | + const mac = isMac() | |
| 17 | + | |
| 18 | + const actions: Action[] = ['newChannel', 'addAgent', 'focusComposer', 'leftDock', 'settings', 'log'] | |
| 19 | + | |
| 20 | + const entries = $derived.by((): PaletteEntry[] => { | |
| 21 | + return [ | |
| 22 | + ...appState.channels.filter((channel) => !channel.direct).map((channel) => ({ | |
| 23 | + id: `channel:${channel.id}`, label: `# ${channel.name}`, hint: t('palette.channel'), run: () => void selectChannel(channel.id), | |
| 24 | + })), | |
| 25 | + ...appState.agents.map((agent) => ({ | |
| 26 | + id: `agent:${agent.name}`, label: `${agent.icon ? agent.icon + ' ' : ''}${agent.title}`, hint: t('palette.direct'), | |
| 27 | + run: () => void openDirect(agent.name), | |
| 28 | + })), | |
| 29 | + ...appState.agents.map((agent) => ({ | |
| 30 | + id: `files:${agent.name}`, label: t('palette.filesOf', { agent: agent.title }), hint: t('palette.files'), run: () => openWorkspace(agent.name), | |
| 31 | + })), | |
| 32 | + ...actions.map((action) => ({ id: `action:${action}`, label: t(`action.${action}`), hint: shortcutLabel(action, mac), run: () => run(action) })), | |
| 33 | + { id: 'action:openConfig', label: t('action.openConfig'), hint: '', run: () => void act(() => ConfigService.Choose()) }, | |
| 34 | + ] | |
| 35 | + }) | |
| 36 | + const found = $derived(filterEntries(query, entries)) | |
| 37 | + | |
| 38 | + $effect(() => { | |
| 39 | + void query | |
| 40 | + selected = 0 | |
| 41 | + }) | |
| 42 | + $effect(() => input?.focus()) | |
| 43 | + | |
| 44 | + function close() { | |
| 45 | + appState.paletteOpen = false | |
| 46 | + } | |
| 47 | + | |
| 48 | + function choose(entry: PaletteEntry | undefined) { | |
| 49 | + if (!entry) return | |
| 50 | + close() | |
| 51 | + entry.run() | |
| 52 | + } | |
| 53 | + | |
| 54 | + function onKeydown(event: KeyboardEvent) { | |
| 55 | + if (event.key === 'Escape') close() | |
| 56 | + else if (event.key === 'ArrowDown') selected = Math.min(selected + 1, found.length - 1) | |
| 57 | + else if (event.key === 'ArrowUp') selected = Math.max(selected - 1, 0) | |
| 58 | + else if (event.key === 'Enter') choose(found[selected]) | |
| 59 | + else return | |
| 60 | + event.preventDefault() | |
| 61 | + } | |
| 62 | +</script> | |
| 63 | + | |
| 64 | +<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions --> | |
| 65 | +<div class="backdrop" onclick={close}> | |
| 66 | + <!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions --> | |
| 67 | + <div class="palette" role="dialog" aria-modal="true" aria-label={t('palette.label')} tabindex="-1" onclick={(event) => event.stopPropagation()}> | |
| 68 | + <input | |
| 69 | + bind:this={input} | |
| 70 | + bind:value={query} | |
| 71 | + onkeydown={onKeydown} | |
| 72 | + placeholder={t('palette.placeholder')} | |
| 73 | + role="combobox" | |
| 74 | + aria-expanded="true" | |
| 75 | + aria-controls="palette-list" | |
| 76 | + aria-activedescendant={found[selected] ? `palette-${selected}` : undefined} | |
| 77 | + spellcheck="false" | |
| 78 | + /> | |
| 79 | + <ul id="palette-list" role="listbox"> | |
| 80 | + {#each found as entry, index (entry.id)} | |
| 81 | + <li id="palette-{index}" role="option" aria-selected={index === selected} class:selected={index === selected}> | |
| 82 | + <button tabindex="-1" onclick={() => choose(entry)} onmousemove={() => (selected = index)}> | |
| 83 | + <span>{entry.label}</span><span class="hint">{entry.hint}</span> | |
| 84 | + </button> | |
| 85 | + </li> | |
| 86 | + {:else} | |
| 87 | + <li class="none">{t('palette.none')}</li> | |
| 88 | + {/each} | |
| 89 | + </ul> | |
| 90 | + </div> | |
| 91 | +</div> | |
| 92 | + | |
| 93 | +<style> | |
| 94 | + .backdrop { position: fixed; inset: 0; background: rgb(0 0 0 / 0.25); display: flex; justify-content: center; align-items: flex-start; padding-top: 12vh; z-index: 50; } | |
| 95 | + .palette { width: min(560px, calc(100vw - 32px)); background: var(--panel); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 12px 40px rgb(0 0 0 / 0.25); overflow: hidden; } | |
| 96 | + input { width: 100%; box-sizing: border-box; border: none; border-bottom: 1px solid var(--border); padding: 12px 14px; font: inherit; font-size: 15px; background: none; color: var(--text); outline: none; } | |
| 97 | + ul { list-style: none; margin: 0; padding: 6px; max-height: 50vh; overflow-y: auto; } | |
| 98 | + li button { width: 100%; display: flex; justify-content: space-between; gap: 12px; border: none; background: none; padding: 7px 10px; border-radius: 6px; text-align: left; color: var(--text); cursor: pointer; } | |
| 99 | + li.selected button { background: var(--panel-2); outline: 1px solid var(--accent); } | |
| 100 | + .hint { color: var(--muted); font-size: 12px; flex: none; } | |
| 101 | + .none { color: var(--muted); padding: 8px 10px; } | |
| 102 | +</style> | |
| new file mode 100644 | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<script lang="ts"> | ||
| 3 | + // The command palette (⌘K, issue #35): go to a channel, an agent's | ||
| 4 | + // conversation or files, or run an action, without the mouse. | ||
| 5 | + // ↑↓ choose, Enter runs, Escape closes. | ||
| 6 | + import { t } from '../i18n/index.svelte' | ||
| 7 | + import { filterEntries, isMac, shortcutLabel, type Action, type PaletteEntry } from '../shortcuts' | ||
| 8 | + import { act, appState, openDirect, openWorkspace, selectChannel } from '../state.svelte' | ||
| 9 | + import { ConfigService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' | ||
| 10 | + | ||
| 11 | + let { run }: { run: (action: Action) => void } = $props() | ||
| 12 | + | ||
| 13 | + let query = $state('') | ||
| 14 | + let selected = $state(0) | ||
| 15 | + let input: HTMLInputElement | undefined = $state() | ||
| 16 | + const mac = isMac() | ||
| 17 | + | ||
| 18 | + const actions: Action[] = ['newChannel', 'addAgent', 'focusComposer', 'leftDock', 'settings', 'log'] | ||
| 19 | + | ||
| 20 | + const entries = $derived.by((): PaletteEntry[] => { | ||
| 21 | + return [ | ||
| 22 | + ...appState.channels.filter((channel) => !channel.direct).map((channel) => ({ | ||
| 23 | + id: `channel:${channel.id}`, label: `# ${channel.name}`, hint: t('palette.channel'), run: () => void selectChannel(channel.id), | ||
| 24 | + })), | ||
| 25 | + ...appState.agents.map((agent) => ({ | ||
| 26 | + id: `agent:${agent.name}`, label: `${agent.icon ? agent.icon + ' ' : ''}${agent.title}`, hint: t('palette.direct'), | ||
| 27 | + run: () => void openDirect(agent.name), | ||
| 28 | + })), | ||
| 29 | + ...appState.agents.map((agent) => ({ | ||
| 30 | + id: `files:${agent.name}`, label: t('palette.filesOf', { agent: agent.title }), hint: t('palette.files'), run: () => openWorkspace(agent.name), | ||
| 31 | + })), | ||
| 32 | + ...actions.map((action) => ({ id: `action:${action}`, label: t(`action.${action}`), hint: shortcutLabel(action, mac), run: () => run(action) })), | ||
| 33 | + { id: 'action:openConfig', label: t('action.openConfig'), hint: '', run: () => void act(() => ConfigService.Choose()) }, | ||
| 34 | + ] | ||
| 35 | + }) | ||
| 36 | + const found = $derived(filterEntries(query, entries)) | ||
| 37 | + | ||
| 38 | + $effect(() => { | ||
| 39 | + void query | ||
| 40 | + selected = 0 | ||
| 41 | + }) | ||
| 42 | + $effect(() => input?.focus()) | ||
| 43 | + | ||
| 44 | + function close() { | ||
| 45 | + appState.paletteOpen = false | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + function choose(entry: PaletteEntry | undefined) { | ||
| 49 | + if (!entry) return | ||
| 50 | + close() | ||
| 51 | + entry.run() | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + function onKeydown(event: KeyboardEvent) { | ||
| 55 | + if (event.key === 'Escape') close() | ||
| 56 | + else if (event.key === 'ArrowDown') selected = Math.min(selected + 1, found.length - 1) | ||
| 57 | + else if (event.key === 'ArrowUp') selected = Math.max(selected - 1, 0) | ||
| 58 | + else if (event.key === 'Enter') choose(found[selected]) | ||
| 59 | + else return | ||
| 60 | + event.preventDefault() | ||
| 61 | + } | ||
| 62 | +</script> | ||
| 63 | + | ||
| 64 | +<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions --> | ||
| 65 | +<div class="backdrop" onclick={close}> | ||
| 66 | + <!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions --> | ||
| 67 | + <div class="palette" role="dialog" aria-modal="true" aria-label={t('palette.label')} tabindex="-1" onclick={(event) => event.stopPropagation()}> | ||
| 68 | + <input | ||
| 69 | + bind:this={input} | ||
| 70 | + bind:value={query} | ||
| 71 | + onkeydown={onKeydown} | ||
| 72 | + placeholder={t('palette.placeholder')} | ||
| 73 | + role="combobox" | ||
| 74 | + aria-expanded="true" | ||
| 75 | + aria-controls="palette-list" | ||
| 76 | + aria-activedescendant={found[selected] ? `palette-${selected}` : undefined} | ||
| 77 | + spellcheck="false" | ||
| 78 | + /> | ||
| 79 | + <ul id="palette-list" role="listbox"> | ||
| 80 | + {#each found as entry, index (entry.id)} | ||
| 81 | + <li id="palette-{index}" role="option" aria-selected={index === selected} class:selected={index === selected}> | ||
| 82 | + <button tabindex="-1" onclick={() => choose(entry)} onmousemove={() => (selected = index)}> | ||
| 83 | + <span>{entry.label}</span><span class="hint">{entry.hint}</span> | ||
| 84 | + </button> | ||
| 85 | + </li> | ||
| 86 | + {:else} | ||
| 87 | + <li class="none">{t('palette.none')}</li> | ||
| 88 | + {/each} | ||
| 89 | + </ul> | ||
| 90 | + </div> | ||
| 91 | +</div> | ||
| 92 | + | ||
| 93 | +<style> | ||
| 94 | + .backdrop { position: fixed; inset: 0; background: rgb(0 0 0 / 0.25); display: flex; justify-content: center; align-items: flex-start; padding-top: 12vh; z-index: 50; } | ||
| 95 | + .palette { width: min(560px, calc(100vw - 32px)); background: var(--panel); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 12px 40px rgb(0 0 0 / 0.25); overflow: hidden; } | ||
| 96 | + input { width: 100%; box-sizing: border-box; border: none; border-bottom: 1px solid var(--border); padding: 12px 14px; font: inherit; font-size: 15px; background: none; color: var(--text); outline: none; } | ||
| 97 | + ul { list-style: none; margin: 0; padding: 6px; max-height: 50vh; overflow-y: auto; } | ||
| 98 | + li button { width: 100%; display: flex; justify-content: space-between; gap: 12px; border: none; background: none; padding: 7px 10px; border-radius: 6px; text-align: left; color: var(--text); cursor: pointer; } | ||
| 99 | + li.selected button { background: var(--panel-2); outline: 1px solid var(--accent); } | ||
| 100 | + .hint { color: var(--muted); font-size: 12px; flex: none; } | ||
| 101 | + .none { color: var(--muted); padding: 8px 10px; } | ||
| 102 | +</style> | ||
added
frontend/src/lib/layout/Logo.svelte +21 -0 | new file mode 100644 | ||
| @@ -0,0 +1,21 @@ | ||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | |
| 2 | +<script lang="ts"> | |
| 3 | + // The Sidekicks mark, "Orbite": you in the centre, your agents in orbit. | |
| 4 | + // Its colours come from the --logo-* tokens, so it follows the theme. | |
| 5 | + // Usage: <Logo size={160} /> | |
| 6 | + let { size = 64 }: { size?: number } = $props() | |
| 7 | + const id = $props.id() | |
| 8 | +</script> | |
| 9 | + | |
| 10 | +<svg width={size} height={size} viewBox="0 0 100 100" aria-hidden="true"> | |
| 11 | + <!-- The ring stops short of the two small dots. --> | |
| 12 | + <mask id="cut-{id}"> | |
| 13 | + <rect width="100" height="100" fill="#fff" /> | |
| 14 | + <circle cx="76" cy="28" r="12" fill="#000" /> | |
| 15 | + <circle cx="18" cy="39" r="10" fill="#000" /> | |
| 16 | + </mask> | |
| 17 | + <circle cx="50" cy="50" r="35" fill="none" stroke="var(--logo-ring)" stroke-width="4" mask="url(#cut-{id})" /> | |
| 18 | + <circle cx="50" cy="50" r="15" fill="var(--logo-centre)" /> | |
| 19 | + <circle cx="76" cy="28" r="9" fill="var(--logo-teal)" /> | |
| 20 | + <circle cx="18" cy="39" r="7" fill="var(--logo-coral)" /> | |
| 21 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | +<!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | ||
| 2 | +<script lang="ts"> | ||
| 3 | + // The Sidekicks mark, "Orbite": you in the centre, your agents in orbit. | ||
| 4 | + // Its colours come from the --logo-* tokens, so it follows the theme. | ||
| 5 | + // Usage: <Logo size={160} /> | ||
| 6 | + let { size = 64 }: { size?: number } = $props() | ||
| 7 | + const id = $props.id() | ||
| 8 | +</script> | ||
| 9 | + | ||
| 10 | +<svg width={size} height={size} viewBox="0 0 100 100" aria-hidden="true"> | ||
| 11 | + <!-- The ring stops short of the two small dots. --> | ||
| 12 | + <mask id="cut-{id}"> | ||
| 13 | + <rect width="100" height="100" fill="#fff" /> | ||
| 14 | + <circle cx="76" cy="28" r="12" fill="#000" /> | ||
| 15 | + <circle cx="18" cy="39" r="10" fill="#000" /> | ||
| 16 | + </mask> | ||
| 17 | + <circle cx="50" cy="50" r="35" fill="none" stroke="var(--logo-ring)" stroke-width="4" mask="url(#cut-{id})" /> | ||
| 18 | + <circle cx="50" cy="50" r="15" fill="var(--logo-centre)" /> | ||
| 19 | + <circle cx="76" cy="28" r="9" fill="var(--logo-teal)" /> | ||
| 20 | + <circle cx="18" cy="39" r="7" fill="var(--logo-coral)" /> | ||
| 21 | +</svg> | ||
modified
frontend/src/lib/layout/Shell.svelte +48 -0 | @@ -5,6 +5,9 @@ | ||
| 5 | 5 | import type { Registry } from '../panels/registry' |
| 6 | 6 | import Dock from './Dock.svelte' |
| 7 | 7 | import StatusBar from './StatusBar.svelte' |
| 8 | + import CommandPalette from './CommandPalette.svelte' | |
| 9 | + import { actionFor, isMac, type Action } from '../shortcuts' | |
| 10 | + import { appState, openAssistant } from '../state.svelte' | |
| 8 | 11 | |
| 9 | 12 | let { registry }: { registry: Registry } = $props() |
| 10 | 13 | |
| @@ -26,6 +29,46 @@ | ||
| 26 | 29 | bottom?.collapse() |
| 27 | 30 | }) |
| 28 | 31 | |
| 32 | + const mac = isMac() | |
| 33 | + | |
| 34 | + // Issue #35: the shortcuts of lib/shortcuts.ts. Outside macOS they use | |
| 35 | + // Ctrl, which the shell of the terminal needs (Ctrl+L, Ctrl+K…): there, | |
| 36 | + // the terminal keeps them. | |
| 37 | + function onKeydown(event: KeyboardEvent) { | |
| 38 | + const action = actionFor(event, mac) | |
| 39 | + if (!action) return | |
| 40 | + if (!mac && event.target instanceof Element && event.target.closest('.xterm')) return | |
| 41 | + event.preventDefault() | |
| 42 | + run(action) | |
| 43 | + } | |
| 44 | + | |
| 45 | + function run(action: Action) { | |
| 46 | + switch (action) { | |
| 47 | + case 'palette': | |
| 48 | + appState.paletteOpen = !appState.paletteOpen | |
| 49 | + break | |
| 50 | + case 'newChannel': | |
| 51 | + if (collapsed.left) toggle('left') | |
| 52 | + appState.newChannelRequest++ | |
| 53 | + break | |
| 54 | + case 'addAgent': | |
| 55 | + openAssistant() | |
| 56 | + break | |
| 57 | + case 'focusComposer': | |
| 58 | + document.querySelector<HTMLTextAreaElement>('.composer textarea')?.focus() | |
| 59 | + break | |
| 60 | + case 'leftDock': | |
| 61 | + toggle('left') | |
| 62 | + break | |
| 63 | + case 'settings': | |
| 64 | + toggle('right') | |
| 65 | + break | |
| 66 | + case 'log': | |
| 67 | + toggle('bottom') | |
| 68 | + break | |
| 69 | + } | |
| 70 | + } | |
| 71 | + | |
| 29 | 72 | function toggle(dock: 'left' | 'right' | 'bottom') { |
| 30 | 73 | const pane = { left, right, bottom }[dock] |
| 31 | 74 | if (!pane) return |
| @@ -41,6 +84,8 @@ | ||
| 41 | 84 | <!-- Layout of issue #12 / wireframe 1: the conversation in the centre, channels |
| 42 | 85 | and agents on the left, Settings on the right and the logs at the bottom |
| 43 | 86 | folded at every launch. autoSaveId keeps the sizes from one launch to the next. --> |
| 87 | +<svelte:window onkeydown={onKeydown} /> | |
| 88 | + | |
| 44 | 89 | <div class="shell"> |
| 45 | 90 | <div class="main"> |
| 46 | 91 | <PaneGroup direction="horizontal" autoSaveId="sidekicks-shell"> |
| @@ -70,6 +115,9 @@ | ||
| 70 | 115 | </div> |
| 71 | 116 | <StatusBar {collapsed} onToggle={toggle} /> |
| 72 | 117 | </div> |
| 118 | +{#if appState.paletteOpen} | |
| 119 | + <CommandPalette {run} /> | |
| 120 | +{/if} | |
| 73 | 121 | |
| 74 | 122 | <style> |
| 75 | 123 | .shell { height: 100%; display: flex; flex-direction: column; } |
| @@ -5,6 +5,9 @@ | |||
| 5 | import type { Registry } from '../panels/registry' | 5 | import type { Registry } from '../panels/registry' |
| 6 | import Dock from './Dock.svelte' | 6 | import Dock from './Dock.svelte' |
| 7 | import StatusBar from './StatusBar.svelte' | 7 | import StatusBar from './StatusBar.svelte' |
| 8 | + import CommandPalette from './CommandPalette.svelte' | ||
| 9 | + import { actionFor, isMac, type Action } from '../shortcuts' | ||
| 10 | + import { appState, openAssistant } from '../state.svelte' | ||
| 8 | 11 | ||
| 9 | let { registry }: { registry: Registry } = $props() | 12 | let { registry }: { registry: Registry } = $props() |
| 10 | 13 | ||
| @@ -26,6 +29,46 @@ | |||
| 26 | bottom?.collapse() | 29 | bottom?.collapse() |
| 27 | }) | 30 | }) |
| 28 | 31 | ||
| 32 | + const mac = isMac() | ||
| 33 | + | ||
| 34 | + // Issue #35: the shortcuts of lib/shortcuts.ts. Outside macOS they use | ||
| 35 | + // Ctrl, which the shell of the terminal needs (Ctrl+L, Ctrl+K…): there, | ||
| 36 | + // the terminal keeps them. | ||
| 37 | + function onKeydown(event: KeyboardEvent) { | ||
| 38 | + const action = actionFor(event, mac) | ||
| 39 | + if (!action) return | ||
| 40 | + if (!mac && event.target instanceof Element && event.target.closest('.xterm')) return | ||
| 41 | + event.preventDefault() | ||
| 42 | + run(action) | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + function run(action: Action) { | ||
| 46 | + switch (action) { | ||
| 47 | + case 'palette': | ||
| 48 | + appState.paletteOpen = !appState.paletteOpen | ||
| 49 | + break | ||
| 50 | + case 'newChannel': | ||
| 51 | + if (collapsed.left) toggle('left') | ||
| 52 | + appState.newChannelRequest++ | ||
| 53 | + break | ||
| 54 | + case 'addAgent': | ||
| 55 | + openAssistant() | ||
| 56 | + break | ||
| 57 | + case 'focusComposer': | ||
| 58 | + document.querySelector<HTMLTextAreaElement>('.composer textarea')?.focus() | ||
| 59 | + break | ||
| 60 | + case 'leftDock': | ||
| 61 | + toggle('left') | ||
| 62 | + break | ||
| 63 | + case 'settings': | ||
| 64 | + toggle('right') | ||
| 65 | + break | ||
| 66 | + case 'log': | ||
| 67 | + toggle('bottom') | ||
| 68 | + break | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + | ||
| 29 | function toggle(dock: 'left' | 'right' | 'bottom') { | 72 | function toggle(dock: 'left' | 'right' | 'bottom') { |
| 30 | const pane = { left, right, bottom }[dock] | 73 | const pane = { left, right, bottom }[dock] |
| 31 | if (!pane) return | 74 | if (!pane) return |
| @@ -41,6 +84,8 @@ | |||
| 41 | <!-- Layout of issue #12 / wireframe 1: the conversation in the centre, channels | 84 | <!-- Layout of issue #12 / wireframe 1: the conversation in the centre, channels |
| 42 | and agents on the left, Settings on the right and the logs at the bottom | 85 | and agents on the left, Settings on the right and the logs at the bottom |
| 43 | folded at every launch. autoSaveId keeps the sizes from one launch to the next. --> | 86 | folded at every launch. autoSaveId keeps the sizes from one launch to the next. --> |
| 87 | +<svelte:window onkeydown={onKeydown} /> | ||
| 88 | + | ||
| 44 | <div class="shell"> | 89 | <div class="shell"> |
| 45 | <div class="main"> | 90 | <div class="main"> |
| 46 | <PaneGroup direction="horizontal" autoSaveId="sidekicks-shell"> | 91 | <PaneGroup direction="horizontal" autoSaveId="sidekicks-shell"> |
| @@ -70,6 +115,9 @@ | |||
| 70 | </div> | 115 | </div> |
| 71 | <StatusBar {collapsed} onToggle={toggle} /> | 116 | <StatusBar {collapsed} onToggle={toggle} /> |
| 72 | </div> | 117 | </div> |
| 118 | +{#if appState.paletteOpen} | ||
| 119 | + <CommandPalette {run} /> | ||
| 120 | +{/if} | ||
| 73 | 121 | ||
| 74 | <style> | 122 | <style> |
| 75 | .shell { height: 100%; display: flex; flex-direction: column; } | 123 | .shell { height: 100%; display: flex; flex-direction: column; } |
modified
frontend/src/lib/panels/AgentsPanel.svelte +6 -2 | @@ -2,8 +2,9 @@ | ||
| 2 | 2 | <script lang="ts"> |
| 3 | 3 | import { hasMessage, t, type MessageKey } from '../i18n/index.svelte' |
| 4 | 4 | import ActionError from '../chat/ActionError.svelte' |
| 5 | + import ErrorText from '../chat/ErrorText.svelte' | |
| 5 | 6 | import { AgentService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' |
| 6 | - import { act, appState, channelOf, openDirect, openWorkspace } from '../state.svelte' | |
| 7 | + import { act, appState, channelOf, openAssistant, openDirect, openWorkspace } from '../state.svelte' | |
| 7 | 8 | |
| 8 | 9 | // The agent of the direct conversation shown, to highlight it. |
| 9 | 10 | const directAgent = $derived(channelOf(appState.selectedChannel)?.direct ?? '') |
| @@ -28,12 +29,13 @@ | ||
| 28 | 29 | {/if} |
| 29 | 30 | </span> |
| 30 | 31 | {#if agent.error} |
| 31 | - <p class="failure">{agent.error}</p> | |
| 32 | + <div class="failure"><ErrorText raw={agent.error} /></div> | |
| 32 | 33 | {/if} |
| 33 | 34 | </li> |
| 34 | 35 | {/each} |
| 35 | 36 | </ul> |
| 36 | 37 | {/if} |
| 38 | +<button class="add" onclick={openAssistant}>{t('agents.add')}</button> | |
| 37 | 39 | <ActionError /> |
| 38 | 40 | |
| 39 | 41 | <style> |
| @@ -55,4 +57,6 @@ | ||
| 55 | 57 | .actions button { padding: 1px 7px; font-size: 11px; } |
| 56 | 58 | .failure { grid-column: 2 / span 2; grid-row: 3; margin: 2px 0 0; color: var(--danger); font-size: 12px; white-space: pre-wrap; } |
| 57 | 59 | .empty { color: var(--muted); padding: 0 8px; } |
| 60 | + .add { margin: 6px 8px; border: 1px dashed var(--border); background: none; color: var(--muted); font-size: 12px; } | |
| 61 | + .add:hover { color: var(--text); border-color: var(--accent); } | |
| 58 | 62 | </style> |
| @@ -2,8 +2,9 @@ | |||
| 2 | <script lang="ts"> | 2 | <script lang="ts"> |
| 3 | import { hasMessage, t, type MessageKey } from '../i18n/index.svelte' | 3 | import { hasMessage, t, type MessageKey } from '../i18n/index.svelte' |
| 4 | import ActionError from '../chat/ActionError.svelte' | 4 | import ActionError from '../chat/ActionError.svelte' |
| 5 | + import ErrorText from '../chat/ErrorText.svelte' | ||
| 5 | import { AgentService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' | 6 | import { AgentService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' |
| 6 | - import { act, appState, channelOf, openDirect, openWorkspace } from '../state.svelte' | 7 | + import { act, appState, channelOf, openAssistant, openDirect, openWorkspace } from '../state.svelte' |
| 7 | 8 | ||
| 8 | // The agent of the direct conversation shown, to highlight it. | 9 | // The agent of the direct conversation shown, to highlight it. |
| 9 | const directAgent = $derived(channelOf(appState.selectedChannel)?.direct ?? '') | 10 | const directAgent = $derived(channelOf(appState.selectedChannel)?.direct ?? '') |
| @@ -28,12 +29,13 @@ | |||
| 28 | {/if} | 29 | {/if} |
| 29 | </span> | 30 | </span> |
| 30 | {#if agent.error} | 31 | {#if agent.error} |
| 31 | - <p class="failure">{agent.error}</p> | 32 | + <div class="failure"><ErrorText raw={agent.error} /></div> |
| 32 | {/if} | 33 | {/if} |
| 33 | </li> | 34 | </li> |
| 34 | {/each} | 35 | {/each} |
| 35 | </ul> | 36 | </ul> |
| 36 | {/if} | 37 | {/if} |
| 38 | +<button class="add" onclick={openAssistant}>{t('agents.add')}</button> | ||
| 37 | <ActionError /> | 39 | <ActionError /> |
| 38 | 40 | ||
| 39 | <style> | 41 | <style> |
| @@ -55,4 +57,6 @@ | |||
| 55 | .actions button { padding: 1px 7px; font-size: 11px; } | 57 | .actions button { padding: 1px 7px; font-size: 11px; } |
| 56 | .failure { grid-column: 2 / span 2; grid-row: 3; margin: 2px 0 0; color: var(--danger); font-size: 12px; white-space: pre-wrap; } | 58 | .failure { grid-column: 2 / span 2; grid-row: 3; margin: 2px 0 0; color: var(--danger); font-size: 12px; white-space: pre-wrap; } |
| 57 | .empty { color: var(--muted); padding: 0 8px; } | 59 | .empty { color: var(--muted); padding: 0 8px; } |
| 60 | + .add { margin: 6px 8px; border: 1px dashed var(--border); background: none; color: var(--muted); font-size: 12px; } | ||
| 61 | + .add:hover { color: var(--text); border-color: var(--accent); } | ||
| 58 | </style> | 62 | </style> |
modified
frontend/src/lib/panels/ChannelsPanel.svelte +8 -0 | @@ -13,6 +13,14 @@ | ||
| 13 | 13 | const directs = $derived(visibleDirects(appState.channels, appState.agents.map((agent) => agent.name))) |
| 14 | 14 | |
| 15 | 15 | let creating = $state(false) |
| 16 | + // ⌘N, or "New channel" in the palette. | |
| 17 | + let lastRequest = appState.newChannelRequest | |
| 18 | + $effect(() => { | |
| 19 | + if (appState.newChannelRequest === lastRequest) return | |
| 20 | + lastRequest = appState.newChannelRequest | |
| 21 | + appState.actionError = '' | |
| 22 | + creating = true | |
| 23 | + }) | |
| 16 | 24 | let newName = $state('') |
| 17 | 25 | // The channel being renamed, and the one waiting for a delete confirmation. |
| 18 | 26 | let renaming = $state('') |
| @@ -13,6 +13,14 @@ | |||
| 13 | const directs = $derived(visibleDirects(appState.channels, appState.agents.map((agent) => agent.name))) | 13 | const directs = $derived(visibleDirects(appState.channels, appState.agents.map((agent) => agent.name))) |
| 14 | 14 | ||
| 15 | let creating = $state(false) | 15 | let creating = $state(false) |
| 16 | + // ⌘N, or "New channel" in the palette. | ||
| 17 | + let lastRequest = appState.newChannelRequest | ||
| 18 | + $effect(() => { | ||
| 19 | + if (appState.newChannelRequest === lastRequest) return | ||
| 20 | + lastRequest = appState.newChannelRequest | ||
| 21 | + appState.actionError = '' | ||
| 22 | + creating = true | ||
| 23 | + }) | ||
| 16 | let newName = $state('') | 24 | let newName = $state('') |
| 17 | // The channel being renamed, and the one waiting for a delete confirmation. | 25 | // The channel being renamed, and the one waiting for a delete confirmation. |
| 18 | let renaming = $state('') | 26 | let renaming = $state('') |
modified
frontend/src/lib/panels/ConversationPanel.svelte +40 -8 | @@ -1,16 +1,19 @@ | ||
| 1 | 1 | <!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> |
| 2 | 2 | <script lang="ts"> |
| 3 | - import { t } from '../i18n/index.svelte' | |
| 3 | + import { t, type MessageKey } from '../i18n/index.svelte' | |
| 4 | 4 | import { tick } from 'svelte' |
| 5 | 5 | import Composer from '../chat/Composer.svelte' |
| 6 | 6 | import MessageView from '../chat/MessageView.svelte' |
| 7 | 7 | import PermissionCard from '../chat/PermissionCard.svelte' |
| 8 | 8 | import Spinner from '../chat/Spinner.svelte' |
| 9 | 9 | import AgentView from '../agent/AgentView.svelte' |
| 10 | + import AddAgentForm from '../agent/AddAgentForm.svelte' | |
| 10 | 11 | import ActionError from '../chat/ActionError.svelte' |
| 12 | + import Logo from '../layout/Logo.svelte' | |
| 11 | 13 | import { isNearBottom, type Trigger } from '../composer' |
| 12 | 14 | import { usagePercent } from '../conversation' |
| 13 | - import { addMember, agentTitle, appState, cancel, channelOf, loadOlder, prepareCommands, removeMember, send } from '../state.svelte' | |
| 15 | + import { act, addMember, agentTitle, appState, cancel, channelOf, loadOlder, openAssistant, prepareCommands, removeMember, send } from '../state.svelte' | |
| 16 | + import { ConfigService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' | |
| 14 | 17 | import { commandSuggestions, isCommandPosition, mentionSuggestions, type AgentInfo, type Suggestions } from '../suggestions' |
| 15 | 18 | import { stuckAfter, trailingFailures } from '../tools' |
| 16 | 19 | |
| @@ -113,7 +116,9 @@ | ||
| 113 | 116 | <div class="banner warning" role="alert">{t('conversation.historyProblem', { problem: appState.config.historyProblem })}</div> |
| 114 | 117 | {/if} |
| 115 | 118 | |
| 116 | - {#if appState.workspaceAgent} | |
| 119 | + {#if appState.assistant} | |
| 120 | + <AddAgentForm /> | |
| 121 | + {:else if appState.workspaceAgent} | |
| 117 | 122 | {#key appState.workspaceAgent} |
| 118 | 123 | <AgentView agent={appState.workspaceAgent} /> |
| 119 | 124 | {/key} |
| @@ -199,11 +204,29 @@ | ||
| 199 | 204 | </div> |
| 200 | 205 | {:else} |
| 201 | 206 | <div class="welcome"> |
| 202 | - <h1>Sidekicks</h1> | |
| 207 | + <Logo size={appState.agents.length === 0 ? 120 : 160} /> | |
| 203 | 208 | {#if appState.agents.length === 0} |
| 204 | - <p>{t('conversation.noAgents')}</p> | |
| 209 | + <h1>{t('welcome.title')}</h1> | |
| 210 | + <p class="tagline">{t('welcome.tagline')}</p> | |
| 211 | + <ol class="steps"> | |
| 212 | + {#each [1, 2, 3] as step (step)} | |
| 213 | + <li> | |
| 214 | + <span class="number" aria-hidden="true">{step}</span> | |
| 215 | + <span><strong>{t(`welcome.step${step}.title` as MessageKey)}</strong><br />{t(`welcome.step${step}.body` as MessageKey)}</span> | |
| 216 | + </li> | |
| 217 | + {/each} | |
| 218 | + </ol> | |
| 219 | + <div class="buttons"> | |
| 220 | + <button class="primary" onclick={openAssistant}>{t('welcome.addFirst')}</button> | |
| 221 | + <button onclick={() => act(() => ConfigService.Choose())}>{t('welcome.openConfig')}</button> | |
| 222 | + </div> | |
| 223 | + {#if appState.config?.path} | |
| 224 | + <p class="path">{t('welcome.configAt', { path: appState.config.path })}</p> | |
| 225 | + {/if} | |
| 226 | + <ActionError /> | |
| 205 | 227 | {:else} |
| 206 | - <p>{t('conversation.pickAgent')}</p> | |
| 228 | + <h1>Sidekicks</h1> | |
| 229 | + <p>{t('welcome.pick')}</p> | |
| 207 | 230 | {/if} |
| 208 | 231 | </div> |
| 209 | 232 | {/if} |
| @@ -229,6 +252,15 @@ | ||
| 229 | 252 | .stuck { display: flex; align-items: center; gap: 10px; margin: 0 18px 8px; padding: 8px 12px; border: 1px solid var(--warn); border-radius: var(--radius); color: var(--warn); font-size: 13px; } |
| 230 | 253 | .stuck button { margin-left: auto; color: var(--danger); border-color: var(--danger); } |
| 231 | 254 | .composer { padding: 0 18px 14px; } |
| 232 | - .welcome { margin: auto; max-width: 460px; text-align: center; color: var(--muted); padding: 24px; } | |
| 233 | - h1 { color: var(--text); font-size: 22px; margin: 0 0 8px; } | |
| 255 | + .welcome { margin: auto; max-width: 560px; text-align: center; color: var(--muted); padding: 24px; overflow-y: auto; } | |
| 256 | + .tagline { margin: 0 0 20px; } | |
| 257 | + .steps { list-style: none; padding: 0; margin: 0 0 20px; display: flex; flex-direction: column; gap: 10px; text-align: left; } | |
| 258 | + .steps li { display: flex; align-items: center; gap: 14px; padding: 12px 16px; border: 1px solid var(--border); border-radius: 12px; background: var(--panel); color: var(--muted); } | |
| 259 | + .steps strong { color: var(--text); } | |
| 260 | + .number { flex: none; width: 30px; height: 30px; border-radius: 50%; background: var(--accent); color: #fff; font-weight: 700; display: grid; place-items: center; } | |
| 261 | + .buttons { display: flex; justify-content: center; flex-wrap: wrap; gap: 10px; } | |
| 262 | + .buttons button { padding: 8px 16px; } | |
| 263 | + .primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; } | |
| 264 | + .path { font-size: 12px; margin-top: 16px; word-break: break-all; } | |
| 265 | + h1 { color: var(--text); font-size: 22px; margin: 16px 0 8px; } | |
| 234 | 266 | </style> |
| @@ -1,16 +1,19 @@ | |||
| 1 | <!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> | 1 | <!-- Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE --> |
| 2 | <script lang="ts"> | 2 | <script lang="ts"> |
| 3 | - import { t } from '../i18n/index.svelte' | 3 | + import { t, type MessageKey } from '../i18n/index.svelte' |
| 4 | import { tick } from 'svelte' | 4 | import { tick } from 'svelte' |
| 5 | import Composer from '../chat/Composer.svelte' | 5 | import Composer from '../chat/Composer.svelte' |
| 6 | import MessageView from '../chat/MessageView.svelte' | 6 | import MessageView from '../chat/MessageView.svelte' |
| 7 | import PermissionCard from '../chat/PermissionCard.svelte' | 7 | import PermissionCard from '../chat/PermissionCard.svelte' |
| 8 | import Spinner from '../chat/Spinner.svelte' | 8 | import Spinner from '../chat/Spinner.svelte' |
| 9 | import AgentView from '../agent/AgentView.svelte' | 9 | import AgentView from '../agent/AgentView.svelte' |
| 10 | + import AddAgentForm from '../agent/AddAgentForm.svelte' | ||
| 10 | import ActionError from '../chat/ActionError.svelte' | 11 | import ActionError from '../chat/ActionError.svelte' |
| 12 | + import Logo from '../layout/Logo.svelte' | ||
| 11 | import { isNearBottom, type Trigger } from '../composer' | 13 | import { isNearBottom, type Trigger } from '../composer' |
| 12 | import { usagePercent } from '../conversation' | 14 | import { usagePercent } from '../conversation' |
| 13 | - import { addMember, agentTitle, appState, cancel, channelOf, loadOlder, prepareCommands, removeMember, send } from '../state.svelte' | 15 | + import { act, addMember, agentTitle, appState, cancel, channelOf, loadOlder, openAssistant, prepareCommands, removeMember, send } from '../state.svelte' |
| 16 | + import { ConfigService } from '../../../bindings/git.rickub.com/bots-garden/sidekicks/internal/app' | ||
| 14 | import { commandSuggestions, isCommandPosition, mentionSuggestions, type AgentInfo, type Suggestions } from '../suggestions' | 17 | import { commandSuggestions, isCommandPosition, mentionSuggestions, type AgentInfo, type Suggestions } from '../suggestions' |
| 15 | import { stuckAfter, trailingFailures } from '../tools' | 18 | import { stuckAfter, trailingFailures } from '../tools' |
| 16 | 19 | ||
| @@ -113,7 +116,9 @@ | |||
| 113 | <div class="banner warning" role="alert">{t('conversation.historyProblem', { problem: appState.config.historyProblem })}</div> | 116 | <div class="banner warning" role="alert">{t('conversation.historyProblem', { problem: appState.config.historyProblem })}</div> |
| 114 | {/if} | 117 | {/if} |
| 115 | 118 | ||
| 116 | - {#if appState.workspaceAgent} | 119 | + {#if appState.assistant} |
| 120 | + <AddAgentForm /> | ||
| 121 | + {:else if appState.workspaceAgent} | ||
| 117 | {#key appState.workspaceAgent} | 122 | {#key appState.workspaceAgent} |
| 118 | <AgentView agent={appState.workspaceAgent} /> | 123 | <AgentView agent={appState.workspaceAgent} /> |
| 119 | {/key} | 124 | {/key} |
| @@ -199,11 +204,29 @@ | |||
| 199 | </div> | 204 | </div> |
| 200 | {:else} | 205 | {:else} |
| 201 | <div class="welcome"> | 206 | <div class="welcome"> |
| 202 | - <h1>Sidekicks</h1> | 207 | + <Logo size={appState.agents.length === 0 ? 120 : 160} /> |
| 203 | {#if appState.agents.length === 0} | 208 | {#if appState.agents.length === 0} |
| 204 | - <p>{t('conversation.noAgents')}</p> | 209 | + <h1>{t('welcome.title')}</h1> |
| 210 | + <p class="tagline">{t('welcome.tagline')}</p> | ||
| 211 | + <ol class="steps"> | ||
| 212 | + {#each [1, 2, 3] as step (step)} | ||
| 213 | + <li> | ||
| 214 | + <span class="number" aria-hidden="true">{step}</span> | ||
| 215 | + <span><strong>{t(`welcome.step${step}.title` as MessageKey)}</strong><br />{t(`welcome.step${step}.body` as MessageKey)}</span> | ||
| 216 | + </li> | ||
| 217 | + {/each} | ||
| 218 | + </ol> | ||
| 219 | + <div class="buttons"> | ||
| 220 | + <button class="primary" onclick={openAssistant}>{t('welcome.addFirst')}</button> | ||
| 221 | + <button onclick={() => act(() => ConfigService.Choose())}>{t('welcome.openConfig')}</button> | ||
| 222 | + </div> | ||
| 223 | + {#if appState.config?.path} | ||
| 224 | + <p class="path">{t('welcome.configAt', { path: appState.config.path })}</p> | ||
| 225 | + {/if} | ||
| 226 | + <ActionError /> | ||
| 205 | {:else} | 227 | {:else} |
| 206 | - <p>{t('conversation.pickAgent')}</p> | 228 | + <h1>Sidekicks</h1> |
| 229 | + <p>{t('welcome.pick')}</p> | ||
| 207 | {/if} | 230 | {/if} |
| 208 | </div> | 231 | </div> |
| 209 | {/if} | 232 | {/if} |
| @@ -229,6 +252,15 @@ | |||
| 229 | .stuck { display: flex; align-items: center; gap: 10px; margin: 0 18px 8px; padding: 8px 12px; border: 1px solid var(--warn); border-radius: var(--radius); color: var(--warn); font-size: 13px; } | 252 | .stuck { display: flex; align-items: center; gap: 10px; margin: 0 18px 8px; padding: 8px 12px; border: 1px solid var(--warn); border-radius: var(--radius); color: var(--warn); font-size: 13px; } |
| 230 | .stuck button { margin-left: auto; color: var(--danger); border-color: var(--danger); } | 253 | .stuck button { margin-left: auto; color: var(--danger); border-color: var(--danger); } |
| 231 | .composer { padding: 0 18px 14px; } | 254 | .composer { padding: 0 18px 14px; } |
| 232 | - .welcome { margin: auto; max-width: 460px; text-align: center; color: var(--muted); padding: 24px; } | 255 | + .welcome { margin: auto; max-width: 560px; text-align: center; color: var(--muted); padding: 24px; overflow-y: auto; } |
| 233 | - h1 { color: var(--text); font-size: 22px; margin: 0 0 8px; } | 256 | + .tagline { margin: 0 0 20px; } |
| 257 | + .steps { list-style: none; padding: 0; margin: 0 0 20px; display: flex; flex-direction: column; gap: 10px; text-align: left; } | ||
| 258 | + .steps li { display: flex; align-items: center; gap: 14px; padding: 12px 16px; border: 1px solid var(--border); border-radius: 12px; background: var(--panel); color: var(--muted); } | ||
| 259 | + .steps strong { color: var(--text); } | ||
| 260 | + .number { flex: none; width: 30px; height: 30px; border-radius: 50%; background: var(--accent); color: #fff; font-weight: 700; display: grid; place-items: center; } | ||
| 261 | + .buttons { display: flex; justify-content: center; flex-wrap: wrap; gap: 10px; } | ||
| 262 | + .buttons button { padding: 8px 16px; } | ||
| 263 | + .primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; } | ||
| 264 | + .path { font-size: 12px; margin-top: 16px; word-break: break-all; } | ||
| 265 | + h1 { color: var(--text); font-size: 22px; margin: 16px 0 8px; } | ||
| 234 | </style> | 266 | </style> |
added
frontend/src/lib/shortcuts.test.ts +60 -0 | new file mode 100644 | ||
| @@ -0,0 +1,60 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +import { describe, expect, it } from 'vitest' | |
| 4 | +import { actionFor, filterEntries, isMac, shortcutLabel, shortcuts, type PaletteEntry } from './shortcuts' | |
| 5 | + | |
| 6 | +const press = (key: string, modifiers: Partial<{ metaKey: boolean; ctrlKey: boolean; shiftKey: boolean; altKey: boolean }> = {}) => ({ | |
| 7 | + key, metaKey: false, ctrlKey: false, shiftKey: false, altKey: false, ...modifiers, | |
| 8 | +}) | |
| 9 | + | |
| 10 | +describe('actionFor', () => { | |
| 11 | + it('uses ⌘ on macOS and Ctrl elsewhere', () => { | |
| 12 | + expect(actionFor(press('k', { metaKey: true }), true)).toBe('palette') | |
| 13 | + expect(actionFor(press('k', { ctrlKey: true }), true)).toBeNull() | |
| 14 | + expect(actionFor(press('k', { ctrlKey: true }), false)).toBe('palette') | |
| 15 | + expect(actionFor(press('k', { metaKey: true }), false)).toBeNull() | |
| 16 | + }) | |
| 17 | + it('tells Shift apart and ignores Alt and plain keys', () => { | |
| 18 | + expect(actionFor(press('n', { metaKey: true }), true)).toBe('newChannel') | |
| 19 | + expect(actionFor(press('N', { metaKey: true, shiftKey: true }), true)).toBe('addAgent') | |
| 20 | + expect(actionFor(press('n', { metaKey: true, altKey: true }), true)).toBeNull() | |
| 21 | + expect(actionFor(press('n'), true)).toBeNull() | |
| 22 | + expect(actionFor(press(',', { metaKey: true }), true)).toBe('settings') | |
| 23 | + }) | |
| 24 | + it('has one shortcut per action and key', () => { | |
| 25 | + const keys = shortcuts.map((shortcut) => `${shortcut.shift ? 'shift+' : ''}${shortcut.key}`) | |
| 26 | + expect(new Set(keys).size).toBe(keys.length) | |
| 27 | + expect(new Set(shortcuts.map((shortcut) => shortcut.action)).size).toBe(shortcuts.length) | |
| 28 | + }) | |
| 29 | +}) | |
| 30 | + | |
| 31 | +describe('shortcutLabel', () => { | |
| 32 | + it('writes the shortcut for each platform', () => { | |
| 33 | + expect(shortcutLabel('palette', true)).toBe('⌘K') | |
| 34 | + expect(shortcutLabel('addAgent', true)).toBe('⇧⌘N') | |
| 35 | + expect(shortcutLabel('settings', false)).toBe('Ctrl+,') | |
| 36 | + expect(shortcutLabel('addAgent', false)).toBe('Ctrl+Shift+N') | |
| 37 | + }) | |
| 38 | +}) | |
| 39 | + | |
| 40 | +describe('isMac', () => { | |
| 41 | + it('reads the platform', () => { | |
| 42 | + expect(isMac('MacIntel')).toBe(true) | |
| 43 | + expect(isMac('Linux x86_64')).toBe(false) | |
| 44 | + expect(isMac('Win32')).toBe(false) | |
| 45 | + }) | |
| 46 | +}) | |
| 47 | + | |
| 48 | +describe('filterEntries', () => { | |
| 49 | + const entry = (label: string): PaletteEntry => ({ id: label, label, hint: '', run: () => {} }) | |
| 50 | + const entries = [entry('# general'), entry('# translations'), entry('🐮 Garfield (translator)'), entry('New channel')] | |
| 51 | + it('keeps every entry for an empty query', () => { | |
| 52 | + expect(filterEntries('', entries)).toHaveLength(4) | |
| 53 | + }) | |
| 54 | + it('matches without the # or the icon, best first', () => { | |
| 55 | + expect(filterEntries('#gen', entries)[0].label).toBe('# general') | |
| 56 | + expect(filterEntries('xyz', entries)).toEqual([]) | |
| 57 | + expect(filterEntries('gar', entries)[0].label).toBe('🐮 Garfield (translator)') | |
| 58 | + expect(filterEntries('trans', entries).map((found) => found.label)).toEqual(['# translations', '🐮 Garfield (translator)']) | |
| 59 | + }) | |
| 60 | +}) | |
| new file mode 100644 | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +import { describe, expect, it } from 'vitest' | ||
| 4 | +import { actionFor, filterEntries, isMac, shortcutLabel, shortcuts, type PaletteEntry } from './shortcuts' | ||
| 5 | + | ||
| 6 | +const press = (key: string, modifiers: Partial<{ metaKey: boolean; ctrlKey: boolean; shiftKey: boolean; altKey: boolean }> = {}) => ({ | ||
| 7 | + key, metaKey: false, ctrlKey: false, shiftKey: false, altKey: false, ...modifiers, | ||
| 8 | +}) | ||
| 9 | + | ||
| 10 | +describe('actionFor', () => { | ||
| 11 | + it('uses ⌘ on macOS and Ctrl elsewhere', () => { | ||
| 12 | + expect(actionFor(press('k', { metaKey: true }), true)).toBe('palette') | ||
| 13 | + expect(actionFor(press('k', { ctrlKey: true }), true)).toBeNull() | ||
| 14 | + expect(actionFor(press('k', { ctrlKey: true }), false)).toBe('palette') | ||
| 15 | + expect(actionFor(press('k', { metaKey: true }), false)).toBeNull() | ||
| 16 | + }) | ||
| 17 | + it('tells Shift apart and ignores Alt and plain keys', () => { | ||
| 18 | + expect(actionFor(press('n', { metaKey: true }), true)).toBe('newChannel') | ||
| 19 | + expect(actionFor(press('N', { metaKey: true, shiftKey: true }), true)).toBe('addAgent') | ||
| 20 | + expect(actionFor(press('n', { metaKey: true, altKey: true }), true)).toBeNull() | ||
| 21 | + expect(actionFor(press('n'), true)).toBeNull() | ||
| 22 | + expect(actionFor(press(',', { metaKey: true }), true)).toBe('settings') | ||
| 23 | + }) | ||
| 24 | + it('has one shortcut per action and key', () => { | ||
| 25 | + const keys = shortcuts.map((shortcut) => `${shortcut.shift ? 'shift+' : ''}${shortcut.key}`) | ||
| 26 | + expect(new Set(keys).size).toBe(keys.length) | ||
| 27 | + expect(new Set(shortcuts.map((shortcut) => shortcut.action)).size).toBe(shortcuts.length) | ||
| 28 | + }) | ||
| 29 | +}) | ||
| 30 | + | ||
| 31 | +describe('shortcutLabel', () => { | ||
| 32 | + it('writes the shortcut for each platform', () => { | ||
| 33 | + expect(shortcutLabel('palette', true)).toBe('⌘K') | ||
| 34 | + expect(shortcutLabel('addAgent', true)).toBe('⇧⌘N') | ||
| 35 | + expect(shortcutLabel('settings', false)).toBe('Ctrl+,') | ||
| 36 | + expect(shortcutLabel('addAgent', false)).toBe('Ctrl+Shift+N') | ||
| 37 | + }) | ||
| 38 | +}) | ||
| 39 | + | ||
| 40 | +describe('isMac', () => { | ||
| 41 | + it('reads the platform', () => { | ||
| 42 | + expect(isMac('MacIntel')).toBe(true) | ||
| 43 | + expect(isMac('Linux x86_64')).toBe(false) | ||
| 44 | + expect(isMac('Win32')).toBe(false) | ||
| 45 | + }) | ||
| 46 | +}) | ||
| 47 | + | ||
| 48 | +describe('filterEntries', () => { | ||
| 49 | + const entry = (label: string): PaletteEntry => ({ id: label, label, hint: '', run: () => {} }) | ||
| 50 | + const entries = [entry('# general'), entry('# translations'), entry('🐮 Garfield (translator)'), entry('New channel')] | ||
| 51 | + it('keeps every entry for an empty query', () => { | ||
| 52 | + expect(filterEntries('', entries)).toHaveLength(4) | ||
| 53 | + }) | ||
| 54 | + it('matches without the # or the icon, best first', () => { | ||
| 55 | + expect(filterEntries('#gen', entries)[0].label).toBe('# general') | ||
| 56 | + expect(filterEntries('xyz', entries)).toEqual([]) | ||
| 57 | + expect(filterEntries('gar', entries)[0].label).toBe('🐮 Garfield (translator)') | ||
| 58 | + expect(filterEntries('trans', entries).map((found) => found.label)).toEqual(['# translations', '🐮 Garfield (translator)']) | ||
| 59 | + }) | ||
| 60 | +}) | ||
added
frontend/src/lib/shortcuts.ts +91 -0 | new file mode 100644 | ||
| @@ -0,0 +1,91 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +// Keyboard shortcuts (issue #35). ⌘ on macOS, Ctrl elsewhere. The table is | |
| 4 | +// the single source: the shell dispatches with actionFor, the palette and | |
| 5 | +// the reference documentation show shortcutLabel. | |
| 6 | + | |
| 7 | +import { matchScore } from './suggestions' | |
| 8 | + | |
| 9 | +export type Action = 'palette' | 'newChannel' | 'addAgent' | 'focusComposer' | 'leftDock' | 'settings' | 'log' | |
| 10 | + | |
| 11 | +export interface Shortcut { | |
| 12 | + action: Action | |
| 13 | + /** The key, lowercase, as KeyboardEvent.key gives it. */ | |
| 14 | + key: string | |
| 15 | + shift?: boolean | |
| 16 | +} | |
| 17 | + | |
| 18 | +export const shortcuts: Shortcut[] = [ | |
| 19 | + { action: 'palette', key: 'k' }, | |
| 20 | + { action: 'newChannel', key: 'n' }, | |
| 21 | + { action: 'addAgent', key: 'n', shift: true }, | |
| 22 | + { action: 'focusComposer', key: 'l' }, | |
| 23 | + { action: 'leftDock', key: 'b' }, | |
| 24 | + { action: 'settings', key: ',' }, | |
| 25 | + { action: 'log', key: 'j' }, | |
| 26 | +] | |
| 27 | + | |
| 28 | +export interface KeyLike { | |
| 29 | + key: string | |
| 30 | + metaKey: boolean | |
| 31 | + ctrlKey: boolean | |
| 32 | + shiftKey: boolean | |
| 33 | + altKey: boolean | |
| 34 | +} | |
| 35 | + | |
| 36 | +/** Whether the computer is a Mac, where shortcuts use ⌘. */ | |
| 37 | +export function isMac(platform = typeof navigator === 'undefined' ? '' : navigator.platform): boolean { | |
| 38 | + return /mac/i.test(platform) | |
| 39 | +} | |
| 40 | + | |
| 41 | +/** | |
| 42 | + * The action of a key press, or null. | |
| 43 | + * | |
| 44 | + * @example | |
| 45 | + * actionFor({ key: 'k', metaKey: true, ctrlKey: false, shiftKey: false, altKey: false }, true) // 'palette' | |
| 46 | + */ | |
| 47 | +export function actionFor(event: KeyLike, mac: boolean): Action | null { | |
| 48 | + const primary = mac ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey | |
| 49 | + if (!primary || event.altKey) return null | |
| 50 | + const key = event.key.toLowerCase() | |
| 51 | + return shortcuts.find((shortcut) => shortcut.key === key && !!shortcut.shift === event.shiftKey)?.action ?? null | |
| 52 | +} | |
| 53 | + | |
| 54 | +/** | |
| 55 | + * How the shortcut of action is written. | |
| 56 | + * | |
| 57 | + * @example | |
| 58 | + * shortcutLabel('addAgent', true) // '⇧⌘N' | |
| 59 | + * shortcutLabel('addAgent', false) // 'Ctrl+Shift+N' | |
| 60 | + */ | |
| 61 | +export function shortcutLabel(action: Action, mac: boolean): string { | |
| 62 | + const shortcut = shortcuts.find((candidate) => candidate.action === action) | |
| 63 | + if (!shortcut) return '' | |
| 64 | + const key = shortcut.key.toUpperCase() | |
| 65 | + if (mac) return `${shortcut.shift ? '⇧' : ''}⌘${key}` | |
| 66 | + return `Ctrl+${shortcut.shift ? 'Shift+' : ''}${key}` | |
| 67 | +} | |
| 68 | + | |
| 69 | +/** An entry of the command palette. */ | |
| 70 | +export interface PaletteEntry { | |
| 71 | + id: string | |
| 72 | + label: string | |
| 73 | + /** Shown on the right: a shortcut, or the kind of entry. */ | |
| 74 | + hint: string | |
| 75 | + run: () => void | |
| 76 | +} | |
| 77 | + | |
| 78 | +/** | |
| 79 | + * The entries matching query, best first; all of them when query is empty. | |
| 80 | + * | |
| 81 | + * @example | |
| 82 | + * filterEntries('gen', entries) // [{ label: '# general', … }] | |
| 83 | + */ | |
| 84 | +export function filterEntries(query: string, entries: PaletteEntry[]): PaletteEntry[] { | |
| 85 | + const q = query.trim().replace(/^#/, '') | |
| 86 | + return entries | |
| 87 | + .map((entry, index) => ({ entry, index, score: matchScore(q, entry.label.replace(/^[#\p{Extended_Pictographic}\s]+/u, '')) })) | |
| 88 | + .filter((candidate) => candidate.score !== null) | |
| 89 | + .sort((a, b) => a.score! - b.score! || a.index - b.index) | |
| 90 | + .map((candidate) => candidate.entry) | |
| 91 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +// Keyboard shortcuts (issue #35). ⌘ on macOS, Ctrl elsewhere. The table is | ||
| 4 | +// the single source: the shell dispatches with actionFor, the palette and | ||
| 5 | +// the reference documentation show shortcutLabel. | ||
| 6 | + | ||
| 7 | +import { matchScore } from './suggestions' | ||
| 8 | + | ||
| 9 | +export type Action = 'palette' | 'newChannel' | 'addAgent' | 'focusComposer' | 'leftDock' | 'settings' | 'log' | ||
| 10 | + | ||
| 11 | +export interface Shortcut { | ||
| 12 | + action: Action | ||
| 13 | + /** The key, lowercase, as KeyboardEvent.key gives it. */ | ||
| 14 | + key: string | ||
| 15 | + shift?: boolean | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +export const shortcuts: Shortcut[] = [ | ||
| 19 | + { action: 'palette', key: 'k' }, | ||
| 20 | + { action: 'newChannel', key: 'n' }, | ||
| 21 | + { action: 'addAgent', key: 'n', shift: true }, | ||
| 22 | + { action: 'focusComposer', key: 'l' }, | ||
| 23 | + { action: 'leftDock', key: 'b' }, | ||
| 24 | + { action: 'settings', key: ',' }, | ||
| 25 | + { action: 'log', key: 'j' }, | ||
| 26 | +] | ||
| 27 | + | ||
| 28 | +export interface KeyLike { | ||
| 29 | + key: string | ||
| 30 | + metaKey: boolean | ||
| 31 | + ctrlKey: boolean | ||
| 32 | + shiftKey: boolean | ||
| 33 | + altKey: boolean | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +/** Whether the computer is a Mac, where shortcuts use ⌘. */ | ||
| 37 | +export function isMac(platform = typeof navigator === 'undefined' ? '' : navigator.platform): boolean { | ||
| 38 | + return /mac/i.test(platform) | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +/** | ||
| 42 | + * The action of a key press, or null. | ||
| 43 | + * | ||
| 44 | + * @example | ||
| 45 | + * actionFor({ key: 'k', metaKey: true, ctrlKey: false, shiftKey: false, altKey: false }, true) // 'palette' | ||
| 46 | + */ | ||
| 47 | +export function actionFor(event: KeyLike, mac: boolean): Action | null { | ||
| 48 | + const primary = mac ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey | ||
| 49 | + if (!primary || event.altKey) return null | ||
| 50 | + const key = event.key.toLowerCase() | ||
| 51 | + return shortcuts.find((shortcut) => shortcut.key === key && !!shortcut.shift === event.shiftKey)?.action ?? null | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +/** | ||
| 55 | + * How the shortcut of action is written. | ||
| 56 | + * | ||
| 57 | + * @example | ||
| 58 | + * shortcutLabel('addAgent', true) // '⇧⌘N' | ||
| 59 | + * shortcutLabel('addAgent', false) // 'Ctrl+Shift+N' | ||
| 60 | + */ | ||
| 61 | +export function shortcutLabel(action: Action, mac: boolean): string { | ||
| 62 | + const shortcut = shortcuts.find((candidate) => candidate.action === action) | ||
| 63 | + if (!shortcut) return '' | ||
| 64 | + const key = shortcut.key.toUpperCase() | ||
| 65 | + if (mac) return `${shortcut.shift ? '⇧' : ''}⌘${key}` | ||
| 66 | + return `Ctrl+${shortcut.shift ? 'Shift+' : ''}${key}` | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +/** An entry of the command palette. */ | ||
| 70 | +export interface PaletteEntry { | ||
| 71 | + id: string | ||
| 72 | + label: string | ||
| 73 | + /** Shown on the right: a shortcut, or the kind of entry. */ | ||
| 74 | + hint: string | ||
| 75 | + run: () => void | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | +/** | ||
| 79 | + * The entries matching query, best first; all of them when query is empty. | ||
| 80 | + * | ||
| 81 | + * @example | ||
| 82 | + * filterEntries('gen', entries) // [{ label: '# general', … }] | ||
| 83 | + */ | ||
| 84 | +export function filterEntries(query: string, entries: PaletteEntry[]): PaletteEntry[] { | ||
| 85 | + const q = query.trim().replace(/^#/, '') | ||
| 86 | + return entries | ||
| 87 | + .map((entry, index) => ({ entry, index, score: matchScore(q, entry.label.replace(/^[#\p{Extended_Pictographic}\s]+/u, '')) })) | ||
| 88 | + .filter((candidate) => candidate.score !== null) | ||
| 89 | + .sort((a, b) => a.score! - b.score! || a.index - b.index) | ||
| 90 | + .map((candidate) => candidate.entry) | ||
| 91 | +} | ||
modified
frontend/src/lib/state.svelte.ts +31 -0 | @@ -71,6 +71,14 @@ export const appState = $state({ | ||
| 71 | 71 | workspaceRevision: {} as Record<string, number>, |
| 72 | 72 | /** The last error returned by an action, shown to the user. */ |
| 73 | 73 | actionError: '', |
| 74 | + /** The "add an agent" assistant is shown in the centre. */ | |
| 75 | + assistant: false, | |
| 76 | + /** An agent just added with the assistant: its conversation opens once it is loaded. */ | |
| 77 | + pendingAgent: '', | |
| 78 | + /** The command palette (⌘K) is open. */ | |
| 79 | + paletteOpen: false, | |
| 80 | + /** Incremented to ask the channels panel for its "new channel" field (⌘N). */ | |
| 81 | + newChannelRequest: 0, | |
| 74 | 82 | }) |
| 75 | 83 | |
| 76 | 84 | // The channels whose conversation was loaded from Go: from then on, the |
| @@ -92,6 +100,11 @@ async function refreshAgents() { | ||
| 92 | 100 | const direct = channelOf(appState.selectedChannel)?.direct |
| 93 | 101 | if (direct && !names.includes(direct)) appState.selectedChannel = '' |
| 94 | 102 | if (appState.workspaceAgent && !names.includes(appState.workspaceAgent)) appState.workspaceAgent = '' |
| 103 | + if (appState.pendingAgent && names.includes(appState.pendingAgent)) { | |
| 104 | + const agent = appState.pendingAgent | |
| 105 | + appState.pendingAgent = '' | |
| 106 | + void openDirect(agent) | |
| 107 | + } | |
| 95 | 108 | } |
| 96 | 109 | |
| 97 | 110 | async function refreshChannels() { |
| @@ -138,6 +151,7 @@ export async function act(action: () => Promise<unknown>) { | ||
| 138 | 151 | export async function selectChannel(id: string) { |
| 139 | 152 | conversationOf(id) // shown empty until loaded |
| 140 | 153 | appState.workspaceAgent = '' |
| 154 | + appState.assistant = false | |
| 141 | 155 | appState.selectedChannel = id |
| 142 | 156 | appState.unread[id] = 0 |
| 143 | 157 | const channel = channelOf(id) |
| @@ -152,9 +166,26 @@ export async function selectChannel(id: string) { | ||
| 152 | 166 | |
| 153 | 167 | /** Shows the workspace of agent (files, terminal, log) in the centre. */ |
| 154 | 168 | export function openWorkspace(agent: string) { |
| 169 | + appState.assistant = false | |
| 155 | 170 | appState.workspaceAgent = agent |
| 156 | 171 | } |
| 157 | 172 | |
| 173 | +/** Shows the "add an agent" assistant in the centre. */ | |
| 174 | +export function openAssistant() { | |
| 175 | + appState.workspaceAgent = '' | |
| 176 | + appState.assistant = true | |
| 177 | +} | |
| 178 | + | |
| 179 | +/** | |
| 180 | + * Called once the assistant has written the agent to the configuration: | |
| 181 | + * its direct conversation opens when the reloaded configuration lists it. | |
| 182 | + */ | |
| 183 | +export function agentAdded(name: string) { | |
| 184 | + appState.assistant = false | |
| 185 | + appState.pendingAgent = name | |
| 186 | + if (appState.agents.some((agent) => agent.name === name)) void refreshAgents() | |
| 187 | +} | |
| 188 | + | |
| 158 | 189 | /** Opens the direct conversation with agent, created the first time. */ |
| 159 | 190 | export function openDirect(agent: string) { |
| 160 | 191 | return act(async () => { |
| @@ -71,6 +71,14 @@ export const appState = $state({ | |||
| 71 | workspaceRevision: {} as Record<string, number>, | 71 | workspaceRevision: {} as Record<string, number>, |
| 72 | /** The last error returned by an action, shown to the user. */ | 72 | /** The last error returned by an action, shown to the user. */ |
| 73 | actionError: '', | 73 | actionError: '', |
| 74 | + /** The "add an agent" assistant is shown in the centre. */ | ||
| 75 | + assistant: false, | ||
| 76 | + /** An agent just added with the assistant: its conversation opens once it is loaded. */ | ||
| 77 | + pendingAgent: '', | ||
| 78 | + /** The command palette (⌘K) is open. */ | ||
| 79 | + paletteOpen: false, | ||
| 80 | + /** Incremented to ask the channels panel for its "new channel" field (⌘N). */ | ||
| 81 | + newChannelRequest: 0, | ||
| 74 | }) | 82 | }) |
| 75 | 83 | ||
| 76 | // The channels whose conversation was loaded from Go: from then on, the | 84 | // The channels whose conversation was loaded from Go: from then on, the |
| @@ -92,6 +100,11 @@ async function refreshAgents() { | |||
| 92 | const direct = channelOf(appState.selectedChannel)?.direct | 100 | const direct = channelOf(appState.selectedChannel)?.direct |
| 93 | if (direct && !names.includes(direct)) appState.selectedChannel = '' | 101 | if (direct && !names.includes(direct)) appState.selectedChannel = '' |
| 94 | if (appState.workspaceAgent && !names.includes(appState.workspaceAgent)) appState.workspaceAgent = '' | 102 | if (appState.workspaceAgent && !names.includes(appState.workspaceAgent)) appState.workspaceAgent = '' |
| 103 | + if (appState.pendingAgent && names.includes(appState.pendingAgent)) { | ||
| 104 | + const agent = appState.pendingAgent | ||
| 105 | + appState.pendingAgent = '' | ||
| 106 | + void openDirect(agent) | ||
| 107 | + } | ||
| 95 | } | 108 | } |
| 96 | 109 | ||
| 97 | async function refreshChannels() { | 110 | async function refreshChannels() { |
| @@ -138,6 +151,7 @@ export async function act(action: () => Promise<unknown>) { | |||
| 138 | export async function selectChannel(id: string) { | 151 | export async function selectChannel(id: string) { |
| 139 | conversationOf(id) // shown empty until loaded | 152 | conversationOf(id) // shown empty until loaded |
| 140 | appState.workspaceAgent = '' | 153 | appState.workspaceAgent = '' |
| 154 | + appState.assistant = false | ||
| 141 | appState.selectedChannel = id | 155 | appState.selectedChannel = id |
| 142 | appState.unread[id] = 0 | 156 | appState.unread[id] = 0 |
| 143 | const channel = channelOf(id) | 157 | const channel = channelOf(id) |
| @@ -152,9 +166,26 @@ export async function selectChannel(id: string) { | |||
| 152 | 166 | ||
| 153 | /** Shows the workspace of agent (files, terminal, log) in the centre. */ | 167 | /** Shows the workspace of agent (files, terminal, log) in the centre. */ |
| 154 | export function openWorkspace(agent: string) { | 168 | export function openWorkspace(agent: string) { |
| 169 | + appState.assistant = false | ||
| 155 | appState.workspaceAgent = agent | 170 | appState.workspaceAgent = agent |
| 156 | } | 171 | } |
| 157 | 172 | ||
| 173 | +/** Shows the "add an agent" assistant in the centre. */ | ||
| 174 | +export function openAssistant() { | ||
| 175 | + appState.workspaceAgent = '' | ||
| 176 | + appState.assistant = true | ||
| 177 | +} | ||
| 178 | + | ||
| 179 | +/** | ||
| 180 | + * Called once the assistant has written the agent to the configuration: | ||
| 181 | + * its direct conversation opens when the reloaded configuration lists it. | ||
| 182 | + */ | ||
| 183 | +export function agentAdded(name: string) { | ||
| 184 | + appState.assistant = false | ||
| 185 | + appState.pendingAgent = name | ||
| 186 | + if (appState.agents.some((agent) => agent.name === name)) void refreshAgents() | ||
| 187 | +} | ||
| 188 | + | ||
| 158 | /** Opens the direct conversation with agent, created the first time. */ | 189 | /** Opens the direct conversation with agent, created the first time. */ |
| 159 | export function openDirect(agent: string) { | 190 | export function openDirect(agent: string) { |
| 160 | return act(async () => { | 191 | return act(async () => { |
modified
frontend/src/style.css +25 -4 | @@ -10,12 +10,19 @@ | ||
| 10 | 10 | --panel-2: #f0f1f3; |
| 11 | 11 | --border: #e2e3e6; |
| 12 | 12 | --text: #1d1f24; |
| 13 | - --muted: #6b6f7a; | |
| 14 | - --accent: #3b6fe0; | |
| 13 | + --muted: #686c77; | |
| 14 | + --accent: #3667d0; | |
| 15 | 15 | --danger: #c9354f; |
| 16 | - --ok: #3e9b4f; | |
| 17 | - --warn: #c98a1b; | |
| 16 | + --ok: #317b3f; | |
| 17 | + --warn: #906313; | |
| 18 | 18 | --code-bg: #f4f5f7; |
| 19 | + /* Text colours reach WCAG AA (4.5:1) on --bg, --panel and --panel-2: | |
| 20 | + lib/contrast.test.ts checks it. */ | |
| 21 | + /* The logo's colours (docs/design/README.md, Logo). */ | |
| 22 | + --logo-ring: #c9cce8; | |
| 23 | + --logo-centre: #1e2240; | |
| 24 | + --logo-teal: #12a39a; | |
| 25 | + --logo-coral: #ff7a59; | |
| 19 | 26 | --radius: 8px; |
| 20 | 27 | --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif; |
| 21 | 28 | --mono: "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace; |
| @@ -37,6 +44,9 @@ | ||
| 37 | 44 | --ok: #9ece6a; |
| 38 | 45 | --warn: #e0af68; |
| 39 | 46 | --code-bg: #15161a; |
| 47 | + --logo-ring: #4a5078; | |
| 48 | + --logo-centre: #ffffff; | |
| 49 | + --logo-teal: #2fd1c5; | |
| 40 | 50 | color-scheme: dark; |
| 41 | 51 | } |
| 42 | 52 | } |
| @@ -53,6 +63,9 @@ | ||
| 53 | 63 | --ok: #9ece6a; |
| 54 | 64 | --warn: #e0af68; |
| 55 | 65 | --code-bg: #15161a; |
| 66 | + --logo-ring: #4a5078; | |
| 67 | + --logo-centre: #ffffff; | |
| 68 | + --logo-teal: #2fd1c5; | |
| 56 | 69 | color-scheme: dark; |
| 57 | 70 | } |
| 58 | 71 | |
| @@ -95,3 +108,11 @@ button:disabled { | ||
| 95 | 108 | opacity: 0.5; |
| 96 | 109 | cursor: default; |
| 97 | 110 | } |
| 111 | + | |
| 112 | +/* Issue #35: whoever uses the keyboard always sees where they are. The | |
| 113 | + composer's text field and the palette's field are inside a bordered box | |
| 114 | + that already shows it. */ | |
| 115 | +:focus-visible { | |
| 116 | + outline: 2px solid var(--accent); | |
| 117 | + outline-offset: 1px; | |
| 118 | +} | |
| @@ -10,12 +10,19 @@ | |||
| 10 | --panel-2: #f0f1f3; | 10 | --panel-2: #f0f1f3; |
| 11 | --border: #e2e3e6; | 11 | --border: #e2e3e6; |
| 12 | --text: #1d1f24; | 12 | --text: #1d1f24; |
| 13 | - --muted: #6b6f7a; | 13 | + --muted: #686c77; |
| 14 | - --accent: #3b6fe0; | 14 | + --accent: #3667d0; |
| 15 | --danger: #c9354f; | 15 | --danger: #c9354f; |
| 16 | - --ok: #3e9b4f; | 16 | + --ok: #317b3f; |
| 17 | - --warn: #c98a1b; | 17 | + --warn: #906313; |
| 18 | --code-bg: #f4f5f7; | 18 | --code-bg: #f4f5f7; |
| 19 | + /* Text colours reach WCAG AA (4.5:1) on --bg, --panel and --panel-2: | ||
| 20 | + lib/contrast.test.ts checks it. */ | ||
| 21 | + /* The logo's colours (docs/design/README.md, Logo). */ | ||
| 22 | + --logo-ring: #c9cce8; | ||
| 23 | + --logo-centre: #1e2240; | ||
| 24 | + --logo-teal: #12a39a; | ||
| 25 | + --logo-coral: #ff7a59; | ||
| 19 | --radius: 8px; | 26 | --radius: 8px; |
| 20 | --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif; | 27 | --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif; |
| 21 | --mono: "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace; | 28 | --mono: "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace; |
| @@ -37,6 +44,9 @@ | |||
| 37 | --ok: #9ece6a; | 44 | --ok: #9ece6a; |
| 38 | --warn: #e0af68; | 45 | --warn: #e0af68; |
| 39 | --code-bg: #15161a; | 46 | --code-bg: #15161a; |
| 47 | + --logo-ring: #4a5078; | ||
| 48 | + --logo-centre: #ffffff; | ||
| 49 | + --logo-teal: #2fd1c5; | ||
| 40 | color-scheme: dark; | 50 | color-scheme: dark; |
| 41 | } | 51 | } |
| 42 | } | 52 | } |
| @@ -53,6 +63,9 @@ | |||
| 53 | --ok: #9ece6a; | 63 | --ok: #9ece6a; |
| 54 | --warn: #e0af68; | 64 | --warn: #e0af68; |
| 55 | --code-bg: #15161a; | 65 | --code-bg: #15161a; |
| 66 | + --logo-ring: #4a5078; | ||
| 67 | + --logo-centre: #ffffff; | ||
| 68 | + --logo-teal: #2fd1c5; | ||
| 56 | color-scheme: dark; | 69 | color-scheme: dark; |
| 57 | } | 70 | } |
| 58 | 71 | ||
| @@ -95,3 +108,11 @@ button:disabled { | |||
| 95 | opacity: 0.5; | 108 | opacity: 0.5; |
| 96 | cursor: default; | 109 | cursor: default; |
| 97 | } | 110 | } |
| 111 | + | ||
| 112 | +/* Issue #35: whoever uses the keyboard always sees where they are. The | ||
| 113 | + composer's text field and the palette's field are inside a bordered box | ||
| 114 | + that already shows it. */ | ||
| 115 | +:focus-visible { | ||
| 116 | + outline: 2px solid var(--accent); | ||
| 117 | + outline-offset: 1px; | ||
| 118 | +} | ||
modified
frontend/vite.config.ts +6 -0 | @@ -1,3 +1,4 @@ | ||
| 1 | +/// <reference types="vitest/config" /> | |
| 1 | 2 | import { defineConfig } from "vite"; |
| 2 | 3 | import { svelte } from "@sveltejs/vite-plugin-svelte"; |
| 3 | 4 | import wails from "@wailsio/runtime/plugins/vite"; |
| @@ -10,4 +11,9 @@ export default defineConfig({ | ||
| 10 | 11 | strictPort: true, |
| 11 | 12 | }, |
| 12 | 13 | plugins: [svelte(), wails("./bindings")], |
| 14 | + test: { | |
| 15 | + // lib/contrast.test.ts reads the theme from style.css (?raw): Vitest | |
| 16 | + // leaves CSS files empty unless they are processed. | |
| 17 | + css: { include: [/style\.css/] }, | |
| 18 | + }, | |
| 13 | 19 | }); |
| @@ -1,3 +1,4 @@ | |||
| 1 | +/// <reference types="vitest/config" /> | ||
| 1 | import { defineConfig } from "vite"; | 2 | import { defineConfig } from "vite"; |
| 2 | import { svelte } from "@sveltejs/vite-plugin-svelte"; | 3 | import { svelte } from "@sveltejs/vite-plugin-svelte"; |
| 3 | import wails from "@wailsio/runtime/plugins/vite"; | 4 | import wails from "@wailsio/runtime/plugins/vite"; |
| @@ -10,4 +11,9 @@ export default defineConfig({ | |||
| 10 | strictPort: true, | 11 | strictPort: true, |
| 11 | }, | 12 | }, |
| 12 | plugins: [svelte(), wails("./bindings")], | 13 | plugins: [svelte(), wails("./bindings")], |
| 14 | + test: { | ||
| 15 | + // lib/contrast.test.ts reads the theme from style.css (?raw): Vitest | ||
| 16 | + // leaves CSS files empty unless they are processed. | ||
| 17 | + css: { include: [/style\.css/] }, | ||
| 18 | + }, | ||
| 13 | }); | 19 | }); |
modified
internal/app/app.go +3 -0 | @@ -38,6 +38,9 @@ type Options struct { | ||
| 38 | 38 | // PickFile asks the user for a configuration file (native dialog), |
| 39 | 39 | // starting in folder; it returns "" when the user cancels. |
| 40 | 40 | PickFile func(folder string) (string, error) |
| 41 | + // PickFolder asks the user for a folder (native dialog), starting in | |
| 42 | + // folder; it returns "" when the user cancels. | |
| 43 | + PickFolder func(folder string) (string, error) | |
| 41 | 44 | // OpenStore opens the history of the configuration file at path; nil |
| 42 | 45 | // opens it in the user's configuration folder (store.DirFor). |
| 43 | 46 | OpenStore func(configPath string) (*store.Store, error) |
| @@ -38,6 +38,9 @@ type Options struct { | |||
| 38 | // PickFile asks the user for a configuration file (native dialog), | 38 | // PickFile asks the user for a configuration file (native dialog), |
| 39 | // starting in folder; it returns "" when the user cancels. | 39 | // starting in folder; it returns "" when the user cancels. |
| 40 | PickFile func(folder string) (string, error) | 40 | PickFile func(folder string) (string, error) |
| 41 | + // PickFolder asks the user for a folder (native dialog), starting in | ||
| 42 | + // folder; it returns "" when the user cancels. | ||
| 43 | + PickFolder func(folder string) (string, error) | ||
| 41 | // OpenStore opens the history of the configuration file at path; nil | 44 | // OpenStore opens the history of the configuration file at path; nil |
| 42 | // opens it in the user's configuration folder (store.DirFor). | 45 | // opens it in the user's configuration folder (store.DirFor). |
| 43 | OpenStore func(configPath string) (*store.Store, error) | 46 | OpenStore func(configPath string) (*store.Store, error) |
modified
internal/app/app_test.go +52 -0 | @@ -435,3 +435,55 @@ func TestATerminalRunsInTheAgentsFolder(t *testing.T) { | ||
| 435 | 435 | core.Shutdown(context.Background()) |
| 436 | 436 | waitFor(t, func() bool { return len(recorder.Named(events.TerminalExit)) == 1 }) |
| 437 | 437 | } |
| 438 | + | |
| 439 | +func TestTheAssistantAddsAnAgentAndCreatesItsFolder(t *testing.T) { | |
| 440 | + directory := t.TempDir() | |
| 441 | + path := filepath.Join(directory, "config.yaml") | |
| 442 | + write(t, path, "# my team\n"+twoAgents) | |
| 443 | + service := &app.ConfigService{Core: app.New(config.Location{Path: path, Source: config.SourceFlag}, app.Options{Starter: starter})} | |
| 444 | + | |
| 445 | + problems, err := service.AddAgent(app.AgentForm{Name: "carol", Title: "Carol", Program: "sh", Arguments: "-c 'echo hi'", Workspace: "agents/carol"}) | |
| 446 | + if err != nil || len(problems) != 0 { | |
| 447 | + t.Fatalf("add: %v %v", problems, err) | |
| 448 | + } | |
| 449 | + if info, err := os.Stat(filepath.Join(directory, "agents", "carol")); err != nil || !info.IsDir() { | |
| 450 | + t.Fatalf("the agent's folder is created next to the configuration: %v", err) | |
| 451 | + } | |
| 452 | + content, _ := os.ReadFile(path) | |
| 453 | + cfg, err := config.Parse(content, path) | |
| 454 | + if err != nil || !strings.HasPrefix(string(content), "# my team") { | |
| 455 | + t.Fatalf("the file stays valid and keeps its comments: %v\n%s", err, content) | |
| 456 | + } | |
| 457 | + if carol, ok := cfg.Agent("carol"); !ok || carol.Args[1] != "echo hi" { | |
| 458 | + t.Fatalf("carol not added:\n%s", content) | |
| 459 | + } | |
| 460 | + | |
| 461 | + problems, err = service.AddAgent(app.AgentForm{Name: "alice", Program: "sh", Workspace: "agents/alice2"}) | |
| 462 | + if err != nil || len(problems) == 0 { | |
| 463 | + t.Fatalf("a name already used is a problem, not an error: %v %v", problems, err) | |
| 464 | + } | |
| 465 | + if after, _ := os.ReadFile(path); string(after) != string(content) { | |
| 466 | + t.Fatal("nothing is written when the result is invalid") | |
| 467 | + } | |
| 468 | + if _, err := service.AddAgent(app.AgentForm{Name: "dave"}); err == nil { | |
| 469 | + t.Fatal("an incomplete form is an error") | |
| 470 | + } | |
| 471 | +} | |
| 472 | + | |
| 473 | +func TestChooseFolderStartsInTheHomeFolder(t *testing.T) { | |
| 474 | + path := filepath.Join(t.TempDir(), "config.yaml") | |
| 475 | + write(t, path, twoAgents) | |
| 476 | + var from string | |
| 477 | + core := app.New(config.Location{Path: path, Source: config.SourceFlag}, app.Options{Starter: starter, PickFolder: func(folder string) (string, error) { | |
| 478 | + from = folder | |
| 479 | + return "/picked", nil | |
| 480 | + }}) | |
| 481 | + got, err := (&app.ConfigService{Core: core}).ChooseFolder() | |
| 482 | + home, _ := os.UserHomeDir() | |
| 483 | + if err != nil || got != "/picked" || from != home { | |
| 484 | + t.Fatalf("got %q %v, started in %q", got, err, from) | |
| 485 | + } | |
| 486 | + if _, err := (&app.ConfigService{Core: app.New(config.Location{Path: path, Source: config.SourceFlag}, app.Options{Starter: starter})}).ChooseFolder(); err == nil { | |
| 487 | + t.Fatal("without a dialog, ChooseFolder is an error") | |
| 488 | + } | |
| 489 | +} | |
| @@ -435,3 +435,55 @@ func TestATerminalRunsInTheAgentsFolder(t *testing.T) { | |||
| 435 | core.Shutdown(context.Background()) | 435 | core.Shutdown(context.Background()) |
| 436 | waitFor(t, func() bool { return len(recorder.Named(events.TerminalExit)) == 1 }) | 436 | waitFor(t, func() bool { return len(recorder.Named(events.TerminalExit)) == 1 }) |
| 437 | } | 437 | } |
| 438 | + | ||
| 439 | +func TestTheAssistantAddsAnAgentAndCreatesItsFolder(t *testing.T) { | ||
| 440 | + directory := t.TempDir() | ||
| 441 | + path := filepath.Join(directory, "config.yaml") | ||
| 442 | + write(t, path, "# my team\n"+twoAgents) | ||
| 443 | + service := &app.ConfigService{Core: app.New(config.Location{Path: path, Source: config.SourceFlag}, app.Options{Starter: starter})} | ||
| 444 | + | ||
| 445 | + problems, err := service.AddAgent(app.AgentForm{Name: "carol", Title: "Carol", Program: "sh", Arguments: "-c 'echo hi'", Workspace: "agents/carol"}) | ||
| 446 | + if err != nil || len(problems) != 0 { | ||
| 447 | + t.Fatalf("add: %v %v", problems, err) | ||
| 448 | + } | ||
| 449 | + if info, err := os.Stat(filepath.Join(directory, "agents", "carol")); err != nil || !info.IsDir() { | ||
| 450 | + t.Fatalf("the agent's folder is created next to the configuration: %v", err) | ||
| 451 | + } | ||
| 452 | + content, _ := os.ReadFile(path) | ||
| 453 | + cfg, err := config.Parse(content, path) | ||
| 454 | + if err != nil || !strings.HasPrefix(string(content), "# my team") { | ||
| 455 | + t.Fatalf("the file stays valid and keeps its comments: %v\n%s", err, content) | ||
| 456 | + } | ||
| 457 | + if carol, ok := cfg.Agent("carol"); !ok || carol.Args[1] != "echo hi" { | ||
| 458 | + t.Fatalf("carol not added:\n%s", content) | ||
| 459 | + } | ||
| 460 | + | ||
| 461 | + problems, err = service.AddAgent(app.AgentForm{Name: "alice", Program: "sh", Workspace: "agents/alice2"}) | ||
| 462 | + if err != nil || len(problems) == 0 { | ||
| 463 | + t.Fatalf("a name already used is a problem, not an error: %v %v", problems, err) | ||
| 464 | + } | ||
| 465 | + if after, _ := os.ReadFile(path); string(after) != string(content) { | ||
| 466 | + t.Fatal("nothing is written when the result is invalid") | ||
| 467 | + } | ||
| 468 | + if _, err := service.AddAgent(app.AgentForm{Name: "dave"}); err == nil { | ||
| 469 | + t.Fatal("an incomplete form is an error") | ||
| 470 | + } | ||
| 471 | +} | ||
| 472 | + | ||
| 473 | +func TestChooseFolderStartsInTheHomeFolder(t *testing.T) { | ||
| 474 | + path := filepath.Join(t.TempDir(), "config.yaml") | ||
| 475 | + write(t, path, twoAgents) | ||
| 476 | + var from string | ||
| 477 | + core := app.New(config.Location{Path: path, Source: config.SourceFlag}, app.Options{Starter: starter, PickFolder: func(folder string) (string, error) { | ||
| 478 | + from = folder | ||
| 479 | + return "/picked", nil | ||
| 480 | + }}) | ||
| 481 | + got, err := (&app.ConfigService{Core: core}).ChooseFolder() | ||
| 482 | + home, _ := os.UserHomeDir() | ||
| 483 | + if err != nil || got != "/picked" || from != home { | ||
| 484 | + t.Fatalf("got %q %v, started in %q", got, err, from) | ||
| 485 | + } | ||
| 486 | + if _, err := (&app.ConfigService{Core: app.New(config.Location{Path: path, Source: config.SourceFlag}, app.Options{Starter: starter})}).ChooseFolder(); err == nil { | ||
| 487 | + t.Fatal("without a dialog, ChooseFolder is an error") | ||
| 488 | + } | ||
| 489 | +} | ||
added
internal/app/newagent.go +178 -0 | new file mode 100644 | ||
| @@ -0,0 +1,178 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +package app | |
| 4 | + | |
| 5 | +import ( | |
| 6 | + "errors" | |
| 7 | + "fmt" | |
| 8 | + "os" | |
| 9 | + "path/filepath" | |
| 10 | + "strings" | |
| 11 | + | |
| 12 | + "git.rickub.com/bots-garden/sidekicks/internal/config" | |
| 13 | +) | |
| 14 | + | |
| 15 | +// Where an agent added with the assistant runs. | |
| 16 | +const ( | |
| 17 | + EnvironmentLocal = "local" | |
| 18 | + EnvironmentContainer = "container" | |
| 19 | + EnvironmentSandbox = "sbx" | |
| 20 | +) | |
| 21 | + | |
| 22 | +// AgentForm is what the "add an agent" assistant asks for. Sidekicks turns | |
| 23 | +// it into the agent's entry of the configuration file (see entryOf), so the | |
| 24 | +// user never writes YAML. | |
| 25 | +type AgentForm struct { | |
| 26 | + Name string `json:"name"` | |
| 27 | + Title string `json:"title"` | |
| 28 | + Icon string `json:"icon"` | |
| 29 | + Description string `json:"description"` | |
| 30 | + // Environment is local, container or sbx. | |
| 31 | + Environment string `json:"environment"` | |
| 32 | + // Box is the name of the Docker container or of the sbx sandbox. | |
| 33 | + Box string `json:"box"` | |
| 34 | + // Program is the agent's program, such as mm. | |
| 35 | + Program string `json:"program"` | |
| 36 | + // Arguments are typed on one line, as in a terminal: quotes group words. | |
| 37 | + Arguments string `json:"arguments"` | |
| 38 | + // Workspace is the agent's folder on this computer. It is created if needed. | |
| 39 | + Workspace string `json:"workspace"` | |
| 40 | +} | |
| 41 | + | |
| 42 | +// errMissingField is returned when the interface sends an incomplete form; | |
| 43 | +// the interface checks the required fields itself before sending it. | |
| 44 | +var errMissingField = errors.New("missing field") | |
| 45 | + | |
| 46 | +// entryOf turns a form into a configuration entry. An agent in a container | |
| 47 | +// or a sandbox is started with "docker exec -i" or "sbx exec -i": ACP goes | |
| 48 | +// through stdin and stdout, so -i is needed and -t must not be used. | |
| 49 | +// | |
| 50 | +// entry, err := entryOf(AgentForm{Name: "scout", Environment: "container", Box: "scout-box", Program: "mm", Workspace: "/agents/scout"}) | |
| 51 | +// // entry.Command == "docker", entry.Args == [exec -i scout-box mm] | |
| 52 | +func entryOf(form AgentForm) (config.AgentEntry, error) { | |
| 53 | + form = trimmed(form) | |
| 54 | + if form.Name == "" || form.Program == "" || form.Workspace == "" { | |
| 55 | + return config.AgentEntry{}, fmt.Errorf("%w: name, program and folder are required", errMissingField) | |
| 56 | + } | |
| 57 | + arguments, err := splitArguments(form.Arguments) | |
| 58 | + if err != nil { | |
| 59 | + return config.AgentEntry{}, err | |
| 60 | + } | |
| 61 | + entry := config.AgentEntry{ | |
| 62 | + Name: form.Name, Title: form.Title, Icon: form.Icon, Description: form.Description, | |
| 63 | + Command: form.Program, Args: arguments, Workspace: form.Workspace, | |
| 64 | + } | |
| 65 | + switch form.Environment { | |
| 66 | + case "", EnvironmentLocal: | |
| 67 | + return entry, nil | |
| 68 | + case EnvironmentContainer, EnvironmentSandbox: | |
| 69 | + if form.Box == "" { | |
| 70 | + return config.AgentEntry{}, fmt.Errorf("%w: the name of the container or sandbox is required", errMissingField) | |
| 71 | + } | |
| 72 | + tool, runtime := "docker", &config.RuntimeEntry{Type: form.Environment, Container: form.Box} | |
| 73 | + if form.Environment == EnvironmentSandbox { | |
| 74 | + tool, runtime = "sbx", &config.RuntimeEntry{Type: form.Environment, Sandbox: form.Box} | |
| 75 | + } | |
| 76 | + entry.Command = tool | |
| 77 | + entry.Args = append([]string{"exec", "-i", form.Box, form.Program}, arguments...) | |
| 78 | + entry.Runtime = runtime | |
| 79 | + return entry, nil | |
| 80 | + default: | |
| 81 | + return config.AgentEntry{}, fmt.Errorf("unknown environment %q", form.Environment) | |
| 82 | + } | |
| 83 | +} | |
| 84 | + | |
| 85 | +func trimmed(form AgentForm) AgentForm { | |
| 86 | + for _, field := range []*string{&form.Name, &form.Title, &form.Icon, &form.Description, &form.Environment, &form.Box, &form.Program, &form.Workspace} { | |
| 87 | + *field = strings.TrimSpace(*field) | |
| 88 | + } | |
| 89 | + return form | |
| 90 | +} | |
| 91 | + | |
| 92 | +// splitArguments splits a line of arguments like a shell does for simple | |
| 93 | +// cases: spaces separate, single or double quotes group, nothing else is | |
| 94 | +// interpreted. | |
| 95 | +// | |
| 96 | +// splitArguments(`-acp -config "my agent.yaml"`) // [-acp -config my agent.yaml] | |
| 97 | +func splitArguments(line string) ([]string, error) { | |
| 98 | + var arguments []string | |
| 99 | + var current strings.Builder | |
| 100 | + inWord, quote := false, rune(0) | |
| 101 | + for _, character := range line { | |
| 102 | + switch { | |
| 103 | + case quote != 0 && character == quote: | |
| 104 | + quote = 0 | |
| 105 | + case quote != 0: | |
| 106 | + current.WriteRune(character) | |
| 107 | + case character == '"' || character == '\'': | |
| 108 | + quote, inWord = character, true | |
| 109 | + case character == ' ' || character == '\t': | |
| 110 | + if inWord { | |
| 111 | + arguments = append(arguments, current.String()) | |
| 112 | + current.Reset() | |
| 113 | + inWord = false | |
| 114 | + } | |
| 115 | + default: | |
| 116 | + current.WriteRune(character) | |
| 117 | + inWord = true | |
| 118 | + } | |
| 119 | + } | |
| 120 | + if quote != 0 { | |
| 121 | + return nil, fmt.Errorf("a quote is not closed in %q", line) | |
| 122 | + } | |
| 123 | + if inWord { | |
| 124 | + arguments = append(arguments, current.String()) | |
| 125 | + } | |
| 126 | + return arguments, nil | |
| 127 | +} | |
| 128 | + | |
| 129 | +// AddAgent adds the agent described by form to the configuration file, | |
| 130 | +// keeping its comments, and creates the agent's folder when it does not | |
| 131 | +// exist. When the result would not be valid (a name already used, a name | |
| 132 | +// with spaces…), nothing is written and the problems are returned. The file | |
| 133 | +// watcher then reloads the configuration, as after a save in Settings. | |
| 134 | +// | |
| 135 | +// problems, err := (&ConfigService{Core: core}).AddAgent(AgentForm{Name: "alice", Program: "mm", Workspace: "~/agents/alice"}) | |
| 136 | +func (s *ConfigService) AddAgent(form AgentForm) ([]string, error) { | |
| 137 | + entry, err := entryOf(form) | |
| 138 | + if err != nil { | |
| 139 | + return nil, err | |
| 140 | + } | |
| 141 | + path := s.Core.path() | |
| 142 | + content, err := os.ReadFile(path) | |
| 143 | + if err != nil { | |
| 144 | + return nil, err | |
| 145 | + } | |
| 146 | + updated, err := config.AppendAgent(content, entry) | |
| 147 | + var configError *config.Error | |
| 148 | + if errors.As(err, &configError) { | |
| 149 | + return messages(configError.Problems), nil | |
| 150 | + } | |
| 151 | + if err != nil { | |
| 152 | + return nil, err | |
| 153 | + } | |
| 154 | + folder := entry.Workspace | |
| 155 | + if folder == "~" || strings.HasPrefix(folder, "~/") { | |
| 156 | + if home, err := os.UserHomeDir(); err == nil { | |
| 157 | + folder = filepath.Join(home, strings.TrimPrefix(folder, "~")) | |
| 158 | + } | |
| 159 | + } | |
| 160 | + if !filepath.IsAbs(folder) { | |
| 161 | + folder = filepath.Join(filepath.Dir(path), folder) | |
| 162 | + } | |
| 163 | + if err := os.MkdirAll(folder, 0o755); err != nil { | |
| 164 | + return nil, err | |
| 165 | + } | |
| 166 | + return []string{}, config.Save(path, updated) | |
| 167 | +} | |
| 168 | + | |
| 169 | +// ChooseFolder asks the user for a folder, starting in their home folder, | |
| 170 | +// for the assistant's "agent's folder" field. It returns "" when the user | |
| 171 | +// cancelled. | |
| 172 | +func (s *ConfigService) ChooseFolder() (string, error) { | |
| 173 | + if s.Core.options.PickFolder == nil { | |
| 174 | + return "", errors.New("no folder dialog available") | |
| 175 | + } | |
| 176 | + home, _ := os.UserHomeDir() | |
| 177 | + return s.Core.options.PickFolder(home) | |
| 178 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,178 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +package app | ||
| 4 | + | ||
| 5 | +import ( | ||
| 6 | + "errors" | ||
| 7 | + "fmt" | ||
| 8 | + "os" | ||
| 9 | + "path/filepath" | ||
| 10 | + "strings" | ||
| 11 | + | ||
| 12 | + "git.rickub.com/bots-garden/sidekicks/internal/config" | ||
| 13 | +) | ||
| 14 | + | ||
| 15 | +// Where an agent added with the assistant runs. | ||
| 16 | +const ( | ||
| 17 | + EnvironmentLocal = "local" | ||
| 18 | + EnvironmentContainer = "container" | ||
| 19 | + EnvironmentSandbox = "sbx" | ||
| 20 | +) | ||
| 21 | + | ||
| 22 | +// AgentForm is what the "add an agent" assistant asks for. Sidekicks turns | ||
| 23 | +// it into the agent's entry of the configuration file (see entryOf), so the | ||
| 24 | +// user never writes YAML. | ||
| 25 | +type AgentForm struct { | ||
| 26 | + Name string `json:"name"` | ||
| 27 | + Title string `json:"title"` | ||
| 28 | + Icon string `json:"icon"` | ||
| 29 | + Description string `json:"description"` | ||
| 30 | + // Environment is local, container or sbx. | ||
| 31 | + Environment string `json:"environment"` | ||
| 32 | + // Box is the name of the Docker container or of the sbx sandbox. | ||
| 33 | + Box string `json:"box"` | ||
| 34 | + // Program is the agent's program, such as mm. | ||
| 35 | + Program string `json:"program"` | ||
| 36 | + // Arguments are typed on one line, as in a terminal: quotes group words. | ||
| 37 | + Arguments string `json:"arguments"` | ||
| 38 | + // Workspace is the agent's folder on this computer. It is created if needed. | ||
| 39 | + Workspace string `json:"workspace"` | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +// errMissingField is returned when the interface sends an incomplete form; | ||
| 43 | +// the interface checks the required fields itself before sending it. | ||
| 44 | +var errMissingField = errors.New("missing field") | ||
| 45 | + | ||
| 46 | +// entryOf turns a form into a configuration entry. An agent in a container | ||
| 47 | +// or a sandbox is started with "docker exec -i" or "sbx exec -i": ACP goes | ||
| 48 | +// through stdin and stdout, so -i is needed and -t must not be used. | ||
| 49 | +// | ||
| 50 | +// entry, err := entryOf(AgentForm{Name: "scout", Environment: "container", Box: "scout-box", Program: "mm", Workspace: "/agents/scout"}) | ||
| 51 | +// // entry.Command == "docker", entry.Args == [exec -i scout-box mm] | ||
| 52 | +func entryOf(form AgentForm) (config.AgentEntry, error) { | ||
| 53 | + form = trimmed(form) | ||
| 54 | + if form.Name == "" || form.Program == "" || form.Workspace == "" { | ||
| 55 | + return config.AgentEntry{}, fmt.Errorf("%w: name, program and folder are required", errMissingField) | ||
| 56 | + } | ||
| 57 | + arguments, err := splitArguments(form.Arguments) | ||
| 58 | + if err != nil { | ||
| 59 | + return config.AgentEntry{}, err | ||
| 60 | + } | ||
| 61 | + entry := config.AgentEntry{ | ||
| 62 | + Name: form.Name, Title: form.Title, Icon: form.Icon, Description: form.Description, | ||
| 63 | + Command: form.Program, Args: arguments, Workspace: form.Workspace, | ||
| 64 | + } | ||
| 65 | + switch form.Environment { | ||
| 66 | + case "", EnvironmentLocal: | ||
| 67 | + return entry, nil | ||
| 68 | + case EnvironmentContainer, EnvironmentSandbox: | ||
| 69 | + if form.Box == "" { | ||
| 70 | + return config.AgentEntry{}, fmt.Errorf("%w: the name of the container or sandbox is required", errMissingField) | ||
| 71 | + } | ||
| 72 | + tool, runtime := "docker", &config.RuntimeEntry{Type: form.Environment, Container: form.Box} | ||
| 73 | + if form.Environment == EnvironmentSandbox { | ||
| 74 | + tool, runtime = "sbx", &config.RuntimeEntry{Type: form.Environment, Sandbox: form.Box} | ||
| 75 | + } | ||
| 76 | + entry.Command = tool | ||
| 77 | + entry.Args = append([]string{"exec", "-i", form.Box, form.Program}, arguments...) | ||
| 78 | + entry.Runtime = runtime | ||
| 79 | + return entry, nil | ||
| 80 | + default: | ||
| 81 | + return config.AgentEntry{}, fmt.Errorf("unknown environment %q", form.Environment) | ||
| 82 | + } | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +func trimmed(form AgentForm) AgentForm { | ||
| 86 | + for _, field := range []*string{&form.Name, &form.Title, &form.Icon, &form.Description, &form.Environment, &form.Box, &form.Program, &form.Workspace} { | ||
| 87 | + *field = strings.TrimSpace(*field) | ||
| 88 | + } | ||
| 89 | + return form | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +// splitArguments splits a line of arguments like a shell does for simple | ||
| 93 | +// cases: spaces separate, single or double quotes group, nothing else is | ||
| 94 | +// interpreted. | ||
| 95 | +// | ||
| 96 | +// splitArguments(`-acp -config "my agent.yaml"`) // [-acp -config my agent.yaml] | ||
| 97 | +func splitArguments(line string) ([]string, error) { | ||
| 98 | + var arguments []string | ||
| 99 | + var current strings.Builder | ||
| 100 | + inWord, quote := false, rune(0) | ||
| 101 | + for _, character := range line { | ||
| 102 | + switch { | ||
| 103 | + case quote != 0 && character == quote: | ||
| 104 | + quote = 0 | ||
| 105 | + case quote != 0: | ||
| 106 | + current.WriteRune(character) | ||
| 107 | + case character == '"' || character == '\'': | ||
| 108 | + quote, inWord = character, true | ||
| 109 | + case character == ' ' || character == '\t': | ||
| 110 | + if inWord { | ||
| 111 | + arguments = append(arguments, current.String()) | ||
| 112 | + current.Reset() | ||
| 113 | + inWord = false | ||
| 114 | + } | ||
| 115 | + default: | ||
| 116 | + current.WriteRune(character) | ||
| 117 | + inWord = true | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + if quote != 0 { | ||
| 121 | + return nil, fmt.Errorf("a quote is not closed in %q", line) | ||
| 122 | + } | ||
| 123 | + if inWord { | ||
| 124 | + arguments = append(arguments, current.String()) | ||
| 125 | + } | ||
| 126 | + return arguments, nil | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +// AddAgent adds the agent described by form to the configuration file, | ||
| 130 | +// keeping its comments, and creates the agent's folder when it does not | ||
| 131 | +// exist. When the result would not be valid (a name already used, a name | ||
| 132 | +// with spaces…), nothing is written and the problems are returned. The file | ||
| 133 | +// watcher then reloads the configuration, as after a save in Settings. | ||
| 134 | +// | ||
| 135 | +// problems, err := (&ConfigService{Core: core}).AddAgent(AgentForm{Name: "alice", Program: "mm", Workspace: "~/agents/alice"}) | ||
| 136 | +func (s *ConfigService) AddAgent(form AgentForm) ([]string, error) { | ||
| 137 | + entry, err := entryOf(form) | ||
| 138 | + if err != nil { | ||
| 139 | + return nil, err | ||
| 140 | + } | ||
| 141 | + path := s.Core.path() | ||
| 142 | + content, err := os.ReadFile(path) | ||
| 143 | + if err != nil { | ||
| 144 | + return nil, err | ||
| 145 | + } | ||
| 146 | + updated, err := config.AppendAgent(content, entry) | ||
| 147 | + var configError *config.Error | ||
| 148 | + if errors.As(err, &configError) { | ||
| 149 | + return messages(configError.Problems), nil | ||
| 150 | + } | ||
| 151 | + if err != nil { | ||
| 152 | + return nil, err | ||
| 153 | + } | ||
| 154 | + folder := entry.Workspace | ||
| 155 | + if folder == "~" || strings.HasPrefix(folder, "~/") { | ||
| 156 | + if home, err := os.UserHomeDir(); err == nil { | ||
| 157 | + folder = filepath.Join(home, strings.TrimPrefix(folder, "~")) | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + if !filepath.IsAbs(folder) { | ||
| 161 | + folder = filepath.Join(filepath.Dir(path), folder) | ||
| 162 | + } | ||
| 163 | + if err := os.MkdirAll(folder, 0o755); err != nil { | ||
| 164 | + return nil, err | ||
| 165 | + } | ||
| 166 | + return []string{}, config.Save(path, updated) | ||
| 167 | +} | ||
| 168 | + | ||
| 169 | +// ChooseFolder asks the user for a folder, starting in their home folder, | ||
| 170 | +// for the assistant's "agent's folder" field. It returns "" when the user | ||
| 171 | +// cancelled. | ||
| 172 | +func (s *ConfigService) ChooseFolder() (string, error) { | ||
| 173 | + if s.Core.options.PickFolder == nil { | ||
| 174 | + return "", errors.New("no folder dialog available") | ||
| 175 | + } | ||
| 176 | + home, _ := os.UserHomeDir() | ||
| 177 | + return s.Core.options.PickFolder(home) | ||
| 178 | +} | ||
added
internal/app/newagent_internal_test.go +76 -0 | new file mode 100644 | ||
| @@ -0,0 +1,76 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +package app | |
| 4 | + | |
| 5 | +import ( | |
| 6 | + "errors" | |
| 7 | + "reflect" | |
| 8 | + "testing" | |
| 9 | +) | |
| 10 | + | |
| 11 | +func TestSplitArgumentsReadsALineLikeAShell(t *testing.T) { | |
| 12 | + cases := map[string][]string{ | |
| 13 | + "": nil, | |
| 14 | + " ": nil, | |
| 15 | + "-acp": {"-acp"}, | |
| 16 | + "-acp -config agent.yaml": {"-acp", "-config", "agent.yaml"}, | |
| 17 | + `-config "my agent.yaml" -v`: {"-config", "my agent.yaml", "-v"}, | |
| 18 | + `--name 'it''s' ""`: {"--name", "its", ""}, | |
| 19 | + "\t-a\tb ": {"-a", "b"}, | |
| 20 | + } | |
| 21 | + for line, want := range cases { | |
| 22 | + got, err := splitArguments(line) | |
| 23 | + if err != nil || !reflect.DeepEqual(got, want) { | |
| 24 | + t.Errorf("splitArguments(%q) = %q, %v; want %q", line, got, err, want) | |
| 25 | + } | |
| 26 | + } | |
| 27 | + if _, err := splitArguments(`-config "unfinished`); err == nil { | |
| 28 | + t.Error("an unclosed quote is an error") | |
| 29 | + } | |
| 30 | +} | |
| 31 | + | |
| 32 | +func TestEntryOfALocalAgent(t *testing.T) { | |
| 33 | + entry, err := entryOf(AgentForm{Name: " alice ", Title: "Alice", Program: "mm", Arguments: "-acp -config agent.yaml", Workspace: "~/agents/alice"}) | |
| 34 | + if err != nil { | |
| 35 | + t.Fatal(err) | |
| 36 | + } | |
| 37 | + if entry.Name != "alice" || entry.Command != "mm" || !reflect.DeepEqual(entry.Args, []string{"-acp", "-config", "agent.yaml"}) || entry.Runtime != nil { | |
| 38 | + t.Fatalf("got %+v", entry) | |
| 39 | + } | |
| 40 | +} | |
| 41 | + | |
| 42 | +func TestEntryOfAnAgentInAContainerOrASandbox(t *testing.T) { | |
| 43 | + container, err := entryOf(AgentForm{Name: "scout", Environment: EnvironmentContainer, Box: "scout-box", Program: "mm", Arguments: "-acp", Workspace: "/agents/scout"}) | |
| 44 | + if err != nil { | |
| 45 | + t.Fatal(err) | |
| 46 | + } | |
| 47 | + if container.Command != "docker" || !reflect.DeepEqual(container.Args, []string{"exec", "-i", "scout-box", "mm", "-acp"}) || | |
| 48 | + container.Runtime == nil || container.Runtime.Type != "container" || container.Runtime.Container != "scout-box" { | |
| 49 | + t.Fatalf("container: %+v %+v", container, container.Runtime) | |
| 50 | + } | |
| 51 | + sandbox, err := entryOf(AgentForm{Name: "milo", Environment: EnvironmentSandbox, Box: "milo-sbx", Program: "mm", Workspace: "/agents/milo"}) | |
| 52 | + if err != nil { | |
| 53 | + t.Fatal(err) | |
| 54 | + } | |
| 55 | + if sandbox.Command != "sbx" || !reflect.DeepEqual(sandbox.Args, []string{"exec", "-i", "milo-sbx", "mm"}) || | |
| 56 | + sandbox.Runtime == nil || sandbox.Runtime.Type != "sbx" || sandbox.Runtime.Sandbox != "milo-sbx" { | |
| 57 | + t.Fatalf("sandbox: %+v %+v", sandbox, sandbox.Runtime) | |
| 58 | + } | |
| 59 | +} | |
| 60 | + | |
| 61 | +func TestEntryOfRefusesAnIncompleteForm(t *testing.T) { | |
| 62 | + incomplete := []AgentForm{ | |
| 63 | + {Program: "mm", Workspace: "/a"}, | |
| 64 | + {Name: "a", Workspace: "/a"}, | |
| 65 | + {Name: "a", Program: "mm"}, | |
| 66 | + {Name: "a", Program: "mm", Workspace: "/a", Environment: EnvironmentContainer}, | |
| 67 | + } | |
| 68 | + for _, form := range incomplete { | |
| 69 | + if _, err := entryOf(form); !errors.Is(err, errMissingField) { | |
| 70 | + t.Errorf("%+v: got %v", form, err) | |
| 71 | + } | |
| 72 | + } | |
| 73 | + if _, err := entryOf(AgentForm{Name: "a", Program: "mm", Workspace: "/a", Environment: "cloud"}); err == nil { | |
| 74 | + t.Error("an unknown environment is refused") | |
| 75 | + } | |
| 76 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +package app | ||
| 4 | + | ||
| 5 | +import ( | ||
| 6 | + "errors" | ||
| 7 | + "reflect" | ||
| 8 | + "testing" | ||
| 9 | +) | ||
| 10 | + | ||
| 11 | +func TestSplitArgumentsReadsALineLikeAShell(t *testing.T) { | ||
| 12 | + cases := map[string][]string{ | ||
| 13 | + "": nil, | ||
| 14 | + " ": nil, | ||
| 15 | + "-acp": {"-acp"}, | ||
| 16 | + "-acp -config agent.yaml": {"-acp", "-config", "agent.yaml"}, | ||
| 17 | + `-config "my agent.yaml" -v`: {"-config", "my agent.yaml", "-v"}, | ||
| 18 | + `--name 'it''s' ""`: {"--name", "its", ""}, | ||
| 19 | + "\t-a\tb ": {"-a", "b"}, | ||
| 20 | + } | ||
| 21 | + for line, want := range cases { | ||
| 22 | + got, err := splitArguments(line) | ||
| 23 | + if err != nil || !reflect.DeepEqual(got, want) { | ||
| 24 | + t.Errorf("splitArguments(%q) = %q, %v; want %q", line, got, err, want) | ||
| 25 | + } | ||
| 26 | + } | ||
| 27 | + if _, err := splitArguments(`-config "unfinished`); err == nil { | ||
| 28 | + t.Error("an unclosed quote is an error") | ||
| 29 | + } | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +func TestEntryOfALocalAgent(t *testing.T) { | ||
| 33 | + entry, err := entryOf(AgentForm{Name: " alice ", Title: "Alice", Program: "mm", Arguments: "-acp -config agent.yaml", Workspace: "~/agents/alice"}) | ||
| 34 | + if err != nil { | ||
| 35 | + t.Fatal(err) | ||
| 36 | + } | ||
| 37 | + if entry.Name != "alice" || entry.Command != "mm" || !reflect.DeepEqual(entry.Args, []string{"-acp", "-config", "agent.yaml"}) || entry.Runtime != nil { | ||
| 38 | + t.Fatalf("got %+v", entry) | ||
| 39 | + } | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +func TestEntryOfAnAgentInAContainerOrASandbox(t *testing.T) { | ||
| 43 | + container, err := entryOf(AgentForm{Name: "scout", Environment: EnvironmentContainer, Box: "scout-box", Program: "mm", Arguments: "-acp", Workspace: "/agents/scout"}) | ||
| 44 | + if err != nil { | ||
| 45 | + t.Fatal(err) | ||
| 46 | + } | ||
| 47 | + if container.Command != "docker" || !reflect.DeepEqual(container.Args, []string{"exec", "-i", "scout-box", "mm", "-acp"}) || | ||
| 48 | + container.Runtime == nil || container.Runtime.Type != "container" || container.Runtime.Container != "scout-box" { | ||
| 49 | + t.Fatalf("container: %+v %+v", container, container.Runtime) | ||
| 50 | + } | ||
| 51 | + sandbox, err := entryOf(AgentForm{Name: "milo", Environment: EnvironmentSandbox, Box: "milo-sbx", Program: "mm", Workspace: "/agents/milo"}) | ||
| 52 | + if err != nil { | ||
| 53 | + t.Fatal(err) | ||
| 54 | + } | ||
| 55 | + if sandbox.Command != "sbx" || !reflect.DeepEqual(sandbox.Args, []string{"exec", "-i", "milo-sbx", "mm"}) || | ||
| 56 | + sandbox.Runtime == nil || sandbox.Runtime.Type != "sbx" || sandbox.Runtime.Sandbox != "milo-sbx" { | ||
| 57 | + t.Fatalf("sandbox: %+v %+v", sandbox, sandbox.Runtime) | ||
| 58 | + } | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +func TestEntryOfRefusesAnIncompleteForm(t *testing.T) { | ||
| 62 | + incomplete := []AgentForm{ | ||
| 63 | + {Program: "mm", Workspace: "/a"}, | ||
| 64 | + {Name: "a", Workspace: "/a"}, | ||
| 65 | + {Name: "a", Program: "mm"}, | ||
| 66 | + {Name: "a", Program: "mm", Workspace: "/a", Environment: EnvironmentContainer}, | ||
| 67 | + } | ||
| 68 | + for _, form := range incomplete { | ||
| 69 | + if _, err := entryOf(form); !errors.Is(err, errMissingField) { | ||
| 70 | + t.Errorf("%+v: got %v", form, err) | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + if _, err := entryOf(AgentForm{Name: "a", Program: "mm", Workspace: "/a", Environment: "cloud"}); err == nil { | ||
| 74 | + t.Error("an unknown environment is refused") | ||
| 75 | + } | ||
| 76 | +} | ||
modified
internal/config/config_test.go +42 -0 | @@ -298,6 +298,48 @@ func TestAppendAgentKeepsComments(t *testing.T) { | ||
| 298 | 298 | } |
| 299 | 299 | } |
| 300 | 300 | |
| 301 | +func TestAppendAgentWritesTheRuntime(t *testing.T) { | |
| 302 | + entry := config.AgentEntry{ | |
| 303 | + Name: "scout", Command: "docker", Args: []string{"exec", "-i", "scout-box", "mm"}, Workspace: "/agents/scout", | |
| 304 | + Runtime: &config.RuntimeEntry{Type: "container", Container: "scout-box"}, | |
| 305 | + } | |
| 306 | + updated, err := config.AppendAgent([]byte(minimal), entry) | |
| 307 | + if err != nil { | |
| 308 | + t.Fatal(err) | |
| 309 | + } | |
| 310 | + cfg, err := config.Parse(updated, "/tmp/config.yaml") | |
| 311 | + if err != nil { | |
| 312 | + t.Fatal(err) | |
| 313 | + } | |
| 314 | + scout, _ := cfg.Agent("scout") | |
| 315 | + if scout.Runtime.Type != "container" || scout.Runtime.Container != "scout-box" || scout.Workspace != "/agents/scout" { | |
| 316 | + t.Fatalf("runtime not written:\n%s", updated) | |
| 317 | + } | |
| 318 | + local, _ := config.AppendAgent([]byte(minimal), config.AgentEntry{Name: "bob", Command: "mm"}) | |
| 319 | + if strings.Contains(string(local), "runtime") { | |
| 320 | + t.Fatalf("a local agent has no runtime key:\n%s", local) | |
| 321 | + } | |
| 322 | +} | |
| 323 | + | |
| 324 | +func TestAppendAgentKeepsEmojiReadable(t *testing.T) { | |
| 325 | + original := "version: 1\nagents:\n - name: alice\n icon: \"👩\"\n description: \"a \\\\U0001F916 literal\"\n command: mm\n" | |
| 326 | + updated, err := config.AppendAgent([]byte(original), config.AgentEntry{Name: "bob", Icon: "🤖", Command: "mm"}) | |
| 327 | + if err != nil { | |
| 328 | + t.Fatal(err) | |
| 329 | + } | |
| 330 | + text := string(updated) | |
| 331 | + if !strings.Contains(text, `"👩"`) || !strings.Contains(text, `"🤖"`) || strings.Contains(text, `"\U0001F`) { | |
| 332 | + t.Fatalf("emoji must stay readable:\n%s", text) | |
| 333 | + } | |
| 334 | + cfg, err := config.Parse(updated, "/tmp/config.yaml") | |
| 335 | + if err != nil { | |
| 336 | + t.Fatal(err) | |
| 337 | + } | |
| 338 | + if alice, _ := cfg.Agent("alice"); alice.Description != `a \U0001F916 literal` { | |
| 339 | + t.Fatalf("a literal backslash-U text is kept: %q", alice.Description) | |
| 340 | + } | |
| 341 | +} | |
| 342 | + | |
| 301 | 343 | func TestAppendAgentRejectsADuplicate(t *testing.T) { |
| 302 | 344 | if _, err := config.AppendAgent([]byte(minimal), config.AgentEntry{Name: "alice", Command: "mm"}); err == nil { |
| 303 | 345 | t.Fatal("a second alice must be refused") |
| @@ -298,6 +298,48 @@ func TestAppendAgentKeepsComments(t *testing.T) { | |||
| 298 | } | 298 | } |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | +func TestAppendAgentWritesTheRuntime(t *testing.T) { | ||
| 302 | + entry := config.AgentEntry{ | ||
| 303 | + Name: "scout", Command: "docker", Args: []string{"exec", "-i", "scout-box", "mm"}, Workspace: "/agents/scout", | ||
| 304 | + Runtime: &config.RuntimeEntry{Type: "container", Container: "scout-box"}, | ||
| 305 | + } | ||
| 306 | + updated, err := config.AppendAgent([]byte(minimal), entry) | ||
| 307 | + if err != nil { | ||
| 308 | + t.Fatal(err) | ||
| 309 | + } | ||
| 310 | + cfg, err := config.Parse(updated, "/tmp/config.yaml") | ||
| 311 | + if err != nil { | ||
| 312 | + t.Fatal(err) | ||
| 313 | + } | ||
| 314 | + scout, _ := cfg.Agent("scout") | ||
| 315 | + if scout.Runtime.Type != "container" || scout.Runtime.Container != "scout-box" || scout.Workspace != "/agents/scout" { | ||
| 316 | + t.Fatalf("runtime not written:\n%s", updated) | ||
| 317 | + } | ||
| 318 | + local, _ := config.AppendAgent([]byte(minimal), config.AgentEntry{Name: "bob", Command: "mm"}) | ||
| 319 | + if strings.Contains(string(local), "runtime") { | ||
| 320 | + t.Fatalf("a local agent has no runtime key:\n%s", local) | ||
| 321 | + } | ||
| 322 | +} | ||
| 323 | + | ||
| 324 | +func TestAppendAgentKeepsEmojiReadable(t *testing.T) { | ||
| 325 | + original := "version: 1\nagents:\n - name: alice\n icon: \"👩\"\n description: \"a \\\\U0001F916 literal\"\n command: mm\n" | ||
| 326 | + updated, err := config.AppendAgent([]byte(original), config.AgentEntry{Name: "bob", Icon: "🤖", Command: "mm"}) | ||
| 327 | + if err != nil { | ||
| 328 | + t.Fatal(err) | ||
| 329 | + } | ||
| 330 | + text := string(updated) | ||
| 331 | + if !strings.Contains(text, `"👩"`) || !strings.Contains(text, `"🤖"`) || strings.Contains(text, `"\U0001F`) { | ||
| 332 | + t.Fatalf("emoji must stay readable:\n%s", text) | ||
| 333 | + } | ||
| 334 | + cfg, err := config.Parse(updated, "/tmp/config.yaml") | ||
| 335 | + if err != nil { | ||
| 336 | + t.Fatal(err) | ||
| 337 | + } | ||
| 338 | + if alice, _ := cfg.Agent("alice"); alice.Description != `a \U0001F916 literal` { | ||
| 339 | + t.Fatalf("a literal backslash-U text is kept: %q", alice.Description) | ||
| 340 | + } | ||
| 341 | +} | ||
| 342 | + | ||
| 301 | func TestAppendAgentRejectsADuplicate(t *testing.T) { | 343 | func TestAppendAgentRejectsADuplicate(t *testing.T) { |
| 302 | if _, err := config.AppendAgent([]byte(minimal), config.AgentEntry{Name: "alice", Command: "mm"}); err == nil { | 344 | if _, err := config.AppendAgent([]byte(minimal), config.AgentEntry{Name: "alice", Command: "mm"}); err == nil { |
| 303 | t.Fatal("a second alice must be refused") | 345 | t.Fatal("a second alice must be refused") |
modified
internal/config/default.go +3 -1 | @@ -31,8 +31,10 @@ limits: | ||
| 31 | 31 | stopIdleAgentsAfter: 10m |
| 32 | 32 | |
| 33 | 33 | # The agents: call them in a conversation by clicking their name. |
| 34 | +# The simplest way to add one is the "Add an agent" button of Sidekicks. | |
| 34 | 35 | agents: [] |
| 35 | -# Example, to copy between the brackets above (removing the "#"): | |
| 36 | +# Or write it yourself. An example (remove the "#", and the "[]" above | |
| 37 | +# while the list is empty): | |
| 36 | 38 | # - name: alice # the name used with @alice |
| 37 | 39 | # title: Alice (assistant) # the name shown |
| 38 | 40 | # icon: "👩" |
| @@ -31,8 +31,10 @@ limits: | |||
| 31 | stopIdleAgentsAfter: 10m | 31 | stopIdleAgentsAfter: 10m |
| 32 | 32 | ||
| 33 | # The agents: call them in a conversation by clicking their name. | 33 | # The agents: call them in a conversation by clicking their name. |
| 34 | +# The simplest way to add one is the "Add an agent" button of Sidekicks. | ||
| 34 | agents: [] | 35 | agents: [] |
| 35 | -# Example, to copy between the brackets above (removing the "#"): | 36 | +# Or write it yourself. An example (remove the "#", and the "[]" above |
| 37 | +# while the list is empty): | ||
| 36 | # - name: alice # the name used with @alice | 38 | # - name: alice # the name used with @alice |
| 37 | # title: Alice (assistant) # the name shown | 39 | # title: Alice (assistant) # the name shown |
| 38 | # icon: "👩" | 40 | # icon: "👩" |
modified
internal/config/save.go +44 -2 | @@ -7,6 +7,8 @@ import ( | ||
| 7 | 7 | "errors" |
| 8 | 8 | "fmt" |
| 9 | 9 | "path/filepath" |
| 10 | + "strconv" | |
| 11 | + "unicode/utf8" | |
| 10 | 12 | |
| 11 | 13 | "go.yaml.in/yaml/v3" |
| 12 | 14 | ) |
| @@ -38,6 +40,17 @@ type AgentEntry struct { | ||
| 38 | 40 | Args []string `yaml:"args,omitempty,flow"` |
| 39 | 41 | Env map[string]string `yaml:"env,omitempty"` |
| 40 | 42 | Workspace string `yaml:"workspace,omitempty"` |
| 43 | + // Runtime is left out for an agent that runs on this computer. | |
| 44 | + Runtime *RuntimeEntry `yaml:"runtime,omitempty"` | |
| 45 | +} | |
| 46 | + | |
| 47 | +// RuntimeEntry is the runtime of an AgentEntry: where its files and its | |
| 48 | +// terminal are when the agent runs in a container or an sbx sandbox. | |
| 49 | +type RuntimeEntry struct { | |
| 50 | + Type string `yaml:"type"` | |
| 51 | + Container string `yaml:"container,omitempty"` | |
| 52 | + Sandbox string `yaml:"sandbox,omitempty"` | |
| 53 | + WorkspacePath string `yaml:"workspacePath,omitempty"` | |
| 41 | 54 | } |
| 42 | 55 | |
| 43 | 56 | // AppendAgent returns content with entry added at the end of the agents list. |
| @@ -79,8 +92,37 @@ func AppendAgent(content []byte, entry AgentEntry) ([]byte, error) { | ||
| 79 | 92 | if err := encoder.Close(); err != nil { |
| 80 | 93 | return nil, err |
| 81 | 94 | } |
| 82 | - if _, err := Parse(buffer.Bytes(), "/"); err != nil { | |
| 95 | + updated := unescapeLongCharacters(buffer.Bytes()) | |
| 96 | + if _, err := Parse(updated, "/"); err != nil { | |
| 83 | 97 | return nil, fmt.Errorf("the agent cannot be added: %w", err) |
| 84 | 98 | } |
| 85 | - return buffer.Bytes(), nil | |
| 99 | + return updated, nil | |
| 100 | +} | |
| 101 | + | |
| 102 | +// unescapeLongCharacters writes back the characters the YAML encoder escapes | |
| 103 | +// as \UXXXXXXXX in double-quoted strings, emoji above all: the file is read | |
| 104 | +// by people, and an icon must stay "🤖", not "\U0001F916". An escaped | |
| 105 | +// backslash ("\\") is copied as it is, so a literal "\U…" text is kept. | |
| 106 | +// | |
| 107 | +// unescapeLongCharacters([]byte(`icon: "\U0001F916"`)) // icon: "🤖" | |
| 108 | +func unescapeLongCharacters(content []byte) []byte { | |
| 109 | + var result bytes.Buffer | |
| 110 | + for index := 0; index < len(content); index++ { | |
| 111 | + if content[index] != '\\' || index+1 >= len(content) { | |
| 112 | + result.WriteByte(content[index]) | |
| 113 | + continue | |
| 114 | + } | |
| 115 | + next := content[index+1] | |
| 116 | + if next == 'U' && index+10 <= len(content) { | |
| 117 | + if code, err := strconv.ParseUint(string(content[index+2:index+10]), 16, 32); err == nil && utf8.ValidRune(rune(code)) { | |
| 118 | + result.WriteRune(rune(code)) | |
| 119 | + index += 9 | |
| 120 | + continue | |
| 121 | + } | |
| 122 | + } | |
| 123 | + result.WriteByte('\\') | |
| 124 | + result.WriteByte(next) | |
| 125 | + index++ | |
| 126 | + } | |
| 127 | + return result.Bytes() | |
| 86 | 128 | } |
| @@ -7,6 +7,8 @@ import ( | |||
| 7 | "errors" | 7 | "errors" |
| 8 | "fmt" | 8 | "fmt" |
| 9 | "path/filepath" | 9 | "path/filepath" |
| 10 | + "strconv" | ||
| 11 | + "unicode/utf8" | ||
| 10 | 12 | ||
| 11 | "go.yaml.in/yaml/v3" | 13 | "go.yaml.in/yaml/v3" |
| 12 | ) | 14 | ) |
| @@ -38,6 +40,17 @@ type AgentEntry struct { | |||
| 38 | Args []string `yaml:"args,omitempty,flow"` | 40 | Args []string `yaml:"args,omitempty,flow"` |
| 39 | Env map[string]string `yaml:"env,omitempty"` | 41 | Env map[string]string `yaml:"env,omitempty"` |
| 40 | Workspace string `yaml:"workspace,omitempty"` | 42 | Workspace string `yaml:"workspace,omitempty"` |
| 43 | + // Runtime is left out for an agent that runs on this computer. | ||
| 44 | + Runtime *RuntimeEntry `yaml:"runtime,omitempty"` | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +// RuntimeEntry is the runtime of an AgentEntry: where its files and its | ||
| 48 | +// terminal are when the agent runs in a container or an sbx sandbox. | ||
| 49 | +type RuntimeEntry struct { | ||
| 50 | + Type string `yaml:"type"` | ||
| 51 | + Container string `yaml:"container,omitempty"` | ||
| 52 | + Sandbox string `yaml:"sandbox,omitempty"` | ||
| 53 | + WorkspacePath string `yaml:"workspacePath,omitempty"` | ||
| 41 | } | 54 | } |
| 42 | 55 | ||
| 43 | // AppendAgent returns content with entry added at the end of the agents list. | 56 | // AppendAgent returns content with entry added at the end of the agents list. |
| @@ -79,8 +92,37 @@ func AppendAgent(content []byte, entry AgentEntry) ([]byte, error) { | |||
| 79 | if err := encoder.Close(); err != nil { | 92 | if err := encoder.Close(); err != nil { |
| 80 | return nil, err | 93 | return nil, err |
| 81 | } | 94 | } |
| 82 | - if _, err := Parse(buffer.Bytes(), "/"); err != nil { | 95 | + updated := unescapeLongCharacters(buffer.Bytes()) |
| 96 | + if _, err := Parse(updated, "/"); err != nil { | ||
| 83 | return nil, fmt.Errorf("the agent cannot be added: %w", err) | 97 | return nil, fmt.Errorf("the agent cannot be added: %w", err) |
| 84 | } | 98 | } |
| 85 | - return buffer.Bytes(), nil | 99 | + return updated, nil |
| 100 | +} | ||
| 101 | + | ||
| 102 | +// unescapeLongCharacters writes back the characters the YAML encoder escapes | ||
| 103 | +// as \UXXXXXXXX in double-quoted strings, emoji above all: the file is read | ||
| 104 | +// by people, and an icon must stay "🤖", not "\U0001F916". An escaped | ||
| 105 | +// backslash ("\\") is copied as it is, so a literal "\U…" text is kept. | ||
| 106 | +// | ||
| 107 | +// unescapeLongCharacters([]byte(`icon: "\U0001F916"`)) // icon: "🤖" | ||
| 108 | +func unescapeLongCharacters(content []byte) []byte { | ||
| 109 | + var result bytes.Buffer | ||
| 110 | + for index := 0; index < len(content); index++ { | ||
| 111 | + if content[index] != '\\' || index+1 >= len(content) { | ||
| 112 | + result.WriteByte(content[index]) | ||
| 113 | + continue | ||
| 114 | + } | ||
| 115 | + next := content[index+1] | ||
| 116 | + if next == 'U' && index+10 <= len(content) { | ||
| 117 | + if code, err := strconv.ParseUint(string(content[index+2:index+10]), 16, 32); err == nil && utf8.ValidRune(rune(code)) { | ||
| 118 | + result.WriteRune(rune(code)) | ||
| 119 | + index += 9 | ||
| 120 | + continue | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + result.WriteByte('\\') | ||
| 124 | + result.WriteByte(next) | ||
| 125 | + index++ | ||
| 126 | + } | ||
| 127 | + return result.Bytes() | ||
| 86 | } | 128 | } |
added
internal/shellpath/shellpath.go +99 -0 | new file mode 100644 | ||
| @@ -0,0 +1,99 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +// Package shellpath gives Sidekicks the PATH of the user's terminal. | |
| 4 | +// | |
| 5 | +// An application opened from the Finder (or a desktop launcher) does not | |
| 6 | +// get the PATH of the user's shell: on macOS it is only | |
| 7 | +// /usr/bin:/bin:/usr/sbin:/sbin, so mm, docker or sbx installed with | |
| 8 | +// Homebrew or in ~/.local/bin cannot be found. At startup, Sidekicks asks the | |
| 9 | +// user's shell for its PATH and adds it to its own. | |
| 10 | +// | |
| 11 | +// ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | |
| 12 | +// defer cancel() | |
| 13 | +// if err := shellpath.Apply(ctx); err != nil { log.Print(err) } | |
| 14 | +package shellpath | |
| 15 | + | |
| 16 | +import ( | |
| 17 | + "bytes" | |
| 18 | + "context" | |
| 19 | + "errors" | |
| 20 | + "os" | |
| 21 | + "os/exec" | |
| 22 | + "path/filepath" | |
| 23 | + "runtime" | |
| 24 | + "strings" | |
| 25 | +) | |
| 26 | + | |
| 27 | +// The PATH is printed between two markers: a shell configuration may print | |
| 28 | +// other things (a greeting, a warning) before or after it. | |
| 29 | +const ( | |
| 30 | + startMarker = "__SIDEKICKS_PATH_START__" | |
| 31 | + endMarker = "__SIDEKICKS_PATH_END__" | |
| 32 | +) | |
| 33 | + | |
| 34 | +// FromShell runs shell as an interactive login shell, so that it reads the | |
| 35 | +// same files as a terminal (.zprofile and .zshrc for zsh), and returns its | |
| 36 | +// PATH. | |
| 37 | +// | |
| 38 | +// path, err := shellpath.FromShell(ctx, "/bin/zsh") | |
| 39 | +func FromShell(ctx context.Context, shell string) (string, error) { | |
| 40 | + command := exec.CommandContext(ctx, shell, "-i", "-l", "-c", `printf '%s%s%s' "`+startMarker+`" "$PATH" "`+endMarker+`"`) | |
| 41 | + command.Stdin = nil | |
| 42 | + var output bytes.Buffer | |
| 43 | + command.Stdout = &output | |
| 44 | + if err := command.Run(); err != nil && !strings.Contains(output.String(), endMarker) { | |
| 45 | + return "", err | |
| 46 | + } | |
| 47 | + text := output.String() | |
| 48 | + start := strings.LastIndex(text, startMarker) | |
| 49 | + if start < 0 { | |
| 50 | + return "", errors.New("the shell did not print its PATH") | |
| 51 | + } | |
| 52 | + text = text[start+len(startMarker):] | |
| 53 | + end := strings.Index(text, endMarker) | |
| 54 | + if end < 0 { | |
| 55 | + return "", errors.New("the shell did not print its PATH") | |
| 56 | + } | |
| 57 | + return text[:end], nil | |
| 58 | +} | |
| 59 | + | |
| 60 | +// Merge returns the folders of first, then those of second that first does | |
| 61 | +// not have, without empty entries. The shell's PATH comes first, as in a | |
| 62 | +// terminal. | |
| 63 | +// | |
| 64 | +// shellpath.Merge("/opt/homebrew/bin:/usr/bin", "/usr/bin:/bin") // "/opt/homebrew/bin:/usr/bin:/bin" | |
| 65 | +func Merge(first, second string) string { | |
| 66 | + seen := map[string]bool{} | |
| 67 | + var folders []string | |
| 68 | + for _, list := range []string{first, second} { | |
| 69 | + for _, folder := range filepath.SplitList(list) { | |
| 70 | + if folder == "" || seen[folder] { | |
| 71 | + continue | |
| 72 | + } | |
| 73 | + seen[folder] = true | |
| 74 | + folders = append(folders, folder) | |
| 75 | + } | |
| 76 | + } | |
| 77 | + return strings.Join(folders, string(os.PathListSeparator)) | |
| 78 | +} | |
| 79 | + | |
| 80 | +// Apply adds the PATH of the user's shell ($SHELL, else zsh on macOS and sh | |
| 81 | +// elsewhere) to the PATH of this process, which the agents inherit. It does | |
| 82 | +// nothing on Windows. On failure the PATH is left unchanged. | |
| 83 | +func Apply(ctx context.Context) error { | |
| 84 | + if runtime.GOOS == "windows" { | |
| 85 | + return nil | |
| 86 | + } | |
| 87 | + shell := os.Getenv("SHELL") | |
| 88 | + if shell == "" { | |
| 89 | + shell = "/bin/sh" | |
| 90 | + if runtime.GOOS == "darwin" { | |
| 91 | + shell = "/bin/zsh" | |
| 92 | + } | |
| 93 | + } | |
| 94 | + path, err := FromShell(ctx, shell) | |
| 95 | + if err != nil { | |
| 96 | + return err | |
| 97 | + } | |
| 98 | + return os.Setenv("PATH", Merge(path, os.Getenv("PATH"))) | |
| 99 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +// Package shellpath gives Sidekicks the PATH of the user's terminal. | ||
| 4 | +// | ||
| 5 | +// An application opened from the Finder (or a desktop launcher) does not | ||
| 6 | +// get the PATH of the user's shell: on macOS it is only | ||
| 7 | +// /usr/bin:/bin:/usr/sbin:/sbin, so mm, docker or sbx installed with | ||
| 8 | +// Homebrew or in ~/.local/bin cannot be found. At startup, Sidekicks asks the | ||
| 9 | +// user's shell for its PATH and adds it to its own. | ||
| 10 | +// | ||
| 11 | +// ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
| 12 | +// defer cancel() | ||
| 13 | +// if err := shellpath.Apply(ctx); err != nil { log.Print(err) } | ||
| 14 | +package shellpath | ||
| 15 | + | ||
| 16 | +import ( | ||
| 17 | + "bytes" | ||
| 18 | + "context" | ||
| 19 | + "errors" | ||
| 20 | + "os" | ||
| 21 | + "os/exec" | ||
| 22 | + "path/filepath" | ||
| 23 | + "runtime" | ||
| 24 | + "strings" | ||
| 25 | +) | ||
| 26 | + | ||
| 27 | +// The PATH is printed between two markers: a shell configuration may print | ||
| 28 | +// other things (a greeting, a warning) before or after it. | ||
| 29 | +const ( | ||
| 30 | + startMarker = "__SIDEKICKS_PATH_START__" | ||
| 31 | + endMarker = "__SIDEKICKS_PATH_END__" | ||
| 32 | +) | ||
| 33 | + | ||
| 34 | +// FromShell runs shell as an interactive login shell, so that it reads the | ||
| 35 | +// same files as a terminal (.zprofile and .zshrc for zsh), and returns its | ||
| 36 | +// PATH. | ||
| 37 | +// | ||
| 38 | +// path, err := shellpath.FromShell(ctx, "/bin/zsh") | ||
| 39 | +func FromShell(ctx context.Context, shell string) (string, error) { | ||
| 40 | + command := exec.CommandContext(ctx, shell, "-i", "-l", "-c", `printf '%s%s%s' "`+startMarker+`" "$PATH" "`+endMarker+`"`) | ||
| 41 | + command.Stdin = nil | ||
| 42 | + var output bytes.Buffer | ||
| 43 | + command.Stdout = &output | ||
| 44 | + if err := command.Run(); err != nil && !strings.Contains(output.String(), endMarker) { | ||
| 45 | + return "", err | ||
| 46 | + } | ||
| 47 | + text := output.String() | ||
| 48 | + start := strings.LastIndex(text, startMarker) | ||
| 49 | + if start < 0 { | ||
| 50 | + return "", errors.New("the shell did not print its PATH") | ||
| 51 | + } | ||
| 52 | + text = text[start+len(startMarker):] | ||
| 53 | + end := strings.Index(text, endMarker) | ||
| 54 | + if end < 0 { | ||
| 55 | + return "", errors.New("the shell did not print its PATH") | ||
| 56 | + } | ||
| 57 | + return text[:end], nil | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// Merge returns the folders of first, then those of second that first does | ||
| 61 | +// not have, without empty entries. The shell's PATH comes first, as in a | ||
| 62 | +// terminal. | ||
| 63 | +// | ||
| 64 | +// shellpath.Merge("/opt/homebrew/bin:/usr/bin", "/usr/bin:/bin") // "/opt/homebrew/bin:/usr/bin:/bin" | ||
| 65 | +func Merge(first, second string) string { | ||
| 66 | + seen := map[string]bool{} | ||
| 67 | + var folders []string | ||
| 68 | + for _, list := range []string{first, second} { | ||
| 69 | + for _, folder := range filepath.SplitList(list) { | ||
| 70 | + if folder == "" || seen[folder] { | ||
| 71 | + continue | ||
| 72 | + } | ||
| 73 | + seen[folder] = true | ||
| 74 | + folders = append(folders, folder) | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + return strings.Join(folders, string(os.PathListSeparator)) | ||
| 78 | +} | ||
| 79 | + | ||
| 80 | +// Apply adds the PATH of the user's shell ($SHELL, else zsh on macOS and sh | ||
| 81 | +// elsewhere) to the PATH of this process, which the agents inherit. It does | ||
| 82 | +// nothing on Windows. On failure the PATH is left unchanged. | ||
| 83 | +func Apply(ctx context.Context) error { | ||
| 84 | + if runtime.GOOS == "windows" { | ||
| 85 | + return nil | ||
| 86 | + } | ||
| 87 | + shell := os.Getenv("SHELL") | ||
| 88 | + if shell == "" { | ||
| 89 | + shell = "/bin/sh" | ||
| 90 | + if runtime.GOOS == "darwin" { | ||
| 91 | + shell = "/bin/zsh" | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + path, err := FromShell(ctx, shell) | ||
| 95 | + if err != nil { | ||
| 96 | + return err | ||
| 97 | + } | ||
| 98 | + return os.Setenv("PATH", Merge(path, os.Getenv("PATH"))) | ||
| 99 | +} | ||
added
internal/shellpath/shellpath_test.go +71 -0 | new file mode 100644 | ||
| @@ -0,0 +1,71 @@ | ||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | + | |
| 3 | +package shellpath_test | |
| 4 | + | |
| 5 | +import ( | |
| 6 | + "context" | |
| 7 | + "os" | |
| 8 | + "path/filepath" | |
| 9 | + "testing" | |
| 10 | + "time" | |
| 11 | + | |
| 12 | + "git.rickub.com/bots-garden/sidekicks/internal/shellpath" | |
| 13 | +) | |
| 14 | + | |
| 15 | +// fakeShell writes a shell that prints noise around what it is asked to run, | |
| 16 | +// with PATH set to path, like a chatty .zshrc would. | |
| 17 | +func fakeShell(t *testing.T, path string) string { | |
| 18 | + t.Helper() | |
| 19 | + shell := filepath.Join(t.TempDir(), "fake-shell") | |
| 20 | + script := "#!/bin/sh\necho 'Welcome!'\nshift 3\nPATH='" + path + "' /bin/sh -c \"$1\"\necho 'bye'\n" | |
| 21 | + if err := os.WriteFile(shell, []byte(script), 0o755); err != nil { | |
| 22 | + t.Fatal(err) | |
| 23 | + } | |
| 24 | + return shell | |
| 25 | +} | |
| 26 | + | |
| 27 | +func TestFromShellReadsThePathBetweenTheNoise(t *testing.T) { | |
| 28 | + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | |
| 29 | + defer cancel() | |
| 30 | + got, err := shellpath.FromShell(ctx, fakeShell(t, "/opt/homebrew/bin:/usr/bin")) | |
| 31 | + if err != nil || got != "/opt/homebrew/bin:/usr/bin" { | |
| 32 | + t.Fatalf("got %q %v", got, err) | |
| 33 | + } | |
| 34 | +} | |
| 35 | + | |
| 36 | +func TestFromShellFailsWithoutAPath(t *testing.T) { | |
| 37 | + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | |
| 38 | + defer cancel() | |
| 39 | + if _, err := shellpath.FromShell(ctx, "/bin/false"); err == nil { | |
| 40 | + t.Fatal("a shell that prints nothing is an error") | |
| 41 | + } | |
| 42 | + if _, err := shellpath.FromShell(ctx, filepath.Join(t.TempDir(), "missing")); err == nil { | |
| 43 | + t.Fatal("a missing shell is an error") | |
| 44 | + } | |
| 45 | +} | |
| 46 | + | |
| 47 | +func TestMergePutsTheShellFirstWithoutDuplicates(t *testing.T) { | |
| 48 | + cases := []struct{ first, second, want string }{ | |
| 49 | + {"/opt/homebrew/bin:/usr/bin", "/usr/bin:/bin", "/opt/homebrew/bin:/usr/bin:/bin"}, | |
| 50 | + {"", "/usr/bin:/bin", "/usr/bin:/bin"}, | |
| 51 | + {"/a::/a", "", "/a"}, | |
| 52 | + } | |
| 53 | + for _, c := range cases { | |
| 54 | + if got := shellpath.Merge(c.first, c.second); got != c.want { | |
| 55 | + t.Errorf("Merge(%q, %q) = %q, want %q", c.first, c.second, got, c.want) | |
| 56 | + } | |
| 57 | + } | |
| 58 | +} | |
| 59 | + | |
| 60 | +func TestApplyAddsTheShellsPathToTheProcess(t *testing.T) { | |
| 61 | + t.Setenv("SHELL", fakeShell(t, "/from/the/shell:/usr/bin")) | |
| 62 | + t.Setenv("PATH", "/usr/bin:/bin") | |
| 63 | + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | |
| 64 | + defer cancel() | |
| 65 | + if err := shellpath.Apply(ctx); err != nil { | |
| 66 | + t.Fatal(err) | |
| 67 | + } | |
| 68 | + if got := os.Getenv("PATH"); got != "/from/the/shell:/usr/bin:/bin" { | |
| 69 | + t.Fatalf("PATH = %q", got) | |
| 70 | + } | |
| 71 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | +// Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | + | ||
| 3 | +package shellpath_test | ||
| 4 | + | ||
| 5 | +import ( | ||
| 6 | + "context" | ||
| 7 | + "os" | ||
| 8 | + "path/filepath" | ||
| 9 | + "testing" | ||
| 10 | + "time" | ||
| 11 | + | ||
| 12 | + "git.rickub.com/bots-garden/sidekicks/internal/shellpath" | ||
| 13 | +) | ||
| 14 | + | ||
| 15 | +// fakeShell writes a shell that prints noise around what it is asked to run, | ||
| 16 | +// with PATH set to path, like a chatty .zshrc would. | ||
| 17 | +func fakeShell(t *testing.T, path string) string { | ||
| 18 | + t.Helper() | ||
| 19 | + shell := filepath.Join(t.TempDir(), "fake-shell") | ||
| 20 | + script := "#!/bin/sh\necho 'Welcome!'\nshift 3\nPATH='" + path + "' /bin/sh -c \"$1\"\necho 'bye'\n" | ||
| 21 | + if err := os.WriteFile(shell, []byte(script), 0o755); err != nil { | ||
| 22 | + t.Fatal(err) | ||
| 23 | + } | ||
| 24 | + return shell | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +func TestFromShellReadsThePathBetweenTheNoise(t *testing.T) { | ||
| 28 | + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
| 29 | + defer cancel() | ||
| 30 | + got, err := shellpath.FromShell(ctx, fakeShell(t, "/opt/homebrew/bin:/usr/bin")) | ||
| 31 | + if err != nil || got != "/opt/homebrew/bin:/usr/bin" { | ||
| 32 | + t.Fatalf("got %q %v", got, err) | ||
| 33 | + } | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +func TestFromShellFailsWithoutAPath(t *testing.T) { | ||
| 37 | + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
| 38 | + defer cancel() | ||
| 39 | + if _, err := shellpath.FromShell(ctx, "/bin/false"); err == nil { | ||
| 40 | + t.Fatal("a shell that prints nothing is an error") | ||
| 41 | + } | ||
| 42 | + if _, err := shellpath.FromShell(ctx, filepath.Join(t.TempDir(), "missing")); err == nil { | ||
| 43 | + t.Fatal("a missing shell is an error") | ||
| 44 | + } | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +func TestMergePutsTheShellFirstWithoutDuplicates(t *testing.T) { | ||
| 48 | + cases := []struct{ first, second, want string }{ | ||
| 49 | + {"/opt/homebrew/bin:/usr/bin", "/usr/bin:/bin", "/opt/homebrew/bin:/usr/bin:/bin"}, | ||
| 50 | + {"", "/usr/bin:/bin", "/usr/bin:/bin"}, | ||
| 51 | + {"/a::/a", "", "/a"}, | ||
| 52 | + } | ||
| 53 | + for _, c := range cases { | ||
| 54 | + if got := shellpath.Merge(c.first, c.second); got != c.want { | ||
| 55 | + t.Errorf("Merge(%q, %q) = %q, want %q", c.first, c.second, got, c.want) | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +func TestApplyAddsTheShellsPathToTheProcess(t *testing.T) { | ||
| 61 | + t.Setenv("SHELL", fakeShell(t, "/from/the/shell:/usr/bin")) | ||
| 62 | + t.Setenv("PATH", "/usr/bin:/bin") | ||
| 63 | + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
| 64 | + defer cancel() | ||
| 65 | + if err := shellpath.Apply(ctx); err != nil { | ||
| 66 | + t.Fatal(err) | ||
| 67 | + } | ||
| 68 | + if got := os.Getenv("PATH"); got != "/from/the/shell:/usr/bin:/bin" { | ||
| 69 | + t.Fatalf("PATH = %q", got) | ||
| 70 | + } | ||
| 71 | +} | ||
modified
main.go +20 -1 | @@ -15,12 +15,14 @@ import ( | ||
| 15 | 15 | "fmt" |
| 16 | 16 | "log" |
| 17 | 17 | "os" |
| 18 | + "time" | |
| 18 | 19 | |
| 19 | 20 | "git.rickub.com/bots-garden/sidekicks/internal/app" |
| 20 | 21 | "git.rickub.com/bots-garden/sidekicks/internal/channels" |
| 21 | 22 | "git.rickub.com/bots-garden/sidekicks/internal/config" |
| 22 | 23 | "git.rickub.com/bots-garden/sidekicks/internal/events" |
| 23 | 24 | "git.rickub.com/bots-garden/sidekicks/internal/prefs" |
| 25 | + "git.rickub.com/bots-garden/sidekicks/internal/shellpath" | |
| 24 | 26 | "git.rickub.com/bots-garden/sidekicks/internal/workspace" |
| 25 | 27 | "github.com/wailsapp/wails/v3/pkg/application" |
| 26 | 28 | ) |
| @@ -54,6 +56,14 @@ func main() { | ||
| 54 | 56 | configPath := flag.String("config", "", "configuration file (default: $"+config.EnvironmentVariable+", then the default location)") |
| 55 | 57 | flag.Parse() |
| 56 | 58 | |
| 59 | + // Before the configuration is read: its warnings say whether each | |
| 60 | + // agent's program can be found, and the agents inherit this PATH. | |
| 61 | + shellCtx, shellCancel := context.WithTimeout(context.Background(), 5*time.Second) | |
| 62 | + if err := shellpath.Apply(shellCtx); err != nil { | |
| 63 | + log.Printf("sidekicks: the PATH of your shell could not be read (%v); programs are looked up in %s", err, os.Getenv("PATH")) | |
| 64 | + } | |
| 65 | + shellCancel() | |
| 66 | + | |
| 57 | 67 | var preferences *prefs.Store |
| 58 | 68 | if path, err := prefs.DefaultPath(); err == nil { |
| 59 | 69 | preferences = prefs.NewStore(path) |
| @@ -84,7 +94,16 @@ func main() { | ||
| 84 | 94 | AddFilter("YAML configuration", "*.yaml;*.yml"). |
| 85 | 95 | PromptForSingleSelection() |
| 86 | 96 | } |
| 87 | - core := app.New(location, app.Options{Emitter: emitter, Preferences: preferences, PickFile: pickFile}) | |
| 97 | + pickFolder := func(folder string) (string, error) { | |
| 98 | + return wailsApp.Dialog.OpenFile(). | |
| 99 | + SetTitle("Choose the agent's folder"). | |
| 100 | + SetDirectory(folder). | |
| 101 | + CanChooseFiles(false). | |
| 102 | + CanChooseDirectories(true). | |
| 103 | + CanCreateDirectories(true). | |
| 104 | + PromptForSingleSelection() | |
| 105 | + } | |
| 106 | + core := app.New(location, app.Options{Emitter: emitter, Preferences: preferences, PickFile: pickFile, PickFolder: pickFolder}) | |
| 88 | 107 | ctx, cancel := context.WithCancel(context.Background()) |
| 89 | 108 | |
| 90 | 109 | wailsApp = application.New(application.Options{ |
| @@ -15,12 +15,14 @@ import ( | |||
| 15 | "fmt" | 15 | "fmt" |
| 16 | "log" | 16 | "log" |
| 17 | "os" | 17 | "os" |
| 18 | + "time" | ||
| 18 | 19 | ||
| 19 | "git.rickub.com/bots-garden/sidekicks/internal/app" | 20 | "git.rickub.com/bots-garden/sidekicks/internal/app" |
| 20 | "git.rickub.com/bots-garden/sidekicks/internal/channels" | 21 | "git.rickub.com/bots-garden/sidekicks/internal/channels" |
| 21 | "git.rickub.com/bots-garden/sidekicks/internal/config" | 22 | "git.rickub.com/bots-garden/sidekicks/internal/config" |
| 22 | "git.rickub.com/bots-garden/sidekicks/internal/events" | 23 | "git.rickub.com/bots-garden/sidekicks/internal/events" |
| 23 | "git.rickub.com/bots-garden/sidekicks/internal/prefs" | 24 | "git.rickub.com/bots-garden/sidekicks/internal/prefs" |
| 25 | + "git.rickub.com/bots-garden/sidekicks/internal/shellpath" | ||
| 24 | "git.rickub.com/bots-garden/sidekicks/internal/workspace" | 26 | "git.rickub.com/bots-garden/sidekicks/internal/workspace" |
| 25 | "github.com/wailsapp/wails/v3/pkg/application" | 27 | "github.com/wailsapp/wails/v3/pkg/application" |
| 26 | ) | 28 | ) |
| @@ -54,6 +56,14 @@ func main() { | |||
| 54 | configPath := flag.String("config", "", "configuration file (default: $"+config.EnvironmentVariable+", then the default location)") | 56 | configPath := flag.String("config", "", "configuration file (default: $"+config.EnvironmentVariable+", then the default location)") |
| 55 | flag.Parse() | 57 | flag.Parse() |
| 56 | 58 | ||
| 59 | + // Before the configuration is read: its warnings say whether each | ||
| 60 | + // agent's program can be found, and the agents inherit this PATH. | ||
| 61 | + shellCtx, shellCancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
| 62 | + if err := shellpath.Apply(shellCtx); err != nil { | ||
| 63 | + log.Printf("sidekicks: the PATH of your shell could not be read (%v); programs are looked up in %s", err, os.Getenv("PATH")) | ||
| 64 | + } | ||
| 65 | + shellCancel() | ||
| 66 | + | ||
| 57 | var preferences *prefs.Store | 67 | var preferences *prefs.Store |
| 58 | if path, err := prefs.DefaultPath(); err == nil { | 68 | if path, err := prefs.DefaultPath(); err == nil { |
| 59 | preferences = prefs.NewStore(path) | 69 | preferences = prefs.NewStore(path) |
| @@ -84,7 +94,16 @@ func main() { | |||
| 84 | AddFilter("YAML configuration", "*.yaml;*.yml"). | 94 | AddFilter("YAML configuration", "*.yaml;*.yml"). |
| 85 | PromptForSingleSelection() | 95 | PromptForSingleSelection() |
| 86 | } | 96 | } |
| 87 | - core := app.New(location, app.Options{Emitter: emitter, Preferences: preferences, PickFile: pickFile}) | 97 | + pickFolder := func(folder string) (string, error) { |
| 98 | + return wailsApp.Dialog.OpenFile(). | ||
| 99 | + SetTitle("Choose the agent's folder"). | ||
| 100 | + SetDirectory(folder). | ||
| 101 | + CanChooseFiles(false). | ||
| 102 | + CanChooseDirectories(true). | ||
| 103 | + CanCreateDirectories(true). | ||
| 104 | + PromptForSingleSelection() | ||
| 105 | + } | ||
| 106 | + core := app.New(location, app.Options{Emitter: emitter, Preferences: preferences, PickFile: pickFile, PickFolder: pickFolder}) | ||
| 88 | ctx, cancel := context.WithCancel(context.Background()) | 107 | ctx, cancel := context.WithCancel(context.Background()) |
| 89 | 108 | ||
| 90 | wailsApp = application.New(application.Options{ | 109 | wailsApp = application.New(application.Options{ |
added
scripts/build-release.sh +69 -0 | new file mode 100755 | ||
| @@ -0,0 +1,69 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 3 | +# | |
| 4 | +# Builds every release package of Sidekicks on this Mac, into dist/, then | |
| 5 | +# writes dist/SHA256SUMS. The files are then attached by hand to the release | |
| 6 | +# that scripts/tag-release.sh starts (see RELEASING.md). | |
| 7 | +# | |
| 8 | +# scripts/build-release.sh # macOS, Windows amd64, Linux amd64 | |
| 9 | +# LINUX_ARCHES="amd64 arm64" scripts/build-release.sh | |
| 10 | +# SKIP="linux" scripts/build-release.sh # skip systems (macos, windows, linux) | |
| 11 | +# | |
| 12 | +# macOS: native (Xcode command line tools). Windows: cross-built (needs | |
| 13 | +# makensis and zip: brew install makensis zip). Linux: in a Docker container | |
| 14 | +# (scripts/linux-packages.Dockerfile, needs Docker running); another | |
| 15 | +# architecture than the Mac's is emulated, hence slower. | |
| 16 | +set -euo pipefail | |
| 17 | + | |
| 18 | +root="$(cd "$(dirname "$0")/.." && pwd)" | |
| 19 | +dist="$root/dist" | |
| 20 | +linux_arches="${LINUX_ARCHES:-amd64}" | |
| 21 | +skip=" ${SKIP:-} " | |
| 22 | + | |
| 23 | +die() { echo "build-release.sh: $*" >&2; exit 1; } | |
| 24 | +step() { printf '\n==> %s\n' "$*"; } | |
| 25 | +skipped() { [[ "$skip" == *" $1 "* ]]; } | |
| 26 | + | |
| 27 | +cd "$root" | |
| 28 | +version="$(scripts/package.sh version)" | |
| 29 | +step "Sidekicks $version" | |
| 30 | +rm -rf "$dist" | |
| 31 | + | |
| 32 | +if ! skipped macos; then | |
| 33 | + [ "$(uname -s)" = Darwin ] || die "the macOS packages are built on macOS (or SKIP=macos)" | |
| 34 | + step "macOS (universal)" | |
| 35 | + scripts/package.sh macos | |
| 36 | +fi | |
| 37 | + | |
| 38 | +if ! skipped windows; then | |
| 39 | + command -v makensis >/dev/null || die "makensis is missing: brew install makensis (or SKIP=windows)" | |
| 40 | + step "Windows (amd64)" | |
| 41 | + scripts/package.sh windows | |
| 42 | +fi | |
| 43 | + | |
| 44 | +if ! skipped linux; then | |
| 45 | + command -v docker >/dev/null && docker info >/dev/null 2>&1 || die "Docker is not running (or SKIP=linux)" | |
| 46 | + go_version="$(awk '/^go /{print $2}' go.mod)" | |
| 47 | + pnpm="$(node -p "require('./frontend/package.json').packageManager")" | |
| 48 | + for arch in $linux_arches; do | |
| 49 | + step "Linux ($arch, in Docker)" | |
| 50 | + image="sidekicks-linux-packages:$arch" | |
| 51 | + docker build --quiet --platform "linux/$arch" \ | |
| 52 | + --build-arg "GO_VERSION=$go_version" --build-arg "PNPM=$pnpm" \ | |
| 53 | + -t "$image" -f scripts/linux-packages.Dockerfile scripts >/dev/null | |
| 54 | + # The Go module cache survives from one release to the next. | |
| 55 | + docker run --rm --platform "linux/$arch" \ | |
| 56 | + -v "$root:/src" -v "sidekicks-gomod-$arch:/root/go/pkg/mod" \ | |
| 57 | + -e "HOST_UID=$(id -u)" -e "HOST_GID=$(id -g)" \ | |
| 58 | + "$image" bash -c 'scripts/package.sh linux && chown -R "$HOST_UID:$HOST_GID" dist bin frontend/dist' | |
| 59 | + done | |
| 60 | +fi | |
| 61 | + | |
| 62 | +step "Checksums" | |
| 63 | +# Written outside dist/ first, so that the list does not include itself. | |
| 64 | +sums="$(mktemp)" | |
| 65 | +(cd "$dist" && if command -v sha256sum >/dev/null; then sha256sum -- *; else shasum -a 256 -- *; fi) > "$sums" | |
| 66 | +mv "$sums" "$dist/SHA256SUMS" | |
| 67 | +chmod 644 "$dist/SHA256SUMS" | |
| 68 | +cat "$dist/SHA256SUMS" | |
| 69 | +step "Done: attach every file of dist/ to the release v$version (scripts/tag-release.sh creates it)" | |
| new file mode 100755 | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 3 | +# | ||
| 4 | +# Builds every release package of Sidekicks on this Mac, into dist/, then | ||
| 5 | +# writes dist/SHA256SUMS. The files are then attached by hand to the release | ||
| 6 | +# that scripts/tag-release.sh starts (see RELEASING.md). | ||
| 7 | +# | ||
| 8 | +# scripts/build-release.sh # macOS, Windows amd64, Linux amd64 | ||
| 9 | +# LINUX_ARCHES="amd64 arm64" scripts/build-release.sh | ||
| 10 | +# SKIP="linux" scripts/build-release.sh # skip systems (macos, windows, linux) | ||
| 11 | +# | ||
| 12 | +# macOS: native (Xcode command line tools). Windows: cross-built (needs | ||
| 13 | +# makensis and zip: brew install makensis zip). Linux: in a Docker container | ||
| 14 | +# (scripts/linux-packages.Dockerfile, needs Docker running); another | ||
| 15 | +# architecture than the Mac's is emulated, hence slower. | ||
| 16 | +set -euo pipefail | ||
| 17 | + | ||
| 18 | +root="$(cd "$(dirname "$0")/.." && pwd)" | ||
| 19 | +dist="$root/dist" | ||
| 20 | +linux_arches="${LINUX_ARCHES:-amd64}" | ||
| 21 | +skip=" ${SKIP:-} " | ||
| 22 | + | ||
| 23 | +die() { echo "build-release.sh: $*" >&2; exit 1; } | ||
| 24 | +step() { printf '\n==> %s\n' "$*"; } | ||
| 25 | +skipped() { [[ "$skip" == *" $1 "* ]]; } | ||
| 26 | + | ||
| 27 | +cd "$root" | ||
| 28 | +version="$(scripts/package.sh version)" | ||
| 29 | +step "Sidekicks $version" | ||
| 30 | +rm -rf "$dist" | ||
| 31 | + | ||
| 32 | +if ! skipped macos; then | ||
| 33 | + [ "$(uname -s)" = Darwin ] || die "the macOS packages are built on macOS (or SKIP=macos)" | ||
| 34 | + step "macOS (universal)" | ||
| 35 | + scripts/package.sh macos | ||
| 36 | +fi | ||
| 37 | + | ||
| 38 | +if ! skipped windows; then | ||
| 39 | + command -v makensis >/dev/null || die "makensis is missing: brew install makensis (or SKIP=windows)" | ||
| 40 | + step "Windows (amd64)" | ||
| 41 | + scripts/package.sh windows | ||
| 42 | +fi | ||
| 43 | + | ||
| 44 | +if ! skipped linux; then | ||
| 45 | + command -v docker >/dev/null && docker info >/dev/null 2>&1 || die "Docker is not running (or SKIP=linux)" | ||
| 46 | + go_version="$(awk '/^go /{print $2}' go.mod)" | ||
| 47 | + pnpm="$(node -p "require('./frontend/package.json').packageManager")" | ||
| 48 | + for arch in $linux_arches; do | ||
| 49 | + step "Linux ($arch, in Docker)" | ||
| 50 | + image="sidekicks-linux-packages:$arch" | ||
| 51 | + docker build --quiet --platform "linux/$arch" \ | ||
| 52 | + --build-arg "GO_VERSION=$go_version" --build-arg "PNPM=$pnpm" \ | ||
| 53 | + -t "$image" -f scripts/linux-packages.Dockerfile scripts >/dev/null | ||
| 54 | + # The Go module cache survives from one release to the next. | ||
| 55 | + docker run --rm --platform "linux/$arch" \ | ||
| 56 | + -v "$root:/src" -v "sidekicks-gomod-$arch:/root/go/pkg/mod" \ | ||
| 57 | + -e "HOST_UID=$(id -u)" -e "HOST_GID=$(id -g)" \ | ||
| 58 | + "$image" bash -c 'scripts/package.sh linux && chown -R "$HOST_UID:$HOST_GID" dist bin frontend/dist' | ||
| 59 | + done | ||
| 60 | +fi | ||
| 61 | + | ||
| 62 | +step "Checksums" | ||
| 63 | +# Written outside dist/ first, so that the list does not include itself. | ||
| 64 | +sums="$(mktemp)" | ||
| 65 | +(cd "$dist" && if command -v sha256sum >/dev/null; then sha256sum -- *; else shasum -a 256 -- *; fi) > "$sums" | ||
| 66 | +mv "$sums" "$dist/SHA256SUMS" | ||
| 67 | +chmod 644 "$dist/SHA256SUMS" | ||
| 68 | +cat "$dist/SHA256SUMS" | ||
| 69 | +step "Done: attach every file of dist/ to the release v$version (scripts/tag-release.sh creates it)" | ||
added
scripts/linux-packages.Dockerfile +34 -0 | new file mode 100644 | ||
| @@ -0,0 +1,34 @@ | ||
| 1 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 2 | +# | |
| 3 | +# The image scripts/build-release.sh uses to build the Linux packages from | |
| 4 | +# macOS (Wails needs GTK 4 and WebKitGTK 6, which macOS cannot link): the | |
| 5 | +# repository is mounted at /src and `scripts/package.sh linux` runs in it. | |
| 6 | +# ubuntu:26.04, like the CI: GTK >= 4.10. The AppImage's GTK plugin copies | |
| 7 | +# folders that only these packages create: the GTK 4 modules (ibus-gtk4, | |
| 8 | +# input methods) and the image loaders (librsvg2-common, SVG). | |
| 9 | +# | |
| 10 | +# docker build --platform linux/amd64 --build-arg GO_VERSION=1.26.0 --build-arg PNPM=pnpm@12.11.2 \ | |
| 11 | +# -t sidekicks-linux-packages:amd64 -f scripts/linux-packages.Dockerfile scripts | |
| 12 | +FROM ubuntu:26.04 | |
| 13 | + | |
| 14 | +ARG GO_VERSION | |
| 15 | +ARG PNPM | |
| 16 | +ENV DEBIAN_FRONTEND=noninteractive | |
| 17 | + | |
| 18 | +RUN apt-get update -qq \ | |
| 19 | + && apt-get install -y -qq --no-install-recommends \ | |
| 20 | + ca-certificates curl git nodejs npm build-essential pkg-config \ | |
| 21 | + libgtk-4-dev libwebkitgtk-6.0-dev file rpm zip \ | |
| 22 | + ibus-gtk4 librsvg2-common \ | |
| 23 | + && rm -rf /var/lib/apt/lists/* | |
| 24 | + | |
| 25 | +RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-$(dpkg --print-architecture).tar.gz" | tar -C /usr/local -xz | |
| 26 | +ENV PATH=/usr/local/go/bin:/usr/local/bin:$PATH | |
| 27 | + | |
| 28 | +RUN npm install -g "${PNPM}" \ | |
| 29 | + && GOBIN=/usr/local/bin go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0 \ | |
| 30 | + && go clean -cache -modcache \ | |
| 31 | + && npm cache clean --force \ | |
| 32 | + && git config --global --add safe.directory '*' | |
| 33 | + | |
| 34 | +WORKDIR /src | |
| new file mode 100644 | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 2 | +# | ||
| 3 | +# The image scripts/build-release.sh uses to build the Linux packages from | ||
| 4 | +# macOS (Wails needs GTK 4 and WebKitGTK 6, which macOS cannot link): the | ||
| 5 | +# repository is mounted at /src and `scripts/package.sh linux` runs in it. | ||
| 6 | +# ubuntu:26.04, like the CI: GTK >= 4.10. The AppImage's GTK plugin copies | ||
| 7 | +# folders that only these packages create: the GTK 4 modules (ibus-gtk4, | ||
| 8 | +# input methods) and the image loaders (librsvg2-common, SVG). | ||
| 9 | +# | ||
| 10 | +# docker build --platform linux/amd64 --build-arg GO_VERSION=1.26.0 --build-arg PNPM=pnpm@12.11.2 \ | ||
| 11 | +# -t sidekicks-linux-packages:amd64 -f scripts/linux-packages.Dockerfile scripts | ||
| 12 | +FROM ubuntu:26.04 | ||
| 13 | + | ||
| 14 | +ARG GO_VERSION | ||
| 15 | +ARG PNPM | ||
| 16 | +ENV DEBIAN_FRONTEND=noninteractive | ||
| 17 | + | ||
| 18 | +RUN apt-get update -qq \ | ||
| 19 | + && apt-get install -y -qq --no-install-recommends \ | ||
| 20 | + ca-certificates curl git nodejs npm build-essential pkg-config \ | ||
| 21 | + libgtk-4-dev libwebkitgtk-6.0-dev file rpm zip \ | ||
| 22 | + ibus-gtk4 librsvg2-common \ | ||
| 23 | + && rm -rf /var/lib/apt/lists/* | ||
| 24 | + | ||
| 25 | +RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-$(dpkg --print-architecture).tar.gz" | tar -C /usr/local -xz | ||
| 26 | +ENV PATH=/usr/local/go/bin:/usr/local/bin:$PATH | ||
| 27 | + | ||
| 28 | +RUN npm install -g "${PNPM}" \ | ||
| 29 | + && GOBIN=/usr/local/bin go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0 \ | ||
| 30 | + && go clean -cache -modcache \ | ||
| 31 | + && npm cache clean --force \ | ||
| 32 | + && git config --global --add safe.directory '*' | ||
| 33 | + | ||
| 34 | +WORKDIR /src | ||
added
scripts/package.sh +102 -0 | new file mode 100755 | ||
| @@ -0,0 +1,102 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 3 | +# | |
| 4 | +# Builds the Sidekicks release packages into dist/, named with the version | |
| 5 | +# of build/config.yml, the system and the architecture. | |
| 6 | +# | |
| 7 | +# scripts/package.sh linux # .deb, .rpm, .AppImage and .tar.gz for this machine's architecture | |
| 8 | +# scripts/package.sh windows # installer (NSIS) and .zip for Windows amd64, cross-built from Linux or macOS | |
| 9 | +# scripts/package.sh macos # .dmg and .zip of the universal .app (arm64 + amd64), on macOS only | |
| 10 | +# scripts/package.sh names linux arm64 # prints the file names, builds nothing | |
| 11 | +# | |
| 12 | +# Linux needs GTK 4 and WebKitGTK 6 dev packages, plus file (AppImage) and | |
| 13 | +# rpm; Windows needs makensis (nsis); macOS needs the Xcode command line tools. | |
| 14 | +set -euo pipefail | |
| 15 | + | |
| 16 | +root="$(cd "$(dirname "$0")/.." && pwd)" | |
| 17 | +dist="$root/dist" | |
| 18 | + | |
| 19 | +die() { echo "package.sh: $*" >&2; exit 1; } | |
| 20 | + | |
| 21 | +# The version of build/config.yml (info.version). | |
| 22 | +version() { | |
| 23 | + awk -F'"' '/^ version:/ { print $2; exit }' "$root/build/config.yml" | |
| 24 | +} | |
| 25 | + | |
| 26 | +# names <system> <arch>: the files a build produces, one per line. | |
| 27 | +names() { | |
| 28 | + local system="$1" arch="$2" v | |
| 29 | + v="$(version)" | |
| 30 | + case "$system" in | |
| 31 | + linux) | |
| 32 | + local appimage_arch="$arch" | |
| 33 | + [ "$arch" = amd64 ] && appimage_arch=x86_64 | |
| 34 | + [ "$arch" = arm64 ] && appimage_arch=aarch64 | |
| 35 | + echo "sidekicks_${v}_linux_${arch}.deb" | |
| 36 | + echo "sidekicks_${v}_linux_${arch}.rpm" | |
| 37 | + echo "Sidekicks-${v}-${appimage_arch}.AppImage" | |
| 38 | + echo "sidekicks_${v}_linux_${arch}.tar.gz" | |
| 39 | + ;; | |
| 40 | + windows) | |
| 41 | + echo "Sidekicks-${v}-windows-${arch}-installer.exe" | |
| 42 | + echo "sidekicks_${v}_windows_${arch}.zip" | |
| 43 | + ;; | |
| 44 | + macos) | |
| 45 | + echo "Sidekicks-${v}-macos-universal.dmg" | |
| 46 | + echo "Sidekicks-${v}-macos-universal.zip" | |
| 47 | + ;; | |
| 48 | + *) die "unknown system: $system (linux, windows or macos)" ;; | |
| 49 | + esac | |
| 50 | +} | |
| 51 | + | |
| 52 | +# The n-th name (1-based) of names. | |
| 53 | +name() { names "$1" "$2" | sed -n "${3}p"; } | |
| 54 | + | |
| 55 | +wails() { (cd "$root" && wails3 task "$@"); } | |
| 56 | + | |
| 57 | +# bin/ is shared between the Mac and Linux (containers, sandbox): a binary | |
| 58 | +# left by the other system is "not an object file" for go build, which then | |
| 59 | +# refuses to overwrite it. | |
| 60 | +forget_previous_binary() { rm -f "$root/bin/sidekicks"; } | |
| 61 | + | |
| 62 | +package_linux() { | |
| 63 | + local arch | |
| 64 | + arch="$(go env GOARCH)" | |
| 65 | + export GOARCH="$arch" | |
| 66 | + forget_previous_binary | |
| 67 | + wails linux:create:deb | |
| 68 | + wails linux:create:rpm | |
| 69 | + wails linux:create:appimage | |
| 70 | + mkdir -p "$dist" | |
| 71 | + mv "$root/bin/sidekicks.deb" "$dist/$(name linux "$arch" 1)" | |
| 72 | + mv "$root"/bin/sidekicks*.rpm "$dist/$(name linux "$arch" 2)" | |
| 73 | + mv "$root"/bin/sidekicks-*.AppImage "$dist/$(name linux "$arch" 3)" | |
| 74 | + tar -czf "$dist/$(name linux "$arch" 4)" -C "$root/bin" sidekicks | |
| 75 | +} | |
| 76 | + | |
| 77 | +package_windows() { | |
| 78 | + wails windows:create:nsis:installer ARCH=amd64 | |
| 79 | + mkdir -p "$dist" | |
| 80 | + mv "$root/bin/sidekicks-amd64-installer.exe" "$dist/$(name windows amd64 1)" | |
| 81 | + (cd "$root/bin" && zip -q -j "$dist/$(name windows amd64 2)" sidekicks.exe) | |
| 82 | +} | |
| 83 | + | |
| 84 | +package_macos() { | |
| 85 | + [ "$(uname -s)" = Darwin ] || die "the macOS packages are built on macOS" | |
| 86 | + forget_previous_binary | |
| 87 | + wails darwin:package:universal | |
| 88 | + wails darwin:create:dmg | |
| 89 | + mkdir -p "$dist" | |
| 90 | + mv "$root/bin/sidekicks.dmg" "$dist/$(name macos universal 1)" | |
| 91 | + ditto -c -k --keepParent "$root/bin/sidekicks.app" "$dist/$(name macos universal 2)" | |
| 92 | +} | |
| 93 | + | |
| 94 | +case "${1:-}" in | |
| 95 | + linux) package_linux ;; | |
| 96 | + windows) package_windows ;; | |
| 97 | + macos) package_macos ;; | |
| 98 | + names) names "${2:?system}" "${3:?arch}" ;; | |
| 99 | + version) version ;; | |
| 100 | + *) die "usage: package.sh linux|windows|macos|names <system> <arch>|version" ;; | |
| 101 | +esac | |
| 102 | +[ "${1:-}" = names ] || [ "${1:-}" = version ] || ls -la "$dist" | |
| new file mode 100755 | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 3 | +# | ||
| 4 | +# Builds the Sidekicks release packages into dist/, named with the version | ||
| 5 | +# of build/config.yml, the system and the architecture. | ||
| 6 | +# | ||
| 7 | +# scripts/package.sh linux # .deb, .rpm, .AppImage and .tar.gz for this machine's architecture | ||
| 8 | +# scripts/package.sh windows # installer (NSIS) and .zip for Windows amd64, cross-built from Linux or macOS | ||
| 9 | +# scripts/package.sh macos # .dmg and .zip of the universal .app (arm64 + amd64), on macOS only | ||
| 10 | +# scripts/package.sh names linux arm64 # prints the file names, builds nothing | ||
| 11 | +# | ||
| 12 | +# Linux needs GTK 4 and WebKitGTK 6 dev packages, plus file (AppImage) and | ||
| 13 | +# rpm; Windows needs makensis (nsis); macOS needs the Xcode command line tools. | ||
| 14 | +set -euo pipefail | ||
| 15 | + | ||
| 16 | +root="$(cd "$(dirname "$0")/.." && pwd)" | ||
| 17 | +dist="$root/dist" | ||
| 18 | + | ||
| 19 | +die() { echo "package.sh: $*" >&2; exit 1; } | ||
| 20 | + | ||
| 21 | +# The version of build/config.yml (info.version). | ||
| 22 | +version() { | ||
| 23 | + awk -F'"' '/^ version:/ { print $2; exit }' "$root/build/config.yml" | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +# names <system> <arch>: the files a build produces, one per line. | ||
| 27 | +names() { | ||
| 28 | + local system="$1" arch="$2" v | ||
| 29 | + v="$(version)" | ||
| 30 | + case "$system" in | ||
| 31 | + linux) | ||
| 32 | + local appimage_arch="$arch" | ||
| 33 | + [ "$arch" = amd64 ] && appimage_arch=x86_64 | ||
| 34 | + [ "$arch" = arm64 ] && appimage_arch=aarch64 | ||
| 35 | + echo "sidekicks_${v}_linux_${arch}.deb" | ||
| 36 | + echo "sidekicks_${v}_linux_${arch}.rpm" | ||
| 37 | + echo "Sidekicks-${v}-${appimage_arch}.AppImage" | ||
| 38 | + echo "sidekicks_${v}_linux_${arch}.tar.gz" | ||
| 39 | + ;; | ||
| 40 | + windows) | ||
| 41 | + echo "Sidekicks-${v}-windows-${arch}-installer.exe" | ||
| 42 | + echo "sidekicks_${v}_windows_${arch}.zip" | ||
| 43 | + ;; | ||
| 44 | + macos) | ||
| 45 | + echo "Sidekicks-${v}-macos-universal.dmg" | ||
| 46 | + echo "Sidekicks-${v}-macos-universal.zip" | ||
| 47 | + ;; | ||
| 48 | + *) die "unknown system: $system (linux, windows or macos)" ;; | ||
| 49 | + esac | ||
| 50 | +} | ||
| 51 | + | ||
| 52 | +# The n-th name (1-based) of names. | ||
| 53 | +name() { names "$1" "$2" | sed -n "${3}p"; } | ||
| 54 | + | ||
| 55 | +wails() { (cd "$root" && wails3 task "$@"); } | ||
| 56 | + | ||
| 57 | +# bin/ is shared between the Mac and Linux (containers, sandbox): a binary | ||
| 58 | +# left by the other system is "not an object file" for go build, which then | ||
| 59 | +# refuses to overwrite it. | ||
| 60 | +forget_previous_binary() { rm -f "$root/bin/sidekicks"; } | ||
| 61 | + | ||
| 62 | +package_linux() { | ||
| 63 | + local arch | ||
| 64 | + arch="$(go env GOARCH)" | ||
| 65 | + export GOARCH="$arch" | ||
| 66 | + forget_previous_binary | ||
| 67 | + wails linux:create:deb | ||
| 68 | + wails linux:create:rpm | ||
| 69 | + wails linux:create:appimage | ||
| 70 | + mkdir -p "$dist" | ||
| 71 | + mv "$root/bin/sidekicks.deb" "$dist/$(name linux "$arch" 1)" | ||
| 72 | + mv "$root"/bin/sidekicks*.rpm "$dist/$(name linux "$arch" 2)" | ||
| 73 | + mv "$root"/bin/sidekicks-*.AppImage "$dist/$(name linux "$arch" 3)" | ||
| 74 | + tar -czf "$dist/$(name linux "$arch" 4)" -C "$root/bin" sidekicks | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +package_windows() { | ||
| 78 | + wails windows:create:nsis:installer ARCH=amd64 | ||
| 79 | + mkdir -p "$dist" | ||
| 80 | + mv "$root/bin/sidekicks-amd64-installer.exe" "$dist/$(name windows amd64 1)" | ||
| 81 | + (cd "$root/bin" && zip -q -j "$dist/$(name windows amd64 2)" sidekicks.exe) | ||
| 82 | +} | ||
| 83 | + | ||
| 84 | +package_macos() { | ||
| 85 | + [ "$(uname -s)" = Darwin ] || die "the macOS packages are built on macOS" | ||
| 86 | + forget_previous_binary | ||
| 87 | + wails darwin:package:universal | ||
| 88 | + wails darwin:create:dmg | ||
| 89 | + mkdir -p "$dist" | ||
| 90 | + mv "$root/bin/sidekicks.dmg" "$dist/$(name macos universal 1)" | ||
| 91 | + ditto -c -k --keepParent "$root/bin/sidekicks.app" "$dist/$(name macos universal 2)" | ||
| 92 | +} | ||
| 93 | + | ||
| 94 | +case "${1:-}" in | ||
| 95 | + linux) package_linux ;; | ||
| 96 | + windows) package_windows ;; | ||
| 97 | + macos) package_macos ;; | ||
| 98 | + names) names "${2:?system}" "${3:?arch}" ;; | ||
| 99 | + version) version ;; | ||
| 100 | + *) die "usage: package.sh linux|windows|macos|names <system> <arch>|version" ;; | ||
| 101 | +esac | ||
| 102 | +[ "${1:-}" = names ] || [ "${1:-}" = version ] || ls -la "$dist" | ||
added
scripts/package_test.sh +50 -0 | new file mode 100755 | ||
| @@ -0,0 +1,50 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 3 | +# | |
| 4 | +# Tests for package.sh: the version and the names of the release files | |
| 5 | +# (the builds themselves are checked by the release workflow). | |
| 6 | +# | |
| 7 | +# Usage: scripts/package_test.sh | |
| 8 | + | |
| 9 | +set -eu | |
| 10 | + | |
| 11 | +script="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/package.sh" | |
| 12 | +failures=0 | |
| 13 | + | |
| 14 | +expect() { | |
| 15 | + local name="$1" expected="$2" | |
| 16 | + shift 2 | |
| 17 | + local output status=0 | |
| 18 | + output="$("$script" "$@" 2>&1)" || status=$? | |
| 19 | + if [ "$status" -eq 0 ] && [ "$output" = "$expected" ]; then | |
| 20 | + echo "ok $name" | |
| 21 | + else | |
| 22 | + echo "FAIL $name (status $status)" | |
| 23 | + printf 'expected:\n%s\ngot:\n%s\n' "$expected" "$output" | sed 's/^/ /' | |
| 24 | + failures=$((failures + 1)) | |
| 25 | + fi | |
| 26 | +} | |
| 27 | + | |
| 28 | +version="$("$script" version)" | |
| 29 | +if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "ok the version comes from build/config.yml ($version)"; else echo "FAIL version: '$version'"; failures=$((failures + 1)); fi | |
| 30 | + | |
| 31 | +expect "linux names on arm64 (AppImage uses aarch64)" "sidekicks_${version}_linux_arm64.deb | |
| 32 | +sidekicks_${version}_linux_arm64.rpm | |
| 33 | +Sidekicks-${version}-aarch64.AppImage | |
| 34 | +sidekicks_${version}_linux_arm64.tar.gz" names linux arm64 | |
| 35 | + | |
| 36 | +expect "linux names on amd64 (AppImage uses x86_64)" "sidekicks_${version}_linux_amd64.deb | |
| 37 | +sidekicks_${version}_linux_amd64.rpm | |
| 38 | +Sidekicks-${version}-x86_64.AppImage | |
| 39 | +sidekicks_${version}_linux_amd64.tar.gz" names linux amd64 | |
| 40 | + | |
| 41 | +expect "windows names" "Sidekicks-${version}-windows-amd64-installer.exe | |
| 42 | +sidekicks_${version}_windows_amd64.zip" names windows amd64 | |
| 43 | + | |
| 44 | +expect "macos names" "Sidekicks-${version}-macos-universal.dmg | |
| 45 | +Sidekicks-${version}-macos-universal.zip" names macos universal | |
| 46 | + | |
| 47 | +if "$script" names plan9 386 >/dev/null 2>&1; then echo "FAIL an unknown system is refused"; failures=$((failures + 1)); else echo "ok an unknown system is refused"; fi | |
| 48 | + | |
| 49 | +if [ "$failures" -gt 0 ]; then echo "$failures failed"; exit 1; fi | |
| 50 | +echo "all package tests passed" | |
| new file mode 100755 | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 3 | +# | ||
| 4 | +# Tests for package.sh: the version and the names of the release files | ||
| 5 | +# (the builds themselves are checked by the release workflow). | ||
| 6 | +# | ||
| 7 | +# Usage: scripts/package_test.sh | ||
| 8 | + | ||
| 9 | +set -eu | ||
| 10 | + | ||
| 11 | +script="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/package.sh" | ||
| 12 | +failures=0 | ||
| 13 | + | ||
| 14 | +expect() { | ||
| 15 | + local name="$1" expected="$2" | ||
| 16 | + shift 2 | ||
| 17 | + local output status=0 | ||
| 18 | + output="$("$script" "$@" 2>&1)" || status=$? | ||
| 19 | + if [ "$status" -eq 0 ] && [ "$output" = "$expected" ]; then | ||
| 20 | + echo "ok $name" | ||
| 21 | + else | ||
| 22 | + echo "FAIL $name (status $status)" | ||
| 23 | + printf 'expected:\n%s\ngot:\n%s\n' "$expected" "$output" | sed 's/^/ /' | ||
| 24 | + failures=$((failures + 1)) | ||
| 25 | + fi | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +version="$("$script" version)" | ||
| 29 | +if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "ok the version comes from build/config.yml ($version)"; else echo "FAIL version: '$version'"; failures=$((failures + 1)); fi | ||
| 30 | + | ||
| 31 | +expect "linux names on arm64 (AppImage uses aarch64)" "sidekicks_${version}_linux_arm64.deb | ||
| 32 | +sidekicks_${version}_linux_arm64.rpm | ||
| 33 | +Sidekicks-${version}-aarch64.AppImage | ||
| 34 | +sidekicks_${version}_linux_arm64.tar.gz" names linux arm64 | ||
| 35 | + | ||
| 36 | +expect "linux names on amd64 (AppImage uses x86_64)" "sidekicks_${version}_linux_amd64.deb | ||
| 37 | +sidekicks_${version}_linux_amd64.rpm | ||
| 38 | +Sidekicks-${version}-x86_64.AppImage | ||
| 39 | +sidekicks_${version}_linux_amd64.tar.gz" names linux amd64 | ||
| 40 | + | ||
| 41 | +expect "windows names" "Sidekicks-${version}-windows-amd64-installer.exe | ||
| 42 | +sidekicks_${version}_windows_amd64.zip" names windows amd64 | ||
| 43 | + | ||
| 44 | +expect "macos names" "Sidekicks-${version}-macos-universal.dmg | ||
| 45 | +Sidekicks-${version}-macos-universal.zip" names macos universal | ||
| 46 | + | ||
| 47 | +if "$script" names plan9 386 >/dev/null 2>&1; then echo "FAIL an unknown system is refused"; failures=$((failures + 1)); else echo "ok an unknown system is refused"; fi | ||
| 48 | + | ||
| 49 | +if [ "$failures" -gt 0 ]; then echo "$failures failed"; exit 1; fi | ||
| 50 | +echo "all package tests passed" | ||
added
scripts/tag-release.sh +55 -0 | new file mode 100755 | ||
| @@ -0,0 +1,55 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 3 | +# | |
| 4 | +# Tags the release of the version of build/config.yml (v<version>) on main | |
| 5 | +# and pushes the tag: the Release workflow then creates the release on | |
| 6 | +# Rickub, and the files of dist/ are attached to it by hand (RELEASING.md). | |
| 7 | +# | |
| 8 | +# scripts/tag-release.sh # checks, tags, pushes to origin | |
| 9 | +# scripts/tag-release.sh --no-push # checks and tags locally only | |
| 10 | +# scripts/tag-release.sh --remote fork | |
| 11 | +# | |
| 12 | +# Refuses when the working tree has changes, when not on main, when main is | |
| 13 | +# not the same as on the remote, or when the tag exists. Warns when dist/ | |
| 14 | +# misses a package of this version (scripts/build-release.sh builds them). | |
| 15 | +set -euo pipefail | |
| 16 | + | |
| 17 | +root="$(cd "$(dirname "$0")/.." && pwd)" | |
| 18 | +remote=origin | |
| 19 | +push=true | |
| 20 | + | |
| 21 | +while [ $# -gt 0 ]; do | |
| 22 | + case "$1" in | |
| 23 | + --remote) remote="${2:?--remote needs a name}"; shift 2 ;; | |
| 24 | + --no-push) push=false; shift ;; | |
| 25 | + *) echo "tag-release.sh: unknown option $1" >&2; exit 2 ;; | |
| 26 | + esac | |
| 27 | +done | |
| 28 | + | |
| 29 | +die() { echo "tag-release.sh: $*" >&2; exit 1; } | |
| 30 | + | |
| 31 | +cd "$root" | |
| 32 | +version="$(scripts/package.sh version)" | |
| 33 | +tag="v$version" | |
| 34 | + | |
| 35 | +[ -z "$(git status --porcelain --untracked-files=no)" ] || die "the working tree has uncommitted changes: commit them first" | |
| 36 | +[ "$(git branch --show-current)" = main ] || die "releases are tagged on main (current branch: $(git branch --show-current))" | |
| 37 | +git fetch --quiet --tags "$remote" main | |
| 38 | +[ "$(git rev-parse HEAD)" = "$(git rev-parse "$remote/main")" ] || die "main differs from $remote/main: pull or push first" | |
| 39 | +if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then | |
| 40 | + die "the tag $tag already exists: raise info.version in build/config.yml" | |
| 41 | +fi | |
| 42 | + | |
| 43 | +missing="" | |
| 44 | +for name in $(scripts/package.sh names macos universal) $(scripts/package.sh names windows amd64) $(scripts/package.sh names linux amd64) SHA256SUMS; do | |
| 45 | + [ -f "dist/$name" ] || missing="$missing $name" | |
| 46 | +done | |
| 47 | +[ -z "$missing" ] || echo "tag-release.sh: warning: dist/ has no$missing (scripts/build-release.sh builds them)" >&2 | |
| 48 | + | |
| 49 | +git tag -a "$tag" -m "Sidekicks $version" | |
| 50 | +if [ "$push" = false ]; then | |
| 51 | + echo "Tagged $tag locally (not pushed)." | |
| 52 | + exit 0 | |
| 53 | +fi | |
| 54 | +git push "$remote" "$tag" | |
| 55 | +echo "Pushed $tag: the Release workflow creates the release; then attach the files of dist/ to it." | |
| new file mode 100755 | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 3 | +# | ||
| 4 | +# Tags the release of the version of build/config.yml (v<version>) on main | ||
| 5 | +# and pushes the tag: the Release workflow then creates the release on | ||
| 6 | +# Rickub, and the files of dist/ are attached to it by hand (RELEASING.md). | ||
| 7 | +# | ||
| 8 | +# scripts/tag-release.sh # checks, tags, pushes to origin | ||
| 9 | +# scripts/tag-release.sh --no-push # checks and tags locally only | ||
| 10 | +# scripts/tag-release.sh --remote fork | ||
| 11 | +# | ||
| 12 | +# Refuses when the working tree has changes, when not on main, when main is | ||
| 13 | +# not the same as on the remote, or when the tag exists. Warns when dist/ | ||
| 14 | +# misses a package of this version (scripts/build-release.sh builds them). | ||
| 15 | +set -euo pipefail | ||
| 16 | + | ||
| 17 | +root="$(cd "$(dirname "$0")/.." && pwd)" | ||
| 18 | +remote=origin | ||
| 19 | +push=true | ||
| 20 | + | ||
| 21 | +while [ $# -gt 0 ]; do | ||
| 22 | + case "$1" in | ||
| 23 | + --remote) remote="${2:?--remote needs a name}"; shift 2 ;; | ||
| 24 | + --no-push) push=false; shift ;; | ||
| 25 | + *) echo "tag-release.sh: unknown option $1" >&2; exit 2 ;; | ||
| 26 | + esac | ||
| 27 | +done | ||
| 28 | + | ||
| 29 | +die() { echo "tag-release.sh: $*" >&2; exit 1; } | ||
| 30 | + | ||
| 31 | +cd "$root" | ||
| 32 | +version="$(scripts/package.sh version)" | ||
| 33 | +tag="v$version" | ||
| 34 | + | ||
| 35 | +[ -z "$(git status --porcelain --untracked-files=no)" ] || die "the working tree has uncommitted changes: commit them first" | ||
| 36 | +[ "$(git branch --show-current)" = main ] || die "releases are tagged on main (current branch: $(git branch --show-current))" | ||
| 37 | +git fetch --quiet --tags "$remote" main | ||
| 38 | +[ "$(git rev-parse HEAD)" = "$(git rev-parse "$remote/main")" ] || die "main differs from $remote/main: pull or push first" | ||
| 39 | +if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then | ||
| 40 | + die "the tag $tag already exists: raise info.version in build/config.yml" | ||
| 41 | +fi | ||
| 42 | + | ||
| 43 | +missing="" | ||
| 44 | +for name in $(scripts/package.sh names macos universal) $(scripts/package.sh names windows amd64) $(scripts/package.sh names linux amd64) SHA256SUMS; do | ||
| 45 | + [ -f "dist/$name" ] || missing="$missing $name" | ||
| 46 | +done | ||
| 47 | +[ -z "$missing" ] || echo "tag-release.sh: warning: dist/ has no$missing (scripts/build-release.sh builds them)" >&2 | ||
| 48 | + | ||
| 49 | +git tag -a "$tag" -m "Sidekicks $version" | ||
| 50 | +if [ "$push" = false ]; then | ||
| 51 | + echo "Tagged $tag locally (not pushed)." | ||
| 52 | + exit 0 | ||
| 53 | +fi | ||
| 54 | +git push "$remote" "$tag" | ||
| 55 | +echo "Pushed $tag: the Release workflow creates the release; then attach the files of dist/ to it." | ||
added
scripts/tag-release_test.sh +67 -0 | new file mode 100755 | ||
| @@ -0,0 +1,67 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | |
| 3 | +# | |
| 4 | +# Tests for tag-release.sh, on a throwaway clone of a bare repository. | |
| 5 | +# | |
| 6 | +# Usage: scripts/tag-release_test.sh | |
| 7 | + | |
| 8 | +set -eu | |
| 9 | + | |
| 10 | +here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| 11 | +failures=0 | |
| 12 | +work="$(mktemp -d)" | |
| 13 | +trap 'rm -rf "$work"' EXIT | |
| 14 | + | |
| 15 | +ok() { echo "ok $1"; } | |
| 16 | +fail() { echo "FAIL $1"; failures=$((failures + 1)); } | |
| 17 | +export GIT_AUTHOR_NAME=test GIT_AUTHOR_EMAIL=test@example.com GIT_COMMITTER_NAME=test GIT_COMMITTER_EMAIL=test@example.com | |
| 18 | + | |
| 19 | +# expect <name> <0|1> <command…>: the script's success or failure. | |
| 20 | +expect() { | |
| 21 | + local name="$1" want="$2" | |
| 22 | + shift 2 | |
| 23 | + if (cd "$work/repo" && "$@") >"$work/out" 2>&1; then got=0; else got=1; fi | |
| 24 | + if [ "$got" = "$want" ]; then ok "$name"; else fail "$name"; sed 's/^/ /' "$work/out"; fi | |
| 25 | +} | |
| 26 | + | |
| 27 | +git init -q --bare -b main "$work/remote.git" | |
| 28 | +git init -q -b main "$work/repo" | |
| 29 | +mkdir -p "$work/repo/scripts" "$work/repo/build" | |
| 30 | +cp "$here/package.sh" "$here/tag-release.sh" "$work/repo/scripts/" | |
| 31 | +printf 'info:\n version: "1.2.3"\n' > "$work/repo/build/config.yml" | |
| 32 | +printf 'dist/\n' > "$work/repo/.gitignore" | |
| 33 | +git -C "$work/repo" add -A | |
| 34 | +git -C "$work/repo" commit -q -m source | |
| 35 | +git -C "$work/repo" remote add origin "$work/remote.git" | |
| 36 | +git -C "$work/repo" push -q origin main | |
| 37 | + | |
| 38 | +printf 'changed\n' >> "$work/repo/build/config.yml" | |
| 39 | +expect "refuses uncommitted changes" 1 scripts/tag-release.sh | |
| 40 | +git -C "$work/repo" checkout -q -- build/config.yml | |
| 41 | + | |
| 42 | +git -C "$work/repo" checkout -q -b feature | |
| 43 | +expect "refuses another branch than main" 1 scripts/tag-release.sh | |
| 44 | +git -C "$work/repo" checkout -q main | |
| 45 | + | |
| 46 | +git -C "$work/repo" commit -q --allow-empty -m "not pushed" | |
| 47 | +expect "refuses a main that differs from the remote" 1 scripts/tag-release.sh | |
| 48 | +git -C "$work/repo" push -q origin main | |
| 49 | + | |
| 50 | +expect "tags and pushes, warning about missing packages" 0 scripts/tag-release.sh | |
| 51 | +grep -q "warning: dist/ has no" "$work/out" && ok "says which packages are missing" || fail "says which packages are missing" | |
| 52 | +[ "$(git -C "$work/remote.git" tag)" = v1.2.3 ] && ok "the tag v1.2.3 is on the remote" || fail "the tag v1.2.3 is on the remote" | |
| 53 | +[ "$(git -C "$work/remote.git" cat-file -t v1.2.3)" = tag ] && ok "the tag is annotated" || fail "the tag is annotated" | |
| 54 | + | |
| 55 | +expect "refuses an existing tag" 1 scripts/tag-release.sh | |
| 56 | + | |
| 57 | +printf 'info:\n version: "1.2.4"\n' > "$work/repo/build/config.yml" | |
| 58 | +git -C "$work/repo" commit -q -am "1.2.4" | |
| 59 | +git -C "$work/repo" push -q origin main | |
| 60 | +mkdir -p "$work/repo/dist" | |
| 61 | +for name in $("$work/repo/scripts/package.sh" names macos universal) $("$work/repo/scripts/package.sh" names windows amd64) $("$work/repo/scripts/package.sh" names linux amd64) SHA256SUMS; do : > "$work/repo/dist/$name"; done | |
| 62 | +expect "--no-push tags locally only" 0 scripts/tag-release.sh --no-push | |
| 63 | +grep -q warning "$work/out" && fail "no warning when dist/ is complete" || ok "no warning when dist/ is complete" | |
| 64 | +git -C "$work/repo" rev-parse -q --verify refs/tags/v1.2.4 >/dev/null && [ -z "$(git -C "$work/remote.git" tag -l v1.2.4)" ] && ok "the local tag is not pushed" || fail "the local tag is not pushed" | |
| 65 | + | |
| 66 | +if [ "$failures" -gt 0 ]; then echo "$failures failed"; exit 1; fi | |
| 67 | +echo "all tag-release tests passed" | |
| new file mode 100755 | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# Copyright (c) 2026 Philippe Charrière — Sidekicks Source-Available License 1.0, see LICENSE | ||
| 3 | +# | ||
| 4 | +# Tests for tag-release.sh, on a throwaway clone of a bare repository. | ||
| 5 | +# | ||
| 6 | +# Usage: scripts/tag-release_test.sh | ||
| 7 | + | ||
| 8 | +set -eu | ||
| 9 | + | ||
| 10 | +here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| 11 | +failures=0 | ||
| 12 | +work="$(mktemp -d)" | ||
| 13 | +trap 'rm -rf "$work"' EXIT | ||
| 14 | + | ||
| 15 | +ok() { echo "ok $1"; } | ||
| 16 | +fail() { echo "FAIL $1"; failures=$((failures + 1)); } | ||
| 17 | +export GIT_AUTHOR_NAME=test GIT_AUTHOR_EMAIL=test@example.com GIT_COMMITTER_NAME=test GIT_COMMITTER_EMAIL=test@example.com | ||
| 18 | + | ||
| 19 | +# expect <name> <0|1> <command…>: the script's success or failure. | ||
| 20 | +expect() { | ||
| 21 | + local name="$1" want="$2" | ||
| 22 | + shift 2 | ||
| 23 | + if (cd "$work/repo" && "$@") >"$work/out" 2>&1; then got=0; else got=1; fi | ||
| 24 | + if [ "$got" = "$want" ]; then ok "$name"; else fail "$name"; sed 's/^/ /' "$work/out"; fi | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +git init -q --bare -b main "$work/remote.git" | ||
| 28 | +git init -q -b main "$work/repo" | ||
| 29 | +mkdir -p "$work/repo/scripts" "$work/repo/build" | ||
| 30 | +cp "$here/package.sh" "$here/tag-release.sh" "$work/repo/scripts/" | ||
| 31 | +printf 'info:\n version: "1.2.3"\n' > "$work/repo/build/config.yml" | ||
| 32 | +printf 'dist/\n' > "$work/repo/.gitignore" | ||
| 33 | +git -C "$work/repo" add -A | ||
| 34 | +git -C "$work/repo" commit -q -m source | ||
| 35 | +git -C "$work/repo" remote add origin "$work/remote.git" | ||
| 36 | +git -C "$work/repo" push -q origin main | ||
| 37 | + | ||
| 38 | +printf 'changed\n' >> "$work/repo/build/config.yml" | ||
| 39 | +expect "refuses uncommitted changes" 1 scripts/tag-release.sh | ||
| 40 | +git -C "$work/repo" checkout -q -- build/config.yml | ||
| 41 | + | ||
| 42 | +git -C "$work/repo" checkout -q -b feature | ||
| 43 | +expect "refuses another branch than main" 1 scripts/tag-release.sh | ||
| 44 | +git -C "$work/repo" checkout -q main | ||
| 45 | + | ||
| 46 | +git -C "$work/repo" commit -q --allow-empty -m "not pushed" | ||
| 47 | +expect "refuses a main that differs from the remote" 1 scripts/tag-release.sh | ||
| 48 | +git -C "$work/repo" push -q origin main | ||
| 49 | + | ||
| 50 | +expect "tags and pushes, warning about missing packages" 0 scripts/tag-release.sh | ||
| 51 | +grep -q "warning: dist/ has no" "$work/out" && ok "says which packages are missing" || fail "says which packages are missing" | ||
| 52 | +[ "$(git -C "$work/remote.git" tag)" = v1.2.3 ] && ok "the tag v1.2.3 is on the remote" || fail "the tag v1.2.3 is on the remote" | ||
| 53 | +[ "$(git -C "$work/remote.git" cat-file -t v1.2.3)" = tag ] && ok "the tag is annotated" || fail "the tag is annotated" | ||
| 54 | + | ||
| 55 | +expect "refuses an existing tag" 1 scripts/tag-release.sh | ||
| 56 | + | ||
| 57 | +printf 'info:\n version: "1.2.4"\n' > "$work/repo/build/config.yml" | ||
| 58 | +git -C "$work/repo" commit -q -am "1.2.4" | ||
| 59 | +git -C "$work/repo" push -q origin main | ||
| 60 | +mkdir -p "$work/repo/dist" | ||
| 61 | +for name in $("$work/repo/scripts/package.sh" names macos universal) $("$work/repo/scripts/package.sh" names windows amd64) $("$work/repo/scripts/package.sh" names linux amd64) SHA256SUMS; do : > "$work/repo/dist/$name"; done | ||
| 62 | +expect "--no-push tags locally only" 0 scripts/tag-release.sh --no-push | ||
| 63 | +grep -q warning "$work/out" && fail "no warning when dist/ is complete" || ok "no warning when dist/ is complete" | ||
| 64 | +git -C "$work/repo" rev-parse -q --verify refs/tags/v1.2.4 >/dev/null && [ -z "$(git -C "$work/remote.git" tag -l v1.2.4)" ] && ok "the local tag is not pushed" || fail "the local tag is not pushed" | ||
| 65 | + | ||
| 66 | +if [ "$failures" -gt 0 ]; then echo "$failures failed"; exit 1; fi | ||
| 67 | +echo "all tag-release tests passed" | ||