version: '3'

# Consumer engine resolution (#2022 Phase 3).
#
# Framework-source checkouts invoke the vendored `packages/cli/dist/bin.js`.
# npm consumer deposits copy @deftai/directive-content only — no bundled CLI —
# so tasks fall back to the globally installed `deft` / `directive` command.
# A deposit marker (package.json deftConsumerDeposit / .deft-consumer-deposit /
# @deftai/directive-content name) forces that fallback for every verb (#3324).

vars:
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'

tasks:
  pm-run:
    internal: true
    desc: "Run a package.json script via pnpm (bare or Corepack pin) or explicit DEFT_PACKAGE_MANAGER=npm (#2410)."
    # Run from USER_WORKING_DIR, NOT an absolute DEFT_ROOT `dir:` — Windows go-task
    # doubles absolute dirs onto the invocation cwd (`C:\repo\C:\repo`, #2126 / #2467).
    # The node script still receives absolute DEFT_ROOT as argv and uses it as cwd.
    dir: '{{.USER_WORKING_DIR}}'
    cmds:
      - |
        set -eu
        node "{{.TASKFILE_DIR}}/engine-pm-run.cjs" "{{.DEFT_ROOT}}" "{{.PM_SCRIPT}}"

  _ts-build:
    internal: true
    desc: "Build CLI dist from the framework source checkout; no-op on consumer deposits (#2022 / #2126 / #3324)."
    # Run from the operator project root (USER_WORKING_DIR), NOT an absolute
    # DEFT_ROOT: an absolute `dir:` doubles onto the invocation cwd on Windows
    # when the Taskfile is invoked via `task -t <absolute-path>` (observed as
    # `D:\a\directive\directive\D:\a\directive\directive`, #2126). Reference the
    # build root by absolute path so the guard stays cwd-independent.
    #
    # Guard on buildability, not source presence alone (#2142): a cold framework
    # checkout has packages/cli/package.json AND a root `build` script, so it
    # still builds when dist/ is gitignored/absent. A clean npm consumer deposit
    # ships no packages/ tree (guard false -> no-op, #2126). Git-vendored-payload
    # repos may carry a stray packages/ under .deft/core without a root `build`
    # script — source-only presence must NOT run `pnpm run build` there.
    #
    # Warm-dist skip (#2563): when packages/cli/dist/bin.js is newer than
    # packages/{cli,core,types} sources, skip rebuild. Override with
    # DEFT_FORCE_TS_BUILD=1; force-skip with DEFT_SKIP_TS_BUILD=1.
    dir: '{{.USER_WORKING_DIR}}'
    cmds:
      - |
        set -eu
        # #3324: consumer-deposit marker forces a no-op even when stray
        # packages/cli + scripts.build make the tree look buildable.
        if node "{{.TASKFILE_DIR}}/engine-invoke.cjs" is-buildable-source "{{.DEFT_ROOT}}"; then
          if node "{{.TASKFILE_DIR}}/ts-build-fresh.cjs" "{{.DEFT_ROOT}}"; then
            exit 0
          fi
          node "{{.TASKFILE_DIR}}/engine-pm-run.cjs" "{{.DEFT_ROOT}}" build --mark-warm
        fi
        : # no-op -- go-task <3.52.0 treats untaken last if/fi as exit 1 (#3381)

  invoke:
    internal: true
    desc: "Run a deft-ts verb from vendored bin.js (source checkout) or global deft (deposit / runtime fallback #2409 / #3324). Runtime/session verbs must not trigger engine:_ts-build / pnpm (#2181)."
    # Run from the operator project root so deft verbs resolve USER_WORKING_DIR
    # correctly; without this, included engine.yml defaults cwd to tasks/ (#2022).
    dir: '{{.USER_WORKING_DIR}}'
    # Operator free-text (e.g. release --summary with apostrophes) must not be
    # interpolated into the shell script body — JSON env transport + argv-spawn in
    # tasks/engine-invoke.cjs (#2547). Avoids shell parse breaks for `'` and `\`.
    env:
      DEFT_ENGINE_CMD_JSON: '{{ .ENGINE_CMD | toSlash | toJson }}'
    cmds:
      - |
        set -eu
        bin="{{.DEFT_ROOT}}/packages/cli/dist/bin.js"
        root_pkg="{{.DEFT_ROOT}}/package.json"
        # #3324: deposit marker (package.json field / file / content-package
        # name) forces is_buildable_source=0 so every verb uses global CLI.
        is_buildable_source=0
        if node "{{.TASKFILE_DIR}}/engine-invoke.cjs" is-buildable-source "{{.DEFT_ROOT}}"; then
          is_buildable_source=1
        fi
        if [ -f "$bin" ]; then
          if [ "$is_buildable_source" = 1 ] && [ -f "$root_pkg" ]; then
            node -e "
              const fs=require('fs');
              const pkg=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));
              const req=pkg.engines&&pkg.engines.node;
              if(!req) process.exit(0);
              const major=Number(process.versions.node.split('.')[0]);
              const m=String(req).match(/>=\\s*(\\d+)/);
              if(m&&major<Number(m[1])){
                console.error('deft: Node '+process.versions.node+' does not satisfy engines.node '+req+' (read from '+process.argv[1]+').');
                process.exit(2);
              }
            " "$root_pkg" || exit $?
          fi
          node "{{.TASKFILE_DIR}}/engine-invoke.cjs" vendored "$bin"
        elif [ "$is_buildable_source" = 1 ]; then
          first_token=$(node -e "process.stdout.write(JSON.parse(process.env.DEFT_ENGINE_CMD_JSON||'\"\"').split(/\\s+/)[0]||'')")
          is_runtime_verb=0
          case " ${first_token} " in
            " session:start "|" session-start "|\
            " session:ready "|" session-ready "|\
            " occupancy:steal "|" occupancy-steal "|\
            " occupancy:release "|" occupancy-release "|\
            " occupancy:heartbeat "|" occupancy-heartbeat "|\
            " occupancy:grant "|" occupancy-grant "|\
            " session:end "|" session-end "|\
            " lifecycle:event "|" lifecycle-event "|\
            " verify:session-ritual "|" verify-session-ritual "|\
            " verify:tools "|" verify-tools "|\
            " triage:summary "|" triage-summary "|\
            " triage:welcome "|" triage-welcome "|\
            " verify:cache-fresh "|" verify-cache-fresh "|\
            " preflight-cache ")
              is_runtime_verb=1
              ;;
          esac
          if [ "${DEFT_USE_GLOBAL_CLI:-}" = "1" ]; then
            is_runtime_verb=1
          fi
          global_cli=""
          if command -v deft >/dev/null 2>&1; then
            global_cli=deft
          elif command -v directive >/dev/null 2>&1; then
            global_cli=directive
          fi
          if [ "$is_runtime_verb" = 1 ] && [ -n "$global_cli" ]; then
            node -e "
              const {execFileSync}=require('child_process');
              const root=process.argv[1];
              const cli=process.argv[2];
              let srcVer='0.0.0-dev';
              try{
                if(process.env.DEFT_RELEASE_VERSION){
                  srcVer=process.env.DEFT_RELEASE_VERSION;
                }else{
                  srcVer=execFileSync('git',['describe','--tags','--abbrev=0'],{cwd:root,encoding:'utf8'}).trim().replace(/^v/,'');
                }
              }catch{}
              let globalVer='unknown';
              try{
                globalVer=execFileSync(cli,['--version'],{encoding:'utf8'}).trim();
              }catch{}
              const m=globalVer.match(/@([0-9]+\\.[0-9]+\\.[0-9]+)/)||globalVer.match(/([0-9]+\\.[0-9]+\\.[0-9]+)/);
              const gv=m?m[1]:globalVer;
              if(srcVer!=='0.0.0-dev'&&gv!=='unknown'&&gv!==srcVer){
                console.error('deft: using global '+cli+' ('+gv+'); source checkout is v'+srcVer+' — run task build for a local engine match.');
              }
            " "{{.DEFT_ROOT}}" "$global_cli" >&2 || true
            node "{{.TASKFILE_DIR}}/engine-invoke.cjs" global "$global_cli"
          else
            echo "deft: CLI artifact missing at {{.DEFT_ROOT}}/packages/cli/dist/bin.js" >&2
            if [ "$is_runtime_verb" = 1 ]; then
              echo "  Install global deft: npm i -g @deftai/directive" >&2
              echo "  Or run \`task build\` first (framework source checkout)." >&2
            else
              echo "  Run \`task build\` first (framework source checkout)." >&2
            fi
            exit 2
          fi
        elif command -v deft >/dev/null 2>&1; then
          node "{{.TASKFILE_DIR}}/engine-invoke.cjs" global deft
        elif command -v directive >/dev/null 2>&1; then
          node "{{.TASKFILE_DIR}}/engine-invoke.cjs" global directive
        else
          echo "deft: neither {{.DEFT_ROOT}}/packages/cli/dist/bin.js nor a global deft command is available." >&2
          echo "  Install with: npm i -g @deftai/directive" >&2
          exit 2
        fi
