Skip to content

Latest commit

 

History

History
176 lines (128 loc) · 4.54 KB

File metadata and controls

176 lines (128 loc) · 4.54 KB

Plugins

ASC supports a plugin system based on compiled .plugin bundles (dylibs) that extend the CLI with server routes, UI components, CLI commands, and domain affordances. Plugins are discovered from ~/.asc/plugins/ at startup.

For browsing and installing plugins from a marketplace, see Plugin Market.

Plugin Bundle Structure

~/.asc/plugins/ASCPro.plugin/
├── manifest.json              # metadata: name, version, server dylib, UI scripts
├── ASCPro.dylib               # compiled dynamic library
└── ui/
    └── sim-stream.js          # web UI scripts (loaded by command-center)

manifest.json

{
  "name": "ASC Pro",
  "version": "1.0",
  "server": "ASCPro.dylib",
  "ui": ["ui/sim-stream.js"]
}

CLI Usage

asc plugins list

List installed dylib plugins.

asc plugins list --pretty

asc plugins install --name <name>

Install a plugin from the marketplace.

asc plugins install --name asc-pro

asc plugins uninstall --name <name>

Remove an installed plugin bundle.

asc plugins uninstall --name ASCPro

asc plugins market list

Browse all available plugins. See Plugin Market.

asc plugins market search --query <text>

Search marketplace by keyword. See Plugin Market.

asc plugins updates

List installed plugins that have a newer version available in the marketplace. Inspired by Sparkle's appcast — each entry pairs the installed version with the latest marketplace version.

asc plugins updates --pretty
{
  "data": [
    {
      "affordances": {
        "list": "asc plugins updates",
        "update": "asc plugins update --name Hello"
      },
      "installedVersion": "1.0.0",
      "latestVersion": "1.2.0",
      "name": "Hello"
    }
  ]
}

asc plugins update --name <name>

Apply a marketplace update by uninstalling the named plugin and reinstalling the latest version. Returns the freshly installed Plugin record.

asc plugins update --name Hello

REST Endpoints

The same operations are reachable over HTTP via asc web-server:

CLI REST Body / Query
asc plugins list GET /api/v1/plugins
asc plugins install --name X POST /api/v1/plugins { "name": "X" }
asc plugins uninstall --name X DELETE /api/v1/plugins/:name — (returns 204)
asc plugins market list GET /api/v1/plugins/market
asc plugins market search --query Q GET /api/v1/plugins/market?q=Q
asc plugins updates GET /api/v1/plugins/updates
asc plugins update --name X POST /api/v1/plugins/:name/update

Example:

# Install
curl -X POST http://localhost:5173/api/v1/plugins \
  -H 'content-type: application/json' \
  -d '{"name":"Hello.plugin"}'

# Search
curl "http://localhost:5173/api/v1/plugins/market?q=hello"

# Uninstall
curl -X DELETE http://localhost:5173/api/v1/plugins/Hello.plugin

# Check for updates (Sparkle-style appcast)
curl http://localhost:5173/api/v1/plugins/updates

# Apply an update
curl -X POST http://localhost:5173/api/v1/plugins/Hello/update

Plugin Protocol

Plugins export a C entry point and conform to ASCPluginBase:

@_cdecl("ascPlugin")
public func ascPlugin() -> UnsafeMutableRawPointer {
    Unmanaged.passRetained(MyPlugin()).toOpaque()
}

public final class MyPlugin: NSObject, ASCPluginBase {
    public let name = "My Plugin"
    public var commands: [Any] { [] }

    public func configureRoutes(_ router: Any) {
        // Register HTTP/WebSocket routes
    }
}

AffordanceRegistry

Plugins extend domain model affordances at runtime using structured Affordance values that render to both CLI commands and REST _links:

AffordanceRegistry.register(Simulator.self) { id, props in
    guard props["isBooted"] == "true" else { return [] }
    return [Affordance(key: "stream", command: "simulators", action: "stream", params: ["udid": id])]
}

This produces:

  • CLI: "stream": "asc simulators stream --udid <id>"
  • REST: "stream": {"href": "/api/v1/simulators/<id>/stream", "method": "POST"}

Architecture

PluginLoader.discover()
  → scans ~/.asc/plugins/ for .plugin, .framework, .dylib
  → loads via dlopen/dlsym("ascPlugin")
  → returns [LoadedPlugin] with name, slug, uiScripts

ASCWebServer.buildRouter()
  → calls plugin.configureRoutes(routerPtr)
  → serves plugin UI scripts at /api/plugins/{slug}/ui/*
  → GET /api/plugins returns manifest list for web app