refactor(fleet): rename tmux socket mosaic-factory → mosaic-fleet
Pure rename of the named production-isolation socket to match the product brand (Mosaic Fleet), per Jason. Behavior is identical — only the socket NAME changes. - 6 example presets: socket_name: mosaic-factory → mosaic-fleet - fleet.ts: DEFAULT_SOCKET_NAME = 'mosaic-fleet' (+ all literals) - systemd units + READMEs, roster.schema.json, start-agent-session.sh - docs/guides + fleet PRD/TASKS + scratchpads; tests updated The PoC roster is socket-LESS (default socket, no -L), so it is unaffected. docs/fleet/north-star.md is intentionally EXCLUDED (owned by the in-flight doctrine PR #629 — its mosaic-factory references are renamed there to avoid a merge conflict). The live legacy canary fleet still running on the old socket is a separate retire/migrate op, not this PR. Single find/replace — target trivially swappable if the brand is reconsidered. Verified: 172 fleet + onboarding tests green; tsc/eslint/prettier/sanitize clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EsgTQzV5YUGk1JtCLP4B83
This commit is contained in:
@@ -7,10 +7,10 @@
|
|||||||
|
|
||||||
## Problem
|
## Problem
|
||||||
|
|
||||||
The durable tmux fleet runs on the isolated `mosaic-factory` socket. That isolation
|
The durable tmux fleet runs on the isolated `mosaic-fleet` socket. That isolation
|
||||||
(which protects the operator's default tmux) makes the fleet **invisible** to default
|
(which protects the operator's default tmux) makes the fleet **invisible** to default
|
||||||
tooling, and truth is split across three planes no single command joins — systemd
|
tooling, and truth is split across three planes no single command joins — systemd
|
||||||
(`systemctl --user`), tmux (`-L mosaic-factory`), and the process tree (`pstree`).
|
(`systemctl --user`), tmux (`-L mosaic-fleet`), and the process tree (`pstree`).
|
||||||
`agent tail` (`capture-pane`) returns **blank for full-screen TUIs**, and `agent send`
|
`agent tail` (`capture-pane`) returns **blank for full-screen TUIs**, and `agent send`
|
||||||
confirms only keystroke injection, not acceptance. Net: the operator has near-zero
|
confirms only keystroke injection, not acceptance. Net: the operator has near-zero
|
||||||
observability and no safe way to watch a session.
|
observability and no safe way to watch a session.
|
||||||
@@ -56,7 +56,7 @@ observability and no safe way to watch a session.
|
|||||||
|
|
||||||
## Acceptance criteria
|
## Acceptance criteria
|
||||||
|
|
||||||
- `mosaic fleet ps` shows all 5 live sessions on `mosaic-factory` with correct
|
- `mosaic fleet ps` shows all 5 live sessions on `mosaic-fleet` with correct
|
||||||
pane/pid/idle and flags the dogfood **drift** (`canary-pi` runtime=pi but pane runs
|
pane/pid/idle and flags the dogfood **drift** (`canary-pi` runtime=pi but pane runs
|
||||||
`dogfood-agent.py`) and the **boot-enable** gap (active but disabled).
|
`dogfood-agent.py`) and the **boot-enable** gap (active but disabled).
|
||||||
- Killing one agent's pane flips its row to dead/stale within one `interval`.
|
- Killing one agent's pane flips its row to dead/stale within one `interval`.
|
||||||
@@ -72,7 +72,7 @@ observability and no safe way to watch a session.
|
|||||||
- Unit/CLI specs in `packages/mosaic/src/commands/fleet.spec.ts` (and a new
|
- Unit/CLI specs in `packages/mosaic/src/commands/fleet.spec.ts` (and a new
|
||||||
`fleet-ps`/`watch`/`send-verify` spec) using the injected `CommandRunner` to assert
|
`fleet-ps`/`watch`/`send-verify` spec) using the injected `CommandRunner` to assert
|
||||||
exact tmux/systemd command construction and JSON shape (tenant+host present).
|
exact tmux/systemd command construction and JSON shape (tenant+host present).
|
||||||
- Situational: run against the live `mosaic-factory` fleet; capture `fleet ps` output,
|
- Situational: run against the live `mosaic-fleet` fleet; capture `fleet ps` output,
|
||||||
a kill-and-detect cycle, a read-only `watch`, and a `send --verify` pass/fail pair.
|
a kill-and-detect cycle, a read-only `watch`, and a `send --verify` pass/fail pair.
|
||||||
|
|
||||||
## Known limitations
|
## Known limitations
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
> Status: `not-started` | `in-progress` | `done` | `blocked` | `failed`
|
> Status: `not-started` | `in-progress` | `done` | `blocked` | `failed`
|
||||||
|
|
||||||
| id | status | description | depends_on | agent | pr | notes |
|
| id | status | description | depends_on | agent | pr | notes |
|
||||||
| ------------- | ----------- | ------------------------------------------------------------------------------------------------------------------ | --------------------- | ----------- | --- | ----------------------------------------------------------------------------------------------------------------------------- |
|
| ------------- | ----------- | ------------------------------------------------------------------------------------------------------------------ | --------------------- | ----------- | --- | --------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| FLEET-OBS-000 | done | Plan: north-star + Phase-2 PRD + workstream scaffolding | — | lead | — | persisted 2026-06-20 on `feat/fleet-observability` |
|
| FLEET-OBS-000 | done | Plan: north-star + Phase-2 PRD + workstream scaffolding | — | lead | — | persisted 2026-06-20 on `feat/fleet-observability` |
|
||||||
| FLEET-OBS-001 | done | Heartbeat protocol v1 spec finalized in PRD + framework doc | FLEET-OBS-000 | lead | — | file-based `~/.config/mosaic/fleet/run/<agent>.hb`; spec in PRD |
|
| FLEET-OBS-001 | done | Heartbeat protocol v1 spec finalized in PRD + framework doc | FLEET-OBS-000 | lead | — | file-based `~/.config/mosaic/fleet/run/<agent>.hb`; spec in PRD |
|
||||||
| FLEET-OBS-002 | in-progress | Implement heartbeat responder in `dogfood-agent.py` | FLEET-OBS-001 | fleet-coder | — | dispatched to ad-hoc `mosaic yolo` fleet agent (dogfood) |
|
| FLEET-OBS-002 | in-progress | Implement heartbeat responder in `dogfood-agent.py` | FLEET-OBS-001 | fleet-coder | — | dispatched to ad-hoc `mosaic yolo` fleet agent (dogfood) |
|
||||||
| FLEET-OBS-003 | done | `mosaic fleet ps` — join systemd+tmux+proc+idle+heartbeat; tenant+host tagged; drift + boot-enable flags; `--json` | FLEET-OBS-001 | worker | — | commit ab47831; LIVE-verified on mosaic-factory; caught canary-pi DRIFT + BOOT-ENABLE. Polish: idleSeconds parse returns null |
|
| FLEET-OBS-003 | done | `mosaic fleet ps` — join systemd+tmux+proc+idle+heartbeat; tenant+host tagged; drift + boot-enable flags; `--json` | FLEET-OBS-001 | worker | — | commit ab47831; LIVE-verified on mosaic-fleet; caught canary-pi DRIFT + BOOT-ENABLE. Polish: idleSeconds parse returns null |
|
||||||
| FLEET-OBS-004 | done | `mosaic agent watch <name>` — read-only join (no resize, no keystrokes) | FLEET-OBS-000 | worker | — | `attach -r`; verb wired |
|
| FLEET-OBS-004 | done | `mosaic agent watch <name>` — read-only join (no resize, no keystrokes) | FLEET-OBS-000 | worker | — | `attach -r`; verb wired |
|
||||||
| FLEET-OBS-005 | done | `mosaic agent send --verify` — delivery/acceptance receipt | FLEET-OBS-000 | worker | — | --verify flag; draft-heuristic verify |
|
| FLEET-OBS-005 | done | `mosaic agent send --verify` — delivery/acceptance receipt | FLEET-OBS-000 | worker | — | --verify flag; draft-heuristic verify |
|
||||||
| FLEET-OBS-006 | done | CLI specs for ps/watch/send-verify (tenant+host shape, command construction) | FLEET-OBS-003,004,005 | worker | — | 62 tests green (31 new); re-verified by lead |
|
| FLEET-OBS-006 | done | CLI specs for ps/watch/send-verify (tenant+host shape, command construction) | FLEET-OBS-003,004,005 | worker | — | 62 tests green (31 new); re-verified by lead |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Local Fleet Canary
|
# Local Fleet Canary
|
||||||
|
|
||||||
The local fleet canary runs a small tmux-backed Mosaic agent fleet on an
|
The local fleet canary runs a small tmux-backed Mosaic agent fleet on an
|
||||||
isolated tmux socket. The default socket is `mosaic-factory`; the commands do
|
isolated tmux socket. The default socket is `mosaic-fleet`; the commands do
|
||||||
not use or stop the default tmux server.
|
not use or stop the default tmux server.
|
||||||
|
|
||||||
## Files
|
## Files
|
||||||
@@ -67,7 +67,7 @@ mosaic agent tail canary-pi -n 80
|
|||||||
|
|
||||||
These commands read the roster and target the configured tmux socket. The
|
These commands read the roster and target the configured tmux socket. The
|
||||||
generated systemd agent services use `start-agent-session.sh`; message delivery
|
generated systemd agent services use `start-agent-session.sh`; message delivery
|
||||||
uses the tmux send tools with `-L mosaic-factory`.
|
uses the tmux send tools with `-L mosaic-fleet`.
|
||||||
|
|
||||||
`mosaic agent send` is operator-origin traffic unless a caller explicitly says
|
`mosaic agent send` is operator-origin traffic unless a caller explicitly says
|
||||||
otherwise. The CLI always passes a deterministic source label to
|
otherwise. The CLI always passes a deterministic source label to
|
||||||
@@ -82,7 +82,7 @@ impersonating a known handoff lane. The lower-level inter-agent wrapper
|
|||||||
Use these checks before expanding the roster:
|
Use these checks before expanding the roster:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tmux -L mosaic-factory ls
|
tmux -L mosaic-fleet ls
|
||||||
tmux ls
|
tmux ls
|
||||||
mosaic fleet verify
|
mosaic fleet verify
|
||||||
systemctl --user status mosaic-tmux-holder.service
|
systemctl --user status mosaic-tmux-holder.service
|
||||||
@@ -90,7 +90,7 @@ systemctl --user status mosaic-tmux-holder.service
|
|||||||
|
|
||||||
Expected results:
|
Expected results:
|
||||||
|
|
||||||
- `tmux -L mosaic-factory ls` shows `_holder` and roster agent sessions.
|
- `tmux -L mosaic-fleet ls` shows `_holder` and roster agent sessions.
|
||||||
- `tmux ls` shows only the default tmux server sessions and is not changed by
|
- `tmux ls` shows only the default tmux server sessions and is not changed by
|
||||||
fleet start/stop operations.
|
fleet start/stop operations.
|
||||||
- `mosaic fleet verify` checks exact session targets on the isolated socket.
|
- `mosaic fleet verify` checks exact session targets on the isolated socket.
|
||||||
@@ -108,7 +108,7 @@ Run this checklist before cutting or dogfooding a fleet release:
|
|||||||
repeated `start` against the named socket; verify the default tmux server is
|
repeated `start` against the named socket; verify the default tmux server is
|
||||||
unchanged.
|
unchanged.
|
||||||
- Liveness verification: run `mosaic fleet verify` and confirm roster sessions
|
- Liveness verification: run `mosaic fleet verify` and confirm roster sessions
|
||||||
with `tmux -L mosaic-factory ls` or exact `has-session` checks.
|
with `tmux -L mosaic-fleet ls` or exact `has-session` checks.
|
||||||
- Package dry-run: run `npm pack --dry-run --json` from `packages/mosaic` and
|
- Package dry-run: run `npm pack --dry-run --json` from `packages/mosaic` and
|
||||||
confirm `framework/fleet`, `framework/systemd/user`,
|
confirm `framework/fleet`, `framework/systemd/user`,
|
||||||
`framework/tools/fleet`, and `framework/tools/tmux` assets are included.
|
`framework/tools/fleet`, and `framework/tools/tmux` assets are included.
|
||||||
@@ -140,5 +140,5 @@ This rollback leaves the default tmux server untouched. If a canary session is
|
|||||||
still present after service stop, remove only the isolated socket server:
|
still present after service stop, remove only the isolated socket server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tmux -L mosaic-factory kill-server
|
tmux -L mosaic-fleet kill-server
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Implement enough product surface to use the fleet locally:
|
|||||||
- roster schema and examples
|
- roster schema and examples
|
||||||
- local canary docs and rollback instructions
|
- local canary docs and rollback instructions
|
||||||
- tests for CLI behavior where practical
|
- tests for CLI behavior where practical
|
||||||
- canary verification on named tmux socket `mosaic-factory`
|
- canary verification on named tmux socket `mosaic-fleet`
|
||||||
|
|
||||||
## Non-goals
|
## Non-goals
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ Implement enough product surface to use the fleet locally:
|
|||||||
|
|
||||||
- CLI can initialize a minimal roster outside product defaults.
|
- CLI can initialize a minimal roster outside product defaults.
|
||||||
- CLI can install user systemd units and fleet helper scripts to a configurable Mosaic home.
|
- CLI can install user systemd units and fleet helper scripts to a configurable Mosaic home.
|
||||||
- CLI can start/stop/status/verify a canary fleet using `mosaic-factory`.
|
- CLI can start/stop/status/verify a canary fleet using `mosaic-fleet`.
|
||||||
- `mosaic agent send` uses existing named-socket/exact-target tmux tooling.
|
- `mosaic agent send` uses existing named-socket/exact-target tmux tooling.
|
||||||
- `mosaic agent reset` targets only the named agent session on the named socket.
|
- `mosaic agent reset` targets only the named agent session on the named socket.
|
||||||
- Verification proves default tmux sessions remain untouched.
|
- Verification proves default tmux sessions remain untouched.
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ with a second agent on `dragon-lin`.
|
|||||||
## Environment facts (verified 2026-06-20)
|
## Environment facts (verified 2026-06-20)
|
||||||
|
|
||||||
- Fleet is live on `W-jarvis` (uid 1000, `jarvis`, `Linger=yes`) on tmux socket
|
- Fleet is live on `W-jarvis` (uid 1000, `jarvis`, `Linger=yes`) on tmux socket
|
||||||
`mosaic-factory`: `_holder`, `canary-pi`, `dogfood-coder`, `dogfood-orchestrator`,
|
`mosaic-fleet`: `_holder`, `canary-pi`, `dogfood-coder`, `dogfood-orchestrator`,
|
||||||
`dogfood-reviewer`. All panes run `~/.config/mosaic/fleet/dogfood-agent.py` (stub),
|
`dogfood-reviewer`. All panes run `~/.config/mosaic/fleet/dogfood-agent.py` (stub),
|
||||||
including `canary-pi` (roster says runtime=pi → **drift**).
|
including `canary-pi` (roster says runtime=pi → **drift**).
|
||||||
- Holder + `mosaic-agent@*` units are `active (exited)` but `UnitFileState=disabled`
|
- Holder + `mosaic-agent@*` units are `active (exited)` but `UnitFileState=disabled`
|
||||||
@@ -56,7 +56,7 @@ with a second agent on `dragon-lin`.
|
|||||||
with dragon-lin coder, commit docs, begin Phase-2 delivery (heartbeat + `fleet ps`).
|
with dragon-lin coder, commit docs, begin Phase-2 delivery (heartbeat + `fleet ps`).
|
||||||
- 2026-06-20 (session 2): Built Phase-2 CLI via worker (commit ab47831): `fleet ps`,
|
- 2026-06-20 (session 2): Built Phase-2 CLI via worker (commit ab47831): `fleet ps`,
|
||||||
`agent watch`, `agent send --verify`, 62 tests. LIVE-verified `fleet ps` on
|
`agent watch`, `agent send --verify`, 62 tests. LIVE-verified `fleet ps` on
|
||||||
mosaic-factory — correctly flagged canary-pi DRIFT + BOOT-ENABLE, tenant_id+host in JSON.
|
mosaic-fleet — correctly flagged canary-pi DRIFT + BOOT-ENABLE, tenant_id+host in JSON.
|
||||||
Heartbeat responder added to dogfood-agent.py (FLEET-OBS-002) — `fleet ps` HB now
|
Heartbeat responder added to dogfood-agent.py (FLEET-OBS-002) — `fleet ps` HB now
|
||||||
`healthy` for all 4 agents.
|
`healthy` for all 4 agents.
|
||||||
- Coordination: dual-engine-reviewed (Claude+Codex) and merged framework PRs #572
|
- Coordination: dual-engine-reviewed (Claude+Codex) and merged framework PRs #572
|
||||||
|
|||||||
@@ -11,14 +11,14 @@
|
|||||||
## FIX 2 — socket default trap (absent ⇒ literal default socket, no -L everywhere)
|
## FIX 2 — socket default trap (absent ⇒ literal default socket, no -L everywhere)
|
||||||
|
|
||||||
- THE TRAP (3 sites): parseRosterText fallback was DEFAULT_SOCKET_NAME; systemd unit had
|
- THE TRAP (3 sites): parseRosterText fallback was DEFAULT_SOCKET_NAME; systemd unit had
|
||||||
`Environment=MOSAIC_TMUX_SOCKET=mosaic-factory` + `ExecStop ${…:-mosaic-factory}`; start-agent-session
|
`Environment=MOSAIC_TMUX_SOCKET=mosaic-fleet` + `ExecStop ${…:-mosaic-fleet}`; start-agent-session
|
||||||
defaulted `:-mosaic-factory`. All fixed → absent socket = '' = default tmux socket (no -L).
|
defaulted `:-mosaic-fleet`. All fixed → absent socket = '' = default tmux socket (no -L).
|
||||||
- `socketArgs(name)` helper → `name ? ['-L', name] : []`; replaced all ~15 -L render sites in fleet.ts.
|
- `socketArgs(name)` helper → `name ? ['-L', name] : []`; replaced all ~15 -L render sites in fleet.ts.
|
||||||
- shellEnvValue('') now emits a **bare** `VAR=` (not `''`) — unambiguous empty in systemd EnvironmentFile
|
- shellEnvValue('') now emits a **bare** `VAR=` (not `''`) — unambiguous empty in systemd EnvironmentFile
|
||||||
(a quoted '' could become a literal socket named "''").
|
(a quoted '' could become a literal socket named "''").
|
||||||
- start-agent-session.sh: `_tmux` wrapper passes -L only when socket set; mosaic-agent@.service: dropped the
|
- start-agent-session.sh: `_tmux` wrapper passes -L only when socket set; mosaic-agent@.service: dropped the
|
||||||
socket default + conditional ExecStop. So spawn == observe == onboarding cheat-sheet.
|
socket default + conditional ExecStop. So spawn == observe == onboarding cheat-sheet.
|
||||||
- CONTAINMENT: all 6 shipped presets set socket_name: mosaic-factory explicitly → unaffected; only
|
- CONTAINMENT: all 6 shipped presets set socket_name: mosaic-fleet explicitly → unaffected; only
|
||||||
socket-less rosters (the PoC) get default-socket behavior. DEFAULT_SOCKET_NAME exported for explicit use.
|
socket-less rosters (the PoC) get default-socket behavior. DEFAULT_SOCKET_NAME exported for explicit use.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package, normally at:
|
|||||||
~/.config/mosaic/fleet/roster.yaml
|
~/.config/mosaic/fleet/roster.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
The default tmux socket is `mosaic-factory` so fleet commands do not touch the
|
The default tmux socket is `mosaic-fleet` so fleet commands do not touch the
|
||||||
default tmux server.
|
default tmux server.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
version: 1
|
version: 1
|
||||||
transport: tmux
|
transport: tmux
|
||||||
tmux:
|
tmux:
|
||||||
socket_name: mosaic-factory
|
socket_name: mosaic-fleet
|
||||||
holder_session: _holder
|
holder_session: _holder
|
||||||
defaults:
|
defaults:
|
||||||
working_directory: ~
|
working_directory: ~
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
version: 1
|
version: 1
|
||||||
transport: tmux
|
transport: tmux
|
||||||
tmux:
|
tmux:
|
||||||
socket_name: mosaic-factory
|
socket_name: mosaic-fleet
|
||||||
holder_session: _holder
|
holder_session: _holder
|
||||||
defaults:
|
defaults:
|
||||||
working_directory: ~
|
working_directory: ~
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
version: 1
|
version: 1
|
||||||
transport: tmux
|
transport: tmux
|
||||||
tmux:
|
tmux:
|
||||||
socket_name: mosaic-factory
|
socket_name: mosaic-fleet
|
||||||
holder_session: _holder
|
holder_session: _holder
|
||||||
defaults:
|
defaults:
|
||||||
working_directory: ~
|
working_directory: ~
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
version: 1
|
version: 1
|
||||||
transport: tmux
|
transport: tmux
|
||||||
tmux:
|
tmux:
|
||||||
socket_name: mosaic-factory
|
socket_name: mosaic-fleet
|
||||||
holder_session: _holder
|
holder_session: _holder
|
||||||
defaults:
|
defaults:
|
||||||
working_directory: ~/src
|
working_directory: ~/src
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
version: 1
|
version: 1
|
||||||
transport: tmux
|
transport: tmux
|
||||||
tmux:
|
tmux:
|
||||||
socket_name: mosaic-factory
|
socket_name: mosaic-fleet
|
||||||
holder_session: _holder
|
holder_session: _holder
|
||||||
defaults:
|
defaults:
|
||||||
working_directory: ~/src
|
working_directory: ~/src
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
version: 1
|
version: 1
|
||||||
transport: tmux
|
transport: tmux
|
||||||
tmux:
|
tmux:
|
||||||
socket_name: mosaic-factory
|
socket_name: mosaic-fleet
|
||||||
holder_session: _holder
|
holder_session: _holder
|
||||||
defaults:
|
defaults:
|
||||||
working_directory: ~
|
working_directory: ~
|
||||||
|
|||||||
@@ -18,11 +18,11 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"socket_name": {
|
"socket_name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "mosaic-factory"
|
"default": "mosaic-fleet"
|
||||||
},
|
},
|
||||||
"socketName": {
|
"socketName": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "mosaic-factory"
|
"default": "mosaic-fleet"
|
||||||
},
|
},
|
||||||
"holder_session": {
|
"holder_session": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ Per-agent overrides live outside the package in:
|
|||||||
Example:
|
Example:
|
||||||
|
|
||||||
```dotenv
|
```dotenv
|
||||||
MOSAIC_TMUX_SOCKET=mosaic-factory
|
MOSAIC_TMUX_SOCKET=mosaic-fleet
|
||||||
MOSAIC_AGENT_RUNTIME=claude
|
MOSAIC_AGENT_RUNTIME=claude
|
||||||
MOSAIC_AGENT_WORKDIR=$HOME/src/your-project
|
MOSAIC_AGENT_WORKDIR=$HOME/src/your-project
|
||||||
# Optional escape hatch for PoC/canary agents:
|
# Optional escape hatch for PoC/canary agents:
|
||||||
@@ -50,8 +50,8 @@ chmod +x ~/.config/mosaic/tools/fleet/start-agent-session.sh
|
|||||||
systemctl --user daemon-reload
|
systemctl --user daemon-reload
|
||||||
systemctl --user start mosaic-tmux-holder.service
|
systemctl --user start mosaic-tmux-holder.service
|
||||||
systemctl --user start mosaic-agent@canary.service
|
systemctl --user start mosaic-agent@canary.service
|
||||||
tmux -L mosaic-factory ls
|
tmux -L mosaic-fleet ls
|
||||||
```
|
```
|
||||||
|
|
||||||
Do not use `tmux kill-server` without `-L mosaic-factory`; this pattern is meant
|
Do not use `tmux kill-server` without `-L mosaic-fleet`; this pattern is meant
|
||||||
to avoid disturbing the user's default tmux server.
|
to avoid disturbing the user's default tmux server.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ After=default.target
|
|||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
RemainAfterExit=yes
|
RemainAfterExit=yes
|
||||||
Environment=MOSAIC_TMUX_SOCKET=mosaic-factory
|
Environment=MOSAIC_TMUX_SOCKET=mosaic-fleet
|
||||||
Environment=MOSAIC_TMUX_HOLDER=_holder
|
Environment=MOSAIC_TMUX_HOLDER=_holder
|
||||||
ExecStart=/bin/bash -lc 'tmux -L "$MOSAIC_TMUX_SOCKET" has-session -t "=${MOSAIC_TMUX_HOLDER}:0.0" 2>/dev/null || tmux -L "$MOSAIC_TMUX_SOCKET" new-session -d -s "$MOSAIC_TMUX_HOLDER" "while true; do sleep 3600; done"'
|
ExecStart=/bin/bash -lc 'tmux -L "$MOSAIC_TMUX_SOCKET" has-session -t "=${MOSAIC_TMUX_HOLDER}:0.0" 2>/dev/null || tmux -L "$MOSAIC_TMUX_SOCKET" new-session -d -s "$MOSAIC_TMUX_HOLDER" "while true; do sleep 3600; done"'
|
||||||
ExecStop=-/bin/bash -lc 'tmux -L "$MOSAIC_TMUX_SOCKET" kill-server'
|
ExecStop=-/bin/bash -lc 'tmux -L "$MOSAIC_TMUX_SOCKET" kill-server'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
AGENT_NAME=${1:-${MOSAIC_AGENT_NAME:-}}
|
AGENT_NAME=${1:-${MOSAIC_AGENT_NAME:-}}
|
||||||
# Absent socket ⇒ the LITERAL default tmux socket (no -L). The roster's
|
# Absent socket ⇒ the LITERAL default tmux socket (no -L). The roster's
|
||||||
# socket_name is honored when set; absent never silently becomes mosaic-factory
|
# socket_name is honored when set; absent never silently becomes mosaic-fleet
|
||||||
# (spawn stays consistent with the onboarding cheat-sheet + fleet ps observe).
|
# (spawn stays consistent with the onboarding cheat-sheet + fleet ps observe).
|
||||||
MOSAIC_TMUX_SOCKET=${MOSAIC_TMUX_SOCKET:-}
|
MOSAIC_TMUX_SOCKET=${MOSAIC_TMUX_SOCKET:-}
|
||||||
MOSAIC_AGENT_RUNTIME=${MOSAIC_AGENT_RUNTIME:-pi}
|
MOSAIC_AGENT_RUNTIME=${MOSAIC_AGENT_RUNTIME:-pi}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ delivers reliably to local OR remote panes.
|
|||||||
agent-send.sh -s <dst_session> -m "message"
|
agent-send.sh -s <dst_session> -m "message"
|
||||||
|
|
||||||
# Local target on a Mosaic fleet socket
|
# Local target on a Mosaic fleet socket
|
||||||
agent-send.sh -L mosaic-factory -s '=coder0' -m "message"
|
agent-send.sh -L mosaic-fleet -s '=coder0' -m "message"
|
||||||
|
|
||||||
# Remote target (over ssh)
|
# Remote target (over ssh)
|
||||||
agent-send.sh -H user@host -s <dst_session> -m "message"
|
agent-send.sh -H user@host -s <dst_session> -m "message"
|
||||||
@@ -58,9 +58,9 @@ commands do not fall back to tmux's prefix matching behavior.
|
|||||||
Durable Mosaic fleets should use a dedicated tmux socket, for example:
|
Durable Mosaic fleets should use a dedicated tmux socket, for example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tmux -L mosaic-factory ls
|
tmux -L mosaic-fleet ls
|
||||||
agent-send.sh -L mosaic-factory -s '=coder0' -m "status?"
|
agent-send.sh -L mosaic-fleet -s '=coder0' -m "status?"
|
||||||
send-message.sh -L mosaic-factory -t '=coder0' -m "raw pane message"
|
send-message.sh -L mosaic-fleet -t '=coder0' -m "raw pane message"
|
||||||
```
|
```
|
||||||
|
|
||||||
This keeps fleet operations away from the user's default tmux server. It is the
|
This keeps fleet operations away from the user's default tmux server. It is the
|
||||||
|
|||||||
@@ -132,14 +132,14 @@ describe('fleet roster parsing', () => {
|
|||||||
|
|
||||||
const roster = await loadFleetRoster(rosterPath);
|
const roster = await loadFleetRoster(rosterPath);
|
||||||
|
|
||||||
expect(roster.tmux.socketName).toBe(''); // absent ⇒ default socket (no -L), not mosaic-factory
|
expect(roster.tmux.socketName).toBe(''); // absent ⇒ default socket (no -L), not mosaic-fleet
|
||||||
expect(roster.tmux.holderSession).toBe('_holder');
|
expect(roster.tmux.holderSession).toBe('_holder');
|
||||||
expect(roster.agents).toHaveLength(1);
|
expect(roster.agents).toHaveLength(1);
|
||||||
expect(getRosterAgent(roster, 'canary-pi').runtime).toBe('pi');
|
expect(getRosterAgent(roster, 'canary-pi').runtime).toBe('pi');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('socketArgs: named socket → -L <name>; empty → no -L (default socket)', () => {
|
it('socketArgs: named socket → -L <name>; empty → no -L (default socket)', () => {
|
||||||
expect(socketArgs('mosaic-factory')).toEqual(['-L', 'mosaic-factory']);
|
expect(socketArgs('mosaic-fleet')).toEqual(['-L', 'mosaic-fleet']);
|
||||||
expect(socketArgs('')).toEqual([]);
|
expect(socketArgs('')).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -152,14 +152,14 @@ describe('fleet roster parsing', () => {
|
|||||||
'version: 1',
|
'version: 1',
|
||||||
'transport: tmux',
|
'transport: tmux',
|
||||||
'tmux:',
|
'tmux:',
|
||||||
' socket_name: mosaic-factory',
|
' socket_name: mosaic-fleet',
|
||||||
'agents:',
|
'agents:',
|
||||||
' - name: canary-pi',
|
' - name: canary-pi',
|
||||||
' runtime: pi',
|
' runtime: pi',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
);
|
);
|
||||||
const roster = await loadFleetRoster(rosterPath);
|
const roster = await loadFleetRoster(rosterPath);
|
||||||
expect(roster.tmux.socketName).toBe('mosaic-factory');
|
expect(roster.tmux.socketName).toBe('mosaic-fleet');
|
||||||
expect(buildTmuxListSessionsCommand(roster.tmux.socketName)).toContain('-L');
|
expect(buildTmuxListSessionsCommand(roster.tmux.socketName)).toContain('-L');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ describe('fleet roster parsing', () => {
|
|||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
transport: 'tmux',
|
transport: 'tmux',
|
||||||
tmux: { socket_name: 'mosaic-factory' },
|
tmux: { socket_name: 'mosaic-fleet' },
|
||||||
defaults: { working_directory: '/srv/mosaic' },
|
defaults: { working_directory: '/srv/mosaic' },
|
||||||
agents: [{ name: 'coder0', runtime: 'codex', class: 'implementer' }],
|
agents: [{ name: 'coder0', runtime: 'codex', class: 'implementer' }],
|
||||||
}),
|
}),
|
||||||
@@ -202,7 +202,7 @@ describe('fleet roster parsing', () => {
|
|||||||
'MOSAIC_AGENT_RUNTIME=codex',
|
'MOSAIC_AGENT_RUNTIME=codex',
|
||||||
'MOSAIC_AGENT_MODEL=',
|
'MOSAIC_AGENT_MODEL=',
|
||||||
'MOSAIC_AGENT_WORKDIR=/srv/mosaic',
|
'MOSAIC_AGENT_WORKDIR=/srv/mosaic',
|
||||||
'MOSAIC_TMUX_SOCKET=mosaic-factory',
|
'MOSAIC_TMUX_SOCKET=mosaic-fleet',
|
||||||
'',
|
'',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
);
|
);
|
||||||
@@ -213,7 +213,7 @@ describe('fleet roster parsing', () => {
|
|||||||
'MOSAIC_AGENT_NAME=coder0',
|
'MOSAIC_AGENT_NAME=coder0',
|
||||||
'MOSAIC_AGENT_RUNTIME=codex',
|
'MOSAIC_AGENT_RUNTIME=codex',
|
||||||
'MOSAIC_AGENT_WORKDIR=/srv/new',
|
'MOSAIC_AGENT_WORKDIR=/srv/new',
|
||||||
'MOSAIC_TMUX_SOCKET=mosaic-factory',
|
'MOSAIC_TMUX_SOCKET=mosaic-fleet',
|
||||||
'',
|
'',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
const existing = [
|
const existing = [
|
||||||
@@ -231,7 +231,7 @@ describe('fleet roster parsing', () => {
|
|||||||
'MOSAIC_AGENT_NAME=coder0',
|
'MOSAIC_AGENT_NAME=coder0',
|
||||||
'MOSAIC_AGENT_RUNTIME=codex',
|
'MOSAIC_AGENT_RUNTIME=codex',
|
||||||
'MOSAIC_AGENT_WORKDIR=/srv/new',
|
'MOSAIC_AGENT_WORKDIR=/srv/new',
|
||||||
'MOSAIC_TMUX_SOCKET=mosaic-factory',
|
'MOSAIC_TMUX_SOCKET=mosaic-fleet',
|
||||||
'MOSAIC_AGENT_COMMAND=/home/jarvis/.config/mosaic/fleet/canary.sh',
|
'MOSAIC_AGENT_COMMAND=/home/jarvis/.config/mosaic/fleet/canary.sh',
|
||||||
'# site note',
|
'# site note',
|
||||||
'',
|
'',
|
||||||
@@ -324,7 +324,7 @@ describe('fleet roster parsing', () => {
|
|||||||
const localCanary = await loadFleetRoster(join(examplesDir, 'local-canary.yaml'));
|
const localCanary = await loadFleetRoster(join(examplesDir, 'local-canary.yaml'));
|
||||||
|
|
||||||
expect(minimal.agents.map((agent) => agent.name)).toEqual(['canary-pi']);
|
expect(minimal.agents.map((agent) => agent.name)).toEqual(['canary-pi']);
|
||||||
expect(localCanary.tmux.socketName).toBe('mosaic-factory');
|
expect(localCanary.tmux.socketName).toBe('mosaic-fleet');
|
||||||
expect(localCanary.agents.map((agent) => agent.name)).toEqual(['lead', 'coder0', 'reviewer0']);
|
expect(localCanary.agents.map((agent) => agent.name)).toEqual(['lead', 'coder0', 'reviewer0']);
|
||||||
expect(localCanaryText).not.toMatch(/usc|ultron|secrev/i);
|
expect(localCanaryText).not.toMatch(/usc|ultron|secrev/i);
|
||||||
});
|
});
|
||||||
@@ -349,11 +349,11 @@ describe('fleet command construction', () => {
|
|||||||
it('builds socket-scoped agent send commands', () => {
|
it('builds socket-scoped agent send commands', () => {
|
||||||
const paths = resolveFleetPaths('/home/test/.config/mosaic');
|
const paths = resolveFleetPaths('/home/test/.config/mosaic');
|
||||||
expect(
|
expect(
|
||||||
buildAgentSendCommand(paths, 'coder0', 'hello', 'mosaic-factory', 'operator:mosaic-cli'),
|
buildAgentSendCommand(paths, 'coder0', 'hello', 'mosaic-fleet', 'operator:mosaic-cli'),
|
||||||
).toEqual([
|
).toEqual([
|
||||||
'/home/test/.config/mosaic/tools/tmux/agent-send.sh',
|
'/home/test/.config/mosaic/tools/tmux/agent-send.sh',
|
||||||
'-L',
|
'-L',
|
||||||
'mosaic-factory',
|
'mosaic-fleet',
|
||||||
'-S',
|
'-S',
|
||||||
'operator:mosaic-cli',
|
'operator:mosaic-cli',
|
||||||
'-s',
|
'-s',
|
||||||
@@ -841,10 +841,10 @@ describe('fleet ps — command construction', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('builds exact tmux list-panes command with the correct format string', () => {
|
it('builds exact tmux list-panes command with the correct format string', () => {
|
||||||
expect(buildTmuxListPanesCommand('canary-pi', 'mosaic-factory')).toEqual([
|
expect(buildTmuxListPanesCommand('canary-pi', 'mosaic-fleet')).toEqual([
|
||||||
'tmux',
|
'tmux',
|
||||||
'-L',
|
'-L',
|
||||||
'mosaic-factory',
|
'mosaic-fleet',
|
||||||
'list-panes',
|
'list-panes',
|
||||||
'-t',
|
'-t',
|
||||||
'=canary-pi:0.0',
|
'=canary-pi:0.0',
|
||||||
@@ -1167,7 +1167,7 @@ describe('fleet install — auto-enable units for boot-survival', () => {
|
|||||||
const minimalRoster: FleetRoster = {
|
const minimalRoster: FleetRoster = {
|
||||||
version: 1,
|
version: 1,
|
||||||
transport: 'tmux',
|
transport: 'tmux',
|
||||||
tmux: { socketName: 'mosaic-factory', holderSession: '_holder' },
|
tmux: { socketName: 'mosaic-fleet', holderSession: '_holder' },
|
||||||
defaults: { workingDirectory: '~/src' },
|
defaults: { workingDirectory: '~/src' },
|
||||||
runtimes: { codex: { resetCommand: '/clear' } },
|
runtimes: { codex: { resetCommand: '/clear' } },
|
||||||
agents: [{ name: 'coder0', runtime: 'codex', className: 'worker' }],
|
agents: [{ name: 'coder0', runtime: 'codex', className: 'worker' }],
|
||||||
@@ -1189,7 +1189,7 @@ describe('fleet install — auto-enable units for boot-survival', () => {
|
|||||||
const minimalRoster: FleetRoster = {
|
const minimalRoster: FleetRoster = {
|
||||||
version: 1,
|
version: 1,
|
||||||
transport: 'tmux',
|
transport: 'tmux',
|
||||||
tmux: { socketName: 'mosaic-factory', holderSession: '_holder' },
|
tmux: { socketName: 'mosaic-fleet', holderSession: '_holder' },
|
||||||
defaults: { workingDirectory: '~/src' },
|
defaults: { workingDirectory: '~/src' },
|
||||||
runtimes: { codex: { resetCommand: '/clear' } },
|
runtimes: { codex: { resetCommand: '/clear' } },
|
||||||
agents: [{ name: 'coder0', runtime: 'codex', className: 'worker' }],
|
agents: [{ name: 'coder0', runtime: 'codex', className: 'worker' }],
|
||||||
@@ -1216,7 +1216,7 @@ describe('fleet install — auto-enable units for boot-survival', () => {
|
|||||||
const minimalRoster: FleetRoster = {
|
const minimalRoster: FleetRoster = {
|
||||||
version: 1,
|
version: 1,
|
||||||
transport: 'tmux',
|
transport: 'tmux',
|
||||||
tmux: { socketName: 'mosaic-factory', holderSession: '_holder' },
|
tmux: { socketName: 'mosaic-fleet', holderSession: '_holder' },
|
||||||
defaults: { workingDirectory: '~/src' },
|
defaults: { workingDirectory: '~/src' },
|
||||||
runtimes: { codex: { resetCommand: '/clear' } },
|
runtimes: { codex: { resetCommand: '/clear' } },
|
||||||
agents: [{ name: 'coder0', runtime: 'codex', className: 'worker' }],
|
agents: [{ name: 'coder0', runtime: 'codex', className: 'worker' }],
|
||||||
@@ -1388,10 +1388,10 @@ describe('fleet ps — command sequences issued', () => {
|
|||||||
|
|
||||||
describe('buildTmuxListSessionsCommand', () => {
|
describe('buildTmuxListSessionsCommand', () => {
|
||||||
it('builds exact list-sessions command with session_name format', () => {
|
it('builds exact list-sessions command with session_name format', () => {
|
||||||
expect(buildTmuxListSessionsCommand('mosaic-factory')).toEqual([
|
expect(buildTmuxListSessionsCommand('mosaic-fleet')).toEqual([
|
||||||
'tmux',
|
'tmux',
|
||||||
'-L',
|
'-L',
|
||||||
'mosaic-factory',
|
'mosaic-fleet',
|
||||||
'list-sessions',
|
'list-sessions',
|
||||||
'-F',
|
'-F',
|
||||||
'#{session_name}',
|
'#{session_name}',
|
||||||
@@ -1642,11 +1642,11 @@ describe('fleet ps — unmanaged socket sessions', () => {
|
|||||||
describe('agent watch', () => {
|
describe('agent watch', () => {
|
||||||
it('builds exact grouped-viewer creation command', () => {
|
it('builds exact grouped-viewer creation command', () => {
|
||||||
expect(
|
expect(
|
||||||
buildAgentWatchCreateViewerCommand('canary-pi', 'canary-pi-watch-123', 'mosaic-factory'),
|
buildAgentWatchCreateViewerCommand('canary-pi', 'canary-pi-watch-123', 'mosaic-fleet'),
|
||||||
).toEqual([
|
).toEqual([
|
||||||
'tmux',
|
'tmux',
|
||||||
'-L',
|
'-L',
|
||||||
'mosaic-factory',
|
'mosaic-fleet',
|
||||||
'new-session',
|
'new-session',
|
||||||
'-d',
|
'-d',
|
||||||
'-t',
|
'-t',
|
||||||
@@ -1657,10 +1657,10 @@ describe('agent watch', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('builds exact viewer attach command (read-only)', () => {
|
it('builds exact viewer attach command (read-only)', () => {
|
||||||
expect(buildAgentWatchAttachCommand('canary-pi-watch-123', 'mosaic-factory')).toEqual([
|
expect(buildAgentWatchAttachCommand('canary-pi-watch-123', 'mosaic-fleet')).toEqual([
|
||||||
'tmux',
|
'tmux',
|
||||||
'-L',
|
'-L',
|
||||||
'mosaic-factory',
|
'mosaic-fleet',
|
||||||
'attach',
|
'attach',
|
||||||
'-r',
|
'-r',
|
||||||
'-t',
|
'-t',
|
||||||
@@ -1669,10 +1669,10 @@ describe('agent watch', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('builds exact viewer kill command', () => {
|
it('builds exact viewer kill command', () => {
|
||||||
expect(buildAgentWatchKillViewerCommand('canary-pi-watch-123', 'mosaic-factory')).toEqual([
|
expect(buildAgentWatchKillViewerCommand('canary-pi-watch-123', 'mosaic-fleet')).toEqual([
|
||||||
'tmux',
|
'tmux',
|
||||||
'-L',
|
'-L',
|
||||||
'mosaic-factory',
|
'mosaic-fleet',
|
||||||
'kill-session',
|
'kill-session',
|
||||||
'-t',
|
'-t',
|
||||||
'canary-pi-watch-123',
|
'canary-pi-watch-123',
|
||||||
@@ -1769,10 +1769,10 @@ describe('agent watch', () => {
|
|||||||
|
|
||||||
describe('agent send --verify', () => {
|
describe('agent send --verify', () => {
|
||||||
it('builds exact verify capture-pane command', () => {
|
it('builds exact verify capture-pane command', () => {
|
||||||
expect(buildAgentVerifyAcceptedCommand('canary-pi', 'mosaic-factory', 5)).toEqual([
|
expect(buildAgentVerifyAcceptedCommand('canary-pi', 'mosaic-fleet', 5)).toEqual([
|
||||||
'tmux',
|
'tmux',
|
||||||
'-L',
|
'-L',
|
||||||
'mosaic-factory',
|
'mosaic-fleet',
|
||||||
'capture-pane',
|
'capture-pane',
|
||||||
'-t',
|
'-t',
|
||||||
'=canary-pi:0.0',
|
'=canary-pi:0.0',
|
||||||
@@ -2484,7 +2484,7 @@ describe('fleet add/remove — pure helpers', () => {
|
|||||||
const baseRoster: FleetRoster = {
|
const baseRoster: FleetRoster = {
|
||||||
version: 1,
|
version: 1,
|
||||||
transport: 'tmux',
|
transport: 'tmux',
|
||||||
tmux: { socketName: 'mosaic-factory', holderSession: '_holder' },
|
tmux: { socketName: 'mosaic-fleet', holderSession: '_holder' },
|
||||||
defaults: { workingDirectory: '~/src' },
|
defaults: { workingDirectory: '~/src' },
|
||||||
runtimes: { codex: { resetCommand: '/clear' } },
|
runtimes: { codex: { resetCommand: '/clear' } },
|
||||||
agents: [
|
agents: [
|
||||||
@@ -2610,7 +2610,7 @@ describe('fleet add/remove — pure helpers', () => {
|
|||||||
await writeFile(rosterPath, yaml);
|
await writeFile(rosterPath, yaml);
|
||||||
const loaded = await loadFleetRoster(rosterPath);
|
const loaded = await loadFleetRoster(rosterPath);
|
||||||
expect(loaded.agents.map((a) => a.name)).toEqual(['orchestrator', 'coder0']);
|
expect(loaded.agents.map((a) => a.name)).toEqual(['orchestrator', 'coder0']);
|
||||||
expect(loaded.tmux.socketName).toBe('mosaic-factory');
|
expect(loaded.tmux.socketName).toBe('mosaic-fleet');
|
||||||
expect(loaded.agents[0]!.className).toBe('orchestrator');
|
expect(loaded.agents[0]!.className).toBe('orchestrator');
|
||||||
} finally {
|
} finally {
|
||||||
await rm(dir, { recursive: true, force: true });
|
await rm(dir, { recursive: true, force: true });
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ type FleetServiceAction = 'start' | 'stop' | 'restart' | 'status';
|
|||||||
* rosters/callers that explicitly want isolation; it is NO LONGER the silent
|
* rosters/callers that explicitly want isolation; it is NO LONGER the silent
|
||||||
* fallback for a socket-less roster (that now resolves to the default socket).
|
* fallback for a socket-less roster (that now resolves to the default socket).
|
||||||
*/
|
*/
|
||||||
export const DEFAULT_SOCKET_NAME = 'mosaic-factory';
|
export const DEFAULT_SOCKET_NAME = 'mosaic-fleet';
|
||||||
const DEFAULT_HOLDER_SESSION = '_holder';
|
const DEFAULT_HOLDER_SESSION = '_holder';
|
||||||
const DEFAULT_WORKING_DIRECTORY = '~/src';
|
const DEFAULT_WORKING_DIRECTORY = '~/src';
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ const DEFAULT_WORKING_DIRECTORY = '~/src';
|
|||||||
* tmux `-L` args for a socket name. An empty/absent socket ⇒ the LITERAL default
|
* tmux `-L` args for a socket name. An empty/absent socket ⇒ the LITERAL default
|
||||||
* tmux socket (no `-L`), so spawn, observe (`fleet ps`/watch), and the onboarding
|
* tmux socket (no `-L`), so spawn, observe (`fleet ps`/watch), and the onboarding
|
||||||
* cheat-sheet all agree. A named socket ⇒ `-L <name>`. `DEFAULT_SOCKET_NAME`
|
* cheat-sheet all agree. A named socket ⇒ `-L <name>`. `DEFAULT_SOCKET_NAME`
|
||||||
* remains a constant for callers that explicitly want mosaic-factory; it is no
|
* remains a constant for callers that explicitly want mosaic-fleet; it is no
|
||||||
* longer the silent fallback for a socket-less roster.
|
* longer the silent fallback for a socket-less roster.
|
||||||
*/
|
*/
|
||||||
export function socketArgs(socketName: string): string[] {
|
export function socketArgs(socketName: string): string[] {
|
||||||
@@ -1689,7 +1689,7 @@ function normalizeRoster(raw: RawFleetRoster): FleetRoster {
|
|||||||
transport: 'tmux',
|
transport: 'tmux',
|
||||||
tmux: {
|
tmux: {
|
||||||
// Absent socket_name ⇒ '' (the literal default tmux socket, no -L) — NOT
|
// Absent socket_name ⇒ '' (the literal default tmux socket, no -L) — NOT
|
||||||
// mosaic-factory. Shipped presets set socket_name explicitly, so they are
|
// mosaic-fleet. Shipped presets set socket_name explicitly, so they are
|
||||||
// unaffected; only socket-less rosters get default-socket behavior.
|
// unaffected; only socket-less rosters get default-socket behavior.
|
||||||
socketName: stringValue(
|
socketName: stringValue(
|
||||||
raw.tmux?.socket_name ?? raw.tmux?.socketName,
|
raw.tmux?.socket_name ?? raw.tmux?.socketName,
|
||||||
|
|||||||
@@ -48,9 +48,9 @@ describe('parseRosterAgents', () => {
|
|||||||
|
|
||||||
it('parses an optional per-agent socket', () => {
|
it('parses an optional per-agent socket', () => {
|
||||||
const peers = parseRosterAgents(
|
const peers = parseRosterAgents(
|
||||||
['agents:', ' - name: a', ' class: worker', ' socket: mosaic-factory'].join('\n'),
|
['agents:', ' - name: a', ' class: worker', ' socket: mosaic-fleet'].join('\n'),
|
||||||
);
|
);
|
||||||
expect(peers[0]).toMatchObject({ name: 'a', socket: 'mosaic-factory' });
|
expect(peers[0]).toMatchObject({ name: 'a', socket: 'mosaic-fleet' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('stops at the next top-level key', () => {
|
it('stops at the next top-level key', () => {
|
||||||
@@ -99,9 +99,9 @@ describe('renderPeerReach — same-host vs cross-host', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('emits -L <socket> for a named socket', () => {
|
it('emits -L <socket> for a named socket', () => {
|
||||||
const peer: CommsPeer = { name: 'coder0', className: 'implementer', socket: 'mosaic-factory' };
|
const peer: CommsPeer = { name: 'coder0', className: 'implementer', socket: 'mosaic-fleet' };
|
||||||
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(
|
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(
|
||||||
`${send} -L mosaic-factory -s coder0 -m "…"`,
|
`${send} -L mosaic-fleet -s coder0 -m "…"`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -111,10 +111,10 @@ describe('renderPeerReach — same-host vs cross-host', () => {
|
|||||||
className: 'implementer',
|
className: 'implementer',
|
||||||
host: '10.1.10.37',
|
host: '10.1.10.37',
|
||||||
ssh: 'jwoltje@10.1.10.37',
|
ssh: 'jwoltje@10.1.10.37',
|
||||||
socket: 'mosaic-factory',
|
socket: 'mosaic-fleet',
|
||||||
};
|
};
|
||||||
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(
|
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(
|
||||||
`${send} -L mosaic-factory -H jwoltje@10.1.10.37 -s coder0-0 -m "…"`,
|
`${send} -L mosaic-fleet -H jwoltje@10.1.10.37 -s coder0-0 -m "…"`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user