Unified · Split
| @@ -0,0 +1,286 @@ | ||
| 1 | +import path from "node:path"; | |
| 2 | + | |
| 3 | +type ApprovalStatus = "pending" | "approved" | "denied"; | |
| 4 | + | |
| 5 | +interface ApprovalItem { | |
| 6 | + id: string; | |
| 7 | + title: string; | |
| 8 | + details: string; | |
| 9 | + status: ApprovalStatus; | |
| 10 | + createdAt: number; | |
| 11 | +} | |
| 12 | + | |
| 13 | +function parseArgs(argv: string[]): { session: string; inline: boolean; tmuxSession: string; agentCommand: string } { | |
| 14 | + const session = argv[0] && !argv[0].startsWith("-") ? argv[0] : "claude"; | |
| 15 | + const inline = argv.includes("--inline"); | |
| 16 | + | |
| 17 | + const tmuxSessionFlagIndex = argv.indexOf("--tmux-session"); | |
| 18 | + const tmuxSession = tmuxSessionFlagIndex >= 0 && argv[tmuxSessionFlagIndex + 1] | |
| 19 | + ? String(argv[tmuxSessionFlagIndex + 1]) | |
| 20 | + : "executor-approvals"; | |
| 21 | + | |
| 22 | + const agentCommandFlagIndex = argv.indexOf("--agent-cmd"); | |
| 23 | + const agentCommand = agentCommandFlagIndex >= 0 && argv[agentCommandFlagIndex + 1] | |
| 24 | + ? String(argv[agentCommandFlagIndex + 1]) | |
| 25 | + : session; | |
| 26 | + | |
| 27 | + return { session, inline, tmuxSession, agentCommand }; | |
| 28 | +} | |
| 29 | + | |
| 30 | +function hasTmuxBinary(): boolean { | |
| 31 | + const result = Bun.spawnSync({ cmd: ["tmux", "-V"] }); | |
| 32 | + return result.exitCode === 0; | |
| 33 | +} | |
| 34 | + | |
| 35 | +function getTmuxClients(): string[] { | |
| 36 | + const result = Bun.spawnSync({ cmd: ["tmux", "list-clients", "-F", "#{client_name}"] }); | |
| 37 | + if (result.exitCode !== 0) return []; | |
| 38 | + | |
| 39 | + return Buffer.from(result.stdout) | |
| 40 | + .toString("utf8") | |
| 41 | + .split("\n") | |
| 42 | + .map((line) => line.trim()) | |
| 43 | + .filter((line) => line.length > 0 && line !== "no current client"); | |
| 44 | +} | |
| 45 | + | |
| 46 | +async function launchTmuxPopup(session: string, clientTarget: string): Promise<void> { | |
| 47 | + const scriptPath = path.resolve(import.meta.dir, "approval-client.ts"); | |
| 48 | + const command = `bun run ${scriptPath} ${session} --inline`; | |
| 49 | + Bun.spawnSync({ | |
| 50 | + cmd: ["tmux", "display-popup", "-t", clientTarget, "-E", "-w", "82%", "-h", "70%", command], | |
| 51 | + stdin: "inherit", | |
| 52 | + stdout: "inherit", | |
| 53 | + stderr: "inherit", | |
| 54 | + }); | |
| 55 | +} | |
| 56 | + | |
| 57 | +function shellQuote(value: string): string { | |
| 58 | + return `'${value.replace(/'/g, "'\\''")}'`; | |
| 59 | +} | |
| 60 | + | |
| 61 | +function tmuxSessionExists(tmuxSession: string): boolean { | |
| 62 | + const result = Bun.spawnSync({ cmd: ["tmux", "has-session", "-t", tmuxSession] }); | |
| 63 | + return result.exitCode === 0; | |
| 64 | +} | |
| 65 | + | |
| 66 | +function runTmuxCommand(cmd: string[]): boolean { | |
| 67 | + const result = Bun.spawnSync({ | |
| 68 | + cmd, | |
| 69 | + stdin: "inherit", | |
| 70 | + stdout: "inherit", | |
| 71 | + stderr: "inherit", | |
| 72 | + }); | |
| 73 | + return result.exitCode === 0; | |
| 74 | +} | |
| 75 | + | |
| 76 | +function ensureSessionUiOptions(tmuxSession: string): void { | |
| 77 | + runTmuxCommand(["tmux", "set-option", "-t", tmuxSession, "mouse", "on"]); | |
| 78 | + runTmuxCommand(["tmux", "set-option", "-t", tmuxSession, "pane-border-status", "top"]); | |
| 79 | + runTmuxCommand(["tmux", "set-option", "-t", tmuxSession, "pane-border-format", "#{pane_index}: #{pane_title}"]); | |
| 80 | +} | |
| 81 | + | |
| 82 | +function setPaneTitles(windowTarget: string): void { | |
| 83 | + runTmuxCommand(["tmux", "select-pane", "-t", `${windowTarget}.0`, "-T", "Claude"]); | |
| 84 | + runTmuxCommand(["tmux", "select-pane", "-t", `${windowTarget}.1`, "-T", "Approvals"]); | |
| 85 | +} | |
| 86 | + | |
| 87 | +async function launchManagedTmuxWorkspace(session: string, tmuxSession: string, agentCommand: string): Promise<boolean> { | |
| 88 | + const scriptPath = path.resolve(import.meta.dir, "approval-client.ts"); | |
| 89 | + const approvalCommand = `bun run ${shellQuote(scriptPath)} ${shellQuote(session)} --inline`; | |
| 90 | + | |
| 91 | + if (!tmuxSessionExists(tmuxSession)) { | |
| 92 | + const created = runTmuxCommand(["tmux", "new-session", "-d", "-s", tmuxSession, agentCommand]); | |
| 93 | + if (!created) return false; | |
| 94 | + | |
| 95 | + ensureSessionUiOptions(tmuxSession); | |
| 96 | + | |
| 97 | + const split = runTmuxCommand(["tmux", "split-window", "-t", `${tmuxSession}:0`, "-v", "-p", "30", approvalCommand]); | |
| 98 | + if (!split) return false; | |
| 99 | + | |
| 100 | + setPaneTitles(`${tmuxSession}:0`); | |
| 101 | + runTmuxCommand(["tmux", "select-pane", "-t", `${tmuxSession}:0.0`]); | |
| 102 | + return runTmuxCommand(["tmux", "attach-session", "-t", tmuxSession]); | |
| 103 | + } | |
| 104 | + | |
| 105 | + const windowName = `exec-${Date.now()}`; | |
| 106 | + const windowTarget = `${tmuxSession}:${windowName}`; | |
| 107 | + ensureSessionUiOptions(tmuxSession); | |
| 108 | + | |
| 109 | + const createdWindow = runTmuxCommand(["tmux", "new-window", "-t", `${tmuxSession}:`, "-n", windowName, agentCommand]); | |
| 110 | + if (!createdWindow) return false; | |
| 111 | + | |
| 112 | + const splitWindow = runTmuxCommand(["tmux", "split-window", "-t", windowTarget, "-v", "-p", "30", approvalCommand]); | |
| 113 | + if (!splitWindow) return false; | |
| 114 | + | |
| 115 | + setPaneTitles(windowTarget); | |
| 116 | + runTmuxCommand(["tmux", "select-pane", "-t", `${windowTarget}.0`]); | |
| 117 | + return runTmuxCommand(["tmux", "attach-session", "-t", tmuxSession]); | |
| 118 | +} | |
| 119 | + | |
| 120 | +function makeApproval(session: string, index: number): ApprovalItem { | |
| 121 | + const actions = [ | |
| 122 | + "Write DNS record", | |
| 123 | + "Delete production file", | |
| 124 | + "Rotate API token", | |
| 125 | + "Deploy migration", | |
| 126 | + "Run destructive cleanup", | |
| 127 | + ]; | |
| 128 | + | |
| 129 | + const title = actions[index % actions.length] ?? "Tool action"; | |
| 130 | + const id = `appr_${crypto.randomUUID().slice(0, 8)}`; | |
| 131 | + | |
| 132 | + return { | |
| 133 | + id, | |
| 134 | + title, | |
| 135 | + details: `Session: ${session} -> tools.example.action()`, | |
| 136 | + status: "pending", | |
| 137 | + createdAt: Date.now(), | |
| 138 | + }; | |
| 139 | +} | |
| 140 | + | |
| 141 | +function statusMarker(status: ApprovalStatus): string { | |
| 142 | + if (status === "approved") return "[approved]"; | |
| 143 | + if (status === "denied") return "[denied]"; | |
| 144 | + return "[pending]"; | |
| 145 | +} | |
| 146 | + | |
| 147 | +function clearAndRender(session: string, approvals: ApprovalItem[], selected: number): void { | |
| 148 | + process.stdout.write("\x1Bc"); | |
| 149 | + process.stdout.write("Approval Popup Demo\n"); | |
| 150 | + process.stdout.write(`Session: ${session}\n`); | |
| 151 | + process.stdout.write("Controls: j/k move a approve d deny n new request q quit\n"); | |
| 152 | + process.stdout.write("tmux tip: Ctrl+b then o to switch panes (mouse is enabled).\n"); | |
| 153 | + process.stdout.write("-".repeat(72) + "\n"); | |
| 154 | + | |
| 155 | + if (approvals.length === 0) { | |
| 156 | + process.stdout.write("No approvals. Press n to enqueue one.\n"); | |
| 157 | + return; | |
| 158 | + } | |
| 159 | + | |
| 160 | + approvals.forEach((item, idx) => { | |
| 161 | + const pointer = idx === selected ? ">" : " "; | |
| 162 | + const time = new Date(item.createdAt).toLocaleTimeString(); | |
| 163 | + process.stdout.write(`${pointer} ${statusMarker(item.status)} ${item.id} ${item.title} (${time})\n`); | |
| 164 | + process.stdout.write(` ${item.details}\n`); | |
| 165 | + }); | |
| 166 | +} | |
| 167 | + | |
| 168 | +async function runInlineUi(session: string): Promise<number> { | |
| 169 | + const approvals: ApprovalItem[] = [makeApproval(session, 0)]; | |
| 170 | + let selected = 0; | |
| 171 | + let sequence = 1; | |
| 172 | + | |
| 173 | + const enqueueTimer = setInterval(() => { | |
| 174 | + approvals.unshift(makeApproval(session, sequence)); | |
| 175 | + sequence += 1; | |
| 176 | + selected = 0; | |
| 177 | + clearAndRender(session, approvals, selected); | |
| 178 | + }, 12000); | |
| 179 | + | |
| 180 | + const cleanup = (): void => { | |
| 181 | + clearInterval(enqueueTimer); | |
| 182 | + if (process.stdin.isTTY) { | |
| 183 | + process.stdin.setRawMode(false); | |
| 184 | + } | |
| 185 | + process.stdin.pause(); | |
| 186 | + }; | |
| 187 | + | |
| 188 | + clearAndRender(session, approvals, selected); | |
| 189 | + | |
| 190 | + return await new Promise<number>((resolve) => { | |
| 191 | + if (process.stdin.isTTY) { | |
| 192 | + process.stdin.setRawMode(true); | |
| 193 | + } | |
| 194 | + | |
| 195 | + process.stdin.setEncoding("utf8"); | |
| 196 | + process.stdin.resume(); | |
| 197 | + | |
| 198 | + const finish = (code: number) => { | |
| 199 | + cleanup(); | |
| 200 | + resolve(code); | |
| 201 | + }; | |
| 202 | + | |
| 203 | + process.stdin.on("data", (chunk) => { | |
| 204 | + const key = typeof chunk === "string" ? chunk : chunk.toString("utf8"); | |
| 205 | + | |
| 206 | + if (key === "\u0003" || key === "q") { | |
| 207 | + finish(0); | |
| 208 | + return; | |
| 209 | + } | |
| 210 | + | |
| 211 | + if (key === "j" || key === "\u001B[B") { | |
| 212 | + if (approvals.length > 0) { | |
| 213 | + selected = Math.min(approvals.length - 1, selected + 1); | |
| 214 | + } | |
| 215 | + clearAndRender(session, approvals, selected); | |
| 216 | + return; | |
| 217 | + } | |
| 218 | + | |
| 219 | + if (key === "k" || key === "\u001B[A") { | |
| 220 | + if (approvals.length > 0) { | |
| 221 | + selected = Math.max(0, selected - 1); | |
| 222 | + } | |
| 223 | + clearAndRender(session, approvals, selected); | |
| 224 | + return; | |
| 225 | + } | |
| 226 | + | |
| 227 | + if (key === "n") { | |
| 228 | + approvals.unshift(makeApproval(session, sequence)); | |
| 229 | + sequence += 1; | |
| 230 | + selected = 0; | |
| 231 | + clearAndRender(session, approvals, selected); | |
| 232 | + return; | |
| 233 | + } | |
| 234 | + | |
| 235 | + const current = approvals[selected]; | |
| 236 | + if (!current || current.status !== "pending") { | |
| 237 | + return; | |
| 238 | + } | |
| 239 | + | |
| 240 | + if (key === "a") { | |
| 241 | + current.status = "approved"; | |
| 242 | + clearAndRender(session, approvals, selected); | |
| 243 | + return; | |
| 244 | + } | |
| 245 | + | |
| 246 | + if (key === "d") { | |
| 247 | + current.status = "denied"; | |
| 248 | + clearAndRender(session, approvals, selected); | |
| 249 | + } | |
| 250 | + }); | |
| 251 | + }); | |
| 252 | +} | |
| 253 | + | |
| 254 | +async function main(): Promise<number> { | |
| 255 | + const { session, inline, tmuxSession, agentCommand } = parseArgs(process.argv.slice(2)); | |
| 256 | + | |
| 257 | + if (!inline) { | |
| 258 | + if (!hasTmuxBinary()) { | |
| 259 | + console.error("tmux is not installed."); | |
| 260 | + console.error("Install tmux, or rerun with --inline."); | |
| 261 | + return 1; | |
| 262 | + } | |
| 263 | + | |
| 264 | + const clients = getTmuxClients(); | |
| 265 | + const target = clients[0]; | |
| 266 | + if (target) { | |
| 267 | + await launchTmuxPopup(session, target); | |
| 268 | + return 0; | |
| 269 | + } | |
| 270 | + | |
| 271 | + console.log(`No active tmux clients. Launching '${agentCommand}' with approvals in session '${tmuxSession}'...`); | |
| 272 | + const started = await launchManagedTmuxWorkspace(session, tmuxSession, agentCommand); | |
| 273 | + if (started) { | |
| 274 | + return 0; | |
| 275 | + } | |
| 276 | + | |
| 277 | + console.error("Unable to launch managed tmux workspace."); | |
| 278 | + console.error("You can still run the inline demo with --inline."); | |
| 279 | + return 1; | |
| 280 | + } | |
| 281 | + | |
| 282 | + return await runInlineUi(session); | |
| 283 | +} | |
| 284 | + | |
| 285 | +const code = await main(); | |
| 286 | +process.exit(code); | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +{ | |
| 2 | + "mcpServers": { | |
| 3 | + "memory-approval-demo": { | |
| 4 | + "command": "bun", | |
| 5 | + "args": [ | |
| 6 | + "run", | |
| 7 | + "/home/rhys/assistant/experiemental/mcp-memory-approvals.ts" | |
| 8 | + ] | |
| 9 | + } | |
| 10 | + } | |
| 11 | +} | |
| @@ -0,0 +1,133 @@ | ||
| 1 | +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| 2 | +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | |
| 3 | +import { z } from "zod"; | |
| 4 | + | |
| 5 | +type ApprovalDecision = "approved" | "denied"; | |
| 6 | + | |
| 7 | +interface ApprovalRecord { | |
| 8 | + id: string; | |
| 9 | + action: string; | |
| 10 | + justification: string; | |
| 11 | + createdAt: number; | |
| 12 | + decision: ApprovalDecision; | |
| 13 | + decidedAt: number; | |
| 14 | +} | |
| 15 | + | |
| 16 | +const approvals: ApprovalRecord[] = []; | |
| 17 | + | |
| 18 | +const mcp = new McpServer( | |
| 19 | + { name: "memory-approval-demo", version: "0.0.1" }, | |
| 20 | + { | |
| 21 | + capabilities: { | |
| 22 | + tools: {}, | |
| 23 | + experimental: { | |
| 24 | + elicitation: { | |
| 25 | + form: {}, | |
| 26 | + }, | |
| 27 | + }, | |
| 28 | + }, | |
| 29 | + }, | |
| 30 | +); | |
| 31 | + | |
| 32 | +mcp.registerTool( | |
| 33 | + "dangerous_action", | |
| 34 | + { | |
| 35 | + description: "Runs a fake dangerous action after explicit approval.", | |
| 36 | + inputSchema: { | |
| 37 | + action: z.string().min(1), | |
| 38 | + justification: z.string().optional(), | |
| 39 | + }, | |
| 40 | + }, | |
| 41 | + async ({ action, justification }) => { | |
| 42 | + const approvalId = `appr_${crypto.randomUUID().slice(0, 8)}`; | |
| 43 | + | |
| 44 | + let decision: ApprovalDecision = "denied"; | |
| 45 | + | |
| 46 | + try { | |
| 47 | + const response = await mcp.server.elicitInput({ | |
| 48 | + mode: "form", | |
| 49 | + message: `Approve dangerous action '${action}'?`, | |
| 50 | + requestedSchema: { | |
| 51 | + type: "object", | |
| 52 | + properties: { | |
| 53 | + decision: { | |
| 54 | + type: "string", | |
| 55 | + oneOf: [ | |
| 56 | + { const: "approved", title: "Approve" }, | |
| 57 | + { const: "denied", title: "Deny" }, | |
| 58 | + ], | |
| 59 | + }, | |
| 60 | + }, | |
| 61 | + required: ["decision"], | |
| 62 | + }, | |
| 63 | + }); | |
| 64 | + | |
| 65 | + if (response.action === "accept" && response.content?.decision === "approved") { | |
| 66 | + decision = "approved"; | |
| 67 | + } | |
| 68 | + } catch (error) { | |
| 69 | + console.error("elicitation failed", error); | |
| 70 | + decision = "denied"; | |
| 71 | + } | |
| 72 | + | |
| 73 | + const now = Date.now(); | |
| 74 | + approvals.unshift({ | |
| 75 | + id: approvalId, | |
| 76 | + action, | |
| 77 | + justification: justification ?? "", | |
| 78 | + createdAt: now, | |
| 79 | + decision, | |
| 80 | + decidedAt: now, | |
| 81 | + }); | |
| 82 | + | |
| 83 | + if (decision === "denied") { | |
| 84 | + return { | |
| 85 | + content: [{ type: "text", text: `Denied '${action}'.` }], | |
| 86 | + structuredContent: { | |
| 87 | + approvalId, | |
| 88 | + status: "denied", | |
| 89 | + action, | |
| 90 | + }, | |
| 91 | + }; | |
| 92 | + } | |
| 93 | + | |
| 94 | + return { | |
| 95 | + content: [{ type: "text", text: `Approved and executed '${action}'.` }], | |
| 96 | + structuredContent: { | |
| 97 | + approvalId, | |
| 98 | + status: "approved", | |
| 99 | + action, | |
| 100 | + executed: true, | |
| 101 | + }, | |
| 102 | + }; | |
| 103 | + }, | |
| 104 | +); | |
| 105 | + | |
| 106 | +mcp.registerTool( | |
| 107 | + "approval_history", | |
| 108 | + { | |
| 109 | + description: "Lists in-memory approval decisions for this MCP server process.", | |
| 110 | + inputSchema: { | |
| 111 | + limit: z.number().int().min(1).max(100).optional(), | |
| 112 | + }, | |
| 113 | + }, | |
| 114 | + async ({ limit }) => { | |
| 115 | + const max = limit ?? 20; | |
| 116 | + const items = approvals.slice(0, max).map((entry) => ({ | |
| 117 | + id: entry.id, | |
| 118 | + action: entry.action, | |
| 119 | + justification: entry.justification, | |
| 120 | + decision: entry.decision, | |
| 121 | + createdAt: entry.createdAt, | |
| 122 | + decidedAt: entry.decidedAt, | |
| 123 | + })); | |
| 124 | + | |
| 125 | + return { | |
| 126 | + content: [{ type: "text", text: `Returning ${items.length} approval entries.` }], | |
| 127 | + structuredContent: { items }, | |
| 128 | + }; | |
| 129 | + }, | |
| 130 | +); | |
| 131 | + | |
| 132 | +const transport = new StdioServerTransport(); | |
| 133 | +await mcp.connect(transport); | |
| @@ -0,0 +1,9 @@ | ||
| 1 | +# Executor v2 Scaffold | |
| 2 | + | |
| 3 | +This directory is a fresh monorepo scaffold for the Executor v2 architecture. | |
| 4 | + | |
| 5 | +## Included | |
| 6 | + | |
| 7 | +- Workspace root `package.json` and `tsconfig.json` | |
| 8 | +- App and package folders with `src/`, `package.json`, `tsconfig.json`, and `README.md` | |
| 9 | +- No implementation files yet | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# app-cli | |
| 2 | + | |
| 3 | +CLI app scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/app-cli", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# app-convex | |
| 2 | + | |
| 3 | +Convex remote server app scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/app-convex", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# app-pm | |
| 2 | + | |
| 3 | +Local Process Manager app scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/app-pm", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# app-web | |
| 2 | + | |
| 3 | +Web UI app scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/app-web", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,13 @@ | ||
| 1 | +{ | |
| 2 | + "name": "executor-v2", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "packageManager": "bun@1.2.22", | |
| 6 | + "workspaces": [ | |
| 7 | + "apps/*", | |
| 8 | + "packages/*" | |
| 9 | + ], | |
| 10 | + "scripts": { | |
| 11 | + "typecheck": "bunx tsc --noEmit" | |
| 12 | + } | |
| 13 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# ai-sdk-adapter | |
| 2 | + | |
| 3 | +AI SDK adapter scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/ai-sdk-adapter", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# approvals | |
| 2 | + | |
| 3 | +Approval and input broker scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/approvals", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,5 @@ | ||
| 1 | +# confect-core | |
| 2 | + | |
| 3 | +Effect schema helper primitives scaffold for Executor v2. | |
| 4 | + | |
| 5 | +Current scaffold includes basic helpers in `src/schema.ts`. | |
| @@ -0,0 +1,14 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/confect-core", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "exports": { | |
| 6 | + ".": "./src/index.ts" | |
| 7 | + }, | |
| 8 | + "scripts": { | |
| 9 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 10 | + }, | |
| 11 | + "dependencies": { | |
| 12 | + "effect": "^3.19.4" | |
| 13 | + } | |
| 14 | +} | |
| @@ -0,0 +1 @@ | ||
| 1 | +export * from "./schema"; | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +export const TimestampMsSchema = Schema.Number; | |
| 4 | + | |
| 5 | +export const makeIdSchema = (brandName: string) => | |
| 6 | + Schema.String.pipe(Schema.brand(brandName)); | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# domain | |
| 2 | + | |
| 3 | +Domain service layer scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/domain", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# engine | |
| 2 | + | |
| 3 | +Runtime execution engine scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/engine", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# mcp-gateway | |
| 2 | + | |
| 3 | +MCP gateway surface scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/mcp-gateway", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# oauth | |
| 2 | + | |
| 3 | +OAuth primitives scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/oauth", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# rpc | |
| 2 | + | |
| 3 | +Effect RPC contract scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/rpc", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,9 @@ | ||
| 1 | +# schema | |
| 2 | + | |
| 3 | +Canonical Effect schema package scaffold for Executor v2. | |
| 4 | + | |
| 5 | +Current scaffold includes: | |
| 6 | +- branded IDs (`src/ids.ts`) | |
| 7 | +- shared enums and primitives (`src/enums.ts`, `src/common.ts`) | |
| 8 | +- core model schemas in `src/models/*` | |
| 9 | +- local snapshot/event schemas (`src/snapshot.ts`) | |
| @@ -0,0 +1,14 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/schema", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "exports": { | |
| 6 | + ".": "./src/index.ts" | |
| 7 | + }, | |
| 8 | + "scripts": { | |
| 9 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 10 | + }, | |
| 11 | + "dependencies": { | |
| 12 | + "effect": "^3.19.4" | |
| 13 | + } | |
| 14 | +} | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +export const SchemaVersionSchema = Schema.Number; | |
| 4 | +export const TimestampMsSchema = Schema.Number; | |
| 5 | +export const JsonStringSchema = Schema.String; | |
| 6 | + | |
| 7 | +export type SchemaVersion = typeof SchemaVersionSchema.Type; | |
| 8 | +export type TimestampMs = typeof TimestampMsSchema.Type; | |
| @@ -0,0 +1,19 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +export const RuntimeModeSchema = Schema.Literal("local", "linked", "remote"); | |
| 4 | +export const SourceKindSchema = Schema.Literal("mcp", "openapi", "graphql", "internal"); | |
| 5 | +export const SourceStatusSchema = Schema.Literal("draft", "probing", "auth_required", "connected", "error"); | |
| 6 | +export const PolicyDecisionSchema = Schema.Literal("allow", "require_approval", "deny"); | |
| 7 | +export const ApprovalStatusSchema = Schema.Literal("pending", "approved", "denied", "expired"); | |
| 8 | +export const TaskRunStatusSchema = Schema.Literal("queued", "running", "completed", "failed", "timed_out", "denied"); | |
| 9 | +export const CredentialModeSchema = Schema.Literal("none", "api_key", "bearer", "oauth2", "custom"); | |
| 10 | +export const SyncTargetSchema = Schema.Literal("remote"); | |
| 11 | + | |
| 12 | +export type RuntimeMode = typeof RuntimeModeSchema.Type; | |
| 13 | +export type SourceKind = typeof SourceKindSchema.Type; | |
| 14 | +export type SourceStatus = typeof SourceStatusSchema.Type; | |
| 15 | +export type PolicyDecision = typeof PolicyDecisionSchema.Type; | |
| 16 | +export type ApprovalStatus = typeof ApprovalStatusSchema.Type; | |
| 17 | +export type TaskRunStatus = typeof TaskRunStatusSchema.Type; | |
| 18 | +export type CredentialMode = typeof CredentialModeSchema.Type; | |
| 19 | +export type SyncTarget = typeof SyncTargetSchema.Type; | |
| @@ -0,0 +1,25 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +export const ProfileIdSchema = Schema.String.pipe(Schema.brand("ProfileId")); | |
| 4 | +export const WorkspaceIdSchema = Schema.String.pipe(Schema.brand("WorkspaceId")); | |
| 5 | +export const SourceIdSchema = Schema.String.pipe(Schema.brand("SourceId")); | |
| 6 | +export const ToolArtifactIdSchema = Schema.String.pipe(Schema.brand("ToolArtifactId")); | |
| 7 | +export const CredentialRefIdSchema = Schema.String.pipe(Schema.brand("CredentialRefId")); | |
| 8 | +export const OAuthTokenIdSchema = Schema.String.pipe(Schema.brand("OAuthTokenId")); | |
| 9 | +export const PolicyIdSchema = Schema.String.pipe(Schema.brand("PolicyId")); | |
| 10 | +export const ApprovalIdSchema = Schema.String.pipe(Schema.brand("ApprovalId")); | |
| 11 | +export const TaskRunIdSchema = Schema.String.pipe(Schema.brand("TaskRunId")); | |
| 12 | +export const SyncStateIdSchema = Schema.String.pipe(Schema.brand("SyncStateId")); | |
| 13 | +export const EventIdSchema = Schema.String.pipe(Schema.brand("EventId")); | |
| 14 | + | |
| 15 | +export type ProfileId = typeof ProfileIdSchema.Type; | |
| 16 | +export type WorkspaceId = typeof WorkspaceIdSchema.Type; | |
| 17 | +export type SourceId = typeof SourceIdSchema.Type; | |
| 18 | +export type ToolArtifactId = typeof ToolArtifactIdSchema.Type; | |
| 19 | +export type CredentialRefId = typeof CredentialRefIdSchema.Type; | |
| 20 | +export type OAuthTokenId = typeof OAuthTokenIdSchema.Type; | |
| 21 | +export type PolicyId = typeof PolicyIdSchema.Type; | |
| 22 | +export type ApprovalId = typeof ApprovalIdSchema.Type; | |
| 23 | +export type TaskRunId = typeof TaskRunIdSchema.Type; | |
| 24 | +export type SyncStateId = typeof SyncStateIdSchema.Type; | |
| 25 | +export type EventId = typeof EventIdSchema.Type; | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +export * from "./common"; | |
| 2 | +export * from "./enums"; | |
| 3 | +export * from "./ids"; | |
| 4 | + | |
| 5 | +export * from "./models/profile"; | |
| 6 | +export * from "./models/workspace"; | |
| 7 | +export * from "./models/source"; | |
| 8 | +export * from "./models/tool-artifact"; | |
| 9 | +export * from "./models/credential-ref"; | |
| 10 | +export * from "./models/oauth-token"; | |
| 11 | +export * from "./models/policy"; | |
| 12 | +export * from "./models/approval"; | |
| 13 | +export * from "./models/task-run"; | |
| 14 | +export * from "./models/sync-state"; | |
| 15 | +export * from "./models/event-envelope"; | |
| 16 | + | |
| 17 | +export * from "./snapshot"; | |
| @@ -0,0 +1,19 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { ApprovalStatusSchema } from "../enums"; | |
| 5 | +import { ApprovalIdSchema, TaskRunIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 6 | + | |
| 7 | +export const ApprovalSchema = Schema.Struct({ | |
| 8 | + id: ApprovalIdSchema, | |
| 9 | + workspaceId: WorkspaceIdSchema, | |
| 10 | + taskRunId: TaskRunIdSchema, | |
| 11 | + toolPath: Schema.String, | |
| 12 | + status: ApprovalStatusSchema, | |
| 13 | + inputPreviewJson: Schema.String, | |
| 14 | + reason: Schema.NullOr(Schema.String), | |
| 15 | + requestedAt: TimestampMsSchema, | |
| 16 | + resolvedAt: Schema.NullOr(TimestampMsSchema), | |
| 17 | +}); | |
| 18 | + | |
| 19 | +export type Approval = typeof ApprovalSchema.Type; | |
| @@ -0,0 +1,19 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { CredentialModeSchema } from "../enums"; | |
| 5 | +import { CredentialRefIdSchema, SourceIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 6 | + | |
| 7 | +export const CredentialRefSchema = Schema.Struct({ | |
| 8 | + id: CredentialRefIdSchema, | |
| 9 | + workspaceId: WorkspaceIdSchema, | |
| 10 | + sourceId: SourceIdSchema, | |
| 11 | + mode: CredentialModeSchema, | |
| 12 | + label: Schema.String, | |
| 13 | + secretRef: Schema.String, | |
| 14 | + headerName: Schema.NullOr(Schema.String), | |
| 15 | + createdAt: TimestampMsSchema, | |
| 16 | + updatedAt: TimestampMsSchema, | |
| 17 | +}); | |
| 18 | + | |
| 19 | +export type CredentialRef = typeof CredentialRefSchema.Type; | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { SchemaVersionSchema, TimestampMsSchema } from "../common"; | |
| 4 | +import { EventIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 5 | + | |
| 6 | +export const EventEnvelopeSchema = Schema.Struct({ | |
| 7 | + id: EventIdSchema, | |
| 8 | + workspaceId: WorkspaceIdSchema, | |
| 9 | + sequence: Schema.Number, | |
| 10 | + schemaVersion: SchemaVersionSchema, | |
| 11 | + eventType: Schema.String, | |
| 12 | + payloadJson: Schema.String, | |
| 13 | + createdAt: TimestampMsSchema, | |
| 14 | +}); | |
| 15 | + | |
| 16 | +export type EventEnvelope = typeof EventEnvelopeSchema.Type; | |
| @@ -0,0 +1,19 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { OAuthTokenIdSchema, SourceIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 5 | + | |
| 6 | +export const OAuthTokenSchema = Schema.Struct({ | |
| 7 | + id: OAuthTokenIdSchema, | |
| 8 | + workspaceId: WorkspaceIdSchema, | |
| 9 | + sourceId: SourceIdSchema, | |
| 10 | + issuer: Schema.String, | |
| 11 | + accessTokenRef: Schema.String, | |
| 12 | + refreshTokenRef: Schema.NullOr(Schema.String), | |
| 13 | + scope: Schema.Array(Schema.String), | |
| 14 | + expiresAt: Schema.NullOr(TimestampMsSchema), | |
| 15 | + createdAt: TimestampMsSchema, | |
| 16 | + updatedAt: TimestampMsSchema, | |
| 17 | +}); | |
| 18 | + | |
| 19 | +export type OAuthToken = typeof OAuthTokenSchema.Type; | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { PolicyDecisionSchema } from "../enums"; | |
| 5 | +import { PolicyIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 6 | + | |
| 7 | +export const PolicySchema = Schema.Struct({ | |
| 8 | + id: PolicyIdSchema, | |
| 9 | + workspaceId: WorkspaceIdSchema, | |
| 10 | + toolPathPattern: Schema.String, | |
| 11 | + decision: PolicyDecisionSchema, | |
| 12 | + createdAt: TimestampMsSchema, | |
| 13 | + updatedAt: TimestampMsSchema, | |
| 14 | +}); | |
| 15 | + | |
| 16 | +export type Policy = typeof PolicySchema.Type; | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { RuntimeModeSchema } from "../enums"; | |
| 5 | +import { ProfileIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 6 | + | |
| 7 | +export const ProfileSchema = Schema.Struct({ | |
| 8 | + id: ProfileIdSchema, | |
| 9 | + defaultWorkspaceId: Schema.NullOr(WorkspaceIdSchema), | |
| 10 | + displayName: Schema.String, | |
| 11 | + runtimeMode: RuntimeModeSchema, | |
| 12 | + createdAt: TimestampMsSchema, | |
| 13 | + updatedAt: TimestampMsSchema, | |
| 14 | +}); | |
| 15 | + | |
| 16 | +export type Profile = typeof ProfileSchema.Type; | |
| @@ -0,0 +1,22 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { SourceKindSchema, SourceStatusSchema } from "../enums"; | |
| 5 | +import { SourceIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 6 | + | |
| 7 | +export const SourceSchema = Schema.Struct({ | |
| 8 | + id: SourceIdSchema, | |
| 9 | + workspaceId: WorkspaceIdSchema, | |
| 10 | + name: Schema.String, | |
| 11 | + kind: SourceKindSchema, | |
| 12 | + endpoint: Schema.String, | |
| 13 | + status: SourceStatusSchema, | |
| 14 | + enabled: Schema.Boolean, | |
| 15 | + configJson: Schema.String, | |
| 16 | + sourceHash: Schema.NullOr(Schema.String), | |
| 17 | + lastError: Schema.NullOr(Schema.String), | |
| 18 | + createdAt: TimestampMsSchema, | |
| 19 | + updatedAt: TimestampMsSchema, | |
| 20 | +}); | |
| 21 | + | |
| 22 | +export type Source = typeof SourceSchema.Type; | |
| @@ -0,0 +1,18 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { SyncTargetSchema } from "../enums"; | |
| 5 | +import { SyncStateIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 6 | + | |
| 7 | +export const SyncStateSchema = Schema.Struct({ | |
| 8 | + id: SyncStateIdSchema, | |
| 9 | + workspaceId: WorkspaceIdSchema, | |
| 10 | + target: SyncTargetSchema, | |
| 11 | + targetUrl: Schema.String, | |
| 12 | + linkedSubject: Schema.NullOr(Schema.String), | |
| 13 | + cursor: Schema.NullOr(Schema.String), | |
| 14 | + lastSyncAt: Schema.NullOr(TimestampMsSchema), | |
| 15 | + updatedAt: TimestampMsSchema, | |
| 16 | +}); | |
| 17 | + | |
| 18 | +export type SyncState = typeof SyncStateSchema.Type; | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { TaskRunStatusSchema } from "../enums"; | |
| 5 | +import { TaskRunIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 6 | + | |
| 7 | +export const TaskRunSchema = Schema.Struct({ | |
| 8 | + id: TaskRunIdSchema, | |
| 9 | + workspaceId: WorkspaceIdSchema, | |
| 10 | + sessionId: Schema.String, | |
| 11 | + runtimeId: Schema.String, | |
| 12 | + codeHash: Schema.String, | |
| 13 | + status: TaskRunStatusSchema, | |
| 14 | + startedAt: Schema.NullOr(TimestampMsSchema), | |
| 15 | + completedAt: Schema.NullOr(TimestampMsSchema), | |
| 16 | + exitCode: Schema.NullOr(Schema.Number), | |
| 17 | + error: Schema.NullOr(Schema.String), | |
| 18 | +}); | |
| 19 | + | |
| 20 | +export type TaskRun = typeof TaskRunSchema.Type; | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { SourceIdSchema, ToolArtifactIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 5 | + | |
| 6 | +export const ToolArtifactSchema = Schema.Struct({ | |
| 7 | + id: ToolArtifactIdSchema, | |
| 8 | + workspaceId: WorkspaceIdSchema, | |
| 9 | + sourceId: SourceIdSchema, | |
| 10 | + sourceHash: Schema.String, | |
| 11 | + toolCount: Schema.Number, | |
| 12 | + manifestJson: Schema.String, | |
| 13 | + createdAt: TimestampMsSchema, | |
| 14 | + updatedAt: TimestampMsSchema, | |
| 15 | +}); | |
| 16 | + | |
| 17 | +export type ToolArtifact = typeof ToolArtifactSchema.Type; | |
| @@ -0,0 +1,14 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { TimestampMsSchema } from "../common"; | |
| 4 | +import { ProfileIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 5 | + | |
| 6 | +export const WorkspaceSchema = Schema.Struct({ | |
| 7 | + id: WorkspaceIdSchema, | |
| 8 | + profileId: ProfileIdSchema, | |
| 9 | + name: Schema.String, | |
| 10 | + createdAt: TimestampMsSchema, | |
| 11 | + updatedAt: TimestampMsSchema, | |
| 12 | +}); | |
| 13 | + | |
| 14 | +export type Workspace = typeof WorkspaceSchema.Type; | |
| @@ -0,0 +1,34 @@ | ||
| 1 | +import { Schema } from "effect"; | |
| 2 | + | |
| 3 | +import { SchemaVersionSchema, TimestampMsSchema } from "./common"; | |
| 4 | +import { EventEnvelopeSchema } from "./models/event-envelope"; | |
| 5 | +import { ApprovalSchema } from "./models/approval"; | |
| 6 | +import { CredentialRefSchema } from "./models/credential-ref"; | |
| 7 | +import { OAuthTokenSchema } from "./models/oauth-token"; | |
| 8 | +import { PolicySchema } from "./models/policy"; | |
| 9 | +import { ProfileSchema } from "./models/profile"; | |
| 10 | +import { SourceSchema } from "./models/source"; | |
| 11 | +import { SyncStateSchema } from "./models/sync-state"; | |
| 12 | +import { TaskRunSchema } from "./models/task-run"; | |
| 13 | +import { ToolArtifactSchema } from "./models/tool-artifact"; | |
| 14 | +import { WorkspaceSchema } from "./models/workspace"; | |
| 15 | + | |
| 16 | +export const StateSnapshotSchema = Schema.Struct({ | |
| 17 | + schemaVersion: SchemaVersionSchema, | |
| 18 | + generatedAt: TimestampMsSchema, | |
| 19 | + profile: ProfileSchema, | |
| 20 | + workspaces: Schema.Array(WorkspaceSchema), | |
| 21 | + sources: Schema.Array(SourceSchema), | |
| 22 | + toolArtifacts: Schema.Array(ToolArtifactSchema), | |
| 23 | + credentials: Schema.Array(CredentialRefSchema), | |
| 24 | + oauthTokens: Schema.Array(OAuthTokenSchema), | |
| 25 | + policies: Schema.Array(PolicySchema), | |
| 26 | + approvals: Schema.Array(ApprovalSchema), | |
| 27 | + taskRuns: Schema.Array(TaskRunSchema), | |
| 28 | + syncStates: Schema.Array(SyncStateSchema), | |
| 29 | +}); | |
| 30 | + | |
| 31 | +export const StateEventLogSchema = Schema.Array(EventEnvelopeSchema); | |
| 32 | + | |
| 33 | +export type StateSnapshot = typeof StateSnapshotSchema.Type; | |
| 34 | +export type StateEventLog = typeof StateEventLogSchema.Type; | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# sdk | |
| 2 | + | |
| 3 | +Typed client SDK scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/sdk", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# secrets | |
| 2 | + | |
| 3 | +Secret-store abstraction scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/secrets", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# source-manager | |
| 2 | + | |
| 3 | +Dynamic source registration scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/source-manager", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# state-contracts | |
| 2 | + | |
| 3 | +Storage and repository interface scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/state-contracts", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# state-convex | |
| 2 | + | |
| 3 | +Convex-backed state adapter scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/state-convex", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# state-local-file | |
| 2 | + | |
| 3 | +Local file-backed state adapter scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/state-local-file", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# sync | |
| 2 | + | |
| 3 | +Local and remote sync/promote scaffold for Executor v2. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor-v2/sync", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 7 | + } | |
| 8 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.json", | |
| 3 | + "include": ["src"] | |
| 4 | +} | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +{ | |
| 2 | + "compilerOptions": { | |
| 3 | + "target": "ES2023", | |
| 4 | + "module": "ESNext", | |
| 5 | + "moduleResolution": "Bundler", | |
| 6 | + "strict": true, | |
| 7 | + "noEmit": true, | |
| 8 | + "verbatimModuleSyntax": true, | |
| 9 | + "skipLibCheck": true, | |
| 10 | + "resolveJsonModule": true, | |
| 11 | + "allowSyntheticDefaultImports": true, | |
| 12 | + "types": [] | |
| 13 | + }, | |
| 14 | + "include": [ | |
| 15 | + "apps/**/*.ts", | |
| 16 | + "apps/**/*.tsx", | |
| 17 | + "packages/**/*.ts", | |
| 18 | + "packages/**/*.tsx" | |
| 19 | + ] | |
| 20 | +} | |