feat: add fullsend CLI with install command (PoC for Story 1) - #132
Closed
ralphbean wants to merge 36 commits into
Closed
feat: add fullsend CLI with install command (PoC for Story 1)#132ralphbean wants to merge 36 commits into
ralphbean wants to merge 36 commits into
Conversation
Implement a Go CLI tool using Cobra that demonstrates the installation and bootstrap workflow described in issue #124. The CLI uses charmbracelet/lipgloss for styled terminal output. What's included: - `fullsend install <org>` command with --repo, --agents, --dry-run flags - GitHub App configuration with minimum required permissions - .fullsend config repo creation with safe defaults (auto_merge: false) - Enrollment PR generation for enabled repositories - Reusable GitHub Actions workflow generation - CODEOWNERS file generation - Comprehensive unit tests (46 tests, 92-100% coverage) - golangci-lint configuration and CI integration - Go build/test/lint/vet/fmt targets in Makefile The install command uses a fake GitHub client for the PoC to demonstrate the full workflow without requiring real API credentials. The Client interface is designed for easy replacement with a real implementation. Note: The .github/workflows/lint.yml update (adding Go CI job) requires the workflow scope and should be applied separately by a maintainer. Resolves #124 Assisted-by: OpenCode claude-opus-4-6@default
The end-of-file-fixer pre-commit hook requires exactly one trailing newline. The previous version had two. Assisted-by: OpenCode claude-opus-4-6@default
No code uses Go 1.26-specific features. All dependencies require Go 1.18 or lower, so lowering the minimum version is safe. Assisted-by: OpenCode claude-opus-4-6@default
Replace the simulated install flow with a real GitHub API client that creates repos, files, branches, and PRs via the REST API. Address all findings from code review. Changes: - Add LiveClient implementing Client interface with real HTTP calls - Authenticate via GITHUB_TOKEN environment variable (removed --token flag) - Add security hardening: io.LimitReader (10MB cap), pagination limit (100 pages), URL path escaping on all user inputs, dedicated http.Client with 30s timeout, GitHub Actions env vars instead of inline interpolation to prevent script injection - Use discovered DefaultBranch for PR base (not hardcoded 'main') - Default .fullsend repo to private - Validate org name format and --repo values against discovered repos - Fix DefaultAgents slice aliasing (now returns fresh copy) - Sort validation error messages for determinism - Validate per-repo agent lists in config - Unexport ui style variables (internal use only) - Remove all PoC/demo language from code and help text - Be honest about GitHub App creation (manual step, not automated) - Add comprehensive tests: httptest-based client tests, org name validation, default branch handling, config validation, repo warnings Note: .github/workflows/lint.yml update (adding Go CI job) requires the workflow scope and should be applied separately by a maintainer. Assisted-by: OpenCode claude-opus-4-6@default
Add token resolution chain: GH_TOKEN > GITHUB_TOKEN > gh auth token. If the user has already authenticated with the gh CLI, fullsend picks up their stored credentials automatically — no env var needed. Assisted-by: OpenCode claude-opus-4-6@default
…e/github Extract forge-neutral interface (Client, Repository, ChangeProposal) into internal/forge/ and move the GitHub-specific implementation to internal/forge/github/. This is a pure structural refactor with no behavior changes, preparing the codebase for multi-forge support (GitLab, Forgejo). Key renames: - PullRequest -> ChangeProposal (with URL instead of HTMLURL) - CreatePullRequest -> CreateChangeProposal - Result.PRs -> Result.Proposals - FakeClient moved to forge package with neutral test URLs Assisted-by: OpenCode claude-opus-4-6@default
Add interactive GitHub App setup using the manifest flow API:
1. fullsend starts a local HTTP server on a random port
2. Opens the user's browser to a form page that auto-submits the
app manifest to GitHub with the correct permissions
3. GitHub shows the app creation form; user clicks 'Create GitHub App'
4. GitHub redirects back to the local server with a temporary code
5. fullsend exchanges the code for app credentials (ID, PEM key,
client secret, webhook secret) via POST /app-manifests/{code}/conversions
6. Prompts user to install the app on their org, opens the install page
7. Verifies the installation exists via the org installations API
The flow is fully interactive with Enter-to-proceed prompts at each
step. The user never has to manually configure permissions or copy
URLs.
New package: internal/appsetup/ with Prompter and BrowserOpener
interfaces for testability. Includes --skip-app-setup flag for
re-running install when the app already exists.
Assisted-by: OpenCode claude-opus-4-6@default
GitHub requires hook_attributes.url in the manifest even when webhooks aren't actively used. Set active: false to disable delivery. Assisted-by: OpenCode claude-opus-4-6@default
- Clarify prompt text: tell user what's about to happen before they
press Enter, not after
- Fix installation URL: use /apps/{slug}/installations/new without
the broken target_id=0 query parameter
- Print confirmation after browser opens for both creation and
installation steps
- Add guidance text: 'Name the app and click Create GitHub App'
Assisted-by: OpenCode claude-opus-4-6@default
The user can rename the GitHub App during creation. The manifest code exchange API returns the actual name and slug they chose. Thread these through the entire install flow: - Add AppIdentity (name + slug) to OrgConfig, written to config.yaml - Add AppName/AppSlug to install.Options so CLI can pass them through - configureApp uses the real name instead of always defaulting to 'fullsend-<org>' - generateConfig writes the app identity into the org config - Falls back to 'fullsend-<org>' when --skip-app-setup is used Assisted-by: OpenCode claude-opus-4-6@default
fmt.Scanln on a [1]byte returns immediately on empty input with an
'unexpected newline' error. In some terminal environments, stdin may
have buffered newlines that cause the prompt to not actually block.
Switch to bufio.NewReader(os.Stdin).ReadString('\n') which reliably
waits for a complete line before returning.
Assisted-by: OpenCode claude-opus-4-6@default
Before walking the user through app creation, check if a fullsend app is already installed on the organization. If found, ask whether to reuse it (Y/n prompt). Similarly for installation: if the app is already installed with access to all repos, skip the installation step entirely. If installed with selected repos, offer to update. Changes: - Add Confirm(prompt) method to Prompter interface for Y/n prompts - Add findExistingApp: scans org installations for apps with 'fullsend' prefix - Replace verifyInstallation with getInstallation returning full installationInfo (includes repository_selection: all vs selected) - Split Run into resolveApp + ensureInstalled for clearer flow - Add StdinPrompter.Confirm with default-yes behavior (Enter = yes) Assisted-by: OpenCode claude-opus-4-6@default
…tection Two fixes: 1. Check if .fullsend repo already exists before attempting to create it. The discoverRepos step already iterates all org repos, so it now returns a ConfigRepoExists flag. If true, the creation step is skipped with a log message. 2. Replace fake PEM key string in appsetup_test.go with a non-PEM placeholder. The detect-private-key pre-commit hook was flagging the test's '-----BEGIN RSA PRIVATE KEY-----' string, causing CI to fail on every push. Assisted-by: OpenCode claude-opus-4-6@default
Add `fullsend uninstall <org>` which reverses the install process: 1. Prompts the user to type the org name to confirm (skip with --yolo) 2. Reads .fullsend/config.yaml to find the app slug (source of truth) 3. Deletes the .fullsend configuration repository 4. Removes the GitHub App installation from the organization 5. Opens the browser to the app settings page for the user to delete the app registration (cannot be done via PAT, requires browser) If config.yaml can't be read (e.g., repo already deleted), falls back to scanning org installations for apps with a 'fullsend' prefix. Each step is resilient — if one fails, the others still proceed, with clear messages about what needs manual cleanup. New interface methods on forge.Client: - GetFileContent: reads a file from a repository - DeleteRepo: deletes a repository Assisted-by: OpenCode claude-opus-4-6@default
Three fixes for the uninstall command:
1. App settings URL was wrong — used /settings/apps/{slug} (user-scoped,
404 for org apps). Fixed to /organizations/{org}/settings/apps/{slug}/advanced
which is the correct org-scoped URL with the delete button visible.
2. Repo deletion now checks token scopes first. Makes a HEAD request to
/user and reads the X-OAuth-Scopes header. If delete_repo scope is
missing, skips the API call entirely and walks the user through
deleting the repo in their browser (opens the repo settings page).
If the scope exists, tries the API first and falls back to browser
on failure.
3. App uninstallation now always uses the browser flow. The API endpoint
(DELETE /app/installations/{id}) requires JWT auth from the app's
private key, which we don't have. Opens the org installation settings
page directly with the installation ID so the user sees the right
Uninstall button.
All three destructive steps (repo delete, app uninstall, app registration
delete) follow the same Enter-prompt-then-open-browser pattern used by
the install command.
Assisted-by: OpenCode claude-opus-4-6@default
If the .fullsend/config.yaml can't be read (repo doesn't exist or config is missing), abort immediately with a clear error message and links to the org's installations and apps settings pages for manual cleanup. This moves the config read before the confirmation prompt so the user isn't asked to confirm something that can't proceed. The confirmation prompt now also shows the specific app name that will be deleted (from the config), not just the org name. Assisted-by: OpenCode claude-opus-4-6@default
Refactor from a single GitHub App to one app per agent role, each with
least-privilege permissions:
triage: issues read/write — labels, assigns, triages issues
coder: contents write, PRs write, checks read — pushes code, creates PRs
review: PRs write, contents read, checks read — reviews code, no push
Config changes:
- Replace singular `app: {name, slug}` with `agents:` list of
`{role, name, slug}` entries in config.yaml
- Rename `defaults.agents` to `defaults.roles` and
`repos[].agents` to `repos[].roles` for clarity
- Default roles: triage, coder, review (was triage, implementation, review)
- Add AgentSlugs() and ValidRoles() helpers
- NewOrgConfig now takes []AgentEntry instead of single app name/slug
Install changes:
- CLI loops through each role, calling appsetup.Run(ctx, org, role)
for each to create and install a separate GitHub App
- --agents flag selects which roles to set up (default: all three)
- Each agent's PEM key gets its own secret name:
FULLSEND_TRIAGE_APP_PRIVATE_KEY, FULLSEND_CODER_APP_PRIVATE_KEY, etc.
Appsetup changes:
- Run() accepts a role parameter and creates role-specific app
- AgentAppConfig(org, role) replaces DefaultAppConfig(org)
- findExistingApp() uses exact slug match per role instead of prefix
- UI messages include the role name throughout
Uninstall changes:
- Reads agents list from config.yaml instead of singular app slug
- Loops over each agent for uninstall and delete steps
- Summary lists each agent separately
Assisted-by: OpenCode claude-opus-4-6@default
The coder agent subscribes to issues and issue_comment events (to know which issue to implement) but was missing the issues permission. GitHub's manifest validation requires that event subscriptions are backed by matching permissions. Added issues: read to the coder's permissions. It needs to read issues to understand what to implement, but doesn't need write access (the triage agent handles issue updates). Assisted-by: OpenCode claude-opus-4-6@default
After creating a repo with auto_init: true, GitHub may not have finished initializing the default branch when we immediately try to create files via the Contents API. This causes 'config.yaml' creation to fail. Add retry with linear backoff (1s, 2s, 3s, 4s) for the first file created in a new repo. Subsequent files don't need retries because if the first succeeds, the branch is confirmed ready. Also includes the actual API error in the failure message so users can see what went wrong. Assisted-by: OpenCode claude-opus-4-6@default
Split repo creation from file writing so that config.yaml, the reusable workflow, and CODEOWNERS are written regardless of whether the repo was just created or already existed. If a file already exists (GitHub returns 422 'already exists'), it is skipped with a log message. This makes the install command idempotent — running it twice produces the same result without errors. The retry-with-backoff for new repo initialization is preserved but only applied when the repo was freshly created. Assisted-by: OpenCode claude-opus-4-6@default
The GitHub Contents API creates a new commit per file. When creating multiple files sequentially, the branch HEAD moves after each commit. Subsequent CreateFile calls can hit 404/409 because the branch ref is still being updated. Add retry with backoff (2s, 4s) for all file creates, not just the first one. The first file on a new repo still gets 5 attempts to handle branch initialization delay. Files that already exist (422) are detected and skipped without retrying. Assisted-by: OpenCode claude-opus-4-6@default
When the .fullsend repo exists but files were already created (from a previous run), the Contents API returns 422 'sha wasn't supplied' because updating an existing file requires the current SHA. Add CreateOrUpdateFile to the forge.Client interface. The GitHub implementation first GETs the file to retrieve its SHA (if it exists), then PUTs with the SHA included for updates. If the file doesn't exist (GET returns 404), it creates without a SHA. This makes install fully idempotent — re-running updates config.yaml with the latest agent entries and settings rather than failing. Assisted-by: OpenCode claude-opus-4-6@default
The GitHub Contents API creates a new commit per file. Sequential writes can hit transient 404s as the branch ref updates between commits. This is especially common for nested paths like .github/workflows/agent.yaml. Split file writes into required (config.yaml) and supplementary (workflow, CODEOWNERS). Config.yaml failures are still fatal. Workflow and CODEOWNERS failures are logged as warnings with guidance to add them manually, allowing install to complete successfully. Extracted writeFileWithRetry helper for cleaner retry logic. Assisted-by: OpenCode claude-opus-4-6@default
The GitHub Contents API returns 404 (not 403) when writing to .github/workflows/ without the 'workflow' token scope. The gh CLI does not request this scope by default, so users hit an opaque 404. Changes: - Make .github/workflows/agent.yaml a required file (was best-effort) - Detect 404 on workflow file and show clear error with fix command: 'gh auth refresh -s workflow' - Keep CODEOWNERS as optional (best-effort) Assisted-by: OpenCode claude-opus-4-6@default
Add GetAuthenticatedUser to forge.Client interface. The install flow calls GET /user to retrieve the logged-in user's login and uses it as the CODEOWNERS owner instead of the generic @org/admin team. Falls back to @org/admin if the user lookup fails. Assisted-by: OpenCode claude-opus-4-6@default
If any repo in the org is private, create .fullsend as private. If all repos are public, create .fullsend as public. The user is informed of the choice and the reason in the CLI output. Previously .fullsend was always created as private. Assisted-by: OpenCode claude-opus-4-6@default
Automate the 'Next steps' that previously required manual secret
creation. After writing config files, the install command now stores
each agent's PEM private key as a GitHub Actions secret on the
.fullsend repo.
Implementation:
- Add CreateRepoSecret to forge.Client interface
- GitHub implementation fetches the repo's public key, encrypts the
value with libsodium sealed box (x/crypto/nacl/box.SealAnonymous),
and PUTs to the Actions secrets API
- Secret names follow FULLSEND_{ROLE}_APP_PRIVATE_KEY convention
- AgentCredentials struct carries the PEM alongside the config entry
- Summary box now lists stored secrets instead of manual instructions
Assisted-by: OpenCode claude-opus-4-6@default
When reusing existing apps (user chose 'yes' to reuse), the PEM key is not available — it's only returned during app creation via the manifest code exchange. The install command was printing 'Secret stored' in the summary even when no secrets were actually stored. Fix: - storeAgentSecrets returns the count of secrets actually stored - Summary only shows 'Secrets stored: N' when N > 0 - When PEM keys are empty (reuse flow), prints a clear explanation: 'Agent apps were reused — PEM keys are only available at creation time. Secrets were not updated.' Assisted-by: OpenCode claude-opus-4-6@default
When an existing fullsend app is found during install, check whether
its PEM private key is stored as a repo secret in .fullsend. If the
secret doesn't exist, the app is useless — the PEM is only available
at creation time and can't be retrieved later.
When the secret is missing:
- Explain that the PEM key is lost
- Walk the user through deleting the app in the browser
- Then create a fresh app (which produces a new PEM that gets stored)
When the secret exists:
- Offer to reuse the app as before
Implementation:
- Add RepoSecretExists to forge.Client interface (GET /actions/secrets/{name})
- Add SecretExistsFunc + WithSecretCheck option to appsetup.Setup
- CLI wires it up: checks FULLSEND_{ROLE}_APP_PRIVATE_KEY existence
Assisted-by: OpenCode claude-opus-4-6@default
Add a fourth agent role 'fullsend' that handles maintenance and bootstrapping operations — managing the .fullsend config repo, workflows, and repo settings. Permissions (broader than other agents by design): - contents: write (manage config files and workflows) - issues: read (receive dispatch commands) - pull_requests: write (create config change PRs) - checks: read (monitor workflow status) - administration: write (manage repo settings) - members: read (discover org members) Events: issues, push, workflow_dispatch The fullsend agent is created first during install, before triage, coder, and review. Default roles are now: fullsend, triage, coder, review. Assisted-by: OpenCode claude-opus-4-6@default
Replace direct enrollment PR creation with a cascading onboarding model driven by a GitHub Actions workflow in the .fullsend repo. How it works: 1. Install writes repo-onboard.yaml to .fullsend/.github/workflows/ 2. This workflow triggers on push to main (when config.yaml changes) or on workflow_dispatch 3. It reads config.yaml, iterates enabled repos, checks if each has .github/workflows/fullsend.yaml, and creates PRs to add it 4. The install command watches the onboarding workflow run and reports the enrollment PRs back to the user New components: - generateOnboardingWorkflow(): produces the repo-onboard.yaml workflow that uses the fullsend maintenance app token to create branches and PRs across org repos - watchOnboarding(): polls the Actions API for the workflow run, waits for completion, then scans enabled repos for fullsend PRs - `fullsend repo onboard <repository>`: manual single-repo onboarding command for when you want to onboard one repo without waiting for the workflow Forge interface additions: - GetLatestWorkflowRun: fetch most recent run of a workflow file - GetWorkflowRun: fetch a specific run by ID - ListRepoPullRequests: list open PRs in a repo The old createEnrollmentPRs/enrollRepo methods are removed — the onboarding workflow handles this now. Assisted-by: OpenCode claude-opus-4-6@default
When config.yaml already exists in .fullsend, the install command now: 1. Fetches the existing config.yaml from the repo 2. Compares it to the new version that would be written 3. If unchanged, skips with a log message 4. If changed, displays a colorized unified diff: - Green (+) for added lines - Red (-) for removed lines - Gray for context lines 5. Asks the user: 'Overwrite config.yaml with the new version? [Y/n]' 6. If yes: overwrites the file 7. If no: writes the new version as config.yaml.new so the user can review and rename manually This fixes the issue where a second install run would skip config.yaml entirely (because the file already existed) without writing the new agent entries from the current session. Assisted-by: OpenCode claude-opus-4-6@default
The findExistingApp function always looked for slug pattern
'fullsend-{org}-{role}', but the fullsend maintenance agent's app
is named 'fullsend-{org}' (no '-fullsend' suffix), as defined in
AgentAppConfig.
Extract expectedAppSlug() helper that matches the naming convention
from AgentAppConfig — returns 'fullsend-{org}' for the fullsend role
and 'fullsend-{org}-{role}' for all others.
Assisted-by: OpenCode claude-opus-4-6@default
App detection during re-runs was using a hardcoded naming convention (expectedAppSlug) to guess what slug to look for in the org's installations. This breaks when the user renames an app during creation, since the actual slug wouldn't match the convention. Fix: before the app setup loop, read the existing config.yaml from the .fullsend repo (if it exists) and extract the slug for each role. Pass these known slugs to appsetup via WithKnownSlugs(). The findExistingApp method now checks the config slug first, falling back to the naming convention only if no config entry exists for that role. This makes detection reliable regardless of whether apps were renamed. Assisted-by: OpenCode claude-opus-4-6@default
The repo onboarding workflow uses actions/create-github-app-token@v1
which requires the app ID as input. The app ID is not sensitive (it's
a public integer) so it's stored as a repo Actions variable, not a
secret.
Changes:
- Add CreateOrUpdateRepoVariable to forge.Client interface
- GitHub implementation tries PATCH first (update), falls back to
POST (create) on 404
- storeAgentSecrets now also stores FULLSEND_{ROLE}_APP_ID as a
variable alongside the PEM secret
- Add AppID field to AgentCredentials, passed from appsetup
- Fix workflow template: FULLSEND_APP_ID → FULLSEND_FULLSEND_APP_ID
to match the naming convention (role is 'fullsend')
Assisted-by: OpenCode claude-opus-4-6@default
Two fixes for the workflow watcher: 1. Skip watching entirely if no config files were actually written (nothing changed, so no workflow will trigger) 2. Only match workflow runs created AFTER our file writes started. Records a timestamp before writing config files and compares it to each run's created_at. This prevents matching stale runs from previous installs. The watcher now has two phases: - Phase 1 (15s timeout): Wait for a new run to appear. If none starts, warn the user with troubleshooting tips and a manual trigger URL. - Phase 2 (120s timeout): Poll the run until it completes, then collect enrollment PRs. Assisted-by: OpenCode claude-opus-4-6@default
ralphbean
added a commit
that referenced
this pull request
Apr 2, 2026
Documents non-obvious GitHub API behaviors discovered during the original implementation: - auto_init is async; file writes after repo creation need retry - Contents API requires existing file SHA for updates (422 otherwise) - Sequential file writes cause transient 404s as branch refs update - Writing to .github/workflows/ returns 404 (not 403) without workflow scope - App PEM private keys are one-shot; only available at creation time - Event subscriptions must have matching permissions or manifest is rejected - App installation URL must not include target_id parameter - Org-scoped app settings need /advanced suffix in URL - App uninstall API requires JWT auth, not PAT (browser fallback needed) - Users can rename apps during creation; match by stored slug first - Token scopes (delete_repo, workflow) are often missing from default gh auth Assisted-by: OpenCode claude-opus-4-6@default
Member
Author
|
Closing this in favor of #142 |
ralphbean
added a commit
that referenced
this pull request
Apr 3, 2026
Documents non-obvious GitHub API behaviors discovered during the original implementation: - auto_init is async; file writes after repo creation need retry - Contents API requires existing file SHA for updates (422 otherwise) - Sequential file writes cause transient 404s as branch refs update - Writing to .github/workflows/ returns 404 (not 403) without workflow scope - App PEM private keys are one-shot; only available at creation time - Event subscriptions must have matching permissions or manifest is rejected - App installation URL must not include target_id parameter - Org-scoped app settings need /advanced suffix in URL - App uninstall API requires JWT auth, not PAT (browser fallback needed) - Users can rename apps during creation; match by stored slug first - Token scopes (delete_repo, workflow) are often missing from default gh auth Assisted-by: OpenCode claude-opus-4-6@default
waynesun09
added a commit
that referenced
this pull request
Apr 12, 2026
Seven specialized agents for working on the fullsend project: - fullsend-architect (opus): architectural coherence guardian; knows all ADRs, five execution layers, story dependencies, repo-as-coordinator invariant - go-developer (sonnet): CLI specialist; forge abstraction, layered config, multi-role GitHub App model, known gaps in PR #132 - doc-architect (sonnet): problem doc and ADR writer; design-exploration conventions, org-agnostic authoring rules - stage-prompt-designer (opus): designs/reviews stage agent prompts; triage/implement/review/fix constraints, injection surface rules, known failure modes from live operation (Issues #4, #5, #010a) - security-reviewer (opus): applies fullsend threat model; prompt injection, ADR 0017 credential isolation, sandbox integrity, workflow file protection - workflow-engineer (sonnet): GitHub Actions and dispatch layer; label state machine, slash commands, concurrency groups, fixes for Issues #1 #003b #4 #5 #7 #9 #010a - e2e-integrator (opus): full flow tracing; integration gap analysis, demo readiness checklist, sprint prioritization across stories Also adds .claude/AGENTS.md with usage guide and team composition patterns.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements a Go CLI tool (
fullsend) that demonstrates the installation and bootstrap workflow described in #124. This is a PoC using a fake GitHub client — theClientinterface is designed for easy replacement with a real implementation.What's included
fullsend install <org>command with--repo,--agents, and--dry-runflags.fullsendconfig repo creation with safe defaults (auto_merge: false, all repos disabled)Testing & CI
go-build,go-test,go-lint,go-fmt,go-vet,go-tidy.github/workflows/lint.ymlupdate (adding a Go CI job) requires theworkflowscope and should be applied separately by a maintainer. The updated file is included in the PR description below.Architecture
Built with Cobra (CLI framework) and charmbracelet/lipgloss (styled output). Uses standard Go project layout:
Demo output
CI workflow update needed
The
.github/workflows/lint.ymlneeds a Go CI job added. Here's the updated workflow that should be committed by a maintainer withworkflowscope:Story 2 considerations (#125)
The CLI structure is designed with Story 2 in mind — the
fullsend entrypointsubcommand and related sub-commands (provider,sandbox,harness,runtime) from the issue comments are natural additions to the Cobra command tree. TheClientinterface and config package are ready for reuse.Related
entrypointsubcommand)