Skip to content

T-B7GN-sdf-locate-sdlc-cli

State: closed/done · Impact: high · Complexity: medium

Every shell-out from SDF to the sdlc CLI hardcodes bun run solutions/ontological/cli/sdlc.ts … with the project root as the working directory. That only works when the registered project is this monorepo. For any other checkout the file does not exist and the spawn fails. SDF needs one seam that finds the sdlc checkout the same way the bash launcher does and invokes it with --project-root <path>, so the watch probe, the dashboard spawn, and the setup action in T-1D8N all work against a foreign project.

LocationRole today
solutions/ontological/desktop/src-tauri/src/backend.rs#sdlcSpawns bun run solutions/ontological/cli/sdlc.ts dashboard … with current_dir(root).
solutions/ontological/desktop/src-tauri/src/actions/watch_probe.rs#probe_argvBuilds the same hardcoded argv for orchestrate watch --dry-run --output json.
solutions/ontological/desktop/src-tauri/src/actions/spawn.rsThe Spawner trait and RecordingSpawner test double; runs an Invocation from a cwd.
solutions/ontological/cli/sdlcThe bash launcher. Resolves the checkout in order: SDLC_HOME, a checkout above $PWD, the link at <config>/sdlc/home, then its own siblings.
packages/rust/fleet/src/lib.rs#standaloneThe Rust fleet SDK’s standalone("sdlc").config() gives the same <config>/sdlc directory the launcher reads home from.
solutions/ontological/cli/registry_adapter.tsEvery registry op accepts --project-root <path>; dashboard start accepts it too.

A new module actions/sdlc_cli.rs with two pure functions and one resolver:

  • resolve_checkout() -> Result<PathBuf, String>: SDLC_HOME when it is a checkout, else the home file under Fleet::standalone("sdlc").config(), else a checkout above SDF’s own cwd. A checkout is a directory containing solutions/ontological/cli/sdlc.ts. The error names every location it tried.
  • invocation(checkout, verb_args, project_root) -> Invocation: program bun, args run <checkout>/solutions/ontological/cli/sdlc.ts <verb…> --project-root <project_root>.
  • Callers run the invocation with cwd = checkout, never the project, so Bun resolves the checkout’s node_modules.

backend.rs#sdlc is rewritten onto it and watch_probe.rs#probe_argv is deleted, its callers going through the shared builder instead. The spawn sets no environment: the launcher’s announce line already goes to stderr, so JSON stdout is clean without silencing anything.

  1. Write actions/sdlc_cli.rs with is_checkout, resolve_checkout, invocation, and a run(verb_args, project_root, spawner) helper that resolves and spawns in one call. The resolver takes its layers as a Layers parameter so unit tests construct them directly against a tempdir checkout and never touch process environment.
  2. Delete watch_probe::probe_argv and route watch_probe::probe through sdlc_cli::run. Its RecordingSpawner tests assert the literal argv, including --project-root, rather than comparing against a helper.
  3. Rewrite backend::sdlc and backend::ensure to resolve the checkout and run dashboard start with --project-root pointing at the checkout itself (the dashboard server scopes per request; its own root is only its fallback). Delete the dev-checkout walk T-FW4Z left there.
  4. Add a SdlcCliUnavailable variant to AppError so the action surface can report “no sdlc checkout found” distinctly from an op failure.
  5. Document the resolution order in the SDF README under Commands.
AreaNote
solutions/ontological/desktop/src-tauri/src/actions/sdlc_cli.rsResolver, argv builder, run helper, unit tests.
solutions/ontological/desktop/src-tauri/src/actions/mod.rsDeclare the module.
solutions/ontological/desktop/src-tauri/src/actions/watch_probe.rsBuild argv through sdlc_cli; tests assert --project-root.
solutions/ontological/desktop/src-tauri/src/backend.rssdlc and ensure go through the resolver.
solutions/ontological/desktop/src-tauri/src/schema/mod.rsAdd the SdlcCliUnavailable error variant.
solutions/ontological/desktop/README.mdDocument how SDF finds the CLI.
  • AC-1: grep -rn "solutions/ontological/cli/sdlc.ts" solutions/ontological/desktop/src-tauri/src matches only actions/sdlc_cli.rs.
  • AC-2: With SDLC_HOME pointing at a fake checkout in a tempdir, resolve_checkout() returns it; with SDLC_HOME unset and a home file under the fleet config tier, it returns that path; with neither and no checkout above cwd, it returns an error naming all three locations tried.
  • AC-3: watch_probe::probe against a registered project at /tmp/x produces argv ending in orchestrate watch --dry-run --output json --project-root /tmp/x, asserted with RecordingSpawner.
  • AC-4: From a registered project that is not this monorepo, orchestrate_watch_probe(project_id) returns a verdict instead of a spawn error (manual check, noted in the PR).
  • AC-5: moon run sdf:check and moon run sdf:test pass.
  • Bundling the CLI or a Bun runtime into the desktop app; SDF still requires bun on PATH and an sdlc checkout on the machine.
  • Any new action (T-1D8N).
  • git and gh spawns in control_plane/ and solutions/ontological/desktop/src-tauri/src/actions/refresh_leases.rs, which do not involve the sdlc CLI.
  • T-FW4Z removes the ambient root that backend::ensure reads today; this task replaces what it leaves behind.

Found while surveying the SDLC setup action for SDF (2026-09-20): the hardcoded argv in backend.rs and watch_probe.rs was the one blocker to running any sdlc verb against a project that is not this repo.

T-FW4Z


← Back to Tasks