Skip to content

dark apps — a daemon / foreground / ui launch model#5669

Draft
StachuDotNet wants to merge 1 commit into
darklang:mainfrom
StachuDotNet:apps-again
Draft

dark apps — a daemon / foreground / ui launch model#5669
StachuDotNet wants to merge 1 commit into
darklang:mainfrom
StachuDotNet:apps-again

Conversation

@StachuDotNet
Copy link
Copy Markdown
Member

The one surface that lists, installs, and runs Apps — covering both background daemons and interactive UI apps, so the same dark apps manages the sync daemon, a print-md run, and the outliner TUI alike. An App is a package VALUE, so the manifest syncs like any other value.

The thin manifest + the three kinds

type AppKind = | Daemon | Foreground | Ui
type App =
  { name: String
    entrypoint: String          // Daemon: the loop fn (detached); Foreground: `dark run` target; Ui: the TUI fn
    description: String
    kind: AppKind
    spawnAllowList: List<String> }   // executables `apps install` grants as a Cli(spawn:…) capability
  • Daemon — backgrounded long-runner; start/stop/status/logs manage it via a pidfile (sync daemon, heartbeat). Detached, survives CLI exit.
  • Foreground — a normal dark run that finishes (print-md).
  • Ui — a full-screen MVU TUI, attached until you quit (the outliner).
$ dark apps                          # the registry, at a glance
print-md   foreground   Render a markdown file to PDF and print it
heartbeat  daemon       A demo daemon: log a heartbeat every interval
outliner   ui           Interactive tree outliner (full-screen TUI)

$ dark apps start heartbeat          # detached; managed by pidfile
heartbeat running (pid 48213)
$ dark apps status heartbeat
heartbeat: running (pid 48213)

Install surface

apps install writes a one-line shell shim (~/.darklang/bin/<app>dark run <entrypoint>) and grants the app's spawnAllowList as Cli(spawn: …). One dir on PATH, so uninstall is one file.

Tests

testfiles/execution/pre-s-and-s/apps.dark6/6: kindTag (×3), aliasPath, spawnGrantSummary (empty / non-empty). (findByName reads the all package-VALUE registry, which the .dark test harness can't resolve, so it's exercised via dark apps list at the CLI.) Build + reload clean.

Deferred

Type-discovery of Apps via the synced value index (this PR lists a static all); dark apps fork (later). Files: apps.dark, apps-daemon.dark, apps-examples.dark, …/cli/commands/apps.dark, core.dark, the testfile.

`dark apps` is one surface over a registry of Apps. An App is a thin package VALUE
declaring how it launches:

  daemon       a backgrounded long-runner, pidfile-tracked — start/stop/status/logs
  foreground   a normal `dark run <entrypoint>` that finishes
  ui           a full-screen TUI that runs attached

  $ dark apps
  Apps:
    heartbeat  [daemon]      A demo daemon: log a heartbeat every interval  (stopped)
    outliner   [ui]          Interactive tree outliner (full-screen TUI)
    review     [ui]          Review branch changesets
    views      [ui]          Browse and preview CLI views
    ui-demo    [foreground]  Render the UI component gallery (a visual check)

  $ dark apps start heartbeat        # detached, survives CLI exit
  $ dark apps status                 # heartbeat: running (pid 48213)
  $ dark apps stop heartbeat

## Generic CLI daemon management — `Darklang.Cli.Daemons`

The daemon lifecycle is a standalone, app-agnostic module: a daemon is a DETACHED `dark`
process tracked by a pidfile (`~/.darklang/run/<name>.pid`), with a signal-0 liveness check,
SIGTERM stop, and tailable logs. Built on the POSIX stdlib. It manages ANY named daemon — the
caller supplies the entrypoint — so `dark apps` is just one client (the heartbeat app proves it).

## Install (preview)

`apps install <name>` plans the PATH shim (`~/.darklang/bin/<name>` -> `dark run <entrypoint>`).
The write step needs a live env. (Capability-scoped install — restricting what an installed app
may spawn — waits for the capability model and is not part of this PR.)

## Tests

`testfiles/execution/cli/apps.dark`: the kind tags + the install-string builders. The daemon
lifecycle (detached process, pidfile, SIGTERM) is exercised live via `dark apps start/stop`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant