History

init v2

Rhys Sullivan committed 8 months ago

Commit 93bf95a1 parent 036371c84 files · +1098 −0Browse files

Unified · Split

84 files
  1. experiemental/approval-client.ts +286 −0
  2. experiemental/claude-mcp-demo.json +11 −0
  3. experiemental/mcp-memory-approvals.ts +133 −0
  4. v2/README.md +9 −0
  5. v2/apps/cli/README.md +3 −0
  6. v2/apps/cli/package.json +8 −0
  7. v2/apps/cli/tsconfig.json +4 −0
  8. v2/apps/convex/README.md +3 −0
  9. v2/apps/convex/package.json +8 −0
  10. v2/apps/convex/tsconfig.json +4 −0
  11. v2/apps/pm/README.md +3 −0
  12. v2/apps/pm/package.json +8 −0
  13. v2/apps/pm/tsconfig.json +4 −0
  14. v2/apps/web/README.md +3 −0
  15. v2/apps/web/package.json +8 −0
  16. v2/apps/web/tsconfig.json +4 −0
  17. v2/package.json +13 −0
  18. v2/packages/ai-sdk-adapter/README.md +3 −0
  19. v2/packages/ai-sdk-adapter/package.json +8 −0
  20. v2/packages/ai-sdk-adapter/tsconfig.json +4 −0
  21. v2/packages/approvals/README.md +3 −0
  22. v2/packages/approvals/package.json +8 −0
  23. v2/packages/approvals/tsconfig.json +4 −0
  24. v2/packages/confect-core/README.md +5 −0
  25. v2/packages/confect-core/package.json +14 −0
  26. v2/packages/confect-core/src/index.ts +1 −0
  27. v2/packages/confect-core/src/schema.ts +6 −0
  28. v2/packages/confect-core/tsconfig.json +4 −0
  29. v2/packages/domain/README.md +3 −0
  30. v2/packages/domain/package.json +8 −0
  31. v2/packages/domain/tsconfig.json +4 −0
  32. v2/packages/engine/README.md +3 −0
  33. v2/packages/engine/package.json +8 −0
  34. v2/packages/engine/tsconfig.json +4 −0
  35. v2/packages/mcp-gateway/README.md +3 −0
  36. v2/packages/mcp-gateway/package.json +8 −0
  37. v2/packages/mcp-gateway/tsconfig.json +4 −0
  38. v2/packages/oauth/README.md +3 −0
  39. v2/packages/oauth/package.json +8 −0
  40. v2/packages/oauth/tsconfig.json +4 −0
  41. v2/packages/rpc/README.md +3 −0
  42. v2/packages/rpc/package.json +8 −0
  43. v2/packages/rpc/tsconfig.json +4 −0
  44. v2/packages/schema/README.md +9 −0
  45. v2/packages/schema/package.json +14 −0
  46. v2/packages/schema/src/common.ts +8 −0
  47. v2/packages/schema/src/enums.ts +19 −0
  48. v2/packages/schema/src/ids.ts +25 −0
  49. v2/packages/schema/src/index.ts +17 −0
  50. v2/packages/schema/src/models/approval.ts +19 −0
  51. v2/packages/schema/src/models/credential-ref.ts +19 −0
  52. v2/packages/schema/src/models/event-envelope.ts +16 −0
  53. v2/packages/schema/src/models/oauth-token.ts +19 −0
  54. v2/packages/schema/src/models/policy.ts +16 −0
  55. v2/packages/schema/src/models/profile.ts +16 −0
  56. v2/packages/schema/src/models/source.ts +22 −0
  57. v2/packages/schema/src/models/sync-state.ts +18 −0
  58. v2/packages/schema/src/models/task-run.ts +20 −0
  59. v2/packages/schema/src/models/tool-artifact.ts +17 −0
  60. v2/packages/schema/src/models/workspace.ts +14 −0
  61. v2/packages/schema/src/snapshot.ts +34 −0
  62. v2/packages/schema/tsconfig.json +4 −0
  63. v2/packages/sdk/README.md +3 −0
  64. v2/packages/sdk/package.json +8 −0
  65. v2/packages/sdk/tsconfig.json +4 −0
  66. v2/packages/secrets/README.md +3 −0
  67. v2/packages/secrets/package.json +8 −0
  68. v2/packages/secrets/tsconfig.json +4 −0
  69. v2/packages/source-manager/README.md +3 −0
  70. v2/packages/source-manager/package.json +8 −0
  71. v2/packages/source-manager/tsconfig.json +4 −0
  72. v2/packages/state-contracts/README.md +3 −0
  73. v2/packages/state-contracts/package.json +8 −0
  74. v2/packages/state-contracts/tsconfig.json +4 −0
  75. v2/packages/state-convex/README.md +3 −0
  76. v2/packages/state-convex/package.json +8 −0
  77. v2/packages/state-convex/tsconfig.json +4 −0
  78. v2/packages/state-local-file/README.md +3 −0
  79. v2/packages/state-local-file/package.json +8 −0
  80. v2/packages/state-local-file/tsconfig.json +4 −0
  81. v2/packages/sync/README.md +3 −0
  82. v2/packages/sync/package.json +8 −0
  83. v2/packages/sync/tsconfig.json +4 −0
  84. v2/tsconfig.json +20 −0
experiemental/approval-client.ts+286−0
@@ -0,0 +1,286 @@
1import path from "node:path";
2
3type ApprovalStatus = "pending" | "approved" | "denied";
4
5interface ApprovalItem {
6 id: string;
7 title: string;
8 details: string;
9 status: ApprovalStatus;
10 createdAt: number;
11}
12
13function 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
30function hasTmuxBinary(): boolean {
31 const result = Bun.spawnSync({ cmd: ["tmux", "-V"] });
32 return result.exitCode === 0;
33}
34
35function 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
46async 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
57function shellQuote(value: string): string {
58 return `'${value.replace(/'/g, "'\\''")}'`;
59}
60
61function tmuxSessionExists(tmuxSession: string): boolean {
62 const result = Bun.spawnSync({ cmd: ["tmux", "has-session", "-t", tmuxSession] });
63 return result.exitCode === 0;
64}
65
66function 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
76function 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
82function 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
87async 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
120function 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
141function statusMarker(status: ApprovalStatus): string {
142 if (status === "approved") return "[approved]";
143 if (status === "denied") return "[denied]";
144 return "[pending]";
145}
146
147function 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
168async 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
254async 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
285const code = await main();
286process.exit(code);
experiemental/claude-mcp-demo.json+11−0
@@ -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}
experiemental/mcp-memory-approvals.ts+133−0
@@ -0,0 +1,133 @@
1import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3import { z } from "zod";
4
5type ApprovalDecision = "approved" | "denied";
6
7interface ApprovalRecord {
8 id: string;
9 action: string;
10 justification: string;
11 createdAt: number;
12 decision: ApprovalDecision;
13 decidedAt: number;
14}
15
16const approvals: ApprovalRecord[] = [];
17
18const 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
32mcp.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
106mcp.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
132const transport = new StdioServerTransport();
133await mcp.connect(transport);
v2/README.md+9−0
@@ -0,0 +1,9 @@
1# Executor v2 Scaffold
2
3This 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
v2/apps/cli/README.md+3−0
@@ -0,0 +1,3 @@
1# app-cli
2
3CLI app scaffold for Executor v2.
v2/apps/cli/package.json+8−0
@@ -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}
v2/apps/cli/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/apps/convex/README.md+3−0
@@ -0,0 +1,3 @@
1# app-convex
2
3Convex remote server app scaffold for Executor v2.
v2/apps/convex/package.json+8−0
@@ -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}
v2/apps/convex/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/apps/pm/README.md+3−0
@@ -0,0 +1,3 @@
1# app-pm
2
3Local Process Manager app scaffold for Executor v2.
v2/apps/pm/package.json+8−0
@@ -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}
v2/apps/pm/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/apps/web/README.md+3−0
@@ -0,0 +1,3 @@
1# app-web
2
3Web UI app scaffold for Executor v2.
v2/apps/web/package.json+8−0
@@ -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}
v2/apps/web/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/package.json+13−0
@@ -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}
v2/packages/ai-sdk-adapter/README.md+3−0
@@ -0,0 +1,3 @@
1# ai-sdk-adapter
2
3AI SDK adapter scaffold for Executor v2.
v2/packages/ai-sdk-adapter/package.json+8−0
@@ -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}
v2/packages/ai-sdk-adapter/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/approvals/README.md+3−0
@@ -0,0 +1,3 @@
1# approvals
2
3Approval and input broker scaffold for Executor v2.
v2/packages/approvals/package.json+8−0
@@ -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}
v2/packages/approvals/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/confect-core/README.md+5−0
@@ -0,0 +1,5 @@
1# confect-core
2
3Effect schema helper primitives scaffold for Executor v2.
4
5Current scaffold includes basic helpers in `src/schema.ts`.
v2/packages/confect-core/package.json+14−0
@@ -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}
v2/packages/confect-core/src/index.ts+1−0
@@ -0,0 +1 @@
1export * from "./schema";
v2/packages/confect-core/src/schema.ts+6−0
@@ -0,0 +1,6 @@
1import { Schema } from "effect";
2
3export const TimestampMsSchema = Schema.Number;
4
5export const makeIdSchema = (brandName: string) =>
6 Schema.String.pipe(Schema.brand(brandName));
v2/packages/confect-core/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/domain/README.md+3−0
@@ -0,0 +1,3 @@
1# domain
2
3Domain service layer scaffold for Executor v2.
v2/packages/domain/package.json+8−0
@@ -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}
v2/packages/domain/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/engine/README.md+3−0
@@ -0,0 +1,3 @@
1# engine
2
3Runtime execution engine scaffold for Executor v2.
v2/packages/engine/package.json+8−0
@@ -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}
v2/packages/engine/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/mcp-gateway/README.md+3−0
@@ -0,0 +1,3 @@
1# mcp-gateway
2
3MCP gateway surface scaffold for Executor v2.
v2/packages/mcp-gateway/package.json+8−0
@@ -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}
v2/packages/mcp-gateway/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/oauth/README.md+3−0
@@ -0,0 +1,3 @@
1# oauth
2
3OAuth primitives scaffold for Executor v2.
v2/packages/oauth/package.json+8−0
@@ -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}
v2/packages/oauth/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/rpc/README.md+3−0
@@ -0,0 +1,3 @@
1# rpc
2
3Effect RPC contract scaffold for Executor v2.
v2/packages/rpc/package.json+8−0
@@ -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}
v2/packages/rpc/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/schema/README.md+9−0
@@ -0,0 +1,9 @@
1# schema
2
3Canonical Effect schema package scaffold for Executor v2.
4
5Current 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`)
v2/packages/schema/package.json+14−0
@@ -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}
v2/packages/schema/src/common.ts+8−0
@@ -0,0 +1,8 @@
1import { Schema } from "effect";
2
3export const SchemaVersionSchema = Schema.Number;
4export const TimestampMsSchema = Schema.Number;
5export const JsonStringSchema = Schema.String;
6
7export type SchemaVersion = typeof SchemaVersionSchema.Type;
8export type TimestampMs = typeof TimestampMsSchema.Type;
v2/packages/schema/src/enums.ts+19−0
@@ -0,0 +1,19 @@
1import { Schema } from "effect";
2
3export const RuntimeModeSchema = Schema.Literal("local", "linked", "remote");
4export const SourceKindSchema = Schema.Literal("mcp", "openapi", "graphql", "internal");
5export const SourceStatusSchema = Schema.Literal("draft", "probing", "auth_required", "connected", "error");
6export const PolicyDecisionSchema = Schema.Literal("allow", "require_approval", "deny");
7export const ApprovalStatusSchema = Schema.Literal("pending", "approved", "denied", "expired");
8export const TaskRunStatusSchema = Schema.Literal("queued", "running", "completed", "failed", "timed_out", "denied");
9export const CredentialModeSchema = Schema.Literal("none", "api_key", "bearer", "oauth2", "custom");
10export const SyncTargetSchema = Schema.Literal("remote");
11
12export type RuntimeMode = typeof RuntimeModeSchema.Type;
13export type SourceKind = typeof SourceKindSchema.Type;
14export type SourceStatus = typeof SourceStatusSchema.Type;
15export type PolicyDecision = typeof PolicyDecisionSchema.Type;
16export type ApprovalStatus = typeof ApprovalStatusSchema.Type;
17export type TaskRunStatus = typeof TaskRunStatusSchema.Type;
18export type CredentialMode = typeof CredentialModeSchema.Type;
19export type SyncTarget = typeof SyncTargetSchema.Type;
v2/packages/schema/src/ids.ts+25−0
@@ -0,0 +1,25 @@
1import { Schema } from "effect";
2
3export const ProfileIdSchema = Schema.String.pipe(Schema.brand("ProfileId"));
4export const WorkspaceIdSchema = Schema.String.pipe(Schema.brand("WorkspaceId"));
5export const SourceIdSchema = Schema.String.pipe(Schema.brand("SourceId"));
6export const ToolArtifactIdSchema = Schema.String.pipe(Schema.brand("ToolArtifactId"));
7export const CredentialRefIdSchema = Schema.String.pipe(Schema.brand("CredentialRefId"));
8export const OAuthTokenIdSchema = Schema.String.pipe(Schema.brand("OAuthTokenId"));
9export const PolicyIdSchema = Schema.String.pipe(Schema.brand("PolicyId"));
10export const ApprovalIdSchema = Schema.String.pipe(Schema.brand("ApprovalId"));
11export const TaskRunIdSchema = Schema.String.pipe(Schema.brand("TaskRunId"));
12export const SyncStateIdSchema = Schema.String.pipe(Schema.brand("SyncStateId"));
13export const EventIdSchema = Schema.String.pipe(Schema.brand("EventId"));
14
15export type ProfileId = typeof ProfileIdSchema.Type;
16export type WorkspaceId = typeof WorkspaceIdSchema.Type;
17export type SourceId = typeof SourceIdSchema.Type;
18export type ToolArtifactId = typeof ToolArtifactIdSchema.Type;
19export type CredentialRefId = typeof CredentialRefIdSchema.Type;
20export type OAuthTokenId = typeof OAuthTokenIdSchema.Type;
21export type PolicyId = typeof PolicyIdSchema.Type;
22export type ApprovalId = typeof ApprovalIdSchema.Type;
23export type TaskRunId = typeof TaskRunIdSchema.Type;
24export type SyncStateId = typeof SyncStateIdSchema.Type;
25export type EventId = typeof EventIdSchema.Type;
v2/packages/schema/src/index.ts+17−0
@@ -0,0 +1,17 @@
1export * from "./common";
2export * from "./enums";
3export * from "./ids";
4
5export * from "./models/profile";
6export * from "./models/workspace";
7export * from "./models/source";
8export * from "./models/tool-artifact";
9export * from "./models/credential-ref";
10export * from "./models/oauth-token";
11export * from "./models/policy";
12export * from "./models/approval";
13export * from "./models/task-run";
14export * from "./models/sync-state";
15export * from "./models/event-envelope";
16
17export * from "./snapshot";
v2/packages/schema/src/models/approval.ts+19−0
@@ -0,0 +1,19 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { ApprovalStatusSchema } from "../enums";
5import { ApprovalIdSchema, TaskRunIdSchema, WorkspaceIdSchema } from "../ids";
6
7export 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
19export type Approval = typeof ApprovalSchema.Type;
v2/packages/schema/src/models/credential-ref.ts+19−0
@@ -0,0 +1,19 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { CredentialModeSchema } from "../enums";
5import { CredentialRefIdSchema, SourceIdSchema, WorkspaceIdSchema } from "../ids";
6
7export 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
19export type CredentialRef = typeof CredentialRefSchema.Type;
v2/packages/schema/src/models/event-envelope.ts+16−0
@@ -0,0 +1,16 @@
1import { Schema } from "effect";
2
3import { SchemaVersionSchema, TimestampMsSchema } from "../common";
4import { EventIdSchema, WorkspaceIdSchema } from "../ids";
5
6export 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
16export type EventEnvelope = typeof EventEnvelopeSchema.Type;
v2/packages/schema/src/models/oauth-token.ts+19−0
@@ -0,0 +1,19 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { OAuthTokenIdSchema, SourceIdSchema, WorkspaceIdSchema } from "../ids";
5
6export 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
19export type OAuthToken = typeof OAuthTokenSchema.Type;
v2/packages/schema/src/models/policy.ts+16−0
@@ -0,0 +1,16 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { PolicyDecisionSchema } from "../enums";
5import { PolicyIdSchema, WorkspaceIdSchema } from "../ids";
6
7export 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
16export type Policy = typeof PolicySchema.Type;
v2/packages/schema/src/models/profile.ts+16−0
@@ -0,0 +1,16 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { RuntimeModeSchema } from "../enums";
5import { ProfileIdSchema, WorkspaceIdSchema } from "../ids";
6
7export 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
16export type Profile = typeof ProfileSchema.Type;
v2/packages/schema/src/models/source.ts+22−0
@@ -0,0 +1,22 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { SourceKindSchema, SourceStatusSchema } from "../enums";
5import { SourceIdSchema, WorkspaceIdSchema } from "../ids";
6
7export 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
22export type Source = typeof SourceSchema.Type;
v2/packages/schema/src/models/sync-state.ts+18−0
@@ -0,0 +1,18 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { SyncTargetSchema } from "../enums";
5import { SyncStateIdSchema, WorkspaceIdSchema } from "../ids";
6
7export 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
18export type SyncState = typeof SyncStateSchema.Type;
v2/packages/schema/src/models/task-run.ts+20−0
@@ -0,0 +1,20 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { TaskRunStatusSchema } from "../enums";
5import { TaskRunIdSchema, WorkspaceIdSchema } from "../ids";
6
7export 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
20export type TaskRun = typeof TaskRunSchema.Type;
v2/packages/schema/src/models/tool-artifact.ts+17−0
@@ -0,0 +1,17 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { SourceIdSchema, ToolArtifactIdSchema, WorkspaceIdSchema } from "../ids";
5
6export 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
17export type ToolArtifact = typeof ToolArtifactSchema.Type;
v2/packages/schema/src/models/workspace.ts+14−0
@@ -0,0 +1,14 @@
1import { Schema } from "effect";
2
3import { TimestampMsSchema } from "../common";
4import { ProfileIdSchema, WorkspaceIdSchema } from "../ids";
5
6export const WorkspaceSchema = Schema.Struct({
7 id: WorkspaceIdSchema,
8 profileId: ProfileIdSchema,
9 name: Schema.String,
10 createdAt: TimestampMsSchema,
11 updatedAt: TimestampMsSchema,
12});
13
14export type Workspace = typeof WorkspaceSchema.Type;
v2/packages/schema/src/snapshot.ts+34−0
@@ -0,0 +1,34 @@
1import { Schema } from "effect";
2
3import { SchemaVersionSchema, TimestampMsSchema } from "./common";
4import { EventEnvelopeSchema } from "./models/event-envelope";
5import { ApprovalSchema } from "./models/approval";
6import { CredentialRefSchema } from "./models/credential-ref";
7import { OAuthTokenSchema } from "./models/oauth-token";
8import { PolicySchema } from "./models/policy";
9import { ProfileSchema } from "./models/profile";
10import { SourceSchema } from "./models/source";
11import { SyncStateSchema } from "./models/sync-state";
12import { TaskRunSchema } from "./models/task-run";
13import { ToolArtifactSchema } from "./models/tool-artifact";
14import { WorkspaceSchema } from "./models/workspace";
15
16export 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
31export const StateEventLogSchema = Schema.Array(EventEnvelopeSchema);
32
33export type StateSnapshot = typeof StateSnapshotSchema.Type;
34export type StateEventLog = typeof StateEventLogSchema.Type;
v2/packages/schema/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/sdk/README.md+3−0
@@ -0,0 +1,3 @@
1# sdk
2
3Typed client SDK scaffold for Executor v2.
v2/packages/sdk/package.json+8−0
@@ -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}
v2/packages/sdk/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/secrets/README.md+3−0
@@ -0,0 +1,3 @@
1# secrets
2
3Secret-store abstraction scaffold for Executor v2.
v2/packages/secrets/package.json+8−0
@@ -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}
v2/packages/secrets/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/source-manager/README.md+3−0
@@ -0,0 +1,3 @@
1# source-manager
2
3Dynamic source registration scaffold for Executor v2.
v2/packages/source-manager/package.json+8−0
@@ -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}
v2/packages/source-manager/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/state-contracts/README.md+3−0
@@ -0,0 +1,3 @@
1# state-contracts
2
3Storage and repository interface scaffold for Executor v2.
v2/packages/state-contracts/package.json+8−0
@@ -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}
v2/packages/state-contracts/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/state-convex/README.md+3−0
@@ -0,0 +1,3 @@
1# state-convex
2
3Convex-backed state adapter scaffold for Executor v2.
v2/packages/state-convex/package.json+8−0
@@ -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}
v2/packages/state-convex/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/state-local-file/README.md+3−0
@@ -0,0 +1,3 @@
1# state-local-file
2
3Local file-backed state adapter scaffold for Executor v2.
v2/packages/state-local-file/package.json+8−0
@@ -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}
v2/packages/state-local-file/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/packages/sync/README.md+3−0
@@ -0,0 +1,3 @@
1# sync
2
3Local and remote sync/promote scaffold for Executor v2.
v2/packages/sync/package.json+8−0
@@ -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}
v2/packages/sync/tsconfig.json+4−0
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "include": ["src"]
4}
v2/tsconfig.json+20−0
@@ -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}