harn-stdlib 0.9.8

Embedded Harn standard library source catalog
Documentation
/**
 * `harn canon check` — evaluate harn-canon packs against changed files.
 *
 * The Rust shim owns clap parsing and passes a read-only plan via
 * HARN_CANON_CHECK_PLAN_JSON. This script owns the policy and rendering: it
 * calls std/agent/canon so canon-packs.json remains the routing source of
 * truth, Flow predicates remain harn-canon-owned, and human feedback matches
 * agent-loop injection.
 */
import { canon_evaluate_slice, canon_feedback_text, canon_slice_from_paths } from "std/agent/canon"
import {
  cli_json_envelope,
  safe_bool,
  safe_dict,
  safe_int_string,
  safe_list,
  safe_string,
} from "std/cli/render"

fn __load_plan(harness: Harness) -> dict {
  let raw = harness.env.get_or("HARN_CANON_CHECK_PLAN_JSON", "")
  if raw == "" {
    harness.stdio.eprintln("canon: internal error - HARN_CANON_CHECK_PLAN_JSON not set")
    exit(70)
  }
  return try {
    json_parse(raw)
  } catch (e) {
    harness.stdio.eprintln("canon: internal error - failed to parse check plan: " + to_string(e))
    exit(70)
  }
}

fn __options(plan: dict, slice: dict) -> dict {
  var options = {
    root: safe_string(plan["workspace_root"], ""),
    workspace_root: safe_string(plan["workspace_root"], ""),
    project_root: safe_string(plan["workspace_root"], ""),
    files: safe_list(slice["files"]),
    include_missing: safe_bool(plan["include_missing"], false),
    include_semantic: safe_bool(plan["include_semantic"], false),
    budget_ms: plan["budget_ms"] ?? 50,
  }
  let canon_root = safe_string(plan["canon_root"], "")
  if canon_root != "" {
    options = options + {canon_root: canon_root}
  }
  let packs = safe_list(plan["pack_ids"])
  if len(packs) > 0 {
    options = options + {packs: packs}
  }
  return options
}

fn __join_text(items: list, sep: string) -> string {
  var out = ""
  var first = true
  for item in items {
    let text = safe_string(item, "")
    if text == "" {
      continue
    }
    if !first {
      out = out + sep
    }
    out = out + text
    first = false
  }
  return out
}

fn __pack_summary(result: dict) -> list {
  var summaries = []
  for pack in safe_list(result["packs"]) {
    let report = safe_dict(pack["report"])
    summaries = summaries
      .push(
      {
        pack_id: safe_string(pack["pack_id"], ""),
        title: safe_string(pack["title"], ""),
        status: safe_string(report["status"], ""),
        ok: safe_bool(report["ok"], false),
        record_count: len(safe_list(report["records"])),
        skipped_count: len(safe_list(report["skipped"])),
        invariants: safe_string(pack["invariants"], ""),
      },
    )
  }
  return summaries
}

fn __report(plan: dict, result: dict, feedback: string) -> dict {
  let paths = safe_list(plan["paths"])
  let selected = safe_list(result["selected_pack_ids"])
  return {
    schema_version: 1,
    ok: safe_bool(result["ok"], false),
    status: safe_string(result["status"], ""),
    advisory: safe_bool(plan["advisory"], false),
    workspace_root: safe_string(plan["workspace_root"], ""),
    canon_root: safe_string(plan["canon_root"], ""),
    paths: paths,
    path_count: len(paths),
    selected_pack_ids: selected,
    pack_count: len(selected),
    packs: __pack_summary(result),
    feedback_text: feedback,
    result: result,
  }
}

fn __render_json(harness: Harness, report: dict) {
  let ok = safe_bool(report["ok"], false) || safe_bool(report["advisory"], false)
  if ok {
    harness.stdio
      .println(
      json_stringify_pretty(cli_json_envelope({schema_version: 1, ok: true, data: report})),
    )
    return
  }
  harness.stdio
    .println(
    json_stringify_pretty(
      cli_json_envelope(
        {
          schema_version: 1,
          ok: false,
          error: {
            code: "canon_check_failed",
            message: "harn-canon reported blocking invariant findings",
            details: report,
          },
        },
      ),
    ),
  )
}

fn __render_human(harness: Harness, report: dict) {
  harness.stdio.println("harn-canon check: " + safe_string(report["status"], "unknown"))
  harness.stdio.println("  paths: " + safe_int_string(report["path_count"], "0"))
  let selected = __join_text(safe_list(report["selected_pack_ids"]), ", ")
  if selected == "" {
    harness.stdio.println("  packs: none")
  } else {
    harness.stdio.println("  packs: " + selected)
  }
  let feedback = safe_string(report["feedback_text"], "")
  if feedback != "" {
    harness.stdio.println("")
    harness.stdio.println(feedback)
  } else if safe_string(report["status"], "") == "no_packs" {
    harness.stdio.println("")
    harness.stdio
      .println("No harn-canon packs selected. Pass --pack or configure canon-packs.json routing.")
  } else {
    harness.stdio.println("")
    harness.stdio.println("No harn-canon findings.")
  }
}

fn main(harness: Harness) -> int {
  let plan = __load_plan(harness)
  let slice = canon_slice_from_paths(
    safe_list(plan["paths"]),
    {
      root: safe_string(plan["workspace_root"], ""),
      workspace_root: safe_string(plan["workspace_root"], ""),
      include_missing: safe_bool(plan["include_missing"], false),
    },
  )
  let result = canon_evaluate_slice(slice, __options(plan, slice))
  let feedback = canon_feedback_text(result, {header: safe_string(plan["feedback_header"], "harn-canon feedback")})
  let report = __report(plan, result, feedback)
  let json_mode = harness.env.get_or("HARN_OUTPUT_JSON", "0") == "1"
  if json_mode {
    __render_json(harness, report)
  } else {
    __render_human(harness, report)
  }
  if safe_bool(report["ok"], false) || safe_bool(report["advisory"], false) {
    return 0
  }
  return 1
}