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
11 changes: 8 additions & 3 deletions .codex/skills/qa-night-shift/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,9 @@ 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
11. use `night-shift dash` when the QA pass needs browser-visible guided init,
bootstrap, SSE, DAG/detail sync, command, audit, or raw artifact
validation

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

Expand All @@ -145,8 +146,12 @@ 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` guided init can move an uninitialized repo into
the normal initialized workspace without restarting Dash
- whether `night-shift dash` bootstrap and SSE payloads stay aligned with the
journal-backed repo-state snapshot
- whether the Dash workspace shows the pending or active DAG with synchronized
graph, list, and detail panes wired to the persisted task metadata
- 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 @@ -180,7 +185,7 @@ In review-driven runs, pay attention to repo-state evidence:
- 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
without scraping command output or inventing a separate control plane
- 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: 5 additions & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,9 @@ If you want a dry proof that the end-to-end harness is wired correctly:

```sh
night-shift --demo
night-shift --demo --ui
night-shift dash
```

`night-shift --demo` keeps validating the fixture-backed CLI flow. Use
`night-shift dash` when you want the real browser workspace and its live audit
surface.
9 changes: 6 additions & 3 deletions docs/providers-and-delivery.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,10 @@ leave that disabled and still use the PR-body overlay.
The local dashboard now uses `night-shift dash`. It binds to `127.0.0.1` and
serves a Dash backend for:

- structured bootstrap state for the current repository
- SSE-first live updates
- structured bootstrap state for the current repository, including init state,
selected-run audit data, DAG metadata, repo-state drift, delivery context,
and runtime identity
- SSE-first live updates for the selected run and audit surface
- browser command handlers for `init`, `plan`, `plan --from-reviews`,
`resolve`, `start`, and `resume`
- audit and raw artifact routes for reports, provenance, logs, payloads, and
Expand All @@ -128,7 +130,8 @@ shelling out to `night-shift` subprocesses.

`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 Dash bootstrap plus browser-command execution as well.
The UI demo validates Dash bootstrap plus browser-command execution as well,
but the supported human entrypoint is `night-shift dash`.

Demo artifacts live under:

Expand Down
6 changes: 5 additions & 1 deletion docs/run-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,17 @@ and the next action becomes `night-shift start`.
night-shift doctor
night-shift resume --explain
night-shift resume
night-shift resume --run run-123 --ui
night-shift dash
```

Night Shift reloads the saved run, validates the saved environment, recovers
in-flight tasks, and continues orchestration. It does not re-resolve provider
or environment settings; it reuses what the run journal already saved.

Use `night-shift dash` when you want the browser workflow for the same durable
run state. Use `resume --explain` and `resume` when you prefer the CLI
recovery path.

`doctor` and `resume --explain` are the read-only recovery surfaces. They
inspect the saved run, active lock, worktrees, logs, review drift, and
interrupted task states, then classify each task as `safe_to_resume`,
Expand Down
11 changes: 3 additions & 8 deletions src/night_shift/app.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -134,20 +134,15 @@ fn run_initialized_command(
)
Error(message) -> message
})
types.Start(run, False) -> io.println(start(repo_root, run, config))
types.Start(run) -> io.println(start(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) ->
io.println(provenance(repo_root, run, task_id, format, config))
types.Doctor(run) -> io.println(doctor(repo_root, run, config))
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, 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`.",
)
types.Resume(run, False) -> io.println(resume(repo_root, run, config))
types.Resume(run, True) -> io.println(doctor(repo_root, run, config))
_ -> io.println("Unsupported command.")
}
}
Expand Down
24 changes: 10 additions & 14 deletions src/night_shift/cli.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub fn usage() -> String {
///
/// ```gleam
/// > parse(["start", "--run", "latest"])
/// Ok(types.Start(types.LatestRun, False))
/// Ok(types.Start(types.LatestRun))
/// ```
///
/// ```gleam
Expand Down Expand Up @@ -225,7 +225,7 @@ fn parse_init_flags(
}

fn parse_start(args: List(String)) -> Result(types.Command, String) {
parse_start_flags(args, types.LatestRun, False)
parse_start_flags(args, types.LatestRun)
}

fn parse_reset(args: List(String)) -> Result(types.Command, String) {
Expand All @@ -248,35 +248,31 @@ fn parse_reset_flags(
fn parse_start_flags(
args: List(String),
run: types.RunSelector,
ui_enabled: Bool,
) -> Result(types.Command, String) {
case args {
[] -> Ok(types.Start(run, ui_enabled))
["--run", "latest", ..rest] ->
parse_start_flags(rest, types.LatestRun, ui_enabled)
["--run", run_id, ..rest] ->
parse_start_flags(rest, types.RunId(run_id), ui_enabled)
[] -> Ok(types.Start(run))
["--run", "latest", ..rest] -> parse_start_flags(rest, types.LatestRun)
["--run", run_id, ..rest] -> parse_start_flags(rest, types.RunId(run_id))
[flag, ..] -> Error("Unsupported start flag: " <> flag)
}
}

fn parse_resume(args: List(String)) -> Result(types.Command, String) {
parse_resume_flags(args, types.LatestRun, False, False)
parse_resume_flags(args, types.LatestRun, False)
}

fn parse_resume_flags(
args: List(String),
run: types.RunSelector,
ui_enabled: Bool,
explain_only: Bool,
) -> Result(types.Command, String) {
case args {
[] -> Ok(types.Resume(run, ui_enabled, explain_only))
[] -> Ok(types.Resume(run, explain_only))
["--run", "latest", ..rest] ->
parse_resume_flags(rest, types.LatestRun, ui_enabled, explain_only)
parse_resume_flags(rest, types.LatestRun, explain_only)
["--run", run_id, ..rest] ->
parse_resume_flags(rest, types.RunId(run_id), ui_enabled, explain_only)
["--explain", ..rest] -> parse_resume_flags(rest, run, ui_enabled, True)
parse_resume_flags(rest, types.RunId(run_id), explain_only)
["--explain", ..rest] -> parse_resume_flags(rest, run, True)
[flag, ..] -> Error("Unsupported flag: " <> flag)
}
}
Expand Down
Loading