Documentation
¶
Overview ¶
Package apps manages installed applications: web frontends built on top of the agent's public API (vision document, section 7.6). An application never receives the agent's full privileges — it declares the permissions it needs in a manifest, and receives a session limited to exactly those (vision document, section 15.4; internal/auth issues and checks such sessions).
This is the minimal first slice (ADR-0026): the manifest only covers workflows.run. connectors.use and capabilities from the vision document are deliberately not modeled yet — there is no enforcement point for them, the same situation plugin permissions are in today (internal/plugins.CatalogEntry.Permissions is recorded but unchecked).
Index ¶
- Constants
- Variables
- func Pack(sourceDir string, key ed25519.PrivateKey, w io.Writer) error
- func Scaffold(dir, id, version string) error
- func ScaffoldVite(dir, id, version string) error
- func Uninstall(ctx context.Context, db *sql.DB, id string) error
- type App
- func Get(ctx context.Context, db *sql.DB, id string) (*App, error)
- func Install(ctx context.Context, db *sql.DB, sourceDir string) (*App, error)
- func InstallOrUpdate(ctx context.Context, db *sql.DB, sourceDir string) (*App, error)
- func InstallPackage(ctx context.Context, db *sql.DB, dataDir, packagePath string, ...) (*App, trust.PolicyResult, error)
- func List(ctx context.Context, db *sql.DB) ([]App, error)
- type AppPermissions
- type Manifest
Constants ¶
const ManifestFileName = "patchcord-app.yaml"
ManifestFileName is the file an application's source/static directory must contain at its root (vision document, section 10.3).
const PackageExtension = ".patchcord-app"
PackageExtension is the conventional file extension for an application package produced by Pack (vision document, section 9.3: ".patchcord-app"). Install only inspects whether the path is a file or a directory, not this extension — it is a naming convention, not part of the format.
Variables ¶
var ErrAlreadyExists = errors.New("app already exists")
ErrAlreadyExists is returned by Install when an application with the manifest's id is already installed.
var ErrInvalidManifest = errors.New("invalid app manifest")
ErrInvalidManifest is returned by ParseManifest and LoadManifest when the manifest is malformed or missing a required field.
var ErrNotFound = errors.New("app not found")
ErrNotFound is returned by Get and Uninstall when no application with the given id has been recorded.
Functions ¶
func Pack ¶
Pack archives sourceDir (which must contain a valid patchcord-app.yaml, vision document section 9.3: "Interface web statique et manifeste de permissions") into w as a gzip-compressed tar stream, plus a checksums.json covering it (see internal/packaging.SignedArchive). If key is non-nil, the package is also signed — key == nil (no --sign-key) produces a package with integrity data but no provenance. The result is what InstallPackage (and therefore `patchcord app install`) expects.
Only regular files and directories are supported; sourceDir must not contain symlinks or other special entries.
func Scaffold ¶
Scaffold writes a minimal patchcord-app.yaml and index.html to dir, ready for `app pack`/`app install` as-is. It returns an error if dir already exists and is not empty — Scaffold never overwrites.
func ScaffoldVite ¶
ScaffoldVite writes a minimal Vite + TypeScript project to dir — no UI framework opinion, just enough to run `npm install && npm run build` and get an installable app directory out of it. It returns an error if dir already exists and is not empty — ScaffoldVite never overwrites.
Unlike Scaffold, the result is not installable as-is: patchcord-app.yaml lives under public/ so Vite's build copies it into dist/ alongside the bundled JS, matching the reference dashboard example (apps/examples/dashboard). Build first, then point app/bundle commands at dir's dist subdirectory:
cd dir && npm install && npm run build patchcord app install dir/dist
Types ¶
type App ¶
type App struct {
ID string
Version string
StaticDir string
Permissions AppPermissions
CreatedAt time.Time
}
App is one installed application, as recorded in the database.
func Get ¶
Get returns one installed application by id. It returns ErrNotFound if no application with that id has been recorded.
func Install ¶
Install reads sourceDir's manifest (patchcord-app.yaml) and records the application, serving its static files straight from sourceDir. There is no packaging or copy step yet — the real .patchcord-app bundle format (vision document, section 9.3) is deferred, see ADR-0026.
It returns ErrAlreadyExists if an application with the manifest's id is already installed, or an error wrapping ErrInvalidManifest if the manifest is malformed.
func InstallOrUpdate ¶
InstallOrUpdate is Install, except that installing over an application whose id is already recorded updates it in place (new version, static_dir, permissions) instead of returning ErrAlreadyExists. It backs `patchcord app dev`: since handleServeApp reads static_dir straight off disk on every request (no copy, no cache), an application registered this way is already "hot reloaded" for free — rebuilding it in place (e.g. `vite build --watch`) is visible on the next browser refresh with no further agent involvement. What InstallOrUpdate removes is the friction Install has for this loop: without it, iterating would require `app remove` before every `app install`.
func InstallPackage ¶
func InstallPackage(ctx context.Context, db *sql.DB, dataDir, packagePath string, requireSignature bool) (*App, trust.PolicyResult, error)
InstallPackage installs an application from a .patchcord-app archive (Pack's output). Unlike Install, which serves an application straight from wherever its source directory happens to live, a package's contents are extracted under dataDir/apps/<id>/<version> — a location the agent owns for as long as the application stays installed, so the archive itself is free to move or disappear afterwards.
The package is verified (internal/packaging.Verify) before anything is installed: a checksum mismatch or an invalid signature aborts unconditionally. requireSignature additionally rejects a package that is unsigned, or signed by a key not trusted for its id (internal/trust) — when false, InstallPackage still returns the verification outcome so the caller can warn about either case instead of failing outright.
It returns ErrAlreadyExists if an application with the manifest's id is already installed, or an error wrapping ErrInvalidManifest if the packaged manifest is malformed.
type AppPermissions ¶
type AppPermissions struct {
WorkflowsRun []string `json:"workflows_run"`
}
AppPermissions is the permission set an application's sessions are limited to (api/app/v1/manifest.schema.json). WorkflowsRun is the only kind enforced today — see the package doc comment.
type Manifest ¶
type Manifest struct {
ID string
Version string
Permissions AppPermissions
}
Manifest is the parsed content of an application's patchcord-app.yaml.
func LoadManifest ¶
LoadManifest reads and parses dir's patchcord-app.yaml.
func ParseManifest ¶
ParseManifest parses and validates an application manifest from its YAML source, returning ErrInvalidManifest if a required field is missing or empty.