feat(trail): drop attachment and watcher commands for now · Entire

feat(trail): drop attachment and watcher commands for now

3fced2a→main·

computermode·1w ago·8 files·+1 added/-383 removed

Scope this PR to metadata, approvals, and discussion threads. Attachment (raw-binary upload) and watchers (presence-based) support is removed for a later change.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

Sessions

01KX6VR2GWJFA44C0255JA7E57View transcript

[?
CLI Trail Commands and UI ParityClaude Code·Opus 4.8·2 steps](/content/gh/entireio/cli/session/a7c8f6a2-7a40-4558-aba8-a31927cc21d3#timeline-01KX6VR2GWJFA44C0255JA7E57/index.html)

Changes

8

package api

// TrailAttachment is a trail attachment (v1: images only). The server strips
// the internal r2_key; there is no URL field — a serve URL is built from the
// id and a variant. Width/Height/CreatedByUserID/DeletedAt are nullable.
type TrailAttachment struct {
    ID              string  `json:"id"`
    TrailID         string  `json:"trail_id"`
    RepoID          string  `json:"repo_id"`
    Kind            string  `json:"kind"`
    ContentType     string  `json:"content_type"`
    Filename        string  `json:"filename"`
    SizeBytes       int64   `json:"size_bytes"`
    Width           *int    `json:"width"`
    Height          *int    `json:"height"`
    CreatedByUserID *string `json:"created_by_user_id"`
    CreatedAt       string  `json:"created_at"`
    DeletedAt       *string `json:"deleted_at"`
}

// TrailAttachmentsResponse is the response from GET .../:number/attachments.
type TrailAttachmentsResponse struct {
    Attachments []TrailAttachment `json:"attachments"`
}

// TrailAttachmentUploadResponse is the response from POST .../:number/attachments.
type TrailAttachmentUploadResponse struct {
    Attachment TrailAttachment `json:"attachment"`
}

Dcmd/entire/cli/api/trail_attachment_types.go-29

package api

// TrailWatchersResponse is the response from GET /api/v1/trails/:trail_id/watchers.
// Watchers are the user IDs of clients currently connected to the trail's live
// event stream (presence-based, not a persisted subscription list).
type TrailWatchersResponse struct {
    Watchers []string `json:"watchers"`
}

Dcmd/entire/cli/api/trail_watcher_types.go-8

package cli

import (
    "bytes"
    "context"
    "encoding/json"
    "errors"
    "fmt"
    "net/http"
    "net/url"
    "os"
    "path/filepath"
    "strings"

"github.com/entireio/cli/cmd/entire/cli/api"
    "github.com/spf13/cobra"
)

// trailAttachmentsPath builds the attachments collection path for a trail number.
func trailAttachmentsPath(forge, owner, repo string, number int) string {
    return trailNumberPath(forge, owner, repo, number) + "/attachments"
}

// detectAttachmentContentType returns the image MIME type for a file's bytes,
// accepting only PNG and JPEG (the only kinds the server stores). It errors on
// anything else so the CLI fails fast with a clear message.
func detectAttachmentContentType(data []byte) (string, error) {
    ct := http.DetectContentType(data)
    switch ct {
    case "image/png", "image/jpeg":
        return ct, nil
    default:
        return "", fmt.Errorf("unsupported attachment type %q: only PNG and JPEG images are supported", ct)
    }
}

// trailAttachmentURL builds the public inline-variant serve URL for an
// attachment. The host/owner/repo segments are decorative server-side; the id
// alone resolves the attachment.
func trailAttachmentURL(forge, owner, repo, id string) string {
    return strings.TrimRight(api.BaseURL(), "/") +
        "/api/v1/trails/" + forge + "/" + owner + "/" + repo + "/attachments/" + id + "/inline"
}

Dcmd/entire/cli/trail_attachment_cmd.go-184

package cli

import (
    "context"
    "errors"
    "fmt"
    "strings"

"github.com/entireio/cli/cmd/entire/cli/api"
    "github.com/spf13/cobra"
)

// withNumberedTrail resolves a numbered trail (by --trail selector or current
// branch / --branch) and invokes fn inside an authenticated API context. It
// centralizes the resolution boilerplate shared by the comment and attachment
// subtrees.
func withNumberedTrail(cmd *cobra.Command, fn func(ctx context.Context, client *api.Client, found *api.TrailResource, forge, owner, repo string) error) error {
    ...
}

Dcmd/entire/cli/trail_cmd.go-2

package cli

// trailWatchersPath returns the watchers path, keyed by the trail's UUID (not
// its number, unlike the other trail subresources).
func trailWatchersPath(trailID string) string {
    return "/api/v1/trails/" + trailID + "/watchers"
}

Dcmd/entire/cli/trail_watchers_cmd.go-82

package cli

import (
    "context"
    "errors"
    "fmt"
    "strings"

"github.com/entireio/cli/cmd/entire/cli/api"
    "github.com/spf13/cobra"
)

func newTrailWatchersCmd() *cobra.Command {
    ...
}