#!/bin/sh
# =============================================================================
# plandb — client for the estate's canonical task graph
#
# Runs the plandb CLI INSIDE the plandb-mcp container on node-01, so every shell
# agent speaks to one database. A locally installed binary would read a local
# .plandb.db and quietly create a second, divergent truth — the exact failure
# this stack exists to avoid.
#
# Two refusals, both deliberate:
#
#   use      `plandb use` writes a sticky current_project AND a scope pointer
#            into plandb_meta, a table global to the database file. Two agents
#            sharing it corrupt each other: one scopes into app A's subtree,
#            then the other's plain `plandb add` in app B creates its task as a
#            child of app A's task. Nothing errors. The MCP surface has no
#            equivalent tool, which is why agents are expected to use MCP.
#
#   --db     pointing the CLI at another file defeats the shared store.
#
# Project selection: the CLI's sticky default is unusable here because EVERY
# project-creating command rewrites it — verified, `init` and `project create`
# both set current_project. So this wrapper always passes an explicit
# --project, taken from $PLANDB_PROJECT or the nearest .plandb-project marker.
#
# Only the subcommands that actually accept --project get the flag, verified
# against the v0.2.1 binary. `done`, `next`, `show` and `split` do NOT take it;
# injecting blindly would break the go/done core loop.
#
# Usage:
#   tools/plandb add "Design schema" --description "..." --as schema
#   tools/plandb go
#   tools/plandb status --detail
#   tools/plandb project create some-app     # not project-scoped
# =============================================================================
set -eu

SSH_HOST="${PLANDB_SSH_HOST:-mildgrim@192.168.1.6}"
CONTAINER="${PLANDB_CONTAINER:-plandb-mcp}"

die() {
  printf 'plandb: %s\n' "$1" >&2
  exit 2
}

[ "$#" -ge 1 ] || die "usage: plandb <command> [args...]   (try: plandb --help)"

cmd="$1"
shift

case "$cmd" in
  use)
    die "refused: 'use' writes shared scope state into plandb_meta on the canonical
database, where it silently corrupts other agents' work. Every command this
wrapper runs already carries an explicit --project. If you genuinely need to
zoom into a subtree, do it on a throwaway local database, never here."
    ;;
esac

for arg in "$@"; do
  case "$arg" in
    --db | --db=*)
      die "refused: --db selects a different database, which splits the canonical
task graph. The shared database is the whole point."
      ;;
  esac
done

# Subcommands that accept --project, verified with `plandb <cmd> --help` on
# v0.2.1. Kept as an explicit list rather than a guess.
takes_project=false
case "$cmd" in
  add | list | status | go | search | context | critical-path | bottlenecks | export | import)
    takes_project=true
    ;;
esac

if [ "$takes_project" = true ]; then
  has_project=false
  for arg in "$@"; do
    case "$arg" in
      --project | --project=*) has_project=true ;;
    esac
  done

  if [ "$has_project" = false ]; then
    project="${PLANDB_PROJECT:-}"
    if [ -z "$project" ]; then
      dir=$(pwd)
      while [ "$dir" != "/" ]; do
        if [ -f "$dir/.plandb-project" ]; then
          project=$(tr -d ' \t\r\n' <"$dir/.plandb-project")
          break
        fi
        dir=$(dirname "$dir")
      done
    fi
    [ -n "$project" ] || die "no project selected: set PLANDB_PROJECT or add a
.plandb-project file containing e.g. p-abc123 at the repo root."
    set -- "$@" --project "$project"
  fi
fi

# `watch` is a TUI and needs a tty; everything else works without one.
if [ -t 0 ] && [ -t 1 ]; then
  exec ssh -o BatchMode=yes -t "$SSH_HOST" docker exec -i -t "$CONTAINER" plandb "$cmd" "$@"
else
  exec ssh -o BatchMode=yes "$SSH_HOST" docker exec -i "$CONTAINER" plandb "$cmd" "$@"
fi
