Commit Graph
11 Commits
Author SHA1 Message Date
Vitor PamplonaandClaude Opus 5 8dcc78056d refactor(buzz): move the Backlog and Workflow boards into the channel overflow
The two new boards were added as top-bar icons, which put a Buzz channel back to
four (Canvas, Backlog, Workflow runs, ⋮) and truncated the title row the bar is
there to show — "nosfabrica.commun…" instead of the full relay. That is the
crowding #3729 had just removed; this branch predates it and the merge stacked
them.

Canvas keeps the only icon: it is the channel's shared document, i.e. content.
Backlog and Workflow runs are two more views of the channel, reached
occasionally, so they join Threads and Share in the overflow — and pick up the
`!isDm` gate the icons never had.

Also gives the job board a string resource; the branch's i18n pass left
"Backlog" hardcoded in JobBoardScreen and in the icon's contentDescription.

Adds cli/tests/buzz/agent-exec.sh, which covers what the two loop harnesses
stub out. job-loop.sh proves the scheduler drives *an* --exec program; nothing
committed exercised the real one — the wrapper that turns a job into a PR. With
a stubbed `gh` and agent (no network, credentials, or Claude Code) it asserts
the happy path end to end (task on stdin → agent → commit → push the job branch
→ PR url on stdout) and, as importantly, the paths that must fail: an agent that
changed nothing becomes a job error, an empty task is rejected before the agent
runs, missing scheduler env is a hard error rather than a silent no-op, an agent
that committed for itself is not double-committed, and the default-branch guard
holds — asserting `main` on the remote is left untouched. 19/19.

Verified on emulator-5554: the bar is Canvas + ⋮ again with the full relay name
visible, the menu reads Threads / Backlog / Workflow runs / Share / Members /
Leave, and Backlog still opens from it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 23:37:22 -04:00
Claude 5d32cc8396 feat(cli): drive Buzz workflows from amy (trigger, run, approve/deny)
Switch the agent-support-channel prototype from the speculative agent-job
kinds (43001-43006, reserved with no upstream builder) to Buzz's real,
source-confirmed workflow primitive: 30620 def / 46020 trigger / 46001-46007
lifecycle / 46010 approval gate / 46030-46031 grant-deny (pinned against
buzz-relay's command_executor.rs). This bakes the human-approval gate into
the protocol — anyone in the channel can drive a run, but a human grants
before anything is pushed.

- commons WorkflowRunAggregator folds trigger + lifecycle + grant/deny into
  per-run state (TRIGGERED/RUNNING/AWAITING_APPROVAL/APPROVED/COMPLETED/
  FAILED/DENIED), correlating by run id (= trigger event id = approval token);
  8-case test.
- cli `amy buzz workflow` — trigger/list/show/approve/deny plus the `run`
  runner: per new trigger it does the agent work in a fresh worktree+branch,
  posts the 46010 gate, and on a later poll runs --on-approve (push + PR) and
  emits 46005 completed; a deny discards the worktree (run is DENIED).

On a real Buzz relay the relay executes the workflow YAML; self-hosted on
geode there is no engine, so amy is the runner and emits the lifecycle events
itself (documented divergence). Two store realities, both verified against
geode: decisions are fetched by author (quartz's store serves #d only for
addressable kinds, and 46030/46031 are regular), and the runner is
restart-safe (runs at the gate are rebuilt from the deterministic run id).

Also hardens the exec helper against a broken pipe when --exec doesn't read
stdin, and fixes worktree teardown to run git against the owning repo.

End-to-end headless harness (cli/tests/buzz/workflow-loop.sh) covers the
grant and deny paths through an embedded geode relay: 14/14 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011mApqAbr8vkLC7gUDjavu6
2026-07-26 16:50:54 +00:00
Claude 635e785753 feat(cli): buzz agent-job loop — file/track jobs + a driving responder
Prototype the "human drives an AI coding agent to develop Amethyst" support
channel on top of the existing block/buzz integration, all through amy.

- commons: BuzzJobAggregator (BuzzJobs.kt) — a pure, tested folder that
  correlates the Buzz agent-job kinds (43001-43006) by their `e` request
  reference into JobView records with a REQUESTED→ACCEPTED→IN_PROGRESS→
  COMPLETED/FAILED/CANCELLED state machine (newest terminal wins). Shared so a
  future mobile Jobs board reuses one correlation path. 9 unit tests.
- cli: `amy buzz job request|list|show|cancel` (requester side) and
  `amy buzz agent serve --exec CMD` (the responder loop): polls for REQUESTED
  jobs targeting my key, gates intake on `--accept-from` (allowlist) and
  `--channel`, then accepts (43002) → progress (43003) → runs `sh -c CMD`
  (task text on stdin; BUZZ_JOB_ID/REQUESTER/CHANNEL/RELAY/AGENT in env) →
  result (43004) or error (43006). Point `--exec` at a coding agent to drive it.
- cli/tests/buzz/job-loop.sh — self-contained headless harness over an embedded
  `amy serve` relay; asserts the full loop AND the permission gate (an allowlist
  excluding the requester handles nothing).
- Design doc cli/plans/2026-07-25-buzz-agent-support-channel.md: the three-layer
  permission model (Buzz scopes by identity, not capability flags — so
  "can't merge/destroy main" lives in GitHub branch protection + the `--exec`
  credential, not the relay), the MVP architecture, and the prioritized mobile
  app gap list (approvals inbox, jobs board, diff/PR review, …).

Schema caveat: kinds 43001-43006 are reserved in Buzz with no upstream builder;
the tag layout is Quartz's best-effort model, to be reconciled upstream.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011mApqAbr8vkLC7gUDjavu6
2026-07-25 17:18:30 +00:00
Claude ad66e6c224 feat(cli): full NIP-34 git collaboration parity for amy git
Extend `amy git` from repo announce/list/show/issue to the complete
pure-Nostr surface of `ngit` and `nak git`, so every NIP-34 collaboration
flow is scriptable without a GUI.

New sub-verbs (all thin assembly over quartz's `nip34Git` builders):

- `git state`   — kind:30618 repository state (branch/tag tips + HEAD)
- `git patch`   — kind:1617 patch from `git format-patch` (--file or stdin),
                  with --root/--root-revision, --commit, --parent-commit,
                  and --in-reply-to for revision chains
- `git pr` / `git pr-update` — kind:1618 pull request + kind:1619 tip update
- `git comment` — NIP-22 kind:1111 reply on an issue/patch/PR/repo (the
                  modern replacement for the deprecated kind:1622 git reply)
- `git open|applied|close|draft` — kind:1630/1631/1632/1633 status events
                  (aliases `merged`/`resolved` for applied); applied carries
                  --merge-commit / --commit / --patch
- `git issues|patches|prs` — list a repo's items with status derived from the
                  newest authoritative (owner/maintainer/author) status event,
                  with --open/--applied/--closed/--draft/--status filters
- `git thread`  — one item plus its status timeline and comments

Shared parsing/fetch/routing glue lives in `GitSupport`; the existing
announce/list/show/issue verbs now reuse it. The git *packfile* transport
(clone/fetch/push of real objects to clone/GRASP servers) stays out of
scope — it needs a git plumbing layer, not an event builder — and is
documented as such.

Adds `cli/tests/git/git-nip34-headless.sh` (21 assertions, drives the whole
flow against `amy serve` and checks the status-deriving reads) and updates
the README/ROADMAP command tables.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UKMaNoK5M2PQKCAxhxWzPr
2026-07-21 03:37:57 +00:00
Claude e87309e038 test(blossom): live interop smoke test for amy blossom (BUD-01/02/04/09)
Adds cli/tests/blossom/blossom-live.sh, an end-to-end harness that drives the
full amy blossom lifecycle against a REAL public Blossom server: upload → HEAD
check → download-and-verify-hash → list → cross-server mirror → delete. Verified
green (6/6) against files.sovbit.host with a mirror to blossom.primal.net, which
exercises the whole quartz/commons/CLI Blossom stack over the wire.

Server-side write rejections (whitelists, rate limits, payment) record as SKIP,
not FAIL — only a broken client contract (bad descriptor, hash mismatch,
unparseable list) fails — since public servers gate anonymous writes very
differently. Documented in cli/tests/README.md; state dir gitignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ckbnz1N94W1hnNC9xpsCNP
2026-07-18 02:16:17 +00:00
Claude 2eb7ff2ef2 Merge remote-tracking branch 'origin/main' into claude/armada-nip29-integration-lwqard
# Conflicts:
#	cli/tests/.gitignore
2026-07-09 21:48:04 +00:00
Claude c011dfca6e test(cli): headless end-to-end for deletion sync (real amy vs amy serve)
Drives the built `amy` binary against a real `amy serve` relay to prove NIP-77
deletion propagation end-to-end — the running answer to "does it actually work",
on top of the in-process geode tests:

  T1 (up)   we deleted a note the relay still has → `amy sync` sends our kind-5
            up and the relay drops it (checked by an isolated third account that
            reads the relay only, so no local tombstone masks the result).
  T2 (off)  `--no-sync-deletions` sends nothing and the relay keeps the note.
  T3 (down) the relay deleted a note we still hold → `amy sync --up` pulls the
            relay's kind-5 down and applies it locally; a second sync converges.

Each amy account gets its own $HOME (accounts under one $HOME share the file
store). Follows the cli/tests/*-headless.sh pattern; state dir gitignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgL1WTV4Hkp2uuXcUHCHGt
2026-07-08 15:09:57 +00:00
Claude d85bac1f55 feat(cli): amy relaygroup — NIP-29 relay groups in the CLI
Adds a first-class `amy relaygroup` verb group so the CLI can drive the
same NIP-29 relay groups as the app. Thin assembly over quartz builders +
Context.publish/drain — no protocol logic in cli/.

Verbs:
- list / browse RELAY / info RELAY GID — reads (joined kind:10009 list with
  private-item decryption; a relay's 39000-39003 directory; one group's
  metadata + roster).
- create / join / leave / message — lifecycle. join/leave also maintain the
  caller's kind:10009 list (add/remove private item) so `list` reflects them,
  mirroring the app's follow/unfollow.
- edit / invite / put-user / remove-user — moderation (9002/9009/9000/9001).

All writes pin to the group's single host relay. Output follows amy's
text/--json contract with snake_case keys.

Verified end-to-end against an embedded relay (amy serve) with a new
self-contained harness, cli/tests/relaygroup/relaygroup-headless.sh:
create/message/join/list/browse all pass (5/5). browse/info return empty
against geode since it doesn't sign 39000-39003 — a relay capability, not a
client issue. README command table + ROADMAP updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B5MLY4hq5LXJ2D5WeLRyXj
2026-07-08 01:41:15 +00:00
Claude 545018a6a3 test(cli): clink-headless harness for amy offer/debit info
Local-only shell suite (no relay): asserts amy decodes the canonical CLINK
interop vectors (same fixtures as quartz ClinkInteropTest) to the right fields
for 'offer info' and 'debit info', plus the argument-error paths (bad pointer,
unknown budget frequency, missing --amount). The round-trip verbs need a live
service and stay out of scope.

12/12 assertions pass locally (amy init -> decode, no network).
2026-06-10 07:01:43 +00:00
Claude 88c158433c test(nests): add manual interop harness against nostrnests.com
Adds cli/tests/nests/nests-interop.sh — a 47-test operator-driven
interop script that walks a tester through every audio-room edge case
between Amethyst Android and the nostrnests.com NestsUI-v2 web client.

Coverage: bidirectional host/listener flows, audio round-trip on
moq-lite Lite-03, hand-raise + role promotion/demotion, mute, kind:7
reactions (including NIP-30 custom emoji + 30 s overlay clear), kind:1311
in-room chat (text + emoji + link + image upload + history backfill),
kind:4312 kick, room edit + close, scheduled rooms (status=planned),
multi-speaker, background audio + PIP, network drop reconnect, 10-min
JWT refresh, custom moq servers (kind:10112), naddr deep links, and
edge cases (long titles, empty rooms, leave-stage, dedupe, race).

The script follows the marmot/marmot-interop.sh pattern: shared
logging + result helpers, color-coded prompts (yellow=Amethyst,
magenta=web, cyan=optional 3rd identity), p/f/s confirms recorded to a
TSV, and a final summary table. Skip / only / keep-state flags are
supported for iteration.

Pure manual harness — amy does not yet ship `amy nests <verb>` so
nothing is automatable from the CLI side.
2026-04-28 07:52:57 +00:00
Claude b0698e0a66 test(cli): move tests/ out of tools/, separate marmot vs dm
`tools/` is for libraries (arti-build); shell-based interop harnesses
that drive the `amy` binary belong with the CLI module. New layout:

  cli/tests/
  ├── lib.sh                       # shared logging + result tracking
  ├── headless/helpers.sh          # shared amy_a / amy_json / assertions
  ├── marmot/                      # MLS group-messaging interop (vs whitenoise-rs)
  │   ├── marmot-interop.sh
  │   ├── marmot-interop-headless.sh
  │   ├── setup.sh
  │   ├── tests-create.sh
  │   ├── tests-manage.sh
  │   ├── tests-extras.sh
  │   └── patches/
  └── dm/                          # NIP-17 DM interop (amy ↔ amy)
      ├── dm-interop-headless.sh
      ├── setup.sh
      └── tests-dm.sh

Per-suite changes:
- Each suite owns its own setup.sh; previously the Marmot setup was at
  headless/setup.sh and the DM setup at headless/setup-dm.sh, which
  implied shared infra they don't actually share.
- `cli/tests/lib.sh` and `cli/tests/headless/helpers.sh` are the only
  shared bits across suites.
- The DM harness still reuses Marmot's `start_local_relay` /
  `stop_local_relay` (sourced via `../marmot/setup.sh`) — same relay
  binary, no duplication.
- All sourcing paths updated; REPO_ROOT now climbs three levels (was
  two when the harness lived under `tools/`); patches/ is now a sibling
  of marmot/setup.sh rather than under marmot/headless/.
- `.gitignore` updated to cover both suites' state dirs.

cli/ROADMAP.md and cli/tests/README.md updated to point at the new paths.
No behavioural change — every test runs the same code; only the file
layout and source paths moved.
2026-04-23 20:37:22 +00:00