StateFile class

Atomic JSON read/write for the artisan state file.

The file is PER PROJECT: ~/.artisan/sessions/<hash>/state.json, keyed by the project root. It used to be one global ~/.artisan/state.json, which meant a second project's artisan start silently took the slot and every connected command from the first project then drove the second app, succeeding each time. The measured case had a worktree in another repository rewrite it mid-session, and two commands later produced a screenshot of an entirely different product.

~/.artisan/state.json is still written, as a pointer to whichever session started last. That is an interop contract rather than a shim: the documented recovery recipe when artisan start cannot boot an app is to hand-write that file, and external tooling reads it.

Written by artisan start after a successful flutter run spawn; consumed by stop, status, logs, doctor, restart, and every connected-mode command (dusk:, telescope:, tinker) to locate the running app's VM Service WebSocket URI.

Schema:

  • pid (int, required): the flutter run process PID
  • stdinPipe (string, required): path to the FIFO flutter run's stdin reads from. reload and hot-restart write r / R into it, so a hand-written state without this key cannot hot restart
  • stdinHolderPid (int, required): PID of the process holding the FIFO open for writing, reaped by stop
  • booting (bool, optional): present and true only between the spawn and the VM Service URI landing. A caller that gave up in that window left the app running, and this says the record is incomplete rather than wrong
  • vmServiceUri (string, null while booting): canonical ws://host:port/<token>/ws
  • webPort (int, required): --web-port passed to flutter
  • vmServicePort (int, optional, informational, default 8181)
  • startedAt (ISO 8601 UTC string, required)
  • profile (string, required, debug | static)
  • projectRoot (string, required)
  • device (string, required, chrome | macos | linux | windows | device UDID)
  • chromePid (int | null, D6 Chrome capture outcome)
  • tmpProfileDir (string | null, D6 Chrome capture outcome)
  • cdpPort (int | null, --cdp-port value passed to start; null when CDP not enabled)

Properties

hashCode int
The hash code for this object.
no setterinherited
runtimeType Type
A representation of the runtime type of the object.
no setterinherited

Methods

noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited

Static Properties

debugHomeOverride String?
Test injection seam: overrides the resolved home directory. Production code never sets this.
getter/setter pair
debugProjectRootOverride String?
Test injection seam: overrides the resolved project root.
getter/setter pair
homeDir String
The directory every artisan artifact lives under, session or not.
no setter
legacyPointerPath String
The single global file every version before session isolation used.
no setter
path String
Absolute path to the state file this process reads and writes.
no setter
pathOverride String?
Explicit path override, set from --state=<path>. Null means "resolve from the project root", subject to explicitPath.
getter/setter pair

Static Methods

delete() Future<void>
Delete this project's state. Idempotent.
explicitPath() String?
The session the caller NAMED, by flag or by environment, or null when they named none.
projectRootFor(String from) String
The package root from belongs to: the nearest ancestor holding a pubspec.yaml, or from itself when there is none.
read() Future<Map<String, dynamic>?>
Read the state for this project. Returns null when absent.
sessionDirFor(String projectRoot) String
The directory holding one session's state, log and FIFO.
sessionPathFor(String projectRoot) String
The session file for projectRoot.
write(Map<String, dynamic> data) Future<void>
Write atomically via .tmp + rename (no partial-state windows).