harn-stdlib 0.8.33

Embedded Harn standard library source catalog
Documentation
// std/run_artifacts - directory-backed run artifact helpers for harnesses.
import { is_dir, read_json, write_json, write_lines } from "std/fs"

type RunArtifactsOpenOptions = {root?: string, namespace?: string, run_id?: string}

type RunArtifactsListOptions = {root?: string, namespace?: string, limit?: int}

type RunArtifactWriteOptions = {pretty?: bool, trailing_newline?: bool, ensure_parent?: bool}

fn __run_artifacts_required_text(value, label) -> string {
  let text = trim(to_string(value ?? ""))
  if text == "" {
    throw "std/run_artifacts: " + label + " is required"
  }
  return text
}

fn __run_artifacts_clean_relative(value, label) -> string {
  let raw = __run_artifacts_required_text(value, label)
  let posix = path_to_posix(raw)
  if path_is_absolute(posix) {
    throw "std/run_artifacts: " + label + " must be relative"
  }
  for segment in path_segments(posix) {
    if segment == ".." {
      throw "std/run_artifacts: " + label + " must not contain '..'"
    }
  }
  let normalized = path_normalize(posix)
  if normalized == "." || normalized == "" {
    throw "std/run_artifacts: " + label + " is required"
  }
  if normalized == ".." || starts_with(normalized, "../") {
    throw "std/run_artifacts: " + label + " must stay inside the run directory"
  }
  return normalized
}

fn __run_artifacts_clean_segment(value, label) -> string {
  let clean = __run_artifacts_clean_relative(value, label)
  if contains(clean, "/") {
    throw "std/run_artifacts: " + label + " must be one path segment"
  }
  return clean
}

fn __run_artifacts_root(options) -> string {
  let opts = options ?? {}
  let root = to_string(opts?.root ?? runtime_paths().run_root)
  if root == "" {
    throw "std/run_artifacts: root is required"
  }
  return path_normalize(root)
}

fn __run_artifacts_namespace(options) {
  let raw = trim(to_string((options ?? {})?.namespace ?? ""))
  if raw == "" {
    return nil
  }
  return __run_artifacts_clean_relative(raw, "namespace")
}

fn __run_artifacts_kind_dir(root, kind, namespace) -> string {
  if namespace == nil {
    return path_join(root, kind)
  }
  return path_join(root, namespace, kind)
}

fn __run_artifacts_default_run_id() -> string {
  return to_string(to_int(harness.clock.timestamp())) + "-" + uuid_v7()
}

fn __run_artifacts_run_dir(run) -> string {
  let dir = to_string(run?.dir ?? "")
  if dir == "" {
    throw "std/run_artifacts: run.dir is required"
  }
  return dir
}

fn __run_artifacts_path(run, name) -> string {
  let rel = __run_artifacts_clean_relative(name, "artifact path")
  let root = path_normalize(__run_artifacts_run_dir(run))
  let joined = path_normalize(path_join(root, rel))
  let relative = path_relative_to(joined, root)
  if relative == nil || relative == ".." || starts_with(relative, "../") {
    throw "std/run_artifacts: artifact path must stay inside the run directory"
  }
  return joined
}

fn __run_artifacts_standard_paths(run) -> dict {
  return {
    facts: __run_artifacts_path(run, "facts.json"),
    audit: __run_artifacts_path(run, "audit.json"),
    review: __run_artifacts_path(run, "review.md"),
    agent_result: __run_artifacts_path(run, "agent-result.json"),
    agent_trace: __run_artifacts_path(run, "agent-trace.json"),
    agent_llm_transcript: __run_artifacts_path(run, "agent-llm/llm_transcript.jsonl"),
  }
}

fn __run_artifacts_make_run(kind, namespace, root, run_id, dir, modified = nil) -> dict {
  let base = {kind: kind, namespace: namespace, run_id: run_id, root: root, dir: dir, modified: modified}
  return base + {paths: __run_artifacts_standard_paths(base)}
}

/**
 * Create or resolve a run artifact directory below the configured run root.
 *
 * @effects: [fs.write]
 * @allocation: heap
 * @errors: [validation, fs]
 * @api_stability: stable
 * @example: run_artifacts_open("release", {root: root, run_id: "run-1"})
 */
pub fn run_artifacts_open(kind: string, options: RunArtifactsOpenOptions = {}) -> dict {
  let opts = options ?? {}
  let clean_kind = __run_artifacts_clean_segment(kind, "kind")
  let namespace = __run_artifacts_namespace(opts)
  let root = __run_artifacts_root(opts)
  let run_id = if opts.run_id == nil {
    __run_artifacts_default_run_id()
  } else {
    __run_artifacts_clean_segment(opts.run_id, "run_id")
  }
  let dir = path_join(__run_artifacts_kind_dir(root, clean_kind, namespace), run_id)
  harness.fs.mkdir(dir)
  return __run_artifacts_make_run(clean_kind, namespace, root, run_id, dir)
}

/**
 * Return an artifact path inside `run.dir`, rejecting absolute paths and traversal.
 *
 * @effects: []
 * @allocation: heap
 * @errors: [validation]
 * @api_stability: stable
 * @example: run_artifact_path(run, "facts.json")
 */
pub fn run_artifact_path(run: dict, name: string) -> string {
  return __run_artifacts_path(run, name)
}

/**
 * Write a JSON artifact using the standard `std/fs.write_json` conventions.
 *
 * @effects: [fs.write]
 * @allocation: heap
 * @errors: [validation, fs]
 * @api_stability: stable
 * @example: run_artifact_write_json(run, "facts.json", facts, {pretty: true})
 */
pub fn run_artifact_write_json(
  run: dict,
  name: string,
  value,
  options: RunArtifactWriteOptions = {},
) {
  write_json(run_artifact_path(run, name), value, options ?? {})
}

/**
 * Read a JSON artifact, returning `fallback` when the file is missing or malformed.
 *
 * @effects: [fs.read]
 * @allocation: heap
 * @errors: [validation]
 * @api_stability: stable
 * @example: run_artifact_read_json(run, "facts.json", {})
 */
pub fn run_artifact_read_json(run: dict, name: string, fallback = nil) {
  return read_json(run_artifact_path(run, name), fallback)
}

/**
 * Write a text artifact with standard parent-directory and newline handling.
 *
 * @effects: [fs.write]
 * @allocation: heap
 * @errors: [validation, fs]
 * @api_stability: stable
 * @example: run_artifact_write_text(run, "review.md", body)
 */
pub fn run_artifact_write_text(
  run: dict,
  name: string,
  text: string,
  options: RunArtifactWriteOptions = {},
) {
  write_lines(run_artifact_path(run, name), [text ?? ""], options ?? {})
}

/**
 * Read a text artifact, returning `fallback` when it cannot be read.
 *
 * @effects: [fs.read]
 * @allocation: heap
 * @errors: [validation]
 * @api_stability: stable
 * @example: run_artifact_read_text(run, "review.md", "")
 */
pub fn run_artifact_read_text(run: dict, name: string, fallback = nil) {
  let result = try {
    harness.fs.read_text(run_artifact_path(run, name))
  }
  if is_ok(result) {
    return unwrap(result)
  }
  return fallback
}

/**
 * Return the transcript sidecar directory for a run without creating it.
 *
 * @effects: []
 * @allocation: heap
 * @errors: [validation]
 * @api_stability: stable
 * @example: run_artifact_transcript_dir(run, "agent-llm")
 */
pub fn run_artifact_transcript_dir(run: dict, name: string = "agent-llm") -> string {
  let dir_name = if trim(to_string(name ?? "")) == "" {
    "agent-llm"
  } else {
    name
  }
  return run_artifact_path(run, dir_name)
}

/**
 * Return the standard JSONL transcript sidecar path for a named transcript directory.
 *
 * @effects: []
 * @allocation: heap
 * @errors: [validation]
 * @api_stability: stable
 * @example: run_artifact_transcript_path(run, "agent-llm")
 */
pub fn run_artifact_transcript_path(run: dict, name: string = "agent-llm") -> string {
  let dir_name = if trim(to_string(name ?? "")) == "" {
    "agent-llm"
  } else {
    name
  }
  return run_artifact_path(run, path_join(dir_name, "llm_transcript.jsonl"))
}

/**
 * List recent run artifact directories newest-first for a kind.
 *
 * @effects: [fs.read]
 * @allocation: heap
 * @errors: [validation]
 * @api_stability: stable
 * @example: run_artifacts_list("release", {limit: 5})
 */
pub fn run_artifacts_list(kind: string, options: RunArtifactsListOptions = {}) -> list<dict> {
  let opts = options ?? {}
  let clean_kind = __run_artifacts_clean_segment(kind, "kind")
  let namespace = __run_artifacts_namespace(opts)
  let root = __run_artifacts_root(opts)
  let limit = to_int(opts.limit ?? 20) ?? 20
  if limit <= 0 {
    return []
  }
  let kind_dir = __run_artifacts_kind_dir(root, clean_kind, namespace)
  if !is_dir(kind_dir) {
    return []
  }
  let names_result = try {
    harness.fs.list_dir(kind_dir)
  }
  if !is_ok(names_result) {
    return []
  }
  var rows = []
  for name in unwrap(names_result) {
    let dir = path_join(kind_dir, name)
    let info = try {
      harness.fs.stat(dir)
    }
    if is_ok(info) && unwrap(info)?.is_dir ?? false {
      let stat = unwrap(info)
      rows = rows.push(__run_artifacts_make_run(clean_kind, namespace, root, name, dir, stat?.modified))
    }
  }
  return rows
    .sort_by(
    { row ->
      let modified = row.modified ?? 0
      return pair(0 - modified, row.run_id ?? "")
    },
  )
    .take(limit)
    .to_list()
}

/**
 * Reconstruct the run artifact shape from an existing directory path without writing.
 *
 * @effects: []
 * @allocation: heap
 * @errors: [validation]
 * @api_stability: stable
 * @example: run_artifacts_from_dir("release", previous_dir)
 */
pub fn run_artifacts_from_dir(kind: string, dir: string) -> dict {
  let clean_kind = __run_artifacts_clean_segment(kind, "kind")
  let clean_dir = path_normalize(__run_artifacts_required_text(dir, "dir"))
  let run_id = __run_artifacts_clean_segment(path_basename(clean_dir), "run_id")
  let root = path_parent(path_parent(clean_dir))
  return __run_artifacts_make_run(clean_kind, nil, root, run_id, clean_dir)
}