import type { ConvexHttpClient } from "convex/browser"; import { makeFunctionReference } from "convex/server"; import { CliArgError } from "./lib/cli-args"; import { parseEnvironmentOptions } from "./lib/environment-cli-args"; export const CONTEXT_SECTIONS = [ "identity", "organisation", "user", "tools", "rules", ] as const; export function validateContextSet(input: readonly string[]) { const parsed = parseEnvironmentOptions( input, ["--content"], ["--stdin", "--json"], ); const [verb, section] = parsed.positional; if ( verb !== "set" || parsed.positional.length !== 2 || !CONTEXT_SECTIONS.includes(section as never) || parsed.child.length ) throw new CliArgError( `Usage: dench context set <${CONTEXT_SECTIONS.join("|")}> --stdin | --content [--json]`, ); if ( Number(parsed.flags["--stdin"] === true) + Number(typeof parsed.flags["--content"] === "string") !== 1 ) throw new CliArgError( "Choose exactly one of --stdin or --content. Store credentials with dench secrets set, never in context.", ); return { section: section as (typeof CONTEXT_SECTIONS)[number], content: parsed.flags["--content"] as string | undefined, }; } export async function runContextSet(opts: { convex: ConvexHttpClient; args: string[]; sessionToken?: string; readStdin?: () => Promise; }) { const parsed = validateContextSet(opts.args); const content = parsed.content ?? (await ( opts.readStdin ?? (async () => { const chunks: Buffer[] = []; let size = 0; for await (const chunk of process.stdin) { size += Buffer.byteLength(chunk); if (size > 32000) throw new CliArgError( "Context exceeds 32 KB. Keep standing instructions short; use workspace files for references.", ); chunks.push(Buffer.from(chunk)); } return Buffer.concat(chunks).toString("utf8"); }) )()); if (!content.trim() || Buffer.byteLength(content) > 32000) throw new CliArgError("Context must contain 1–32000 UTF-8 bytes."); const fn = { identity: "updateIdentity", organisation: "updateOrganisation", user: "updateUserProfile", tools: "updateToolsNotes", rules: "writeMagicFileFromUI", }[parsed.section]; await opts.convex.mutation( makeFunctionReference<"mutation">(`functions/agentConfig:${fn}`), { ...(opts.sessionToken ? { sessionToken: opts.sessionToken } : {}), content, ...(parsed.section === "rules" ? { path: "/RULES.md" } : {}), }, ); console.log(JSON.stringify({ ok: true, section: parsed.section })); }