import {
  recordObjectiveStateSnapshot
} from "./chunk-LOBRX7VD.js";
import "./chunk-DGXUHMOV.js";
import "./chunk-LPSF4OQH.js";
import "./chunk-PZ5AY32C.js";

// src/objective-state-writers.ts
import crypto from "crypto";
function hashSha256(value) {
  return crypto.createHash("sha256").update(value).digest("hex");
}
function isRecord(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
function optionalString(value) {
  if (typeof value !== "string") return void 0;
  const trimmed = value.trim();
  return trimmed.length > 0 ? trimmed : void 0;
}
function toolNameTokens(toolName) {
  if (!toolName) return [];
  return toolName.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
}
function normalizedToolName(toolName) {
  return toolNameTokens(toolName).join("_");
}
function parseToolArguments(value) {
  if (isRecord(value)) return value;
  if (typeof value !== "string") return void 0;
  try {
    const parsed = JSON.parse(value);
    return isRecord(parsed) ? parsed : void 0;
  } catch {
    return void 0;
  }
}
function extractTextContent(value) {
  if (typeof value === "string") return value.trim();
  if (Array.isArray(value)) {
    return value.map((block) => {
      if (typeof block === "string") return block.trim();
      if (isRecord(block) && block.type === "text" && typeof block.text === "string") {
        return block.text.trim();
      }
      return "";
    }).filter((item) => item.length > 0).join("\n");
  }
  if (isRecord(value)) {
    return JSON.stringify(value);
  }
  return "";
}
function parseToolResultPayload(content) {
  const text = extractTextContent(content);
  if (text.length === 0) return void 0;
  try {
    return JSON.parse(text);
  } catch {
    return text;
  }
}
function resultHash(value) {
  if (value === void 0) return void 0;
  const canonical = typeof value === "string" ? value : JSON.stringify(value);
  if (!canonical || canonical.length === 0) return void 0;
  return `sha256:${hashSha256(canonical)}`;
}
function getToolCallContexts(messages) {
  const contexts = /* @__PURE__ */ new Map();
  for (const message of messages) {
    if (message.role !== "assistant") continue;
    const toolCalls = message.tool_calls ?? message.toolCalls;
    if (!Array.isArray(toolCalls)) continue;
    for (const call of toolCalls) {
      if (!isRecord(call)) continue;
      const toolCallId = optionalString(call.id) ?? optionalString(call.toolCallId);
      if (!toolCallId) continue;
      const fn = isRecord(call.function) ? call.function : void 0;
      const toolName = optionalString(fn?.name) ?? optionalString(call.name);
      const args = parseToolArguments(fn?.arguments) ?? parseToolArguments(call.arguments) ?? parseToolArguments(call.args) ?? parseToolArguments(call.input);
      contexts.set(toolCallId, { toolCallId, toolName, args });
    }
  }
  return contexts;
}
function toolCallIdForMessage(message) {
  return optionalString(message.tool_call_id) ?? optionalString(message.toolCallId) ?? optionalString(message.tool_use_id) ?? optionalString(message.toolUseId);
}
function toolNameForMessage(message, context) {
  return optionalString(message.name) ?? optionalString(message.toolName) ?? optionalString(message.tool) ?? context?.toolName;
}
function pickString(args, keys) {
  if (!args) return void 0;
  for (const key of keys) {
    const value = optionalString(args[key]);
    if (value) return value;
  }
  return void 0;
}
function pickFirstStringArrayValue(args, key) {
  const value = args?.[key];
  if (!Array.isArray(value)) return void 0;
  for (const item of value) {
    const candidate = optionalString(item);
    if (candidate) return candidate;
  }
  return void 0;
}
function fileScopeFromArgs(args) {
  const destinationPath = pickString(args, ["destination", "dest", "targetPath", "target", "to"]) ?? pickString(args, ["path", "filePath", "workspacePath", "projectPath"]) ?? pickFirstStringArrayValue(args, "paths");
  const sourcePath = pickString(args, ["source", "src", "from", "oldPath"]);
  const scope = destinationPath ?? sourcePath;
  return { scope, sourcePath, destinationPath };
}
function fileContentHash(args) {
  const content = pickString(args, ["content", "patch", "diff", "text", "value"]) ?? args?.updates;
  return resultHash(content);
}
function inferOutcome(message, parsedPayload) {
  if (message.isError === true) return "failure";
  if (isRecord(parsedPayload)) {
    if (parsedPayload.partial === true || parsedPayload.status === "partial") return "partial";
    if (parsedPayload.success === false || parsedPayload.ok === false) return "failure";
    if (parsedPayload.success === true || parsedPayload.ok === true) return "success";
    if (typeof parsedPayload.exitCode === "number") {
      return parsedPayload.exitCode === 0 ? "success" : "failure";
    }
    if (optionalString(parsedPayload.error)) return "failure";
    if (parsedPayload.status === "error" || parsedPayload.status === "failed") return "failure";
    if (parsedPayload.status === "ok" || parsedPayload.status === "success") return "success";
  }
  if (typeof parsedPayload === "string") {
    const lowered = parsedPayload.toLowerCase();
    const loweredForFailure = lowered.replace(/\b(?:previously\s+)?failed tests?\s+now\s+pass(?:ed|es)?\b/g, "");
    const hasZeroCountMarker = /\b(?:0|no)\s+(?:errors?|failures?|exceptions?|timeouts?)\b/.test(lowered);
    const loweredForFailureCounts = loweredForFailure.replace(/\b(?:0|no)\s+errors?\b/g, "").replace(/\b(?:0|no)\s+failures?\b/g, "").replace(/\b(?:0|no)\s+exceptions?\b/g, "").replace(/\b(?:0|no)\s+timeouts?\b/g, "");
    const hasNonZeroErrorCounts = /\b[1-9]\d*\s+errors?\b/.test(loweredForFailureCounts);
    const hasNegatedSuccessMarkers = /\b(?:not|did not|didn't|doesn't|isn't|aren't|wasn't|weren't|won't|can't|couldn't|shouldn't|wouldn't)\s+(?:ok|pass|passed|passes|succeeded|success)\b/.test(loweredForFailure);
    const hasSuccessMarkers = /\b(success|succeeded|pass|passes|passed|ok)\b/.test(lowered) || hasZeroCountMarker;
    const hasFailureMarkers = hasNegatedSuccessMarkers || /\b(exceptions?|failed|failures?|fatal|timeouts?|timed out)\b/.test(loweredForFailureCounts) || hasNonZeroErrorCounts || /\berrors?\b/.test(loweredForFailureCounts) || /\b[a-z]+error\b/.test(loweredForFailureCounts) || /\b[a-z]+exception\b/.test(loweredForFailureCounts);
    if (hasFailureMarkers) return "failure";
    if (hasSuccessMarkers) return "success";
  }
  return "unknown";
}
function isProcessTool(toolName, args) {
  const tokens = toolNameTokens(toolName);
  const normalizedName = normalizedToolName(toolName);
  if (pickString(args, ["cmd", "command", "script"])) return true;
  return ["exec", "shell", "bash", "terminal", "run_command", "exec_command"].some(
    (token) => token.includes("_") ? normalizedName === token : tokens.includes(token)
  );
}
function isFileTool(toolName, args) {
  const tokens = toolNameTokens(toolName);
  const fileScope = fileScopeFromArgs(args);
  if (fileScope.scope) return true;
  return ["file", "path", "patch", "directory", "mkdir", "rename", "move"].some(
    (token) => tokens.includes(token)
  );
}
function inferFileChangeKind(toolName, outcome) {
  if (outcome === "failure") return "failed";
  const tokens = toolNameTokens(toolName);
  if (["delete", "remove", "unlink"].some((token) => tokens.includes(token))) return "deleted";
  if (["create", "mkdir", "new"].some((token) => tokens.includes(token))) return "created";
  if (["write", "edit", "patch", "update", "append", "move", "rename"].some((token) => tokens.includes(token))) {
    return "updated";
  }
  return "observed";
}
function buildFileValueRefs(args, changeKind) {
  const { sourcePath, destinationPath, scope } = fileScopeFromArgs(args);
  const contentHash = fileContentHash(args);
  if (changeKind === "failed") {
    if (sourcePath && destinationPath && sourcePath !== destinationPath) {
      return {
        before: { ref: sourcePath },
        after: { ref: destinationPath }
      };
    }
    return {
      before: sourcePath ? { ref: sourcePath } : void 0,
      after: scope ? { ref: scope } : void 0
    };
  }
  if (changeKind === "deleted") {
    return {
      before: scope ? { exists: true, ref: scope } : void 0,
      after: { exists: false }
    };
  }
  if (changeKind === "created") {
    return {
      after: {
        exists: true,
        ref: scope,
        valueHash: contentHash
      }
    };
  }
  if (sourcePath && destinationPath && sourcePath !== destinationPath) {
    return {
      before: { exists: true, ref: sourcePath },
      after: {
        exists: true,
        ref: destinationPath
      }
    };
  }
  return {
    after: {
      exists: true,
      ref: scope,
      valueHash: contentHash
    }
  };
}
function summarizeSnapshot(kind, changeKind, toolName, scope) {
  const action = changeKind === "executed" ? "Executed" : changeKind === "failed" ? "Failed" : changeKind === "created" ? "Created" : changeKind === "deleted" ? "Deleted" : changeKind === "updated" ? "Updated" : "Observed";
  if (kind === "process") return `${action} process via ${toolName}: ${scope}`;
  if (kind === "file") return `${action} file via ${toolName}: ${scope}`;
  return `${action} tool result from ${toolName}: ${scope}`;
}
function buildGenericToolAfterRef(outcome, parsedPayload) {
  const valueHash = resultHash(parsedPayload);
  return valueHash ? { valueHash } : { exists: outcome !== "failure" };
}
function snapshotIdFor(sessionKey, recordedAt, index, toolName, scope) {
  const digest = crypto.createHash("sha256").update(`${sessionKey}|${recordedAt}|${index}|${toolName}|${scope}`).digest("hex").slice(0, 12);
  return `obj-${digest}`;
}
function deriveObjectiveStateSnapshotsFromAgentMessages(options) {
  const toolCallsById = getToolCallContexts(options.messages);
  const snapshots = [];
  for (const message of options.messages) {
    if (message.role !== "tool") continue;
    const toolCallId = toolCallIdForMessage(message);
    const context = toolCallId ? toolCallsById.get(toolCallId) : void 0;
    const toolName = toolNameForMessage(message, context);
    if (!toolName) continue;
    const parsedPayload = parseToolResultPayload(message.content);
    const outcome = inferOutcome(message, parsedPayload);
    const args = context?.args;
    const command = pickString(args, ["cmd", "command", "script"]);
    let kind = "tool";
    let changeKind = outcome === "failure" ? "failed" : "observed";
    let scope = toolName;
    let before;
    let after;
    if (isProcessTool(toolName, args)) {
      kind = "process";
      changeKind = outcome === "failure" ? "failed" : "executed";
      scope = command ?? toolName;
      after = { exists: outcome !== "failure", valueHash: resultHash(parsedPayload) };
    } else if (isFileTool(toolName, args)) {
      kind = "file";
      changeKind = inferFileChangeKind(toolName, outcome);
      const fileScope = fileScopeFromArgs(args);
      scope = fileScope.scope ?? toolName;
      const refs = buildFileValueRefs(args, changeKind);
      before = refs.before;
      after = refs.after;
    } else {
      after = buildGenericToolAfterRef(outcome, parsedPayload);
    }
    snapshots.push({
      schemaVersion: 1,
      snapshotId: snapshotIdFor(options.sessionKey, options.recordedAt, snapshots.length, toolName, scope),
      recordedAt: options.recordedAt,
      sessionKey: options.sessionKey,
      source: "tool_result",
      kind,
      changeKind,
      scope,
      summary: summarizeSnapshot(kind, changeKind, toolName, scope),
      toolName,
      command,
      outcome,
      before,
      after,
      tags: ["agent-end", `tool:${toolName}`],
      metadata: toolCallId ? { toolCallId } : void 0
    });
  }
  return snapshots;
}
async function recordObjectiveStateSnapshotsFromAgentMessages(options) {
  if (!options.objectiveStateMemoryEnabled || !options.objectiveStateSnapshotWritesEnabled) {
    return { snapshots: [], filePaths: [] };
  }
  const snapshots = deriveObjectiveStateSnapshotsFromAgentMessages({
    sessionKey: options.sessionKey,
    recordedAt: options.recordedAt,
    messages: options.messages
  });
  const filePaths = [];
  for (const snapshot of snapshots) {
    filePaths.push(
      await recordObjectiveStateSnapshot({
        memoryDir: options.memoryDir,
        objectiveStateStoreDir: options.objectiveStateStoreDir,
        snapshot
      })
    );
  }
  return { snapshots, filePaths };
}
export {
  deriveObjectiveStateSnapshotsFromAgentMessages,
  recordObjectiveStateSnapshotsFromAgentMessages
};
//# sourceMappingURL=objective-state-writers.js.map