import {
  authenticateToolRequest
} from "./chunk-3EJ6SFJI.js";
import {
  ToolInputError,
  findCustomTool,
  isAppToolName
} from "./chunk-YEFFHORB.js";
import {
  base64UrlDecodeText,
  base64UrlEncodeText,
  constantTimeEqual,
  hmacSha256Base64Url
} from "./chunk-S5SRJJQG.js";

// src/tools/capability.ts
async function createCapabilityToken(userId, opts) {
  const secret = opts.secret?.trim();
  if (!secret) return void 0;
  const prefix = opts.prefix ?? "cap_";
  return `${prefix}${await sign(userId, secret)}`;
}
async function verifyCapabilityToken(userId, token, opts) {
  const secret = opts.secret?.trim();
  const prefix = opts.prefix ?? "cap_";
  if (!secret || !token.startsWith(prefix)) return false;
  const expected = `${prefix}${await sign(userId, secret)}`;
  return constantTimeEqual(token, expected);
}
async function createExpiringCapabilityToken(subject, opts) {
  const secret = opts.secret?.trim();
  if (!secret) return void 0;
  if (!Number.isFinite(opts.expiresInMs) || opts.expiresInMs <= 0) throw new Error("expiresInMs must be a positive number");
  const prefix = opts.prefix ?? "cap_";
  const now = opts.now ?? Date.now;
  const payload = base64UrlEncodeText(JSON.stringify({ sub: subject, exp: now() + opts.expiresInMs, n: crypto.randomUUID() }));
  return `${prefix}${payload}.${await hmacSha256Base64Url(payload, secret)}`;
}
async function verifyExpiringCapabilityToken(subject, token, opts) {
  const secret = opts.secret?.trim();
  const prefix = opts.prefix ?? "cap_";
  if (!secret || !token.startsWith(prefix)) return false;
  const body = token.slice(prefix.length);
  const dot = body.lastIndexOf(".");
  if (dot <= 0 || dot === body.length - 1) return false;
  const payload = body.slice(0, dot);
  const sig = body.slice(dot + 1);
  if (!constantTimeEqual(sig, await hmacSha256Base64Url(payload, secret))) return false;
  let parsed;
  try {
    parsed = JSON.parse(base64UrlDecodeText(payload));
  } catch {
    return false;
  }
  if (parsed.sub !== subject) return false;
  if (typeof parsed.exp !== "number") return false;
  const now = opts.now ?? Date.now;
  return parsed.exp > now();
}
async function sign(userId, secret) {
  return hmacSha256Base64Url(`user:${userId}`, secret);
}

// src/tools/gating.ts
function resolveToolCapabilities(opts) {
  const { taxonomy, capabilities, enabled } = opts;
  if (enabled === void 0) {
    return {
      proposalTypes: [...taxonomy.proposalTypes],
      toolGroups: [...new Set(capabilities.flatMap((c) => c.toolGroups ?? []))]
    };
  }
  const base = new Set(
    opts.baseProposalTypes ?? capabilities.flatMap((c) => c.proposalTypes ?? [])
  );
  const domainTypes = taxonomy.proposalTypes.filter((t) => !base.has(t));
  const byId = new Map(capabilities.map((c) => [c.id, c]));
  const proposalTypes = /* @__PURE__ */ new Set();
  const toolGroups = /* @__PURE__ */ new Set();
  for (const id of enabled) {
    const cap = byId.get(id);
    if (!cap) continue;
    for (const t of cap.proposalTypes ?? []) {
      if (taxonomy.proposalTypes.includes(t)) proposalTypes.add(t);
    }
    if (cap.domainActions) for (const t of domainTypes) proposalTypes.add(t);
    for (const g of cap.toolGroups ?? []) toolGroups.add(g);
  }
  return { proposalTypes: [...proposalTypes], toolGroups: [...toolGroups] };
}
function restrictTaxonomy(taxonomy, allowed) {
  const allow = new Set(allowed);
  return {
    proposalTypes: taxonomy.proposalTypes.filter((t) => allow.has(t)),
    regulatedTypes: taxonomy.regulatedTypes.filter((t) => allow.has(t))
  };
}

// src/tools/dispatch.ts
async function dispatchAppTool(toolName, rawArgs, ctx, opts) {
  try {
    if (!isAppToolName(toolName)) {
      const custom = findCustomTool(toolName, opts.customTools);
      if (!custom) return { ok: false, code: "unknown_tool", message: `${toolName} is not an app tool.` };
      const result = await custom.execute(rawArgs, ctx);
      return { ok: true, result };
    }
    if (toolName === "submit_proposal") {
      const type = String(rawArgs.type ?? "").trim();
      const title = String(rawArgs.title ?? "").trim();
      if (!type || !opts.taxonomy.proposalTypes.includes(type)) {
        return { ok: false, code: "invalid_type", message: `type must be one of: ${opts.taxonomy.proposalTypes.join(", ")}.` };
      }
      if (!title) return { ok: false, code: "missing_title", message: "title is required." };
      const description = rawArgs.description == null ? null : String(rawArgs.description);
      let regulated = opts.taxonomy.regulatedTypes.includes(type);
      if (opts.needsApproval) {
        try {
          regulated = await opts.needsApproval(type, { title, description }, ctx);
        } catch {
          regulated = true;
        }
      }
      const r2 = await opts.handlers.submitProposal({ type, title, description, regulated }, ctx);
      const { proposalId, deduped, status, ...extra } = r2;
      const effectiveStatus = status ?? "queued_for_approval";
      opts.onProduced?.({
        type: "proposal_created",
        proposalId,
        title,
        status: effectiveStatus === "executed" ? "executed" : "pending",
        content: description ?? void 0
      });
      return { ok: true, result: { ...extra, status: effectiveStatus, proposalId, deduped, regulated } };
    }
    if (toolName === "schedule_followup") {
      const r2 = await opts.handlers.scheduleFollowup(
        { title: String(rawArgs.title ?? ""), dueDate: String(rawArgs.dueDate ?? ""), priority: rawArgs.priority },
        ctx
      );
      return { ok: true, result: { followupId: r2.id, dueDate: r2.dueDate, deduped: r2.deduped } };
    }
    if (toolName === "render_ui") {
      const r2 = await opts.handlers.renderUi({ title: String(rawArgs.title ?? ""), schema: rawArgs.schema }, ctx);
      opts.onProduced?.({ type: "artifact", path: r2.path, content: r2.content });
      return { ok: true, result: { path: r2.path } };
    }
    const r = await opts.handlers.addCitation(
      { path: String(rawArgs.path ?? ""), quote: String(rawArgs.quote ?? ""), label: rawArgs.label },
      ctx
    );
    return { ok: true, result: { citationId: r.citationId, path: r.path } };
  } catch (err) {
    if (err instanceof ToolInputError) return { ok: false, code: err.code, message: err.message, status: err.status };
    return { ok: false, code: "app_tool_error", message: err instanceof Error ? err.message : String(err), status: 500 };
  }
}
function outcomeStatus(outcome) {
  return outcome.status ?? 400;
}

// src/tools/runtime.ts
function createAppToolRuntimeExecutor(opts) {
  return ({ toolName, args }) => dispatchAppTool(toolName, args, opts.ctx, opts);
}

// src/tools/http.ts
async function handleAppToolRequest(request, opts) {
  if (request.method !== "POST") return Response.json({ error: "Method not allowed" }, { status: 405 });
  const auth = await authenticateToolRequest(request, { verifyToken: opts.verifyToken, headerNames: opts.headerNames });
  if (!auth.ok) return auth.response;
  let body;
  try {
    body = await request.json();
  } catch {
    return Response.json({ error: "Invalid JSON" }, { status: 400 });
  }
  const args = body.args ?? body.arguments ?? body;
  const toolName = typeof opts.tool === "string" ? opts.tool : opts.tool.name;
  const customTools = typeof opts.tool === "string" ? opts.customTools : [...opts.customTools ?? [], opts.tool];
  const outcome = await dispatchAppTool(toolName, args, auth.ctx, { ...opts, customTools });
  if (!outcome.ok) {
    return Response.json({ error: outcome.code, message: outcome.message }, { status: outcomeStatus(outcome) });
  }
  const payload = outcome.result;
  return Response.json({ ok: true, ...payload, ...opts.message ? { message: opts.message(outcome.result) } : {} });
}

export {
  createCapabilityToken,
  verifyCapabilityToken,
  createExpiringCapabilityToken,
  verifyExpiringCapabilityToken,
  resolveToolCapabilities,
  restrictTaxonomy,
  dispatchAppTool,
  outcomeStatus,
  createAppToolRuntimeExecutor,
  handleAppToolRequest
};
//# sourceMappingURL=chunk-ICOHEZK6.js.map