synartesis 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +501 -0
- package/dist/chunk-K3QIPVBY.js +85 -0
- package/dist/chunk-K3QIPVBY.js.map +1 -0
- package/dist/chunk-X4VQNEP5.js +1383 -0
- package/dist/chunk-X4VQNEP5.js.map +1 -0
- package/dist/cli.js +1708 -0
- package/dist/cli.js.map +1 -0
- package/dist/demo-agent.js +67 -0
- package/dist/demo-agent.js.map +1 -0
- package/dist/proxy.js +913 -0
- package/dist/proxy.js.map +1 -0
- package/dist/toy-crm.js +293 -0
- package/dist/toy-crm.js.map +1 -0
- package/manifests/filesystem.yaml +97 -0
- package/manifests/git.yaml +77 -0
- package/manifests/github.yaml +175 -0
- package/manifests/memory.yaml +96 -0
- package/manifests/toy-crm.yaml +66 -0
- package/package.json +67 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/init/draft.ts","../src/rollback/rollback.ts","../src/watch.ts","../src/keys.ts","../src/console.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * better-sqlite3 requires Node 22, and on Node 20 it does not fail politely:\n * it segfaults the moment a database is opened. Saying so is better than\n * letting somebody meet exit code 139.\n */\nconst NODE_MAJOR = Number(process.versions.node.split(\".\")[0]);\nif (NODE_MAJOR < 22) {\n process.stderr.write(\n `synartesis: needs Node 22 or newer, and this is ${process.version}.\\n`,\n );\n process.exit(2);\n}\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\n\nimport { ManifestError, SynartesisError, describe } from \"./errors.js\";\nimport { draftManifest } from \"./init/draft.js\";\nimport { loadManifest, parseManifest } from \"./manifest/load.js\";\nimport { labelFor, openJournal, wasRefused, type ActionClass, type ActionRow, type Journal } from \"./journal/journal.js\";\nimport { verifyAgainstServers } from \"./manifest/verify.js\";\nimport { createRouter } from \"./proxy/routing.js\";\nimport { connectStdioUpstream, type Upstream } from \"./proxy/upstream.js\";\nimport { rollback, type RollbackReport } from \"./rollback/rollback.js\";\nimport { banner, rule, style } from \"./style.js\";\nimport { findJournal, findManifest } from \"./locate.js\";\nimport { watch } from \"./watch.js\";\nimport { openConsole } from \"./console.js\";\nimport { cliCommand, proxyCommand } from \"./invocation.js\";\n\nconst COMMANDS = `\n synartesis the screen; everything below,\n driven with the arrow keys\n synartesis init <server> -- <command> [args...] [--manifest <path>]\n synartesis check [--manifest <path>]\n synartesis list [--journal <path>]\n synartesis show <runId> [--journal <path>]\n synartesis gates [--journal <path>]\n synartesis close [runId] [--journal <path>]\n synartesis proxy --manifest <path> [--journal <path>] what your agent runs\n synartesis watch [--by <name>] [--journal <path>]\n synartesis approve [actionId|--all] [--by <name>] [--journal <path>]\n synartesis deny [actionId|--all] [--by <name>] [--reason <text>] [--journal <path>]\n synartesis undo [runId] [--to <seq>] [--dry-run] [--replan]\n [--manifest <path>] [--journal <path>]\n\nclose ends a run left active by a proxy that was killed; nothing guesses at\nthat, since several proxies can share one journal.\n\nIds may be shortened to any unambiguous prefix. show and undo default to the\nmost recent run; approve and deny default to the only request waiting. init\nadds to an existing manifest rather than replacing it.\n\nwatch is the one to leave running. Anything held for approval appears there,\nand a and d answer it without a second terminal or an id to copy.\n\n --manifest synartesis.yaml, looked for here and upwards, then in the home\n --journal beside the manifest, or the one in the home\n --to lowest sequence to undo; earlier actions are left alone\n --by who is deciding; defaults to the logged-in user\n --all approve or deny everything currently waiting\n --once watch prints the current state and exits\n --json machine-readable output for list, show and gates\n --dry-run read current state and print the plan without changing anything\n --replan rebuild each undo from the current manifest, for a run recorded\n under a policy that turned out to be wrong\n\nNeither path usually needs giving. A policy that belongs to a project sits in\nit and is found from any directory inside it, the way a version control tool\nfinds its root; anything else lives in ~/.synartesis, which is where the\njournal is too. Set SYNARTESIS_HOME to put that somewhere else.\n\nExit codes: 0 complete, 1 halted or partial, 2 bad usage or configuration.\n`;\n\nclass UsageError extends Error {}\n\nfunction flag(argv: readonly string[], name: string): string | undefined {\n const at = argv.indexOf(name);\n if (at === -1) {\n return undefined;\n }\n const value = argv[at + 1];\n if (value === undefined || value.startsWith(\"--\")) {\n throw new UsageError(`${name} needs a value`);\n }\n return value;\n}\n\nfunction positional(argv: readonly string[]): string[] {\n const skip = new Set([\"--manifest\", \"--journal\", \"--to\", \"--by\", \"--reason\", \"--gate-timeout\"]);\n const values: string[] = [];\n // Everything after `--` belongs to the wrapped command, not to us.\n const end = argv.indexOf(\"--\");\n const ours = end === -1 ? argv : argv.slice(0, end);\n for (let i = 0; i < ours.length; i += 1) {\n const token = ours[i] ?? \"\";\n if (skip.has(token)) {\n i += 1;\n continue;\n }\n if (!token.startsWith(\"--\")) {\n values.push(token);\n }\n }\n return values;\n}\n\n/**\n * Loads a manifest and checks it against the servers it names, without\n * touching a journal or serving anything. This is what you run before wiring\n * a policy into a client, rather than finding out from a client that will not\n * start.\n */\nasync function runCheck(argv: readonly string[]): Promise<number> {\n const path = findManifest(flag(argv, \"--manifest\"));\n const manifest = loadManifest(path);\n\n const upstreams: Upstream[] = [];\n try {\n for (const [name, spec] of Object.entries(manifest.servers)) {\n upstreams.push(\n await connectStdioUpstream({\n name,\n command: spec.command,\n args: spec.args,\n stderr: \"capture\",\n ...(spec.env === undefined ? {} : { env: spec.env }),\n }),\n );\n }\n await verifyAgainstServers(upstreams, manifest);\n } finally {\n for (const upstream of upstreams) {\n await upstream.close();\n }\n }\n\n const counts = new Map<string, number>();\n for (const policy of manifest.tools) {\n counts.set(policy.class, (counts.get(policy.class) ?? 0) + 1);\n }\n const gated = manifest.tools.filter((policy) => policy.gate !== \"never\").length;\n\n out(\"\");\n out(` ${style.label(\"policy\")} ${style.strong(path)}`);\n out(` ${rule(54)}`);\n out(\"\");\n out(` ${style.quiet(\"servers \")} ${Object.keys(manifest.servers).join(\", \")}`);\n out(` ${style.quiet(\"policies\")} ${[...counts].map(([k, v]) => `${String(v)} ${k}`).join(\", \")}`);\n out(` ${style.quiet(\"guarded \")} ${style.accent(String(gated))}`);\n out(\"\");\n out(` ${style.quiet(\"Anything not mentioned here is treated as irreversible and guarded.\")}`);\n out(\"\");\n return 0;\n}\n\nasync function runInit(argv: readonly string[]): Promise<number> {\n const name = positional(argv)[1];\n const separator = argv.indexOf(\"--\");\n const command = separator === -1 ? undefined : argv[separator + 1];\n if (name === undefined || command === undefined) {\n throw new UsageError(\"init needs a server name and a command, as: init crm -- npx -y some-mcp-server\");\n }\n if (name.includes(\".\") || name.includes(\"__\")) {\n throw new UsageError(`server name ${name} may not contain \".\" or \"__\"; both qualify tool names`);\n }\n\n // The home unless a project already has one above where you are standing.\n // Setting a server up should not mean choosing a directory to keep it in.\n const path = findManifest(flag(argv, \"--manifest\"));\n const force = argv.includes(\"--force\");\n const present = existsSync(path);\n if (present && force) {\n throw new UsageError(\n `--force would discard ${path}. Delete it yourself if that is what you want; init will otherwise add to it.`,\n );\n }\n\n const yaml = await draftManifest({\n name,\n command,\n args: argv.slice(separator + 2),\n ...(present ? { existing: readFileSync(path, \"utf8\") } : {}),\n });\n\n // Never write a manifest that would not start: a drafted policy that fails\n // to load is worse than no policy, because it looks finished.\n parseManifest(yaml, path);\n mkdirSync(dirname(resolve(path)), { recursive: true });\n writeFileSync(path, yaml);\n\n out(\"\");\n out(` ${style.label(present ? \"extended\" : \"wrote\")} ${style.strong(path)}`);\n out(` ${rule(54)}`);\n out(\"\");\n out(` ${style.quiet(\"Every tool is guarded until you say how to undo it.\")}`);\n out(` ${style.quiet(\"Work through the TODOs, then point your MCP client at:\")}`);\n out(\"\");\n out(` ${style.accent(`${proxyCommand()} --manifest ${resolve(path)}`)}`);\n out(\"\");\n return 0;\n}\n\n/**\n * Ids are uuids, and copying one between two terminals is the clunkiest part\n * of using this. Any unambiguous prefix will do, and where there is only one\n * sensible answer, no id is needed at all.\n */\ninterface Noun {\n readonly one: string;\n readonly many: string;\n}\n\n/**\n * `newest` is for the commands whose default is a run rather than the only\n * candidate. show and undo have always been documented as defaulting to the\n * most recent run; without this that held only until a second run existed,\n * after which both refused and listed every id -- offering --all, which\n * neither of them takes. approve and deny stay strict: \"the only one waiting\"\n * is a different promise, and guessing which of several to allow is not a\n * guess anything should make.\n */\nfunction pick<T extends { id: string }>(\n candidates: readonly T[],\n given: string | undefined,\n noun: Noun,\n newest = false,\n): T {\n const listed = (items: readonly T[]): string =>\n items.map((item) => ` ${item.id}`).join(\"\\n\");\n\n if (given === undefined) {\n const [only, ...rest] = candidates;\n if (only === undefined) {\n throw new UsageError(`there is no ${noun.one} to act on`);\n }\n if (rest.length > 0 && !newest) {\n throw new UsageError(\n `there are ${String(candidates.length)} ${noun.many}; name one, or use --all:\\n${listed(candidates)}`,\n );\n }\n return only;\n }\n\n const exact = candidates.find((item) => item.id === given);\n if (exact !== undefined) {\n return exact;\n }\n const matches = candidates.filter((item) => item.id.startsWith(given));\n const [first, ...rest] = matches;\n if (first === undefined) {\n throw new UsageError(`no ${noun.one} matches ${given}`);\n }\n if (rest.length > 0) {\n throw new UsageError(\n `${given} matches ${String(matches.length)} ${noun.many}:\\n${listed(matches)}`,\n );\n }\n return first;\n}\n\nconst RUN: Noun = { one: \"run\", many: \"runs\" };\nconst WAITING: Noun = { one: \"action awaiting approval\", many: \"actions awaiting approval\" };\n\n// Piping into head or less closes the pipe early. That is the reader saying it\n// has seen enough, not an error, and a stack trace there is pure noise.\nprocess.stdout.on(\"error\", (error: NodeJS.ErrnoException) => {\n if (error.code === \"EPIPE\") {\n process.exit(0);\n }\n throw error;\n});\n\nfunction out(line: string): void {\n process.stdout.write(`${line}\\n`);\n}\n\nfunction runList(journal: Journal, asJson: boolean): number {\n // Most recent first: the run someone wants to undo is nearly always the last\n // thing that happened.\n const runs = [...journal.listRuns()].reverse();\n if (asJson) {\n out(JSON.stringify(runs.map((run) => ({ ...run, actions: journal.getActions(run.id).length }))));\n return 0;\n }\n if (runs.length === 0) {\n out(\"no runs recorded\");\n return 0;\n }\n out(\"\");\n out(` ${style.label(\"runs\")} ${style.quiet(\"most recent first\")}`);\n out(` ${rule(96)}`);\n out(\"\");\n out(\n style.quiet(\n ` ${\"run\".padEnd(36)} ${\"started\".padEnd(24)} ${\"status\".padEnd(12)} actions agent`,\n ),\n );\n for (const run of runs) {\n const actions = journal.getActions(run.id);\n const unknown = actions.filter((action) => action.status === \"pending\").length;\n const waiting = actions.filter((action) => action.status === \"gated\").length;\n const notes = [\n unknown === 0 ? \"\" : `${String(unknown)} of unknown outcome`,\n waiting === 0 ? \"\" : `${String(waiting)} awaiting approval`,\n ].filter((note) => note !== \"\");\n const note =\n notes.length === 0 ? \"\" : ` ${style.accent(`(${notes.join(\"; \")})`)}`;\n out(\n ` ${style.strong(run.id)} ${style.quiet(run.startedAt)} ${run.status.padEnd(12)} ` +\n `${String(actions.length).padStart(7)} ${run.label ?? \"-\"}${note}`,\n );\n }\n out(\"\");\n return 0;\n}\n\nfunction runShow(argv: readonly string[], journal: Journal, asJson: boolean): number {\n const runs = [...journal.listRuns()].reverse();\n const run = pick(runs, positional(argv)[1], RUN, true);\n const runId = run.id;\n\n if (asJson) {\n out(JSON.stringify({ run, actions: journal.getActions(runId) }));\n return 0;\n }\n\n out(\"\");\n out(` ${style.label(\"run\")} ${style.strong(run.id)}`);\n out(` ${rule(54)}`);\n out(\"\");\n out(` ${style.quiet(\"agent \")} ${run.label ?? \"-\"}`);\n out(` ${style.quiet(\"started\")} ${run.startedAt}`);\n out(\n ` ${style.quiet(\"status \")} ${run.status}` +\n (run.endedAt === undefined ? \"\" : style.quiet(` ended ${run.endedAt}`)),\n );\n\n const actions = journal.getActions(runId);\n if (actions.length === 0) {\n out(\"\");\n out(\"no actions recorded\");\n return 0;\n }\n\n out(\"\");\n out(\"\");\n out(` ${style.label(\"timeline\")}`);\n out(` ${rule(72)}`);\n out(\"\");\n for (const action of actions) {\n out(\n ` ${style.quiet(String(action.seq).padStart(3))} ${badgeOf(action)} ` +\n `${statusOf(action)} ${style.strong(`${action.server}.${action.tool}`)}`,\n );\n out(` ${style.quiet(truncate(JSON.stringify(action.args), 96))}`);\n if (action.approvedAt !== undefined) {\n const verb = action.status === \"denied\" ? \"denied\" : \"approved\";\n out(\n ` ${style.accent(`${verb} by ${action.approvedBy ?? \"nobody\"}`)} ${style.quiet(`at ${action.approvedAt}`)}`,\n );\n }\n if (action.error !== undefined) {\n out(` ${style.quiet(`note: ${truncate(action.error, 200)}`)}`);\n }\n if (action.inverse !== undefined) {\n out(` ${style.quiet(\"undo:\")} ${truncate(JSON.stringify(action.inverse), 200)}`);\n }\n }\n\n out(\"\");\n out(` ${summarise(actions)}`);\n out(\"\");\n return 0;\n}\n\nconst CLASS_MARK: Record<ActionClass, string> = {\n readonly: \"\\u00b7\",\n reversible: \"\\u2190\",\n compensable: \"\\u2248\",\n irreversible: \"!\",\n unclassified: \"?\",\n};\n\n/** Wide enough for the longest class name plus its marker. */\nconst BADGE_WIDTH = \"irreversible\".length + 2;\n\n/** Padded before it is coloured: escape codes are not printable width. */\nfunction badgeOf(action: ActionRow): string {\n const plain = `${CLASS_MARK[action.class]} ${action.class}`.padEnd(BADGE_WIDTH);\n return action.class === \"irreversible\" ? style.accent(plain) : style.quiet(plain);\n}\n\nfunction statusOf(action: ActionRow): string {\n const text = labelFor(action).padEnd(13);\n if (wasRefused(action)) {\n return style.accent(text);\n }\n if (action.status === \"gated\") {\n return style.strong(text);\n }\n return style.quiet(text);\n}\n\n/**\n * Broken over lines rather than cut off. The reason a call is being held ends\n * with the server's own words, so truncating it removes the only part that\n * says anything the tool name did not already.\n */\nfunction wrapped(text: string, width: number): string[] {\n const lines: string[] = [];\n let line = \"\";\n for (const word of text.split(/\\s+/).filter((part) => part !== \"\")) {\n if (line === \"\") {\n line = word;\n } else if (line.length + 1 + word.length <= width) {\n line = `${line} ${word}`;\n } else {\n lines.push(line);\n line = word;\n }\n }\n if (line !== \"\") {\n lines.push(line);\n }\n return lines;\n}\n\nfunction truncate(text: string, limit: number): string {\n return text.length <= limit ? text : `${text.slice(0, limit - 3)}...`;\n}\n\nfunction summarise(actions: readonly ActionRow[]): string {\n const counts = new Map<string, number>();\n for (const action of actions) {\n counts.set(action.status, (counts.get(action.status) ?? 0) + 1);\n }\n const parts = [...counts].sort(([a], [b]) => (a < b ? -1 : 1)).map(([k, v]) => `${String(v)} ${k}`);\n const undoable = actions.filter((a) => a.inverse !== undefined).length;\n return `${String(actions.length)} actions: ${parts.join(\", \")} | ${String(undoable)} with a recorded undo`;\n}\n\n/**\n * Repeated back in any command this prints, because whoever copies the line may\n * well be in a different directory than the one it was printed from.\n */\nlet journalArg = \"\";\n\nfunction runClose(argv: readonly string[], journal: Journal): number {\n // Left active by a proxy that was killed rather than disconnected. Nothing\n // can tell that apart from a run still going, so this is asked for, never\n // guessed: several proxies can share one journal.\n const active = journal.listRuns().filter((candidate) => candidate.status === \"active\");\n const run = pick([...active].reverse(), positional(argv)[1], RUN, true);\n const closed = journal.closeAbandonedRun(run.id);\n out(\"\");\n out(\n closed\n ? ` ${style.label(\"closed\")} ${style.strong(run.id)}`\n : ` ${style.quiet(`${run.id} was not active.`)}`,\n );\n out(\"\");\n return closed ? 0 : 1;\n}\n\nfunction runGates(journal: Journal, asJson: boolean): number {\n const waiting = journal.listGated();\n if (asJson) {\n out(JSON.stringify(waiting));\n return 0;\n }\n if (waiting.length === 0) {\n out(\"\");\n out(` ${style.quiet(\"Nothing is waiting for a decision.\")}`);\n out(\"\");\n return 0;\n }\n out(\"\");\n out(` ${style.label(\"awaiting approval\")}`);\n out(` ${rule(72)}`);\n out(\"\");\n for (const action of waiting) {\n out(` ${style.strong(action.id)} ${style.quiet(action.ts)}`);\n out(` ${style.accent(`${action.server}.${action.tool}`)} ${style.quiet(truncate(JSON.stringify(action.args), 88))}`);\n // The reason, because approving is the decision this screen exists for and\n // it was being made on a tool name and a bag of arguments alone.\n for (const [at, line] of wrapped(action.error ?? \"held by policy\", 76).entries()) {\n out(` ${at === 0 ? style.quiet(action.class) : \" \".repeat(action.class.length)} ${style.quiet(line)}`);\n }\n out(\"\");\n }\n const self = cliCommand();\n out(\n ` ${style.quiet(`${self} approve`)} ${style.accent(waiting[0]?.id.slice(0, 8) ?? \"<id>\")} ${style.quiet(`--by <name>${journalArg}`)}`,\n );\n out(` ${style.quiet(`${self} approve --all --by <name>${journalArg}`)}`);\n out(\"\");\n return 0;\n}\n\nfunction runDecision(argv: readonly string[], journal: Journal, approving: boolean): number {\n const waiting = journal.listGated();\n const given = positional(argv)[1];\n // \"unknown\" is a poor thing to find in an audit trail when the machine knows\n // perfectly well who is logged in. --by still wins, for approving on behalf\n // of someone else.\n const by =\n flag(argv, \"--by\") ?? process.env[\"USER\"] ?? process.env[\"LOGNAME\"] ?? \"unknown\";\n const reason = flag(argv, \"--reason\") ?? \"denied by operator\";\n\n // Looked up among everything first, so an action that has already been\n // settled gets told what became of it rather than \"no such action\".\n if (given !== undefined) {\n const settled = journal.getAction(given);\n if (settled !== undefined && settled.status !== \"gated\") {\n process.stderr.write(\n `synartesis: ${given} is no longer awaiting approval (it is ${settled.status})\\n`,\n );\n return 1;\n }\n }\n\n const targets = argv.includes(\"--all\")\n ? waiting\n : [pick(waiting, given, WAITING)];\n if (targets.length === 0) {\n out(\"nothing is awaiting approval\");\n return 0;\n }\n\n let failed = 0;\n for (const action of targets) {\n const changed = approving\n ? journal.approve(action.id, by)\n : journal.deny(action.id, by, reason);\n if (!changed) {\n // A decision that lands after the action settled must not look like it\n // took effect.\n const now = journal.getAction(action.id);\n process.stderr.write(\n `synartesis: ${action.id} is no longer awaiting approval (it is ${now?.status ?? \"gone\"})\\n`,\n );\n failed += 1;\n continue;\n }\n out(\n ` ${style.accent(approving ? \"approved\" : \"denied\")} ${style.strong(`${action.server}.${action.tool}`)} ${style.quiet(action.id)}`,\n );\n }\n return failed === 0 ? 0 : 1;\n}\n\nfunction report(result: RollbackReport): number {\n out(\"\");\n out(` ${style.label(result.dryRun ? \"dry run\" : \"undo\")} ${style.strong(result.runId)}`);\n out(` ${rule(72)}`);\n out(\"\");\n for (const step of result.steps) {\n const unverified =\n step.kind === \"revert\" && !step.verified ? ` ${style.accent(\"[unverified]\")}` : \"\";\n const kind =\n step.kind === \"halt\" || step.kind === \"permanent\"\n ? style.accent(step.kind.padEnd(16))\n : step.kind.padEnd(16);\n out(\n ` ${style.quiet(String(step.seq).padStart(3))} ${kind} ` +\n `${style.strong(`${step.server}.${step.tool}`)} ${style.quiet(step.reason)}${unverified}`,\n );\n if (step.plan !== undefined && step.kind === \"revert\") {\n const verb = `${step.replanned === true ? \"replanned, \" : \"\"}${result.dryRun ? \"would call\" : \"called\"}`;\n out(\n ` ${style.quiet(verb)} ${step.plan.server}.${step.plan.tool} ` +\n style.quiet(truncate(JSON.stringify(step.plan.args), 120)),\n );\n }\n }\n if (result.halted !== undefined) {\n out(\"\");\n out(\n ` ${style.accent(\"halted\")} ${style.quiet(`at sequence ${String(result.halted.seq)}`)} ${result.halted.reason}`,\n );\n if (result.halted.detail !== \"\") {\n for (const line of result.halted.detail.split(\"\\n\")) {\n out(` ${style.quiet(line)}`);\n }\n }\n }\n const permanent = result.steps.filter((step) => step.kind === \"permanent\");\n if (permanent.length > 0) {\n out(\"\");\n out(\n ` ${style.quiet(`${String(permanent.length)} action${permanent.length === 1 ? \"\" : \"s\"} could not be undone and ${permanent.length === 1 ? \"was\" : \"were\"} left in place.`)}`,\n );\n }\n out(\"\");\n out(\n ` ${style.label(\"result\")} ${result.status === \"rolled_back\" ? result.status : style.accent(result.status)}`,\n );\n out(\"\");\n return result.status === \"rolled_back\" ? 0 : 1;\n}\n\n/**\n * Starting every server the manifest names, undoing, and shutting them down\n * again. Shared, because the console does exactly this when somebody presses\n * u and there must not be two answers to what undo means.\n */\nasync function performUndo(\n manifestPath: string,\n journal: Journal,\n runId: string,\n options: { dryRun: boolean; toSeq?: number; replan?: boolean },\n): Promise<RollbackReport> {\n const manifest = loadManifest(manifestPath);\n const upstreams: Upstream[] = [];\n try {\n for (const [name, spec] of Object.entries(manifest.servers)) {\n upstreams.push(\n await connectStdioUpstream({\n name,\n command: spec.command,\n args: spec.args,\n stderr: \"capture\",\n ...(spec.env === undefined ? {} : { env: spec.env }),\n }),\n );\n }\n return await rollback({\n journal,\n router: createRouter(upstreams, manifest),\n runId,\n ...(options.toSeq === undefined ? {} : { toSeq: options.toSeq }),\n dryRun: options.dryRun,\n ...(options.replan === true ? { replanWith: manifest } : {}),\n });\n } finally {\n for (const upstream of upstreams) {\n await upstream.close();\n }\n }\n}\n\nasync function runUndo(argv: readonly string[], journal: Journal): Promise<number> {\n // Defaults to the most recent run: the thing anyone wants to undo is\n // almost always the last thing that happened.\n const runId = pick([...journal.listRuns()].reverse(), positional(argv)[1], RUN, true).id;\n\n const rawTo = flag(argv, \"--to\");\n const toSeq = rawTo === undefined ? undefined : Number(rawTo);\n if (toSeq !== undefined && (!Number.isInteger(toSeq) || toSeq < 1)) {\n throw new UsageError(\"--to needs a positive whole number\");\n }\n // Past the end, every action is below the floor, so nothing is planned and\n // the empty plan reads exactly like a run with nothing left to undo. A typed\n // digit too many looked like a result.\n if (toSeq !== undefined) {\n const highest = journal.getActions(runId).reduce((top, action) => Math.max(top, action.seq), 0);\n if (toSeq > highest) {\n throw new UsageError(\n `--to ${String(toSeq)} is past the end of this run, which goes up to ${String(highest)}`,\n );\n }\n }\n\n return report(\n await performUndo(findManifest(flag(argv, \"--manifest\")), journal, runId, {\n dryRun: argv.includes(\"--dry-run\"),\n ...(toSeq === undefined ? {} : { toSeq }),\n replan: argv.includes(\"--replan\"),\n }),\n );\n}\n\nasync function main(argv: readonly string[]): Promise<number> {\n const command = positional(argv)[0];\n if (command === \"proxy\") {\n // The proxy, run through this command rather than its own binary, so the\n // line people paste into a client config is one package and one word:\n // npx -y synartesis proxy --manifest ... . Loaded only here, and before\n // anything else in this file runs, because from this point stdout carries\n // protocol frames and a banner on it would corrupt the stream.\n await import(\"./proxy/stdio.js\");\n return 0;\n }\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) {\n process.stdout.write(`${banner()}\\n${COMMANDS}`);\n return 0;\n }\n // Nothing typed opens the screen. Being handed a page of eight commands is a\n // fine answer for a script and a poor one for a person, who wants to see\n // what happened rather than be told the names of the words for asking.\n if (command === undefined) {\n const manifestPath = findManifest(flag(argv, \"--manifest\"));\n const journalPath = findJournal(flag(argv, \"--journal\"), manifestPath);\n return await openConsole({\n journalPath,\n write: (text) => process.stdout.write(text),\n live: process.stdout.isTTY,\n decideAs: flag(argv, \"--by\") ?? process.env[\"USER\"] ?? process.env[\"LOGNAME\"] ?? \"unknown\",\n undo: async (runId, dryRun) => {\n const journal = openJournal(journalPath, { mustExist: true });\n try {\n return await performUndo(manifestPath, journal, runId, { dryRun });\n } finally {\n journal.close();\n }\n },\n });\n }\n\n // None of these needs an existing journal, and none should create one.\n if (command === \"init\") {\n return await runInit(argv);\n }\n if (command === \"check\") {\n return await runCheck(argv);\n }\n\n const asJson = argv.includes(\"--json\");\n const given = flag(argv, \"--journal\");\n const journalPath = findJournal(given, findManifest(flag(argv, \"--manifest\")));\n\n // Watching is the one thing you do before anything has happened, so it opens\n // its own handle when there is one and waits when there is not.\n if (command === \"watch\") {\n const live = process.stdout.isTTY && !argv.includes(\"--once\");\n return await watch({\n journalPath,\n approveWith: cliCommand(),\n write: (text) => process.stdout.write(text),\n live,\n // A decision has to be attributable, so the view can only make one when\n // it knows whose it is.\n decideAs: flag(argv, \"--by\") ?? process.env[\"USER\"] ?? process.env[\"LOGNAME\"] ?? \"unknown\",\n });\n }\n\n // Repeated back only when it was not the obvious one, so a copied command\n // works from anywhere without being cluttered when it need not be.\n journalArg = given === undefined ? \"\" : ` --journal ${resolve(given)}`;\n // Every remaining command reads an existing journal. Only the proxy makes one.\n const journal = openJournal(journalPath, { mustExist: true });\n try {\n switch (command) {\n case \"list\":\n return runList(journal, asJson);\n case \"show\":\n return runShow(argv, journal, asJson);\n case \"close\":\n return runClose(argv, journal);\n case \"gates\":\n return runGates(journal, asJson);\n case \"approve\":\n return runDecision(argv, journal, true);\n case \"deny\":\n return runDecision(argv, journal, false);\n case \"undo\":\n return await runUndo(argv, journal);\n default:\n throw new UsageError(`unknown command ${command}`);\n }\n } finally {\n journal.close();\n }\n}\n\ntry {\n process.exitCode = await main(process.argv.slice(2));\n} catch (error: unknown) {\n if (error instanceof UsageError) {\n process.stderr.write(`synartesis: ${error.message}\\n\\n${COMMANDS}`);\n process.exitCode = 2;\n } else if (error instanceof ManifestError) {\n process.stderr.write(`synartesis: ${error.message}\\n`);\n process.exitCode = 2;\n } else if (error instanceof SynartesisError) {\n // Without the code. It read as synartesis: JOURNAL_ERROR: journal open\n // failed: ... -- three prefixes before the sentence that says what is\n // wrong. The exit code is the part a script reads.\n process.stderr.write(`synartesis: ${error.message}\\n`);\n process.exitCode = 1;\n } else {\n process.stderr.write(`synartesis: ${describe(error)}\\n`);\n process.exitCode = 1;\n }\n}\n","import { z } from \"zod\";\n\nimport { ManifestError, UpstreamError, describe } from \"../errors.js\";\nimport { connectStdioUpstream } from \"../proxy/upstream.js\";\n\nexport interface DraftOptions {\n readonly name: string;\n readonly command: string;\n readonly args: readonly string[];\n /** Existing manifest source to extend rather than replace. */\n readonly existing?: string;\n}\n\nconst toolSchema = z.looseObject({\n name: z.string(),\n description: z.string().optional(),\n annotations: z\n .looseObject({\n readOnlyHint: z.boolean().optional(),\n destructiveHint: z.boolean().optional(),\n idempotentHint: z.boolean().optional(),\n })\n .optional(),\n});\n\nconst listSchema = z.looseObject({\n tools: z.array(toolSchema),\n nextCursor: z.string().optional(),\n});\n\ntype Tool = z.infer<typeof toolSchema>;\n\nfunction quote(value: string): string {\n return JSON.stringify(value);\n}\n\n/** Keeps a description readable on one comment line. */\nfunction summarise(text: string | undefined): string {\n if (text === undefined) {\n return \"\";\n }\n const single = text.replace(/\\s+/g, \" \").trim();\n return single.length > 96 ? `${single.slice(0, 93)}...` : single;\n}\n\nfunction draftTool(server: string, tool: Tool): string {\n const match = `${server}.${tool.name}`;\n const lines: string[] = [];\n const description = summarise(tool.description);\n if (description !== \"\") {\n lines.push(` # ${description}`);\n }\n\n // A server's own readOnlyHint is the one claim worth taking at face value:\n // it is the server saying it does not write. Everything else is a hint about\n // intent, not a guarantee, and D4 says an unproven tool is irreversible.\n if (tool.annotations?.readOnlyHint === true) {\n lines.push(` # classified readonly from the server's readOnlyHint; verify it before relying on it.`);\n lines.push(` - match: ${quote(match)}`);\n lines.push(` class: readonly`);\n return lines.join(\"\\n\");\n }\n\n lines.push(` # TODO: this is gated on every call until you describe how to undo it.`);\n lines.push(` # reversible needs a snapshot (a pre-read) and an inverse.`);\n lines.push(` # compensable needs an inverse only, usually built from $result.`);\n lines.push(` # irreversible is correct when neither exists; leave gate: always.`);\n lines.push(` - match: ${quote(match)}`);\n lines.push(` class: irreversible`);\n lines.push(` gate: always`);\n return lines.join(\"\\n\");\n}\n\n/**\n * Introspects a server and writes a starting policy for it. The draft is\n * deliberately unhelpful in one direction only: everything it cannot vouch for\n * is gated, so an unfinished manifest is annoying rather than dangerous.\n */\nexport async function draftManifest(options: DraftOptions): Promise<string> {\n const upstream = await connectStdioUpstream({\n name: options.name,\n command: options.command,\n args: options.args,\n stderr: \"capture\",\n });\n\n let tools: Tool[];\n try {\n const collected: Tool[] = [];\n let cursor: string | undefined;\n do {\n const page = listSchema.parse(\n await upstream.client.request(\n { method: \"tools/list\", params: cursor === undefined ? {} : { cursor } },\n z.looseObject({}),\n ),\n );\n collected.push(...page.tools);\n cursor = page.nextCursor;\n } while (cursor !== undefined);\n tools = collected;\n } catch (error: unknown) {\n throw new UpstreamError(options.name, \"tools/list\", error);\n } finally {\n await upstream.close();\n }\n\n if (tools.length === 0) {\n throw new ManifestError(`${options.name} exposes no tools, so there is no policy to write`);\n }\n\n const existing = options.existing?.trimEnd();\n if (existing !== undefined && existing.includes(`\\n ${options.name}:`)) {\n throw new ManifestError(\n `${options.name} is already declared in the manifest; remove it first or choose another name`,\n );\n }\n\n const server = [\n ` ${options.name}:`,\n ` command: ${quote(options.command)}`,\n ` args: [${options.args.map(quote).join(\", \")}]`,\n ].join(\"\\n\");\n\n const policies = tools.map((tool) => draftTool(options.name, tool)).join(\"\\n\\n\");\n\n if (existing === undefined) {\n return [\n `# Generated by synartesis init from ${options.name}'s tools/list.`,\n `# Every tool starts gated. Working through the TODOs is the whole job:`,\n `# a tool with no inverse is one an agent cannot use unsupervised.`,\n ``,\n `version: 1`,\n ``,\n `servers:`,\n server,\n ``,\n `tools:`,\n policies,\n ``,\n ].join(\"\\n\");\n }\n\n return mergeInto(existing, server, policies, options.name);\n}\n\n/**\n * Textual merge rather than parse-and-reserialise: a round trip through the\n * YAML AST would strip the author's comments, which in this format carry the\n * reasoning behind every classification.\n */\nfunction mergeInto(existing: string, server: string, policies: string, name: string): string {\n const serversAt = existing.indexOf(\"\\nservers:\");\n const toolsAt = existing.indexOf(\"\\ntools:\");\n if (serversAt === -1 || toolsAt === -1 || toolsAt < serversAt) {\n throw new ManifestError(\n \"the existing manifest does not have a servers: block followed by a tools: block, so it cannot be extended automatically\",\n );\n }\n\n const head = existing.slice(0, toolsAt);\n const tail = existing.slice(toolsAt);\n return [\n head.trimEnd(),\n server,\n tail.trimEnd(),\n ``,\n ` # --- added by synartesis init for ${name} ---`,\n policies,\n ``,\n ].join(\"\\n\");\n}\n\nexport { describe };\n","import { z } from \"zod\";\n\nimport { canonical } from \"../canonical.js\";\nimport { DriftConflict, RollbackHalted, describe } from \"../errors.js\";\nimport type { ActionRow, Journal } from \"../journal/journal.js\";\nimport type { Router } from \"../proxy/routing.js\";\nimport {\n observeState,\n planInverse,\n planRead,\n toPayload,\n type InversePlan,\n type StateObservation,\n} from \"../proxy/snapshot.js\";\nimport { createPolicyResolver } from \"../manifest/match.js\";\nimport { qualify, type Manifest } from \"../manifest/types.js\";\n\n/**\n * D7. Derived from the action rather than generated, so a retried rollback\n * presents the same key for the same action. It rides in `_meta`, which is\n * advisory: a server that ignores it gives no protection, which is why the\n * journal's own state transitions are the real guard against re-applying.\n */\nexport const IDEMPOTENCY_META_KEY = \"synartesis.dev/idempotency-key\";\n\nexport type StepKind =\n | \"revert\"\n | \"skip\"\n | \"already-reverted\"\n /** Known to be permanent. Not an obstacle to stop at, a fact to report. */\n | \"permanent\"\n | \"halt\";\n\nexport interface RollbackStep {\n readonly seq: number;\n readonly server: string;\n readonly tool: string;\n readonly kind: StepKind;\n readonly reason: string;\n /** Whether drift could be ruled out before acting. */\n readonly verified: boolean;\n readonly plan?: InversePlan;\n /** True when the inverse came from a corrected manifest, not the journal. */\n readonly replanned?: boolean;\n}\n\nexport interface RollbackHalt {\n readonly seq: number;\n readonly reason: string;\n readonly detail: string;\n}\n\nexport interface RollbackReport {\n readonly runId: string;\n readonly status: \"rolled_back\" | \"partial\";\n readonly dryRun: boolean;\n readonly steps: readonly RollbackStep[];\n readonly halted?: RollbackHalt;\n}\n\nexport interface RollbackOptions {\n readonly journal: Journal;\n readonly router: Router;\n readonly runId: string;\n /** Lowest sequence to undo. Sequences below it are left in place. */\n readonly toSeq?: number;\n readonly dryRun?: boolean;\n /**\n * Re-resolve each inverse from this manifest instead of using the one\n * recorded at capture time. For recovering from a policy that was wrong when\n * the run happened: the captured pre-state and result are replayed through\n * the corrected template, so no upstream state is re-read and D5 still holds.\n */\n readonly replanWith?: Manifest;\n readonly signal?: AbortSignal;\n}\n\nconst inversePlan = z.object({\n server: z.string(),\n tool: z.string(),\n args: z.record(z.string(), z.unknown()),\n});\n\nconst observation = z.union([\n z.object({ present: z.literal(true), value: z.unknown() }),\n z.object({ present: z.literal(false) }),\n]);\n\nconst toolResult = z.looseObject({ isError: z.boolean().default(false) });\n\nfunction sameState(a: unknown, b: unknown): boolean {\n return canonical(a) === canonical(b);\n}\n\ninterface Decision {\n readonly kind: StepKind;\n readonly reason: string;\n readonly verified: boolean;\n}\n\n/**\n * Decides what to do with one action without touching any upstream. Statuses\n * that mean \"never applied\" are skipped; statuses that mean \"we cannot know\"\n * halt, because continuing past them produces a state that is neither the\n * before nor the after (D6).\n */\nfunction classify(action: ActionRow, replanning: boolean): Decision | undefined {\n switch (action.status) {\n case \"rolled_back\":\n return { kind: \"already-reverted\", reason: \"already rolled back\", verified: true };\n case \"failed\":\n case \"denied\":\n return { kind: \"skip\", reason: `never applied (${action.status})`, verified: true };\n case \"pending\":\n return {\n kind: \"halt\",\n reason: \"outcome unknown: the process died mid-call, so whether this applied cannot be determined\",\n verified: false,\n };\n case \"gated\":\n return { kind: \"skip\", reason: \"never applied (awaiting approval)\", verified: true };\n case \"approved\":\n // Somebody said yes and the agent never made the call again, so it never\n // went out. Distinct from `pending`, where it did and we cannot say what\n // happened.\n return { kind: \"skip\", reason: \"never applied (approved, never retried)\", verified: true };\n case \"unrecoverable\":\n // With no inverse there is nothing that could be wrongly re-applied and\n // nothing for a person to decide. An earlier run having labelled it does\n // not make a permanent action any less permanent, and halting here would\n // keep a whole run stuck behind something that can never be undone.\n if (action.inverse === undefined) {\n return undefined;\n }\n // Otherwise it is genuine uncertainty. A replan is a person saying they\n // corrected the policy and want it tried again; every check still runs,\n // so real drift halts on it a second time.\n return replanning\n ? undefined\n : { kind: \"halt\", reason: \"halted here on an earlier attempt\", verified: false };\n case \"applied\":\n case \"rolling_back\":\n return undefined;\n }\n}\n\nexport async function rollback(options: RollbackOptions): Promise<RollbackReport> {\n const { journal, router, runId } = options;\n const dryRun = options.dryRun ?? false;\n const signal = options.signal ?? new AbortController().signal;\n\n const policies = options.replanWith === undefined ? undefined : createPolicyResolver(options.replanWith);\n\n /**\n * Rebuilds an action's inverse and verify read from a corrected policy,\n * using only what was already captured.\n */\n const replan = (\n action: ActionRow,\n ): { inverse?: InversePlan; verify?: InversePlan; error?: string } => {\n if (policies === undefined) {\n return {};\n }\n const policy = policies.resolve(qualify(action.server, action.tool)).policy;\n const context = {\n args: action.args,\n ...(action.snapshot === undefined ? {} : { snapshot: action.snapshot }),\n ...(action.result === undefined ? {} : { result: toPayload(action.result) }),\n };\n try {\n return {\n ...(policy.inverse === undefined ? {} : { inverse: planInverse(policy.inverse, context) }),\n ...(policy.snapshot === undefined\n ? {}\n : { verify: planRead(policy.snapshot, { args: action.args }) }),\n };\n } catch (error: unknown) {\n return { error: describe(error) };\n }\n };\n\n const all = journal.getActions(runId);\n const inScope = [...all]\n .filter((action) => options.toSeq === undefined || action.seq >= options.toSeq)\n .sort((a, b) => b.seq - a.seq);\n\n const steps: RollbackStep[] = [];\n let halted: RollbackHalt | undefined;\n /** Something permanent was stepped over, so the run is not fully reverted. */\n let leftInPlace = false;\n\n for (const action of inScope) {\n const early = classify(action, policies !== undefined);\n if (early?.kind === \"halt\") {\n // Deliberately not written back. Every halt classify can reach was read\n // off the row's own status, so there is nothing here this rollback\n // learned. Relabelling a `pending` action as `unrecoverable` destroyed\n // the one fact that mattered about it -- that its outcome is unknown --\n // and the next attempt, seeing an unrecoverable row with no inverse,\n // stepped straight over it. Running undo twice undid more than running\n // it once, which is the last thing this command may do.\n // What it saw then, said as that. Reading the stored conflict out as\n // \"actual\" states a fact about a moment that has passed as a fact about\n // now, and after the conflict is resolved that reading is simply false.\n // The way on was --replan, which nothing said.\n const seen = action.error ?? \"\";\n const detail =\n action.status === \"unrecoverable\" && seen !== \"\"\n ? `what it saw when it halted, which may no longer hold:\\n${seen}\\n` +\n `Resolve the conflict, then run undo --replan to check it against the world as it is now.`\n : seen;\n halted = { seq: action.seq, reason: early.reason, detail };\n steps.push({ ...describeStep(action), ...early });\n break;\n }\n if (early !== undefined) {\n steps.push({ ...describeStep(action), ...early });\n continue;\n }\n\n if (action.class === \"readonly\") {\n steps.push({ ...describeStep(action), kind: \"skip\", reason: \"readonly\", verified: true });\n continue;\n }\n\n const rebuilt = replan(action);\n const parsedPlan = inversePlan.safeParse(rebuilt.inverse ?? action.inverse);\n if (!parsedPlan.success) {\n // An applied action with nothing to undo. Nothing here is uncertain: the\n // email was sent, and no amount of stopping un-sends it. Stopping only\n // decides whether everything older stays wrong as well, and when the\n // permanent action is the newest one that means undoing nothing at all.\n // So it is reported and stepped over, and the run is marked partial.\n const approved =\n action.approvedBy === undefined ? \"\" : `, approved by ${action.approvedBy}`;\n const reason =\n action.class === \"irreversible\"\n ? `cannot be undone${approved}; left in place`\n : `no usable inverse was recorded${action.error === undefined ? \"\" : `: ${action.error}`}; left in place`;\n steps.push({ ...describeStep(action), kind: \"permanent\", reason, verified: false });\n leftInPlace = true;\n continue;\n }\n const plan = parsedPlan.data;\n\n // Drift check. Only possible where a pre-read was declared, which is what\n // produced both the stored verify call and the post-state.\n const verifyRead = inversePlan.safeParse(rebuilt.verify ?? action.verify);\n const recordedPost = observation.safeParse(action.postSnapshot);\n let verified = false;\n\n if (recordedPost.success && verifyRead.success) {\n let current: StateObservation;\n try {\n current = await observeState(router, verifyRead.data, signal);\n } catch (error: unknown) {\n const reason = `could not read current state to check for drift: ${describe(error)}`;\n halted = { seq: action.seq, reason, detail: \"\" };\n steps.push({ ...describeStep(action), kind: \"halt\", reason, verified: false });\n if (!dryRun) {\n journal.markUnrecoverable(action.id, reason);\n }\n break;\n }\n\n if (sameState(current, recordedPost.data)) {\n verified = true;\n } else if (sameState(current, intendedAfterInverse(action))) {\n // The inverse has already taken effect, whether by an interrupted\n // rollback or by someone doing it by hand.\n steps.push({\n ...describeStep(action),\n kind: \"already-reverted\",\n reason: \"the resource is already in the state this inverse would produce\",\n verified: true,\n plan,\n });\n if (!dryRun) {\n journal.markRolledBack(action.id);\n }\n continue;\n } else {\n const conflict = new DriftConflict(action.seq, recordedPost.data, current);\n halted = { seq: action.seq, reason: \"drift detected\", detail: conflict.message };\n steps.push({\n ...describeStep(action),\n kind: \"halt\",\n reason: \"drift detected\",\n verified: false,\n plan,\n });\n if (!dryRun) {\n journal.markUnrecoverable(action.id, conflict.message);\n }\n break;\n }\n }\n\n if (!verified && action.status === \"rolling_back\") {\n // An inverse was already sent for this action before something\n // interrupted us, and there is no declared read to tell us whether it\n // landed. Sending it again could double-apply, so a human decides.\n const reason =\n \"an inverse was already sent before an interruption and no pre-read is declared, so whether it applied cannot be determined\";\n halted = { seq: action.seq, reason, detail: action.error ?? \"\" };\n steps.push({ ...describeStep(action), kind: \"halt\", reason, verified: false, plan });\n if (!dryRun) {\n journal.markUnrecoverable(action.id, reason);\n }\n break;\n }\n\n steps.push({\n ...describeStep(action),\n kind: \"revert\",\n reason: verified ? \"state matches; applying inverse\" : unverifiedBecause(action),\n verified,\n plan,\n ...(rebuilt.inverse === undefined ? {} : { replanned: true }),\n });\n\n if (dryRun) {\n continue;\n }\n\n // Written before the call so a resume can tell \"possibly applied\" from\n // \"definitely not applied\", and claimed rather than announced: if this was\n // not the call that moved it out of `applied`, another rollback is already\n // working on it and sending the inverse again would apply it twice. An\n // action already in `rolling_back` is the other case -- a resume, which\n // has been checked for drift above -- and goes ahead.\n const claimed = journal.markRollingBack(action.id);\n if (!claimed && action.status === \"applied\") {\n const reason = \"another undo is already working on this action\";\n halted = { seq: action.seq, reason, detail: \"\" };\n steps[steps.length - 1] = {\n ...describeStep(action),\n kind: \"halt\",\n reason,\n verified,\n plan,\n };\n break;\n }\n const outcome = await executeInverse(router, plan, action.idempotencyKey, signal);\n\n if (outcome.ok) {\n journal.markRolledBack(action.id);\n continue;\n }\n\n const halt = new RollbackHalted(action.seq, outcome.message);\n if (outcome.rejected) {\n // Nothing was applied, so the action still needs undoing. Retrying is\n // the right move once whatever refused it is healthy again.\n journal.markInverseRejected(action.id, halt.message);\n } else {\n // The row stays in rolling_back: whether the call arrived is unknown,\n // and the next attempt resolves it by reading the current state.\n journal.markUnknownInverse(action.id, halt.message);\n }\n halted = { seq: action.seq, reason: \"the inverse failed\", detail: halt.message };\n steps[steps.length - 1] = {\n ...describeStep(action),\n kind: \"halt\",\n reason: \"the inverse failed\",\n verified,\n plan,\n };\n break;\n }\n\n const completedWholeRun =\n halted === undefined && !leftInPlace && options.toSeq === undefined;\n const status = completedWholeRun ? \"rolled_back\" : \"partial\";\n if (!dryRun) {\n journal.endRun(runId, status);\n }\n\n return {\n runId,\n status,\n dryRun,\n steps,\n ...(halted === undefined ? {} : { halted }),\n };\n}\n\n/**\n * Why drift could not be ruled out. The two cases are not the same thing to\n * read at the moment you are deciding whether to let an unverified revert\n * proceed: one is a policy that never claimed it could check, the other is a\n * check that was supposed to happen and did not.\n */\nfunction unverifiedBecause(action: ActionRow): string {\n return action.verify === undefined\n ? \"no pre-read declared, so drift could not be ruled out\"\n : \"the post-state was never captured, so drift could not be ruled out\";\n}\n\nfunction describeStep(action: ActionRow): { seq: number; server: string; tool: string } {\n return { seq: action.seq, server: action.server, tool: action.tool };\n}\n\n/** The state the recorded inverse is expected to leave behind. */\nfunction intendedAfterInverse(action: ActionRow): StateObservation | undefined {\n return action.snapshot === undefined ? undefined : { present: true, value: action.snapshot };\n}\n\n/**\n * `rejected` separates the two failures that matter. A tool-level error means\n * the upstream processed the inverse and refused it, so nothing was applied.\n * Anything else means the call may never have arrived, and whether it applied\n * is unknown.\n */\ntype InverseOutcome =\n | { readonly ok: true }\n | { readonly ok: false; readonly rejected: boolean; readonly message: string };\n\nasync function executeInverse(\n router: Router,\n plan: InversePlan,\n idempotencyKey: string,\n signal: AbortSignal,\n): Promise<InverseOutcome> {\n const upstream = router.byName(plan.server);\n if (upstream === undefined) {\n return { ok: false, rejected: false, message: `server ${plan.server} is not connected` };\n }\n\n let raw: unknown;\n try {\n raw = await upstream.client.request(\n {\n method: \"tools/call\",\n params: {\n name: plan.tool,\n arguments: plan.args,\n _meta: { [IDEMPOTENCY_META_KEY]: idempotencyKey },\n },\n },\n z.looseObject({}),\n { signal },\n );\n } catch (error: unknown) {\n return { ok: false, rejected: false, message: describe(error) };\n }\n\n const parsed = toolResult.safeParse(raw);\n if (parsed.success && parsed.data.isError) {\n return {\n ok: false,\n rejected: true,\n message: `the inverse was refused: ${JSON.stringify(raw)}`,\n };\n }\n return { ok: true };\n}\n","import { existsSync } from \"node:fs\";\n\nimport { labelFor, openJournal, wasRefused, type ActionRow, type Journal } from \"./journal/journal.js\";\nimport { keysIn } from \"./keys.js\";\nimport { rule, style, WORDMARK } from \"./style.js\";\n\n/**\n * A live view of the journal.\n *\n * Synartesis is not a daemon and cannot be one: an MCP client spawns a stdio\n * server itself and owns its lifetime, so nothing long-running could sit in\n * between and see those calls. What a person actually wants from a daemon is\n * the reassurance that it is there and doing something, and that does not\n * require a background process. It requires somewhere to look.\n */\n\nconst FRAMES = [\"\\u280b\", \"\\u2819\", \"\\u2839\", \"\\u2838\", \"\\u283c\", \"\\u2834\", \"\\u2826\", \"\\u2827\", \"\\u2807\", \"\\u280f\"];\n\nconst MARK: Record<string, string> = {\n readonly: \"\\u00b7\",\n reversible: \"\\u2190\",\n compensable: \"\\u2248\",\n irreversible: \"!\",\n unclassified: \"?\",\n};\n\nexport interface WatchOptions {\n readonly journalPath: string;\n readonly approveWith: string;\n readonly intervalMs?: number;\n /** Stop after this many ticks. Only tests pass it. */\n readonly maxTicks?: number;\n readonly write: (text: string) => void;\n readonly live: boolean;\n /**\n * Who a decision made from here is recorded as. Absent means the view is\n * read-only, which is what a pipe gets.\n */\n readonly decideAs?: string;\n /** Key presses. Defaults to the terminal; tests drive it directly. */\n readonly keys?: AsyncIterable<string>;\n}\n\ninterface View {\n stop: boolean;\n /** Which waiting call the keys act on. */\n cursor: number;\n notice: string;\n /** The tick the notice stops being shown at. */\n noticeUntil: number;\n}\n\n/**\n * How long a confirmation stays up, in ticks. Measured from when it was shown\n * rather than to a fixed boundary: clearing on every twenty-fourth tick meant\n * a decision made on the twenty-third was confirmed for a single frame, and\n * how long you got to read it came down to when you happened to press.\n */\nconst NOTICE_TICKS = 26;\n\nfunction line(action: ActionRow): string {\n const mark = MARK[action.class] ?? \"?\";\n const badge = `${mark} ${action.class}`.padEnd(14);\n const when = action.ts.slice(11, 19);\n const label = labelFor(action).padEnd(13);\n const status =\n action.status === \"gated\"\n ? style.strong(label)\n : wasRefused(action)\n ? style.accent(label)\n : style.quiet(label);\n return ` ${style.quiet(when)} ${style.quiet(badge)} ${status} ${action.server}.${action.tool}`;\n}\n\n/**\n * What there is to look at before the proxy has run once.\n *\n * Refusing to start was the wrong answer for this one command. Every other\n * command answers a question, and inventing an empty journal to answer it with\n * would look exactly like a real answer of \"nothing happened\". Watching is not\n * a question: the ordinary way round is to start watching, then point an agent\n * at the proxy, and the proxy is what creates the journal. A watch that will\n * not begin until something has already happened is no use at the only moment\n * anyone wants one.\n */\nfunction waitingForJournal(options: WatchOptions, tick: number): string {\n const spinner = options.live ? `${style.accent(FRAMES[tick % FRAMES.length] ?? \"\")} ` : \"\";\n return [\n \"\",\n ` ${style.plate(WORDMARK)} ${style.quiet(options.journalPath)}`,\n ` ${rule(64)}`,\n \"\",\n ` ${spinner}${style.quiet(\"no journal here yet\")}`,\n \"\",\n ` ${style.quiet(\"One appears the first time an agent calls a tool through the proxy.\")}`,\n ` ${style.quiet(\"Point your client at it, then work as usual; this will fill in.\")}`,\n \"\",\n ].join(\"\\n\");\n}\n\nfunction render(journal: Journal, options: WatchOptions, tick: number, view: View): string {\n const runs = journal.listRuns();\n const recent = journal.recentActions(12);\n const waiting = journal.listGated();\n const active = runs.filter((run) => run.status === \"active\").length;\n\n const out: string[] = [];\n out.push(\"\");\n out.push(` ${style.plate(WORDMARK)} ${style.quiet(options.journalPath)}`);\n out.push(` ${rule(64)}`);\n out.push(\"\");\n\n const spinner = options.live ? `${style.accent(FRAMES[tick % FRAMES.length] ?? \"\")} ` : \"\";\n out.push(\n ` ${spinner}${style.quiet(\"watching\")} ` +\n `${String(runs.length)} runs, ${String(active)} live ` +\n `${style.quiet(\"\\u00b7\")} ${String(recent.length)} recent actions ` +\n `${style.quiet(\"\\u00b7\")} ${waiting.length > 0 ? style.accent(`${String(waiting.length)} awaiting approval`) : style.quiet(\"nothing waiting\")}`,\n );\n out.push(\"\");\n\n if (recent.length === 0) {\n out.push(` ${style.quiet(\"No agent has done anything through this journal yet.\")}`);\n } else {\n for (const action of recent) {\n out.push(line(action));\n }\n }\n\n if (waiting.length > 0) {\n const at = Math.min(view.cursor, waiting.length - 1);\n out.push(\"\");\n out.push(` ${style.label(\"awaiting approval\")}`);\n waiting.forEach((action, index) => {\n // A cursor rather than a key that acts on all of them. One keystroke\n // that approves everything waiting is one keystroke away from\n // approving something nobody read.\n const here = index === at && canDecide(options);\n const mark = here ? style.accent(\"\\u276f\") : \" \";\n const name = here\n ? style.accent(`${action.server}.${action.tool}`)\n : style.quiet(`${action.server}.${action.tool}`);\n out.push(` ${mark} ${name} ${style.quiet(truncate(JSON.stringify(action.args), 56))}`);\n });\n out.push(\"\");\n out.push(\n canDecide(options)\n ? ` ${keyHint(\"a\", \"approve\")} ${keyHint(\"d\", \"deny\")} ${keyHint(\"j/k\", \"move\")} ${keyHint(\"q\", \"quit\")}`\n : ` ${style.quiet(`${options.approveWith} approve --all`)}`,\n );\n }\n\n if (view.notice !== \"\") {\n out.push(\"\");\n out.push(` ${style.accent(view.notice)}`);\n }\n\n out.push(\"\");\n return out.join(\"\\n\");\n}\n\nfunction truncate(text: string, limit: number): string {\n return text.length <= limit ? text : `${text.slice(0, limit - 3)}...`;\n}\n\nfunction keyHint(key: string, what: string): string {\n return `${style.strong(`[${key}]`)} ${style.quiet(what)}`;\n}\n\n/**\n * Deciding needs both a name to record it under and a keyboard to press. A\n * piped view is a report, and a report must not be able to approve anything.\n */\n/**\n * Node declares isTTY as a boolean and then leaves it undefined whenever there\n * is no terminal. Taking it as unknown is the only way to test the value that\n * is actually there rather than the one the types promise.\n */\nfunction isTerminal(value: unknown): boolean {\n return value === true;\n}\n\nfunction canDecide(options: WatchOptions): boolean {\n // stdout can be a terminal while stdin is not -- `synartesis watch\n // < /dev/null` -- and offering [a] approve there promises a key that can\n // never be pressed.\n const keyboard = options.keys !== undefined || isTerminal(process.stdin.isTTY);\n return options.live && options.decideAs !== undefined && keyboard;\n}\n\n/** Raw keystrokes from the terminal, as an iterable the loop below can read. */\nasync function* terminalKeys(): AsyncIterable<string> {\n const input = process.stdin;\n if (!input.isTTY) {\n return;\n }\n input.setRawMode(true);\n input.resume();\n try {\n for await (const chunk of input) {\n // The stream's iterator is untyped, so the shape is checked rather than\n // asserted: a wrong guess here would be a key nobody can press.\n const raw: unknown = chunk;\n const text =\n typeof raw === \"string\" ? raw : Buffer.isBuffer(raw) ? raw.toString(\"utf8\") : \"\";\n // Split, because a read is not a keypress: a terminal hands over\n // everything that has accumulated, so two quick presses arrive together.\n for (const key of keysIn(text)) {\n yield key;\n }\n }\n } finally {\n input.setRawMode(false);\n input.pause();\n }\n}\n\nexport async function watch(options: WatchOptions): Promise<number> {\n // Opened lazily, and only once there is something to open.\n let journal: Journal | undefined;\n const open = (): Journal | undefined => {\n if (journal === undefined && existsSync(options.journalPath)) {\n journal = openJournal(options.journalPath, { mustExist: true });\n }\n return journal;\n };\n\n const interval = options.intervalMs ?? 120;\n const clear = \"\\u001b[H\\u001b[2J\\u001b[3J\";\n // A holder, not plain locals: these are written from a signal handler and a\n // key loop, neither of which narrowing can see.\n const view: View = { stop: false, cursor: 0, notice: \"\", noticeUntil: 0 };\n let tick = 0;\n\n const frame = (tick: number): string => {\n const ready = open();\n return ready === undefined\n ? waitingForJournal(options, tick)\n : render(ready, options, tick, view);\n };\n\n /**\n * Answering from here rather than from a second terminal.\n *\n * The loop it removes is the one that actually hurts: an agent stops, you\n * notice, you switch window, you list what is waiting, you copy an id, you\n * run approve, you switch back. Six moves to say yes once, and every one of\n * them a chance to approve the wrong thing because you are working from an\n * id rather than from the call itself.\n */\n const decide = (approve: boolean): void => {\n const ready = open();\n if (ready === undefined || options.decideAs === undefined) {\n return;\n }\n const waiting = ready.listGated();\n const action = waiting[Math.min(view.cursor, waiting.length - 1)];\n if (action === undefined) {\n return;\n }\n const changed = approve\n ? ready.approve(action.id, options.decideAs)\n : ready.deny(action.id, options.decideAs, \"denied from the watch view\");\n // Approving is not the call. The agent was refused and is not waiting on\n // anything, so nothing happens until somebody asks it again -- and a view\n // that says only \"approved\" leaves you watching a screen that has already\n // done everything it is going to do.\n view.notice = !changed\n ? `${action.server}.${action.tool} was already settled`\n : approve\n ? `approved ${action.server}.${action.tool} \\u00b7 now tell the agent to try again`\n : `denied ${action.server}.${action.tool} \\u00b7 it will not go through`;\n view.noticeUntil = tick + NOTICE_TICKS;\n view.cursor = 0;\n };\n\n const press = (key: string): void => {\n switch (key) {\n case \"q\":\n case \"\\u0003\":\n // Ctrl-C does not raise a signal while the terminal is raw, so the\n // key that everyone reaches for has to be handled here or the view\n // cannot be left at all.\n view.stop = true;\n return;\n case \"a\":\n decide(true);\n return;\n case \"d\":\n decide(false);\n return;\n case \"j\":\n case \"\\u001b[B\":\n view.cursor += 1;\n return;\n case \"k\":\n case \"\\u001b[A\":\n view.cursor = Math.max(0, view.cursor - 1);\n return;\n default:\n return;\n }\n };\n\n // Read through a call rather than touched directly: the compiler narrows a\n // property once it has been tested and does not un-narrow it across a call\n // that could have changed it, so the check that actually matters -- the one\n // after a key has been pressed -- was being read as dead.\n const stopped = (): boolean => view.stop;\n\n const onSignal = (): void => {\n view.stop = true;\n };\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n\n const source = canDecide(options) ? (options.keys ?? terminalKeys()) : undefined;\n // Held rather than left inside a for-await. The loop only closes the\n // iterator when the loop itself ends, so a view that stopped for any other\n // reason -- a signal, a client going away -- left the reader sitting on a\n // terminal that was still in raw mode, with stdin still flowing. The\n // terminal never got its echo back and the process had a live handle it\n // would not let go of.\n const reader = source?.[Symbol.asyncIterator]();\n const reading =\n reader === undefined\n ? Promise.resolve()\n : (async (): Promise<void> => {\n for (;;) {\n const next = await reader.next();\n if (next.done === true || stopped()) {\n return;\n }\n press(next.value);\n if (stopped()) {\n return;\n }\n }\n })();\n\n try {\n if (!options.live) {\n // Not a terminal: print the state once and leave, so this is still\n // usable from a script without spraying escape codes into a pipe.\n options.write(`${frame(0)}\\n`);\n return 0;\n }\n\n options.write(\"\\u001b[?25l\");\n for (; !view.stop; tick += 1) {\n if (view.notice !== \"\" && tick >= view.noticeUntil) {\n view.notice = \"\";\n }\n options.write(clear + frame(tick));\n if (options.maxTicks !== undefined && tick + 1 >= options.maxTicks) {\n break;\n }\n await new Promise<void>((resolve) => setTimeout(resolve, interval));\n }\n return 0;\n } finally {\n if (options.live) {\n options.write(\"\\u001b[?25h\\n\");\n }\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n view.stop = true;\n // Asked to close, but not waited on indefinitely: a source blocked on a\n // read it will never get would otherwise hold the view open at exactly the\n // moment it is trying to leave.\n await Promise.race([\n (async (): Promise<void> => {\n await reader?.return?.(undefined);\n await reading;\n })(),\n new Promise<void>((resolve) => setTimeout(resolve, 50).unref()),\n ]);\n journal?.close();\n }\n}\n","/**\n * Splitting what a terminal actually hands over into the keys a person pressed.\n *\n * A raw terminal delivers whatever has accumulated since the last read, not one\n * keypress per event. Two quick presses arrive as one string, and a paste\n * arrives as a hundred. Matched whole, \"uy\" is neither u nor y, so both are\n * lost -- which is how confirming an undo by typing u and then y quickly did\n * nothing at all.\n */\n\n/**\n * ESC [ params final, or ESC O final. Everything a keyboard sends that is more\n * than one character is one of these two shapes; anything else beginning with\n * an escape is a lone escape, which is a key in its own right here.\n */\nconst SEQUENCE = /^\\u001b(\\[[0-9;?]*[ -\\/]*[@-~]|O[@-~])/;\n\nexport function keysIn(chunk: string): string[] {\n const keys: string[] = [];\n let at = 0;\n while (at < chunk.length) {\n const rest = chunk.slice(at);\n const sequence = rest.startsWith(\"\\u001b\") ? SEQUENCE.exec(rest) : null;\n const key = sequence?.[0] ?? rest.slice(0, 1);\n keys.push(key);\n at += key.length;\n }\n return keys;\n}\n","import { existsSync } from \"node:fs\";\n\nimport { labelFor, openJournal, wasRefused, type ActionRow, type Journal, type RunRow } from \"./journal/journal.js\";\nimport type { RollbackReport } from \"./rollback/rollback.js\";\nimport { keysIn } from \"./keys.js\";\nimport { rule, style, WORDMARK } from \"./style.js\";\n\n/**\n * One screen you drive, rather than eight commands you have to remember.\n *\n * The commands are still there and still what a script uses. But a person\n * looking at what an agent just did should not have to know that runs are\n * listed by one word, opened by a second and undone by a third, nor carry an\n * id between them by hand. Everything here acts on the thing under the cursor,\n * which is the thing you are already looking at.\n */\n\nconst FRAMES = [\n \"⠋\",\n \"⠙\",\n \"⠹\",\n \"⠸\",\n \"⠼\",\n \"⠴\",\n \"⠦\",\n \"⠧\",\n \"⠇\",\n \"⠏\",\n];\n\nconst MARK: Record<string, string> = {\n readonly: \"·\",\n reversible: \"←\",\n compensable: \"≈\",\n irreversible: \"!\",\n unclassified: \"?\",\n};\n\nconst CURSOR = \"❯\";\nconst DOT = \"·\";\nconst ESC = \"\\u001b\";\n\n/** How long a confirmation stays up, in ticks, counted from when it appeared. */\nconst NOTICE_TICKS = 26;\n\nexport type Undo = (runId: string, dryRun: boolean) => Promise<RollbackReport>;\n\nexport interface ConsoleOptions {\n readonly journalPath: string;\n readonly write: (text: string) => void;\n readonly live: boolean;\n /** Who a decision made here is recorded as. */\n readonly decideAs: string;\n readonly intervalMs?: number;\n /** Terminal height. Defaults to the real one, or a conservative 24. */\n readonly rows?: number;\n /** Stop after this many ticks. Only tests pass it. */\n readonly maxTicks?: number;\n /** Key presses. Defaults to the terminal; tests drive it directly. */\n readonly keys?: AsyncIterable<string>;\n /**\n * How an undo is actually carried out. Injected because performing one means\n * starting every server the manifest names, which a test of what the screen\n * does has no business doing.\n */\n readonly undo?: Undo;\n}\n\ntype Mode = \"runs\" | \"run\" | \"gates\";\n\ninterface Screen {\n stop: boolean;\n mode: Mode;\n cursor: number;\n openRun: string | undefined;\n /** An undo waiting on a yes. */\n confirming: string | undefined;\n busy: string | undefined;\n notice: string;\n noticeUntil: number;\n}\n\n/**\n * The rows a list may use, once the header, the footer and a little air are\n * taken out. A frame taller than the terminal scrolls its own top away, and\n * the top of a list is where the cursor starts, so the thing you are about to\n * act on is the first thing to disappear.\n */\nfunction roomFor(options: ConsoleOptions): number {\n const rows = options.rows ?? rowsOf(process.stdout.rows) ?? 24;\n return Math.max(3, rows - 11);\n}\n\n/**\n * A window of a long list, moved so the cursor is always inside it, with a\n * count of what is out of sight in either direction.\n */\nfunction windowed(lines: readonly string[], at: number, room: number): string[] {\n if (lines.length <= room) {\n return [...lines];\n }\n const start = Math.max(0, Math.min(at - Math.floor(room / 2), lines.length - room));\n const shown = lines.slice(start, start + room);\n const above = start;\n const below = lines.length - (start + room);\n return [\n ...(above === 0 ? [] : [` ${style.quiet(`${String(above)} more above`)}`]),\n ...shown.slice(above === 0 ? 0 : 1, below === 0 ? undefined : -1),\n ...(below === 0 ? [] : [` ${style.quiet(`${String(below)} more below`)}`]),\n ];\n}\n\nfunction truncate(text: string, limit: number): string {\n return text.length <= limit ? text : `${text.slice(0, limit - 3)}...`;\n}\n\nfunction keyHint(key: string, what: string): string {\n return `${style.strong(`[${key}]`)} ${style.quiet(what)}`;\n}\n\n/**\n * Node declares isTTY as a boolean and then leaves it undefined whenever there\n * is no terminal. Taking it as unknown is the only way to test the value that\n * is actually there rather than the one the types promise.\n */\nfunction isTerminal(value: unknown): boolean {\n return value === true;\n}\n\n/** The same for rows, which Node declares a number and leaves undefined. */\nfunction rowsOf(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0 ? value : undefined;\n}\n\nfunction canPress(options: ConsoleOptions): boolean {\n return options.live && (options.keys !== undefined || isTerminal(process.stdin.isTTY));\n}\n\nfunction modeLabel(screen: Screen): string {\n switch (screen.mode) {\n case \"runs\":\n return \"everything an agent has done through this journal\";\n case \"run\":\n return \"one run, in the order it happened\";\n case \"gates\":\n return \"held until a person decides\";\n }\n}\n\nfunction header(options: ConsoleOptions, screen: Screen, tick: number): string[] {\n const spinner = options.live ? `${style.accent(FRAMES[tick % FRAMES.length] ?? \"\")} ` : \"\";\n return [\n \"\",\n ` ${style.plate(WORDMARK)} ${style.quiet(options.journalPath)}`,\n ` ${rule(70)}`,\n \"\",\n ` ${spinner}${style.quiet(screen.busy ?? modeLabel(screen))}`,\n \"\",\n ];\n}\n\nfunction runsView(journal: Journal, screen: Screen, options: ConsoleOptions): string[] {\n const runs = [...journal.listRuns()].reverse();\n if (runs.length === 0) {\n return [\n ` ${style.quiet(\"No agent has done anything through this journal yet.\")}`,\n \"\",\n ` ${style.quiet(\"A run appears the first time one calls a tool through the proxy.\")}`,\n ];\n }\n\n const at = Math.min(screen.cursor, runs.length - 1);\n return runs.map((run, index) => {\n const actions = journal.getActions(run.id);\n const held = actions.filter((action) => action.status === \"gated\").length;\n const here = index === at && canPress(options);\n const name = (run.label ?? \"an agent\").padEnd(24);\n const note = held === 0 ? \"\" : ` ${style.accent(`${String(held)} awaiting approval`)}`;\n return (\n ` ${here ? style.accent(CURSOR) : \" \"} ${here ? style.accent(name) : style.strong(name)} ` +\n `${style.quiet(run.startedAt.slice(0, 19).replace(\"T\", \" \"))} ` +\n `${style.quiet(run.status.padEnd(11))} ${style.quiet(`${String(actions.length)} actions`)}${note}`\n );\n });\n}\n\nfunction statusOf(action: ActionRow): string {\n const text = labelFor(action).padEnd(13);\n if (wasRefused(action)) {\n return style.accent(text);\n }\n return action.status === \"gated\" ? style.strong(text) : style.quiet(text);\n}\n\nfunction runView(journal: Journal, screen: Screen): string[] {\n const runId = screen.openRun;\n if (runId === undefined) {\n return [` ${style.quiet(\"no run selected\")}`];\n }\n const run = journal.getRun(runId);\n const actions = journal.getActions(runId);\n const out = [\n ` ${style.label(\"run\")} ${style.strong(run?.label ?? \"an agent\")} ${style.quiet(runId.slice(0, 8))}`,\n \"\",\n ];\n if (actions.length === 0) {\n out.push(` ${style.quiet(\"nothing was recorded in this run\")}`);\n return out;\n }\n for (const action of actions) {\n const badge = `${MARK[action.class] ?? \"?\"} ${action.class}`.padEnd(14);\n out.push(\n ` ${style.quiet(String(action.seq).padStart(3))} ${style.quiet(badge)} ` +\n `${statusOf(action)} ${style.strong(`${action.server}.${action.tool}`)}`,\n );\n out.push(` ${style.quiet(truncate(JSON.stringify(action.args), 62))}`);\n if (action.inverse !== undefined) {\n out.push(` ${style.quiet(`undo: ${truncate(JSON.stringify(action.inverse), 56)}`)}`);\n }\n }\n return out;\n}\n\nfunction gatesView(journal: Journal, screen: Screen, options: ConsoleOptions): string[] {\n const waiting = journal.listGated();\n if (waiting.length === 0) {\n return [` ${style.quiet(\"Nothing is waiting for a decision.\")}`];\n }\n const at = Math.min(screen.cursor, waiting.length - 1);\n return waiting.map((action, index) => {\n const here = index === at && canPress(options);\n const name = `${action.server}.${action.tool}`;\n const shown = here ? style.accent(name) : style.quiet(name);\n const args = style.quiet(truncate(JSON.stringify(action.args), 54));\n return ` ${here ? style.accent(CURSOR) : \" \"} ${shown} ${args}`;\n });\n}\n\nfunction footer(screen: Screen, options: ConsoleOptions): string[] {\n if (!canPress(options)) {\n return [];\n }\n if (screen.confirming !== undefined) {\n return [\n \"\",\n ` ${style.accent(\"undo this whole run?\")} ${keyHint(\"y\", \"yes\")} ${keyHint(\"n\", \"no\")}`,\n ];\n }\n const keys =\n screen.mode === \"gates\"\n ? [keyHint(\"a\", \"approve\"), keyHint(\"d\", \"deny\"), keyHint(\"j/k\", \"move\"), keyHint(\"r\", \"runs\")]\n : screen.mode === \"run\"\n ? [\n keyHint(\"p\", \"preview undo\"),\n keyHint(\"u\", \"undo\"),\n keyHint(\"esc\", \"back\"),\n keyHint(\"g\", \"held\"),\n ]\n : [\n keyHint(\"enter\", \"open\"),\n keyHint(\"p\", \"preview undo\"),\n keyHint(\"u\", \"undo\"),\n keyHint(\"j/k\", \"move\"),\n keyHint(\"g\", \"held\"),\n ];\n return [\"\", ` ${keys.join(\" \")} ${keyHint(\"q\", \"quit\")}`];\n}\n\nfunction waitingForJournal(options: ConsoleOptions, tick: number): string {\n const spinner = options.live ? `${style.accent(FRAMES[tick % FRAMES.length] ?? \"\")} ` : \"\";\n return [\n \"\",\n ` ${style.plate(WORDMARK)} ${style.quiet(options.journalPath)}`,\n ` ${rule(70)}`,\n \"\",\n ` ${spinner}${style.quiet(\"no journal here yet\")}`,\n \"\",\n ` ${style.quiet(\"One appears the first time an agent calls a tool through the proxy.\")}`,\n ` ${style.quiet(\"Point your client at it, then work as usual; this will fill in.\")}`,\n \"\",\n ].join(\"\\n\");\n}\n\n/** Raw keystrokes from the terminal, as an iterable the loop below can read. */\nasync function* terminalKeys(): AsyncIterable<string> {\n const input = process.stdin;\n if (!isTerminal(input.isTTY)) {\n return;\n }\n input.setRawMode(true);\n input.resume();\n try {\n for await (const chunk of input) {\n // The stream's iterator is untyped, so the shape is checked rather than\n // asserted: a wrong guess here would be a key nobody can press.\n const raw: unknown = chunk;\n const text =\n typeof raw === \"string\" ? raw : Buffer.isBuffer(raw) ? raw.toString(\"utf8\") : \"\";\n // Split, because a read is not a keypress: a terminal hands over\n // everything that has accumulated, so two quick presses arrive together.\n for (const key of keysIn(text)) {\n yield key;\n }\n }\n } finally {\n input.setRawMode(false);\n input.pause();\n }\n}\n\n// Named openConsole, not console: an export called console shadows the global\n// inside its own module, so the first console.log anyone reaches for in here\n// would call this function instead.\nexport async function openConsole(options: ConsoleOptions): Promise<number> {\n let journal: Journal | undefined;\n const open = (): Journal | undefined => {\n if (journal === undefined && existsSync(options.journalPath)) {\n journal = openJournal(options.journalPath, { mustExist: true });\n }\n return journal;\n };\n\n const screen: Screen = {\n stop: false,\n mode: \"runs\",\n cursor: 0,\n openRun: undefined,\n confirming: undefined,\n busy: undefined,\n notice: \"\",\n noticeUntil: 0,\n };\n let tick = 0;\n // Read through a call rather than touched directly: the compiler narrows a\n // property once it has been tested and does not un-narrow it across a call\n // that could have changed it.\n const stopped = (): boolean => screen.stop;\n\n const say = (text: string): void => {\n screen.notice = text;\n screen.noticeUntil = tick + NOTICE_TICKS;\n };\n\n const frame = (): string => {\n const ready = open();\n if (ready === undefined) {\n return waitingForJournal(options, tick);\n }\n const room = roomFor(options);\n const body =\n screen.mode === \"runs\"\n ? windowed(runsView(ready, screen, options), screen.cursor, room)\n : screen.mode === \"run\"\n ? windowed(runView(ready, screen), 0, room)\n : windowed(gatesView(ready, screen, options), screen.cursor, room);\n const notice = screen.notice === \"\" ? [] : [\"\", ` ${style.accent(screen.notice)}`];\n return [\n ...header(options, screen, tick),\n ...body,\n ...notice,\n ...footer(screen, options),\n \"\",\n ].join(\"\\n\");\n };\n\n /** The run the cursor is on, or the one already open. */\n const selectedRun = (ready: Journal): RunRow | undefined => {\n if (screen.mode === \"run\" && screen.openRun !== undefined) {\n return ready.getRun(screen.openRun);\n }\n const runs = [...ready.listRuns()].reverse();\n return runs[Math.min(screen.cursor, runs.length - 1)];\n };\n\n const decide = (approve: boolean): void => {\n const ready = open();\n if (ready === undefined) {\n return;\n }\n const waiting = ready.listGated();\n const action = waiting[Math.min(screen.cursor, waiting.length - 1)];\n if (action === undefined) {\n return;\n }\n const changed = approve\n ? ready.approve(action.id, options.decideAs)\n : ready.deny(action.id, options.decideAs, \"denied from the console\");\n // Approving is not the call. The agent was refused and is not waiting on\n // anything, so nothing happens until somebody asks it again.\n say(\n !changed\n ? `${action.server}.${action.tool} was already settled`\n : approve\n ? `approved ${action.server}.${action.tool} ${DOT} now tell the agent to try again`\n : `denied ${action.server}.${action.tool} ${DOT} it will not go through`,\n );\n screen.cursor = 0;\n };\n\n const perform = async (runId: string, dryRun: boolean): Promise<void> => {\n if (options.undo === undefined) {\n say(\"no way to undo was configured\");\n return;\n }\n // One at a time. Undoing is slow -- it starts every server the manifest\n // names -- and a key is easy to lean on, so without this a second rollback\n // of the same run began while the first was mid-flight and both of them\n // sent the same inverses.\n if (screen.busy !== undefined) {\n say(\"still working on the last one\");\n return;\n }\n screen.busy = dryRun ? \"reading the current state...\" : \"putting it back...\";\n try {\n const report = await options.undo(runId, dryRun);\n const reverted = report.steps.filter((step) => step.kind === \"revert\").length;\n const halted = report.halted === undefined ? \"\" : ` ${DOT} halted: ${report.halted.reason}`;\n say(\n dryRun\n ? `${String(reverted)} would be reverted ${DOT} nothing changed${halted}`\n : `${report.status} ${DOT} ${String(reverted)} reverted${halted}`,\n );\n } catch (error: unknown) {\n say(error instanceof Error ? error.message : \"the undo failed\");\n } finally {\n screen.busy = undefined;\n }\n };\n\n const press = (key: string): void => {\n if (screen.confirming !== undefined) {\n const runId = screen.confirming;\n screen.confirming = undefined;\n if (key === \"y\") {\n void perform(runId, false);\n } else {\n say(\"left alone\");\n }\n return;\n }\n\n switch (key) {\n case \"q\":\n case \"\\u0003\":\n // Ctrl-C raises no signal while the terminal is raw, so the key\n // everyone reaches for has to be handled here.\n screen.stop = true;\n return;\n case \"j\":\n case `${ESC}[B`:\n screen.cursor += 1;\n return;\n case \"k\":\n case `${ESC}[A`:\n screen.cursor = Math.max(0, screen.cursor - 1);\n return;\n case \"g\":\n screen.mode = \"gates\";\n screen.cursor = 0;\n return;\n case \"r\":\n screen.mode = \"runs\";\n screen.cursor = 0;\n return;\n case ESC:\n case \"h\":\n screen.mode = \"runs\";\n screen.openRun = undefined;\n return;\n case \"\\r\":\n case \"\\n\": {\n const ready = open();\n const run = ready === undefined ? undefined : selectedRun(ready);\n if (run !== undefined) {\n screen.openRun = run.id;\n screen.mode = \"run\";\n }\n return;\n }\n case \"a\":\n if (screen.mode === \"gates\") {\n decide(true);\n }\n return;\n case \"d\":\n if (screen.mode === \"gates\") {\n decide(false);\n }\n return;\n case \"p\": {\n const ready = open();\n const run = ready === undefined ? undefined : selectedRun(ready);\n if (run !== undefined) {\n void perform(run.id, true);\n }\n return;\n }\n case \"u\": {\n if (screen.busy !== undefined) {\n say(\"still working on the last one\");\n return;\n }\n const ready = open();\n const run = ready === undefined ? undefined : selectedRun(ready);\n if (run !== undefined) {\n // Undo is the one direction that cannot itself be taken back, so it\n // is the one thing here that asks twice.\n screen.confirming = run.id;\n }\n return;\n }\n default:\n return;\n }\n };\n\n const onSignal = (): void => {\n screen.stop = true;\n };\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n\n const source = canPress(options) ? (options.keys ?? terminalKeys()) : undefined;\n // Held rather than left inside a for-await, so it can be closed however the\n // screen stops: a reader left on a raw terminal never gives the shell its\n // echo back and keeps a handle the process will not let go of.\n const reader = source?.[Symbol.asyncIterator]();\n const reading =\n reader === undefined\n ? Promise.resolve()\n : (async (): Promise<void> => {\n for (;;) {\n const next = await reader.next();\n if (next.done === true || stopped()) {\n return;\n }\n press(next.value);\n if (stopped()) {\n return;\n }\n }\n })();\n\n const interval = options.intervalMs ?? 120;\n const clear = `${ESC}[H${ESC}[2J${ESC}[3J`;\n\n try {\n if (!options.live) {\n options.write(`${frame()}\\n`);\n return 0;\n }\n options.write(`${ESC}[?25l`);\n for (; !screen.stop; tick += 1) {\n if (screen.notice !== \"\" && tick >= screen.noticeUntil) {\n screen.notice = \"\";\n }\n options.write(clear + frame());\n if (options.maxTicks !== undefined && tick + 1 >= options.maxTicks) {\n break;\n }\n await new Promise<void>((resolve) => setTimeout(resolve, interval));\n }\n return 0;\n } finally {\n if (options.live) {\n options.write(`${ESC}[?25h\\n`);\n }\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n screen.stop = true;\n // Asked to close, but not waited on indefinitely: a source blocked on a\n // read it will never get would otherwise hold the screen open at exactly\n // the moment it is trying to leave.\n await Promise.race([\n (async (): Promise<void> => {\n await reader?.return?.(undefined);\n await reading;\n })(),\n new Promise<void>((resolve) => setTimeout(resolve, 50).unref()),\n ]);\n journal?.close();\n }\n}\n"],"mappings":"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","names":["existsSync","z","z","out","tick","resolve","existsSync","FRAMES","MARK","NOTICE_TICKS","truncate","keyHint","isTerminal","out","waitingForJournal","terminalKeys","existsSync","report","resolve","existsSync","rest","line","note","statusOf","truncate","summarise","journalPath","journal"]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
describe
|
|
4
|
+
} from "./chunk-K3QIPVBY.js";
|
|
5
|
+
|
|
6
|
+
// demo/agent.ts
|
|
7
|
+
import { dirname, join } from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
10
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
var said = z.looseObject({
|
|
13
|
+
isError: z.boolean().default(false),
|
|
14
|
+
content: z.array(z.looseObject({ type: z.string(), text: z.string().optional() })).default([])
|
|
15
|
+
});
|
|
16
|
+
function line(name, raw) {
|
|
17
|
+
const parsed = said.safeParse(raw);
|
|
18
|
+
if (!parsed.success) {
|
|
19
|
+
return ` called ${name}`;
|
|
20
|
+
}
|
|
21
|
+
const text = parsed.data.content.map((block) => block.text ?? "").join(" ").replace(/\s+/g, " ");
|
|
22
|
+
return ` ${parsed.data.isError ? "refused " : "called "} ${name} ${text.slice(0, 110)}`;
|
|
23
|
+
}
|
|
24
|
+
function inherited() {
|
|
25
|
+
const env = {};
|
|
26
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
27
|
+
if (value !== void 0) {
|
|
28
|
+
env[key] = value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return env;
|
|
32
|
+
}
|
|
33
|
+
var toolArgs = z.record(z.string(), z.unknown());
|
|
34
|
+
var [journal, manifest, ...calls] = process.argv.slice(2);
|
|
35
|
+
if (journal === void 0 || manifest === void 0) {
|
|
36
|
+
throw new Error("usage: demo-agent <journal> <manifest> '<tool> <jsonArgs>' ...");
|
|
37
|
+
}
|
|
38
|
+
var client = new Client({ name: "agent", version: "0" });
|
|
39
|
+
await client.connect(
|
|
40
|
+
new StdioClientTransport({
|
|
41
|
+
command: process.execPath,
|
|
42
|
+
args: [
|
|
43
|
+
join(dirname(fileURLToPath(import.meta.url)), "proxy.js"),
|
|
44
|
+
"--manifest",
|
|
45
|
+
manifest,
|
|
46
|
+
"--journal",
|
|
47
|
+
journal
|
|
48
|
+
],
|
|
49
|
+
stderr: "ignore",
|
|
50
|
+
env: inherited()
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
for (const call of calls) {
|
|
54
|
+
const at = call.indexOf(" ");
|
|
55
|
+
const name = at === -1 ? call : call.slice(0, at);
|
|
56
|
+
const given = at === -1 ? {} : JSON.parse(call.slice(at + 1));
|
|
57
|
+
const args = toolArgs.parse(given);
|
|
58
|
+
try {
|
|
59
|
+
process.stdout.write(`${line(name, await client.callTool({ name, arguments: args }))}
|
|
60
|
+
`);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
process.stdout.write(` blocked ${name} ${describe(error).slice(0, 200)}
|
|
63
|
+
`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
await client.close();
|
|
67
|
+
//# sourceMappingURL=demo-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../demo/agent.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * A real MCP client, for the demos.\n *\n * Piping every frame into a server at once is not what a client does, and the\n * difference is not cosmetic: it makes the server run both handlers at the\n * same time. The memory server does a load-modify-save with no lock, so two\n * overlapping calls lose one of the writes outright. Waiting for each reply\n * before sending the next is both what really happens and the only way to\n * demonstrate anything about a server rather than about a race inside it.\n *\n * node dist/demo-agent.js <journal> <manifest> '<toolName> <jsonArgs>' ...\n */\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { z } from \"zod\";\n\nimport { describe } from \"../src/errors.js\";\n\nconst said = z.looseObject({\n isError: z.boolean().default(false),\n content: z.array(z.looseObject({ type: z.string(), text: z.string().optional() })).default([]),\n});\n\nfunction line(name: string, raw: unknown): string {\n const parsed = said.safeParse(raw);\n if (!parsed.success) {\n return ` called ${name}`;\n }\n const text = parsed.data.content\n .map((block) => block.text ?? \"\")\n .join(\" \")\n .replace(/\\s+/g, \" \");\n return ` ${parsed.data.isError ? \"refused \" : \"called \"} ${name} ${text.slice(0, 110)}`;\n}\n\n/** process.env types every value as optional; the transport wants only the set ones. */\nfunction inherited(): Record<string, string> {\n const env: Record<string, string> = {};\n for (const [key, value] of Object.entries(process.env)) {\n if (value !== undefined) {\n env[key] = value;\n }\n }\n return env;\n}\n\nconst toolArgs = z.record(z.string(), z.unknown());\n\nconst [journal, manifest, ...calls] = process.argv.slice(2);\nif (journal === undefined || manifest === undefined) {\n throw new Error(\"usage: demo-agent <journal> <manifest> '<tool> <jsonArgs>' ...\");\n}\n\nconst client = new Client({ name: \"agent\", version: \"0\" });\nawait client.connect(\n new StdioClientTransport({\n command: process.execPath,\n args: [\n join(dirname(fileURLToPath(import.meta.url)), \"proxy.js\"),\n \"--manifest\",\n manifest,\n \"--journal\",\n journal,\n ],\n stderr: \"ignore\",\n env: inherited(),\n }),\n);\n\nfor (const call of calls) {\n const at = call.indexOf(\" \");\n const name = at === -1 ? call : call.slice(0, at);\n const given: unknown = at === -1 ? {} : JSON.parse(call.slice(at + 1));\n const args = toolArgs.parse(given);\n try {\n process.stdout.write(`${line(name, await client.callTool({ name, arguments: args }))}\\n`);\n } catch (error: unknown) {\n process.stdout.write(` blocked ${name} ${describe(error).slice(0, 200)}\\n`);\n }\n}\n\nawait client.close();\n"],"mappings":";;;;;;AAaA,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAE9B,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC,SAAS,SAAS;AAIlB,IAAM,OAAO,EAAE,YAAY;AAAA,EACzB,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAClC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC/F,CAAC;AAED,SAAS,KAAK,MAAc,KAAsB;AAChD,QAAM,SAAS,KAAK,UAAU,GAAG;AACjC,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,cAAc,IAAI;AAAA,EAC3B;AACA,QAAM,OAAO,OAAO,KAAK,QACtB,IAAI,CAAC,UAAU,MAAM,QAAQ,EAAE,EAC/B,KAAK,GAAG,EACR,QAAQ,QAAQ,GAAG;AACtB,SAAO,KAAK,OAAO,KAAK,UAAU,aAAa,UAAU,IAAI,IAAI,KAAK,KAAK,MAAM,GAAG,GAAG,CAAC;AAC1F;AAGA,SAAS,YAAoC;AAC3C,QAAM,MAA8B,CAAC;AACrC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG,GAAG;AACtD,QAAI,UAAU,QAAW;AACvB,UAAI,GAAG,IAAI;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;AAEjD,IAAM,CAAC,SAAS,UAAU,GAAG,KAAK,IAAI,QAAQ,KAAK,MAAM,CAAC;AAC1D,IAAI,YAAY,UAAa,aAAa,QAAW;AACnD,QAAM,IAAI,MAAM,gEAAgE;AAClF;AAEA,IAAM,SAAS,IAAI,OAAO,EAAE,MAAM,SAAS,SAAS,IAAI,CAAC;AACzD,MAAM,OAAO;AAAA,EACX,IAAI,qBAAqB;AAAA,IACvB,SAAS,QAAQ;AAAA,IACjB,MAAM;AAAA,MACJ,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,GAAG,UAAU;AAAA,MACxD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,IACR,KAAK,UAAU;AAAA,EACjB,CAAC;AACH;AAEA,WAAW,QAAQ,OAAO;AACxB,QAAM,KAAK,KAAK,QAAQ,GAAG;AAC3B,QAAM,OAAO,OAAO,KAAK,OAAO,KAAK,MAAM,GAAG,EAAE;AAChD,QAAM,QAAiB,OAAO,KAAK,CAAC,IAAI,KAAK,MAAM,KAAK,MAAM,KAAK,CAAC,CAAC;AACrE,QAAM,OAAO,SAAS,MAAM,KAAK;AACjC,MAAI;AACF,YAAQ,OAAO,MAAM,GAAG,KAAK,MAAM,MAAM,OAAO,SAAS,EAAE,MAAM,WAAW,KAAK,CAAC,CAAC,CAAC;AAAA,CAAI;AAAA,EAC1F,SAAS,OAAgB;AACvB,YAAQ,OAAO,MAAM,cAAc,IAAI,KAAK,SAAS,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC;AAAA,CAAI;AAAA,EAC/E;AACF;AAEA,MAAM,OAAO,MAAM;","names":[]}
|