;; sx-forge — SX-based Git Forge
;; Plan: a Gitea/Forgejo-style git hosting platform where everything —
;; repositories, issues, pull requests, CI, permissions — is SX.

(defcomp ()
  (~docs/page :title "sx-forge: Git Forge in SX"

    (~docs/section :title "Vision" :id "vision"
      (p "A git forge where the entire interface, configuration, and automation layer "
         "is written in SX. Repositories are browsed, issues are filed, pull requests "
         "are reviewed, and CI pipelines are triggered — all through SX components "
         "rendered via the same hypermedia pipeline as every other SX app.")
      (p "Configuration is SX. Webhooks are SX. Access control policies are SX macros "
         "that expand to permission checks. Repository templates are defcomps. "
         "The forge doesn't use SX — it " (em "is") " SX."))

    (~docs/section :title "Why" :id "why"
      (p "Gitea/Forgejo are excellent but they're Go binaries with YAML/INI config, "
         "Markdown rendering, and a template engine that's separate from the application logic. "
         "Every layer speaks a different language.")
      (p "sx-forge collapses these layers:")
      (ul (~tw :tokens "space-y-2 text-stone-600 list-disc pl-5")
        (li "Repository browsing = SX components rendering git tree objects")
        (li "Issue tracking = SX forms with sx-post, stored as content-addressed SX documents")
        (li "Pull requests = SX diff viewer + sx-activity for review comments")
        (li "CI integration = sx-ci pipelines triggered by push hooks")
        (li "Configuration = SX s-expressions, manipulated by macros")
        (li "Access control = SX macros that expand to permission predicates")
        (li "API = SX wire format (text/sx) alongside JSON for compatibility")))

    (~docs/section :title "Architecture" :id "architecture"
      (div (~tw :tokens "overflow-x-auto mt-4")
        (table (~tw :tokens "w-full text-sm text-left")
          (thead
            (tr (~tw :tokens "border-b border-stone-200")
              (th (~tw :tokens "py-2 px-3 font-semibold text-stone-700") "Layer")
              (th (~tw :tokens "py-2 px-3 font-semibold text-stone-700") "Implementation")
              (th (~tw :tokens "py-2 px-3 font-semibold text-stone-700") "Notes")))
          (tbody (~tw :tokens "text-stone-600")
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "py-2 px-3 font-semibold") "Git backend")
              (td (~tw :tokens "py-2 px-3") "libgit2 or shell-out to git")
              (td (~tw :tokens "py-2 px-3") "Smart HTTP + SSH protocols. Bare repos on disk."))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "py-2 px-3 font-semibold") "UI")
              (td (~tw :tokens "py-2 px-3") "SX components (defcomp)")
              (td (~tw :tokens "py-2 px-3") "Tree browser, diff viewer, blame, commit log — all defcomps."))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "py-2 px-3 font-semibold") "Issues / PRs")
              (td (~tw :tokens "py-2 px-3") "SX documents on IPFS")
              (td (~tw :tokens "py-2 px-3") "Content-addressed. Federated via sx-activity."))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "py-2 px-3 font-semibold") "CI")
              (td (~tw :tokens "py-2 px-3") "sx-ci pipelines")
              (td (~tw :tokens "py-2 px-3") "Push hook triggers pipeline. Results as SX components."))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "py-2 px-3 font-semibold") "Auth")
              (td (~tw :tokens "py-2 px-3") "OAuth2 + SX policy macros")
              (td (~tw :tokens "py-2 px-3") "Permissions are macro-expanded predicates."))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "py-2 px-3 font-semibold") "Config")
              (td (~tw :tokens "py-2 px-3") "SX s-expressions")
              (td (~tw :tokens "py-2 px-3") "forge.sx per-instance. repo.sx per-repo."))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "py-2 px-3 font-semibold") "Federation")
              (td (~tw :tokens "py-2 px-3") "sx-activity (ActivityPub)")
              (td (~tw :tokens "py-2 px-3") "Cross-instance PRs, issues, stars, forks."))))))

    (~docs/section :title "Configuration as SX" :id "config"
      (p "Instance configuration is an SX file, not YAML or INI:")
      (highlight "(define forge-config
  {:name \"Rose Ash Forge\"
   :domain \"forge.rose-ash.com\"
   :ssh-port 2222
   :storage {:backend :filesystem :root \"/data/repos\"}
   :auth {:provider :oauth2
          :issuer \"https://account.rose-ash.com\"}
   :federation {:enabled true
                :allowlist (list \"*.rose-ash.com\")}
   :ci {:runner :sx-ci
        :default-pipeline \"ci/default.sx\"}})" "lisp")
      (p "Macros transform configuration:")
      (highlight ";; Macro: generate mirror config from upstream
(defmacro mirror-repo (name upstream)
  `(define-repo ,name
     {:mirror true
      :upstream ,upstream
      :sync-interval 3600
      :ci false}))" "lisp")
      (p "Per-repository configuration lives in " (code "repo.sx") " at the repo root:")
      (highlight "(define repo-config
  {:default-branch \"main\"
   :ci (pipeline
     (stage :test (sx-ci/run \"test.sx\"))
     (stage :deploy
       (when-branch \"main\"
         (sx-ci/deploy :target :production))))
   :permissions
     {:push (or (role? :maintainer) (role? :admin))
      :merge-pr (and (ci-passed?) (approved-by? 1))
      :admin (role? :admin)}})" "lisp"))

    (~docs/section :title "SX Diff Viewer" :id "diff-viewer"
      (p "Diffs rendered as SX components, not pre-formatted text:")
      (highlight ";; The diff viewer is a defcomp, composable like any other
(defcomp ~plans/sx-forge/diff-view (&key (diff :as dict))
  (map (fn (hunk)
    (~diff-hunk
      :file (get hunk \"file\")
      :old-start (get hunk \"old-start\")
      :new-start (get hunk \"new-start\")
      :lines (get hunk \"lines\")))
    (get diff \"hunks\")))" "lisp")
      (p "Because diffs are SX data, macros can transform them:")
      (ul (~tw :tokens "space-y-2 text-stone-600 list-disc pl-5")
        (li "Syntax highlighting via the same " (code "highlight") " helper used everywhere")
        (li "Inline review comments as SX forms (sx-post to comment endpoint)")
        (li "Suggestion blocks — click to apply a proposed change")
        (li "SX-aware diffs — show component-level changes, not just line changes")))

    (~docs/section :title "Federated Forge" :id "federation"
      (p "sx-activity enables cross-instance collaboration:")
      (ul (~tw :tokens "space-y-2 text-stone-600 list-disc pl-5")
        (li (strong "Cross-instance PRs") " — open a PR from your fork on another instance")
        (li (strong "Federated issues") " — file an issue on a remote repo from your instance")
        (li (strong "Stars and forks") " — ActivityPub Follow/Like activities")
        (li (strong "Mirror sync") " — subscribe to upstream changes via sx-activity")
        (li (strong "Review comments") " — threaded discussions federated as SX documents"))
      (p "Every issue, comment, and review is a content-addressed SX document on IPFS. "
         "Federation distributes references. The content is permanent and verifiable."))

    (~docs/section :title "Git Operations as IO Primitives" :id "git-ops"
      (p "Git operations exposed as SX IO primitives in boundary.sx:")
      (highlight ";; boundary.sx additions
(io git-log       (repo &key branch limit offset) list)
(io git-tree      (repo ref path) list)
(io git-blob      (repo ref path) string)
(io git-diff      (repo base head) dict)
(io git-refs      (repo) list)
(io git-commit    (repo message files &key author) dict)
(io git-create-branch (repo name from) dict)
(io git-merge     (repo source target &key strategy) dict)" "lisp")
      (p "Pages use these directly — no controller layer, no ORM:"))

    (~docs/section :title "Implementation Path" :id "implementation"
      (ol (~tw :tokens "space-y-3 text-stone-600 list-decimal pl-5")
        (li (strong "Phase 1: Read-only browser") " — git-tree, git-blob, git-log, git-diff as IO primitives. "
            "SX components for tree view, blob view, commit log, diff view.")
        (li (strong "Phase 2: Issues") " — SX forms for create/edit. Content-addressed storage. "
            "Labels, milestones, assignees as SX data.")
        (li (strong "Phase 3: Pull requests") " — fork model, diff + review UI, merge strategies. "
            "CI status checks from sx-ci.")
        (li (strong "Phase 4: CI integration") " — push hooks trigger sx-ci pipelines. "
            "Results rendered as SX components on the PR page.")
        (li (strong "Phase 5: Federation") " — sx-activity for cross-instance PRs, issues, stars.")
        (li (strong "Phase 6: Admin") " — SX macro-based permission policies. "
            "Instance and org management via SX config.")))))
