Skip to content

fix(cli): 2.0.0-preview.2 upgrade/health fixes from dogfooding - #2303

Merged
tamirdresher merged 5 commits into
devfrom
squad2-preview2-cli-upgrade-fixes
Oct 24, 2026
Merged

tamirdresher merged 5 commits into
devfrom
squad2-preview2-cli-upgrade-fixes

Conversation

@tamirdresher

@tamirdresher tamirdresher commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Dogfooding 2.0.0-preview.1 found CLI upgrade, health, self-update, client, and migration defects. This branch is rebased onto dev at de1c4e66 and now includes an independent post-review revision addressing Worf findings CL-1 through CL-4.

Fixes #2295, Fixes #2297, Fixes #2298, Fixes #2299
Fixes #2047, Fixes #2174
Refs #2266, #2232, #2234, #1785, #2283, #2301

Reviewer revision

The rejected head ca77de68 automatically added Rai and Fact Checker to user-owned .squad/team.md. That behavior has been removed.

  • Plain squad upgrade, --dry-run, client projection, and projection uninstall preserve team.md byte-for-byte.
  • Rai and Fact Checker remain optional for existing squads. Health reports installed-but-unselected optional built-ins as INFO: available but not configured.
  • A missing charter referenced by routing remains a real health failure.
  • New explicit commands provide the consent boundary:
    • squad roster add <rai|fact-checker|all> [--dry-run]
    • squad roster remove <rai|fact-checker|all> [--dry-run]
    • disable and uninstall are remove aliases.
  • Roster changes preview the exact diff, create and verify a byte-exact backup before writing, preserve LF/CRLF and custom content, detect equivalent/case-only rows, remain idempotent, and record provenance. Removal deletes only provenance-owned rows and restores exact prior bytes when otherwise unchanged.
  • Compound textual templates such as mesh.json.example now use EOL-normalized comparison, eliminating CRLF false overwrites.
  • The project-label test is host-native and hermetic.
  • First-upgrade backup output says prior provenance is unavailable instead of asserting customization without proof.

Bug → fix → test

Area Fix Main coverage
Self-upgrade dry-run/channel (#2295) Zero execution during dry-run; preview/insider channels stay on insider; stable stays on latest; downgrade refusal unless forced upgrade-idempotent.test.ts
Squad-owned file safety (#2297, #2047, #2232) Content plan, verified .local-backup, shipped manifest, retired-file cleanup, EOL-preserving no-op upgrades upgrade-idempotent, upgrade/template suites
Optional built-ins (#2298) No automatic roster edits; INFO health state; explicit provenance-backed roster command roster.test.ts, health-legacy.test.ts, Upgrade Matrix
Legacy health/routing (#2298, #2234, #1785) Legacy charter compatibility, routing-table filtering, installed built-in routing validation health suites
Rai casing migration (#2299) Two-step tracked Rai → rai rename with restart-safe fallback rai-rename-git.test.ts
Client/update diagnostics (#2299) Client list/add, project label, stale update cache, doctor mode/DEP0190 fixes preview2-cli-fixes, doctor suites
Workstream decision inbox (#2299) Active-workstream-aware inbox resolution and safe slugs squad-decide-inbox.test.ts
Changeset drain (#2283, #2301) CI validates pending fragments; release mode still fails closed until drained release-policy-changeset-drain.test.ts

Relationship to #2269

Compatible, not superseding. #2269 owns casting JSON normalization and its .gitattributes rule. This PR now handles compound textual .example templates in the squad-owned file planner; it still does not normalize or rewrite the casting registry/history pair.

Commits after rebase

  • 65245d4c — dogfood upgrade/health fixes
  • 84839419 — event-aware changeset drain
  • 8df2b794 — legacy upgrade/help test alignment
  • 0e58cd07 — explicit optional built-in roster contract
  • 7e422a5e — compound text-template CRLF idempotence and provenance-neutral backup wording

Validation

  • SKIP_BUILD_BUMP=1 npm run build — pass
  • npm run lint — pass
  • Mandated focused suites (rai-rename-git, health-legacy, preview2-cli-fixes, squad-decide-inbox, release-policy-changeset-drain, command-help, roster) — 58/58 pass
  • Upgrade suites — 139 pass, 1 platform skip
  • Health/doctor/init/template suites — 726 pass; three loaded-host hook timeouts passed when rerun alone with a 30-second hook timeout
  • policy-gates --mode=ci — pass with 9 valid pending changesets
  • policy-gates --mode=release — expected fail-closed on those pending changesets
  • check-release-scripts — 21 scripts clean
  • Local Windows Upgrade Matrix, producer 0.13.1, shapes default + ai-team — 2/2 rows pass; user-state-preserved and projection-uninstall-byte-exact both pass for both shapes
  • GitHub Squad CI 40089219878 — pass
  • GitHub Upgrade Matrix 40089168150 — Ubuntu and Windows pass
  • GitHub Release Verify 40089168164 — product build, lint, full Vitest, and node:test steps passed; final reconciliation failed on one pre-existing unclassified Linux skip in est/mcp-root-write.test.ts, introduced by base commit de1c4e6 and unchanged by this branch

Leftovers / not in this PR

Copilot AI balanced review requested due to automatic review settings October 24, 2026 09:43
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

🟠 Impact Analysis — PR #2303

Risk tier: 🟠 HIGH

📊 Summary

Metric Count
Files changed 45
Files added 14
Files modified 31
Files deleted 0
Modules touched 8
Critical files 1

🎯 Risk Factors

  • 45 files changed (21-50 → HIGH)
  • 8 modules touched (5-8 → HIGH)
  • Critical files touched: packages/squad-sdk/src/tools/index.ts

📦 Modules Affected

ci-workflows (2 files)
  • .github/agents/squad.agent.md
  • .github/workflows/squad-release-verify.yml
docs (3 files)
  • docs/src/content/docs/features/self-upgrade.md
  • docs/src/content/docs/reference/cli.md
  • docs/src/content/docs/scenarios/upgrading.md
root (7 files)
  • .changeset/health-legacy-and-roster.md
  • .changeset/preview2-command-fixes.md
  • .changeset/self-upgrade-dry-run-channel.md
  • .changeset/upgrade-idempotent-backups.md
  • README.md
  • templates/README.md
  • templates/squad.agent.md.template
scripts (1 file)
  • scripts/release/policy-gates.mjs
squad-cli (13 files)
  • packages/squad-cli/src/cli-entry.ts
  • packages/squad-cli/src/cli/commands/client.ts
  • packages/squad-cli/src/cli/commands/doctor.ts
  • packages/squad-cli/src/cli/commands/health.ts
  • packages/squad-cli/src/cli/commands/roster.ts
  • packages/squad-cli/src/cli/commands/update-check.ts
  • packages/squad-cli/src/cli/core/command-help.ts
  • packages/squad-cli/src/cli/core/init.ts
  • packages/squad-cli/src/cli/core/squad-owned-files.ts
  • packages/squad-cli/src/cli/core/team-md.ts
  • packages/squad-cli/src/cli/core/upgrade.ts
  • packages/squad-cli/templates/README.md
  • packages/squad-cli/templates/squad.agent.md.template
squad-sdk (8 files)
  • packages/squad-sdk/src/agents/charter-markdown.ts
  • packages/squad-sdk/src/agents/onboarding.ts
  • packages/squad-sdk/src/config/init.ts
  • packages/squad-sdk/src/config/markdown-migration.ts
  • packages/squad-sdk/src/ralph/triage.ts
  • packages/squad-sdk/src/tools/index.ts
  • packages/squad-sdk/templates/README.md
  • packages/squad-sdk/templates/squad.agent.md.template
templates (2 files)
  • .squad-templates/README.md
  • .squad-templates/squad.agent.md
tests (9 files)
  • test/cli/command-help.test.ts
  • test/cli/health-legacy.test.ts
  • test/cli/preview2-cli-fixes.test.ts
  • test/cli/rai-rename-git.test.ts
  • test/cli/roster.test.ts
  • test/cli/upgrade-idempotent.test.ts
  • test/cli/upgrade.test.ts
  • test/release-policy-changeset-drain.test.ts
  • test/sdk/squad-decide-inbox.test.ts

⚠️ Critical Files

  • packages/squad-sdk/src/tools/index.ts

This report is generated automatically for every PR. See #733 for details.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit 7e422a5

PR Scope: 📦🔧 Mixed (product + infrastructure)

⚠️ 4 item(s) to address before review

Status Check Details
❌ Single commit 5 commits — consider squashing before review
✅ Not in draft Ready for review
✅ Branch up to date Up to date with dev
❌ Copilot review No Copilot review yet — it may still be processing
✅ Changeset present Changeset file found
✅ Scope clean No .squad/ or docs/proposals/ files
✅ No merge conflicts No merge conflicts
❌ Copilot threads resolved 8 unresolved Copilot thread(s) — fix and resolve before merging
❌ CI passing 4 check(s) failing: test, sdk-exports-validation, samples-build, Verify exact SHA and build evidence

Files Changed (45 files, +3112 −351)

File +/−
.changeset/health-legacy-and-roster.md +6 −0
.changeset/preview2-command-fixes.md +6 −0
.changeset/self-upgrade-dry-run-channel.md +5 −0
.changeset/upgrade-idempotent-backups.md +5 −0
.github/agents/squad.agent.md +2 −2
.github/workflows/squad-release-verify.yml +6 −2
.squad-templates/README.md +2 −2
.squad-templates/squad.agent.md +2 −2
README.md +3 −2
docs/src/content/docs/features/self-upgrade.md +41 −30
docs/src/content/docs/reference/cli.md +2 −0
docs/src/content/docs/scenarios/upgrading.md +27 −1
packages/squad-cli/src/cli-entry.ts +47 −19
packages/squad-cli/src/cli/commands/client.ts +159 −0
packages/squad-cli/src/cli/commands/doctor.ts +20 −5
packages/squad-cli/src/cli/commands/health.ts +74 −4
packages/squad-cli/src/cli/commands/roster.ts +323 −0
packages/squad-cli/src/cli/commands/update-check.ts +17 −3
packages/squad-cli/src/cli/core/command-help.ts +40 −8
packages/squad-cli/src/cli/core/init.ts +5 −3
packages/squad-cli/src/cli/core/squad-owned-files.ts +368 −0
packages/squad-cli/src/cli/core/team-md.ts +87 −0
packages/squad-cli/src/cli/core/upgrade.ts +439 −212
packages/squad-cli/templates/README.md +2 −2
packages/squad-cli/templates/squad.agent.md.template +2 −2
packages/squad-sdk/src/agents/charter-markdown.ts +21 −8
packages/squad-sdk/src/agents/onboarding.ts +1 −1
packages/squad-sdk/src/config/init.ts +5 −0
packages/squad-sdk/src/config/markdown-migration.ts +28 −7
packages/squad-sdk/src/ralph/triage.ts +3 −1
packages/squad-sdk/src/tools/index.ts +50 −4
packages/squad-sdk/templates/README.md +2 −2
packages/squad-sdk/templates/squad.agent.md.template +2 −2
scripts/release/policy-gates.mjs +55 −5
templates/README.md +2 −2
templates/squad.agent.md.template +2 −2
test/cli/command-help.test.ts +2 −0
test/cli/health-legacy.test.ts +204 −0
test/cli/preview2-cli-fixes.test.ts +174 −0
test/cli/rai-rename-git.test.ts +90 −0
test/cli/roster.test.ts +157 −0
test/cli/upgrade-idempotent.test.ts +427 −0
test/cli/upgrade.test.ts +22 −18
test/release-policy-changeset-drain.test.ts +91 −0
test/sdk/squad-decide-inbox.test.ts +84 −0

Total: +3112 −351


This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

🏗️ Architectural Review

Authoritative evidence: base-controlled pull_request_target reporter.

⚠️ Architectural review: 2 warning(s).

Severity Category Finding Files
🟡 warning bootstrap-area 5 file(s) in the bootstrap area (packages/squad-cli/src/cli/core/) were modified. These files must maintain zero external dependencies. Review carefully. packages/squad-cli/src/cli/core/command-help.ts, packages/squad-cli/src/cli/core/init.ts, packages/squad-cli/src/cli/core/squad-owned-files.ts, packages/squad-cli/src/cli/core/team-md.ts, packages/squad-cli/src/cli/core/upgrade.ts
🟡 warning sweeping-refactor This PR touches 45 files (45 modified/added, 0 deleted). Large PRs are harder to review — consider splitting if possible. —

Automated architectural review — informational only.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved deletion and migration data-loss risks, incomplete downgrade protection, and a Linux-failing test assertion block approval.

10 open issues
What changed in this PR

This PR addresses preview-release dogfooding issues across Squad’s CLI upgrade flow, health checks, and SDK decision routing. It also adjusts release verification so pull requests can retain valid pending changesets.

Changes:

  • Adds content-aware upgrade planning, verified backups, retired-file cleanup, and channel-aware self-upgrade safeguards.
  • Improves legacy charter handling, built-in roster migration, client commands, diagnostics, and workstream inbox selection.
  • Adds regression coverage, updates upgrade documentation, and synchronizes lowercase Rai paths across templates.
File Description
test/​sdk/​squad-decide-inbox.test.ts Tests workstream inbox routing and filename handling.
test/​release-policy-changeset-drain.test.ts Tests event-aware changeset policy.
test/​cli/​upgrade.test.ts Updates upgrade and Rai migration expectations.
test/​cli/​upgrade-idempotent.test.ts Covers backups, idempotence, dry runs, and self-upgrade.
test/​cli/​rai-rename-git.test.ts Tests Git-recorded Rai directory renames.
test/​cli/​preview2-cli-fixes.test.ts Covers roster, client, diagnostic, and header fixes.
test/​cli/​health-legacy.test.ts Covers legacy health checks and roster drift.
test/​cli/​command-help.test.ts Adds client command help coverage.
templates/​squad.agent.md.template Updates documented Rai paths.
templates/​README.md Documents lowercase Rai destinations.
scripts/​release/​policy-gates.mjs Validates pending changesets in CI mode.
README.md Describes upgrade safeguards and client commands.
packages/​squad-sdk/​templates/​squad.agent.md.template Synchronizes SDK coordinator Rai references.
packages/​squad-sdk/​templates/​README.md Synchronizes SDK Rai path documentation.
packages/​squad-sdk/​src/​tools/​index.ts Adds workstream-aware decision inbox selection.
packages/​squad-sdk/​src/​ralph/​triage.ts Excludes built-in support agents from triage.
packages/​squad-sdk/​src/​config/​markdown-migration.ts Filters routing headers and placeholders.
packages/​squad-sdk/​src/​config/​init.ts Recognizes the lowercase Rai role.
packages/​squad-sdk/​src/​agents/​onboarding.ts Uses the lowercase Rai template key.
packages/​squad-sdk/​src/​agents/​charter-markdown.ts Parses BOM-prefixed and compact legacy charters.
packages/​squad-cli/​templates/​squad.agent.md.template Synchronizes CLI coordinator Rai references.
packages/​squad-cli/​templates/​README.md Synchronizes CLI Rai path documentation.
packages/​squad-cli/​src/​cli/​core/​upgrade.ts Integrates upgrade planning, migrations, and downgrade checks.
packages/​squad-cli/​src/​cli/​core/​team-md.ts Adds missing built-in roster rows.
packages/​squad-cli/​src/​cli/​core/​squad-owned-files.ts Implements managed-file planning, backups, and retirement.
packages/​squad-cli/​src/​cli/​core/​init.ts Seeds lowercase Rai and records shipped-file hashes.
packages/​squad-cli/​src/​cli/​core/​command-help.ts Expands upgrade and client help.
packages/​squad-cli/​src/​cli/​commands/​update-check.ts Flags stale cached update results.
packages/​squad-cli/​src/​cli/​commands/​health.ts Adds warnings and built-in recognition.
packages/​squad-cli/​src/​cli/​commands/​doctor.ts Corrects local-mode detection and subprocess usage.
packages/​squad-cli/​src/​cli/​commands/​client.ts Adds client listing and projection commands.
packages/​squad-cli/​src/​cli-entry.ts Wires client commands and dry-run handling.
docs/​src/​content/​docs/​features/​self-upgrade.md Documents revised upgrade behavior.
.squad-templates/​squad.agent.md Updates canonical coordinator Rai references.
.squad-templates/​README.md Updates canonical Rai path documentation.
.github/​workflows/​squad-release-verify.yml Selects policy mode from the triggering event.
.github/​agents/​squad.agent.md Synchronizes active coordinator Rai references.
.changeset/​upgrade-idempotent-backups.md Records managed-file upgrade changes.
.changeset/​self-upgrade-dry-run-channel.md Records self-upgrade safety changes.
.changeset/​preview2-command-fixes.md Records CLI and SDK command fixes.
.changeset/​health-legacy-and-roster.md Records health and roster changes.

Review effort: Balanced

Comment on lines +302 to +305
const absPath = path.join(dest, ...relPath.split('/'));
const existing = readExistingText(absPath);
if (existing === undefined) continue;
retired.push({ relPath, absPath, customized: contentHash(existing) !== hash });
Comment on lines +1349 to +1350
if (hasCanonical) {
storage.deleteDirSync(tempDir);
Comment thread test/cli/preview2-cli-fixes.test.ts Outdated
});

it('uses the project name from config or the repository directory name, never "undefined"', async () => {
expect(readProjectLabel('C:\\repos\\my-squad', {})).toBe('my-squad');
Comment on lines +148 to +150
reportClientResults(synced.results);
console.log(`${GREEN}✓${RESET} clients configured: ${synced.clients.join(', ')}`);
return 0;
Comment on lines +360 to +363
// Built-in support agents are legitimate routing targets even though they are not cast (#1785).
for (const { id, name } of BUILTIN_AGENTS) {
keys.add(normalizeAgentRef(id));
keys.add(normalizeAgentRef(name));
}
}

if (!hasLegacy) return { migrated, tombstoned, recordedInGit };
Comment on lines +1808 to +1812
const res = await fetch('https://registry.npmjs.org/-/package/@bradygaster%2Fsquad-cli/dist-tags', { signal: controller.signal });
clearTimeout(timer);
if (!res.ok) return null;
const tags = await res.json() as Record<string, string>;
return typeof tags[tag] === 'string' ? tags[tag]! : null;
const resolve = options.resolveTagVersion ?? resolveSelfUpgradeTagVersion;
const targetVersion = await resolve(tag);

if (targetVersion && safeCompareVersions(targetVersion, currentVersion) < 0) {
{ root: 'identity', kind: 'dir' },
];

const WORKSTREAM_SLUG = /^[A-Za-z0-9._-]+$/;
Comment on lines +313 to +316
const activationFile = path.join(path.dirname(squadRoot), '.squad-workstream');
if (storage.existsSync(activationFile)) {
const fromFile = (storage.readSync(activationFile) ?? '').split(/\r?\n/)[0]?.trim();
if (isActive(fromFile)) return inboxFor(fromFile);
tamirdresher and others added 5 commits October 24, 2026 13:22
- upgrade --self: honor --dry-run (zero exec), follow the installed channel
  (prerelease -> @insider, stable -> @latest), refuse downgrades without --force (#2295)
- upgrade: one content-compared plan for every squad-owned file; verified
  <file>.local-backup before overwrite; shipped-files manifest distinguishes user
  edits from template revisions; dry-run writes nothing and reports nothing
  right after an upgrade (also on CRLF checkouts); .gitignore/.gitattributes
  appended in the file's own EOL; retired files removed when unmodified;
  provably Squad-shipped stale .copilot/skills copies cleaned (#2297, #2266,
  #2047, #2232)
- health: table headers/placeholders never parsed as agents, built-ins are
  valid routing targets, BOM/pipe-joined legacy charters parse, missing
  identity is a warn with a hint, roster drift warns; upgrade adds built-in
  rows to team.md (#2298, #2234, #1785)
- Rai -> rai: two-step rename recorded with git mv; templates reference
  agents/rai/; init scaffolds rai/ (#2299)
- squad client list|add, dry-run header shows project name, update-check
  stale cache, squad_decide workstream inbox + 80-char slug, doctor Mode: local
  for same-project teamRoot and no DEP0190 (#2299, #2174)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
squad-release-verify.yml ran policy-gates.mjs --mode=release on pull_request
too, so every PR carrying a changeset failed the gate (#2283, #2301). The
workflow now passes --mode=ci on pull_request and --mode=release only on the
release path (workflow_call from squad-release.yml). In ci mode the gate still
runs: pending fragments are allowed but must be well-formed (allowlisted
package, patch|minor|major bump, non-empty summary); malformed ones fail.
Release mode keeps enforcing the drain unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…ade and lowercase rai init

- upgrade.test: customized-skill expectations now assert the .local-backup message;
  Rai migration test recreates the legacy mixed-case layout (init scaffolds rai/)
- command-help.test: 'client' has a dedicated help block
- cli-entry: --self --dry-run returns through the single success branch (performed=false)
- team-md: never invent a roster table in a team.md without one
- .github/agents/squad.agent.md: agents/rai/ (template-sync parity)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Keep team.md byte-stable during upgrade, report unconfigured optional built-ins as informational, and add a provenance-backed roster command with exact restore semantics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Treat compound .example templates as text for EOL-normalized planning and distinguish unproven first-upgrade provenance from confirmed customization in backup output.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
@tamirdresher
tamirdresher force-pushed the squad2-preview2-cli-upgrade-fixes branch from ca77de6 to 7e422a5 Compare October 24, 2026 11:15
@tamirdresher

Copy link
Copy Markdown
Collaborator Author

Revision pushed at 7e422a5e8ca8816c9a7a2ad221275be99dc8987d.

Commits on rebased dev de1c4e66:

  • 65245d4c dogfood upgrade/health fixes
  • 84839419 event-aware changeset drain
  • 8df2b794 legacy upgrade/help test alignment
  • 0e58cd07 explicit optional built-in roster contract
  • 7e422a5e compound .example CRLF idempotence and provenance-neutral backup wording

This addresses review findings CL-1..CL-4; roster additions are now explicit opt-in per reviewer contract. Plain upgrade/dry-run and projection uninstall preserve team.md byte-for-byte, health reports unselected Rai/Fact Checker as INFO, and squad roster provides diff preview, verified backup, idempotence, provenance-only removal, and exact LF/CRLF restore.

Validation: build + TypeScript lint pass; mandated focused suites 58/58; upgrade suites 139 pass / 1 platform skip; health/doctor/init/template suites 726 pass after isolated timeout rerun; CI policy gates pass; release mode fails closed on 9 pending changesets as expected; 21 release scripts clean. Local Windows Upgrade Matrix for 0.13.1 default + ai-team passed 2/2, including user-state-preserved and projection-uninstall-byte-exact in both rows.

@tamirdresher

Copy link
Copy Markdown
Collaborator Author

Final CI update:

  • Squad CI 40089219878: ✅
  • Upgrade Matrix 40089168150: ✅ Ubuntu + Windows
  • Release Verify 40089168164: product build/lint/full Vitest/node:test steps passed, then reconciliation failed on one pre-existing unclassified Linux skip: test/mcp-root-write.test.ts Windows uppercase-drive case. That test came from base de1c4e66; this branch has no diff in the test or reconciliation policy. Per scope, I did not touch the bridge area.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants