Intelligence

Artifacts

Browse the repository, read documents, and manage the governance folders. Source, runtime, and infrastructure are read-only.

Repository
README.md
CONSTITUTION_COMPLIANCE_AUDIT_V1.mdREADME.md
repositories/aaf-holdings/hq01/lib/missions/work-orders.ts
5.2 KB
import fs from "node:fs";
import path from "node:path";
import { missionDir, readMission } from "./store";
import { getObjective } from "./objectives";
import type {
  CreateWorkOrderInput,
  ExecChainEvent,
  ExecChainEventType,
  WorkOrder,
  WorkOrderStatus,
  WorkOrderView,
} from "./types";

/**
 * Work Orders (PASS M3) — translate an objective into executable organizational
 * work. Stored flat under each mission: MISSION-xxxxx/work-orders/WORKORDER-...,
 * linked to their objective by id. Not assignments, not workers.
 */

export class WorkOrderError extends Error {
  constructor(
    message: string,
    readonly status = 400,
  ) {
    super(message);
    this.name = "WorkOrderError";
  }
}

const WID_RE = /^WORKORDER-\d{6}$/;

function nowIso(): string {
  return new Date().toISOString();
}
function workOrdersDir(mid: string): string {
  return path.join(missionDir(mid), "work-orders");
}
function woDir(mid: string, wid: string): string {
  return path.join(workOrdersDir(mid), wid);
}
function woJson(mid: string, wid: string): string {
  return path.join(woDir(mid, wid), "work-order.json");
}
function woHistory(mid: string, wid: string): string {
  return path.join(woDir(mid, wid), "history", "log.jsonl");
}

function writeJsonAtomic(file: string, data: unknown): void {
  fs.mkdirSync(path.dirname(file), { recursive: true });
  const tmp = `${file}.tmp`;
  fs.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
  fs.renameSync(tmp, file);
}

function append(
  mid: string,
  wid: string,
  type: ExecChainEventType,
  extra: Partial<ExecChainEvent> = {},
): void {
  const file = woHistory(mid, wid);
  fs.mkdirSync(path.dirname(file), { recursive: true });
  const ev: ExecChainEvent = { type, at: nowIso(), ...extra };
  fs.appendFileSync(file, JSON.stringify(ev) + "\n", "utf8");
}

function nextId(mid: string): string {
  let max = 0;
  let entries: fs.Dirent[] = [];
  try {
    entries = fs.readdirSync(workOrdersDir(mid), { withFileTypes: true });
  } catch {
    /* none */
  }
  for (const e of entries) {
    if (e.isDirectory() && WID_RE.test(e.name)) {
      const n = Number(e.name.slice("WORKORDER-".length));
      if (Number.isFinite(n) && n > max) max = n;
    }
  }
  return `WORKORDER-${String(max + 1).padStart(6, "0")}`;
}

export function readWorkOrder(mid: string, wid: string): WorkOrder | null {
  if (!WID_RE.test(wid)) return null;
  try {
    return JSON.parse(fs.readFileSync(woJson(mid, wid), "utf8")) as WorkOrder;
  } catch {
    return null;
  }
}

export function listWorkOrders(mid: string): WorkOrder[] {
  let entries: fs.Dirent[];
  try {
    entries = fs.readdirSync(workOrdersDir(mid), { withFileTypes: true });
  } catch {
    return [];
  }
  return entries
    .filter((e) => e.isDirectory() && WID_RE.test(e.name))
    .map((e) => readWorkOrder(mid, e.name))
    .filter((w): w is WorkOrder => Boolean(w))
    .sort((a, b) => a.id.localeCompare(b.id));
}

function readHistory(mid: string, wid: string): ExecChainEvent[] {
  let raw: string;
  try {
    raw = fs.readFileSync(woHistory(mid, wid), "utf8");
  } catch {
    return [];
  }
  return raw
    .split("\n")
    .filter(Boolean)
    .map((l) => {
      try {
        return JSON.parse(l) as ExecChainEvent;
      } catch {
        return null;
      }
    })
    .filter((e): e is ExecChainEvent => Boolean(e));
}

export function getWorkOrderView(mid: string, wid: string): WorkOrderView | null {
  const work_order = readWorkOrder(mid, wid);
  if (!work_order) return null;
  return {
    work_order,
    history: readHistory(mid, wid).sort((a, b) => b.at.localeCompare(a.at)),
  };
}

export function createWorkOrder(
  mid: string,
  input: CreateWorkOrderInput,
): WorkOrder {
  if (!readMission(mid)) throw new WorkOrderError("Mission not found.", 404);
  if (!input.objective_id || !getObjective(mid, input.objective_id)) {
    throw new WorkOrderError("A valid objective is required.", 400);
  }
  const title = input.title?.trim();
  if (!title) throw new WorkOrderError("Title is required.");
  const description = input.description?.trim();
  if (!description) throw new WorkOrderError("Description is required.");
  const owner = input.owner_executive?.trim();
  if (!owner) throw new WorkOrderError("Owner executive is required.");
  if (!input.priority) throw new WorkOrderError("Priority is required.");

  const id = nextId(mid);
  const created = nowIso();
  const wo: WorkOrder = {
    id,
    mission_id: mid,
    objective_id: input.objective_id,
    title,
    description,
    owner_executive: owner,
    priority: input.priority,
    status: "Draft",
    created_at: created,
    updated_at: created,
  };
  fs.mkdirSync(path.join(woDir(mid, id), "history"), { recursive: true });
  writeJsonAtomic(woJson(mid, id), wo);
  append(mid, id, "work_order_created", { detail: title });
  return wo;
}

export function setWorkOrderStatus(
  mid: string,
  wid: string,
  to: WorkOrderStatus,
): WorkOrder {
  const wo = readWorkOrder(mid, wid);
  if (!wo) throw new WorkOrderError("Work order not found.", 404);
  const from = wo.status;
  const next: WorkOrder = { ...wo, status: to, updated_at: nowIso() };
  writeJsonAtomic(woJson(mid, wid), next);
  append(mid, wid, "state_changed", {
    previous_state: from,
    new_state: to,
    detail: `${from} → ${to}`,
  });
  return next;
}

root · /srv/aaf