Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .codex/skills/qa-night-shift/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ Typical flow:
resume attempt when the run was interrupted
10. use `night-shift resolve` or `night-shift resume` only if the run actually
requires it
11. use `night-shift dash` when the QA pass needs browser-visible bootstrap,
SSE, command, audit, or raw artifact validation

For review-driven investigations, replace steps 3-4 with:

Expand All @@ -143,6 +145,8 @@ In review-driven runs, pay attention to repo-state evidence:

- the stored open-PR snapshot captured during planning
- whether `status`, `report`, or the dashboard show repo-state drift
- whether `night-shift dash` bootstrap and SSE payloads stay aligned with the
journal-backed repo-state snapshot
- whether `night-shift report` shows the actionable/impacted subtree and
replacement lineage, while the persisted `report.md` remains readable
without live GitHub refresh
Expand Down Expand Up @@ -175,6 +179,8 @@ In review-driven runs, pay attention to repo-state evidence:
failures with usable artifact paths
- whether `status`, `report`, and the dashboard agree on the confidence posture
and its reasons
- whether Dash command handlers mutate the same durable run state as the CLI,
without scraping command output
- whether `provenance` records the expected prompt paths, payload artifacts,
verification evidence, worktree paths, and PR linkage
- whether `doctor` classifies interrupted tasks as `safe_to_resume`,
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Night Shift already has working support for:
- provider adapters for Codex CLI and Cursor Agent
- local verification before pull request delivery
- review-loop ingestion for open Night Shift pull requests
- a local monitor-only dashboard via `start --ui` and `resume --ui`
- a localhost-only Dash control surface via `night-shift dash`

The current operator flow is:

Expand Down Expand Up @@ -126,10 +126,10 @@ night-shift resume --explain
night-shift resume
```

If you want the local dashboard while a run is active:
If you want the local dashboard:

```sh
night-shift start --ui
night-shift dash
```

## Source Development
Expand Down
5 changes: 2 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ Kick off the most recent pending run:
night-shift start
```

You can also target a specific run or open the local dashboard:
You can also target a specific run or open Dash:

```sh
night-shift start --run run-123
night-shift start --ui
night-shift dash
```

`start` is execution-only. It uses the execution agent, environment, and brief
Expand Down Expand Up @@ -154,7 +154,6 @@ If a run was interrupted, resume from the saved journal:
night-shift doctor
night-shift resume --explain
night-shift resume
night-shift resume --ui
```

`doctor` is the dry recovery pass. It classifies each task as
Expand Down
21 changes: 11 additions & 10 deletions docs/providers-and-delivery.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,23 +111,24 @@ leave that disabled and still use the PR-body overlay.

## Dashboard

The local dashboard is intentionally narrow in scope. It binds to `127.0.0.1`,
prefers port `8787`, and serves a monitor-only UI for:
The local dashboard now uses `night-shift dash`. It binds to `127.0.0.1` and
serves a Dash backend for:

- run history
- summary metadata for the selected run
- repo-state summary for review-driven runs, including snapshot time and drift
- task status
- event timeline
- report content
- structured bootstrap state for the current repository
- SSE-first live updates
- browser command handlers for `init`, `plan`, `plan --from-reviews`,
`resolve`, `start`, and `resume`
- audit and raw artifact routes for reports, provenance, logs, payloads, and
runtime identity files

There are no browser-side mutation controls.
The browser surface reuses the same in-process usecases as the CLI rather than
shelling out to `night-shift` subprocesses.

## Demo Mode

`night-shift --demo` exercises a fixture-backed flow and prints a compact proof
summary. The headless demo validates `plan`, `start`, `status`, and `report`.
The UI demo validates the local dashboard payload as well.
The UI demo validates Dash bootstrap plus browser-command execution as well.

Demo artifacts live under:

Expand Down
21 changes: 7 additions & 14 deletions docs/run-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,22 +151,15 @@ attention with both the original and repair artifacts recorded.

## Dashboard

The dashboard is monitor-only:
Dash is the human-first local control surface:

```sh
night-shift start --ui
night-shift resume --ui
night-shift dash
```

Night Shift binds to `127.0.0.1`, prefers port `8787`, and serves:
Night Shift binds Dash to `127.0.0.1` for the current repository and serves:

- run history for the current repository
- run summary metadata
- repo-state summary for review-driven runs, including open PR counts and drift
- confidence posture and provenance path
- task status
- event timeline
- report content

There are no browser-side controls for starting or resuming runs in this
version.
- structured bootstrap state for initialization, runs, task DAG metadata, repo-state drift, confidence, runtime identities, report, and provenance references
- SSE-first live updates for the selected repository state
- browser command endpoints for `init`, `plan`, `plan --from-reviews`, `resolve`, `start`, and `resume`
- raw artifact and audit routes for reports, provenance, logs, payloads, and runtime handoff files
33 changes: 9 additions & 24 deletions src/night_shift/app.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ pub fn run(command: types.Command) -> Nil {
<> "\n"
<> crate_summary(types.default_config()),
)
types.Dash ->
case dashboard_session.start(repo_root) {
Ok(Nil) -> Nil
Error(message) -> io.println(message)
}
types.Demo(ui) ->
case demo.run(ui) {
Ok(summary) -> io.println(summary)
Expand Down Expand Up @@ -130,7 +135,6 @@ fn run_initialized_command(
Error(message) -> message
})
types.Start(run, False) -> io.println(start(repo_root, run, config))
types.Start(run, True) -> start_with_ui(repo_root, run, config)
types.Status(run) -> io.println(status(repo_root, run, config))
types.Report(run) -> io.println(report(repo_root, run, config))
types.Provenance(run, task_id, format) ->
Expand All @@ -139,8 +143,11 @@ fn run_initialized_command(
types.Resolve(run) -> io.println(resolve(repo_root, run, config))
types.Resume(run, False, False) ->
io.println(resume(repo_root, run, config))
types.Resume(run, True, False) -> resume_with_ui(repo_root, run, config)
types.Resume(run, False, True) -> io.println(doctor(repo_root, run, config))
types.Start(_, True) | types.Resume(_, True, False) ->
io.println(
"The `--ui` entrypoint was replaced by `night-shift dash`.",
)
_ -> io.println("Unsupported command.")
}
}
Expand Down Expand Up @@ -330,28 +337,6 @@ fn reset(repo_root: String, assume_yes: Bool, force: Bool) -> String {
}
}

fn start_with_ui(
repo_root: String,
selector: types.RunSelector,
config: types.Config,
) -> Nil {
case dashboard_session.start(repo_root, selector, config) {
Ok(Nil) -> Nil
Error(message) -> io.println(message)
}
}

fn resume_with_ui(
repo_root: String,
run: types.RunSelector,
config: types.Config,
) -> Nil {
case dashboard_session.resume(repo_root, run, config) {
Ok(Nil) -> Nil
Error(message) -> io.println(message)
}
}

fn review_profile_deprecation_fragment(review_profile: String) -> String {
case review_profile {
"" -> ""
Expand Down
14 changes: 5 additions & 9 deletions src/night_shift/cli.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ pub fn usage() -> String {
<> "\n"
<> "Commands:\n"
<> " --demo [--ui]\n"
<> " dash\n"
<> " init [--profile <name>] [--provider <codex|cursor>] [--model <id>] [--reasoning <low|medium|high|xhigh>] [--yes] [--generate-setup]\n"
<> " Prompts interactively for provider, model, and initial worktree setup when those answers are not supplied.\n"
<> " reset [--yes] [--force]\n"
<> " plan --notes <file-or-inline-text> [--doc <path>] [--profile <name>] [--provider <codex|cursor>] [--model <id>] [--reasoning <low|medium|high|xhigh>]\n"
<> " plan --from-reviews [--notes <file-or-inline-text>] [--doc <path>] [--profile <name>] [--provider <codex|cursor>] [--model <id>] [--reasoning <low|medium|high|xhigh>]\n"
<> " start [--run <id>|latest] [--ui]\n"
<> " start [--run <id>|latest]\n"
<> " status [--run <id>|latest]\n"
<> " report [--run <id>|latest]\n"
<> " provenance [--run <id>|latest] [--task <task-id>] [--format <json|md>]\n"
<> " doctor [--run <id>|latest]\n"
<> " resolve [--run <id>|latest]\n"
<> " resume [--run <id>|latest] [--ui|--explain]\n"
<> " resume [--run <id>|latest] [--explain]\n"
}

/// Parse raw command-line arguments into a `Command`.
Expand All @@ -44,6 +45,7 @@ pub fn parse(args: List(String)) -> Result(types.Command, String) {
case args {
[] -> Ok(types.Help)
["help", ..] -> Ok(types.Help)
["dash"] -> Ok(types.Dash)
["init", ..rest] -> parse_init(rest)
["reset", ..rest] -> parse_reset(rest)
["plan", ..rest] -> parse_plan(rest)
Expand Down Expand Up @@ -254,7 +256,6 @@ fn parse_start_flags(
parse_start_flags(rest, types.LatestRun, ui_enabled)
["--run", run_id, ..rest] ->
parse_start_flags(rest, types.RunId(run_id), ui_enabled)
["--ui", ..rest] -> parse_start_flags(rest, run, True)
[flag, ..] -> Error("Unsupported start flag: " <> flag)
}
}
Expand All @@ -270,16 +271,11 @@ fn parse_resume_flags(
explain_only: Bool,
) -> Result(types.Command, String) {
case args {
[] ->
case ui_enabled && explain_only {
True -> Error("`resume --explain` cannot be combined with `--ui`.")
False -> Ok(types.Resume(run, ui_enabled, explain_only))
}
[] -> Ok(types.Resume(run, ui_enabled, explain_only))
["--run", "latest", ..rest] ->
parse_resume_flags(rest, types.LatestRun, ui_enabled, explain_only)
["--run", run_id, ..rest] ->
parse_resume_flags(rest, types.RunId(run_id), ui_enabled, explain_only)
["--ui", ..rest] -> parse_resume_flags(rest, run, True, explain_only)
["--explain", ..rest] -> parse_resume_flags(rest, run, ui_enabled, True)
[flag, ..] -> Error("Unsupported flag: " <> flag)
}
Expand Down
Loading
Loading