web-task-api 0.2.1

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.
Files changed (121) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +284 -0
  3. package/dist/scripts/demo.d.ts +1 -0
  4. package/dist/scripts/demo.js +32 -0
  5. package/dist/scripts/demo.js.map +1 -0
  6. package/dist/scripts/profile-login.d.ts +1 -0
  7. package/dist/scripts/profile-login.js +38 -0
  8. package/dist/scripts/profile-login.js.map +1 -0
  9. package/dist/src/agents/auto-agent.d.ts +22 -0
  10. package/dist/src/agents/auto-agent.js +54 -0
  11. package/dist/src/agents/auto-agent.js.map +1 -0
  12. package/dist/src/agents/cliproxy-agent.d.ts +18 -0
  13. package/dist/src/agents/cliproxy-agent.js +137 -0
  14. package/dist/src/agents/cliproxy-agent.js.map +1 -0
  15. package/dist/src/agents/index.d.ts +2 -0
  16. package/dist/src/agents/index.js +17 -0
  17. package/dist/src/agents/index.js.map +1 -0
  18. package/dist/src/agents/mock-agent.d.ts +15 -0
  19. package/dist/src/agents/mock-agent.js +132 -0
  20. package/dist/src/agents/mock-agent.js.map +1 -0
  21. package/dist/src/agents/opencode-agent.d.ts +20 -0
  22. package/dist/src/agents/opencode-agent.js +122 -0
  23. package/dist/src/agents/opencode-agent.js.map +1 -0
  24. package/dist/src/agents/planner-prompt.d.ts +6 -0
  25. package/dist/src/agents/planner-prompt.js +116 -0
  26. package/dist/src/agents/planner-prompt.js.map +1 -0
  27. package/dist/src/browser/session.d.ts +41 -0
  28. package/dist/src/browser/session.js +267 -0
  29. package/dist/src/browser/session.js.map +1 -0
  30. package/dist/src/client.d.ts +44 -0
  31. package/dist/src/client.js +59 -0
  32. package/dist/src/client.js.map +1 -0
  33. package/dist/src/config.d.ts +16 -0
  34. package/dist/src/config.js +18 -0
  35. package/dist/src/config.js.map +1 -0
  36. package/dist/src/index.d.ts +2 -0
  37. package/dist/src/index.js +15 -0
  38. package/dist/src/index.js.map +1 -0
  39. package/dist/src/lib.d.ts +6 -0
  40. package/dist/src/lib.js +5 -0
  41. package/dist/src/lib.js.map +1 -0
  42. package/dist/src/mcp-server.d.ts +3 -0
  43. package/dist/src/mcp-server.js +191 -0
  44. package/dist/src/mcp-server.js.map +1 -0
  45. package/dist/src/mcp.d.ts +2 -0
  46. package/dist/src/mcp.js +14 -0
  47. package/dist/src/mcp.js.map +1 -0
  48. package/dist/src/recipes/registry.d.ts +21 -0
  49. package/dist/src/recipes/registry.js +38 -0
  50. package/dist/src/recipes/registry.js.map +1 -0
  51. package/dist/src/server/app.d.ts +5 -0
  52. package/dist/src/server/app.js +89 -0
  53. package/dist/src/server/app.js.map +1 -0
  54. package/dist/src/sessions/store.d.ts +48 -0
  55. package/dist/src/sessions/store.js +84 -0
  56. package/dist/src/sessions/store.js.map +1 -0
  57. package/dist/src/storage/run-store.d.ts +12 -0
  58. package/dist/src/storage/run-store.js +30 -0
  59. package/dist/src/storage/run-store.js.map +1 -0
  60. package/dist/src/tasks/errors.d.ts +5 -0
  61. package/dist/src/tasks/errors.js +11 -0
  62. package/dist/src/tasks/errors.js.map +1 -0
  63. package/dist/src/tasks/output-validator.d.ts +1 -0
  64. package/dist/src/tasks/output-validator.js +21 -0
  65. package/dist/src/tasks/output-validator.js.map +1 -0
  66. package/dist/src/tasks/runner.d.ts +38 -0
  67. package/dist/src/tasks/runner.js +236 -0
  68. package/dist/src/tasks/runner.js.map +1 -0
  69. package/dist/src/tasks/schemas.d.ts +266 -0
  70. package/dist/src/tasks/schemas.js +67 -0
  71. package/dist/src/tasks/schemas.js.map +1 -0
  72. package/dist/tests/agent-adapters.test.d.ts +1 -0
  73. package/dist/tests/agent-adapters.test.js +87 -0
  74. package/dist/tests/agent-adapters.test.js.map +1 -0
  75. package/dist/tests/agent-selection.test.d.ts +1 -0
  76. package/dist/tests/agent-selection.test.js +26 -0
  77. package/dist/tests/agent-selection.test.js.map +1 -0
  78. package/dist/tests/auto-agent.test.d.ts +1 -0
  79. package/dist/tests/auto-agent.test.js +86 -0
  80. package/dist/tests/auto-agent.test.js.map +1 -0
  81. package/dist/tests/browser-session.test.d.ts +1 -0
  82. package/dist/tests/browser-session.test.js +41 -0
  83. package/dist/tests/browser-session.test.js.map +1 -0
  84. package/dist/tests/client.test.d.ts +1 -0
  85. package/dist/tests/client.test.js +35 -0
  86. package/dist/tests/client.test.js.map +1 -0
  87. package/dist/tests/fixture-site.d.ts +6 -0
  88. package/dist/tests/fixture-site.js +93 -0
  89. package/dist/tests/fixture-site.js.map +1 -0
  90. package/dist/tests/mcp.test.d.ts +1 -0
  91. package/dist/tests/mcp.test.js +186 -0
  92. package/dist/tests/mcp.test.js.map +1 -0
  93. package/dist/tests/output-validator.test.d.ts +1 -0
  94. package/dist/tests/output-validator.test.js +27 -0
  95. package/dist/tests/output-validator.test.js.map +1 -0
  96. package/dist/tests/request-validation.test.d.ts +1 -0
  97. package/dist/tests/request-validation.test.js +25 -0
  98. package/dist/tests/request-validation.test.js.map +1 -0
  99. package/dist/tests/runner-options.test.d.ts +1 -0
  100. package/dist/tests/runner-options.test.js +44 -0
  101. package/dist/tests/runner-options.test.js.map +1 -0
  102. package/dist/tests/session-api.test.d.ts +1 -0
  103. package/dist/tests/session-api.test.js +244 -0
  104. package/dist/tests/session-api.test.js.map +1 -0
  105. package/dist/tests/session-client.test.d.ts +1 -0
  106. package/dist/tests/session-client.test.js +28 -0
  107. package/dist/tests/session-client.test.js.map +1 -0
  108. package/dist/tests/task-api-failure.test.d.ts +1 -0
  109. package/dist/tests/task-api-failure.test.js +39 -0
  110. package/dist/tests/task-api-failure.test.js.map +1 -0
  111. package/dist/tests/task-api.test.d.ts +1 -0
  112. package/dist/tests/task-api.test.js +50 -0
  113. package/dist/tests/task-api.test.js.map +1 -0
  114. package/docs/design.md +513 -0
  115. package/docs/releasing.md +62 -0
  116. package/package.json +78 -0
  117. package/recipes/dexscreener-token-read.json +19 -0
  118. package/recipes/fixture-catalog.json +14 -0
  119. package/recipes/generic-search.json +14 -0
  120. package/recipes/gmgn-token-read.json +19 -0
  121. package/server.json +79 -0
@@ -0,0 +1,191 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { z } from "zod";
4
+ import { SessionCreateSchema, SessionUpdateSchema, TaskRequestSchema } from "./tasks/schemas.js";
5
+ import { TaskRunner } from "./tasks/runner.js";
6
+ function readPackageVersion() {
7
+ for (const candidate of ["../package.json", "../../package.json"]) {
8
+ try {
9
+ return JSON.parse(readFileSync(new URL(candidate, import.meta.url), "utf8")).version;
10
+ }
11
+ catch {
12
+ // Try the next relative location.
13
+ }
14
+ }
15
+ throw new Error("Unable to locate package.json for MCP version metadata");
16
+ }
17
+ const packageVersion = readPackageVersion();
18
+ const AgentKindSchema = z.enum(["auto", "cliproxy", "opencode", "mock"]);
19
+ const JsonRecordSchema = z.record(z.string(), z.unknown());
20
+ function renderTask(result) {
21
+ const lines = [
22
+ `Task ${result.taskId}: ${result.status}`,
23
+ `Goal: ${result.goal}`,
24
+ `Mode: ${result.mode}`,
25
+ ...(result.sessionId ? [`Session: ${result.sessionId}`] : []),
26
+ ...(result.recipe ? [`Recipe: ${result.recipe.name} (${result.recipe.id})`] : []),
27
+ ...(result.profile ? [`Profile: ${result.profile}`] : []),
28
+ ...(result.backend ? [`Planner: ${result.backend.planner} (${result.backend.reason})`] : []),
29
+ `Steps: ${result.steps.length}`,
30
+ `Artifacts: ${result.artifactsDir}`,
31
+ ];
32
+ if (result.status === "completed" && result.result) {
33
+ lines.push("", "Result:", JSON.stringify(result.result, null, 2));
34
+ }
35
+ if (result.status === "failed" && result.error) {
36
+ lines.push("", `Error: ${result.error}`);
37
+ }
38
+ return lines.join("\n");
39
+ }
40
+ function renderSession(session) {
41
+ return [
42
+ `Session ${session.id}`,
43
+ `Name: ${session.name}`,
44
+ `Mode: ${session.mode}`,
45
+ ...(session.profile ? [`Profile: ${session.profile}`] : []),
46
+ ...(session.startUrl ? [`Start URL: ${session.startUrl}`] : []),
47
+ ...(session.notes ? [`Notes: ${session.notes}`] : []),
48
+ `Tasks: ${session.taskCount}`,
49
+ ].join("\n");
50
+ }
51
+ function renderRecipes(recipes) {
52
+ if (recipes.length === 0)
53
+ return "No recipes registered.";
54
+ return recipes.map((recipe) => `- ${String(recipe.id || "")}: ${String(recipe.name || "")}`).join("\n");
55
+ }
56
+ function renderSessions(sessions) {
57
+ if (sessions.length === 0)
58
+ return "No sessions saved.";
59
+ return sessions.map((session) => `- ${session.id}: ${session.name} (${session.mode}, tasks=${session.taskCount})`).join("\n");
60
+ }
61
+ export function createMcpServer(taskRunner = new TaskRunner()) {
62
+ const server = new McpServer({
63
+ name: "web-task-api",
64
+ version: packageVersion,
65
+ });
66
+ server.tool("webtask_run", "Run a browser task through the web-task runtime with optional session reuse, recipe hints, and structured output validation.", {
67
+ goal: z.string().min(1).describe("Goal for the browser task"),
68
+ start_url: z.string().url().optional().describe("Optional starting URL"),
69
+ mode: z.enum(["read", "act"]).optional().describe("Task mode"),
70
+ profile: z.string().min(1).optional().describe("Optional named browser profile"),
71
+ session_id: z.string().uuid().optional().describe("Optional session to reuse"),
72
+ input: JsonRecordSchema.optional().describe("Task input values"),
73
+ output_schema: JsonRecordSchema.optional().describe("Optional JSON Schema-like object for validating the final result"),
74
+ recipe_id: z.string().min(1).optional().describe("Optional recipe id to guide the run"),
75
+ agent_kind: AgentKindSchema.optional().describe("Planner backend"),
76
+ agent_model: z.string().optional().describe("Optional planner model override"),
77
+ max_steps: z.number().int().min(1).max(50).optional().describe("Maximum browser steps"),
78
+ timeout_ms: z.number().int().min(1000).max(600000).optional().describe("Run timeout in milliseconds"),
79
+ headless: z.boolean().optional().describe("Whether to prefer headless browser mode"),
80
+ }, async ({ goal, start_url, mode, profile, session_id, input, output_schema, recipe_id, agent_kind, agent_model, max_steps, timeout_ms, headless }) => {
81
+ const request = TaskRequestSchema.parse({
82
+ goal,
83
+ ...(start_url === undefined ? {} : { startUrl: start_url }),
84
+ ...(mode === undefined ? {} : { mode }),
85
+ ...(profile === undefined ? {} : { profile }),
86
+ ...(session_id === undefined ? {} : { sessionId: session_id }),
87
+ input: input ?? {},
88
+ ...(output_schema === undefined ? {} : { outputSchema: output_schema }),
89
+ ...(recipe_id === undefined ? {} : { recipeId: recipe_id }),
90
+ agent: {
91
+ kind: agent_kind ?? "auto",
92
+ ...(agent_model === undefined ? {} : { model: agent_model }),
93
+ },
94
+ limits: {
95
+ ...(max_steps === undefined ? {} : { maxSteps: max_steps }),
96
+ ...(timeout_ms === undefined ? {} : { timeoutMs: timeout_ms }),
97
+ ...(headless === undefined ? {} : { headless }),
98
+ },
99
+ });
100
+ const result = await taskRunner.run(request);
101
+ return {
102
+ structuredContent: result,
103
+ content: [{ type: "text", text: renderTask(result) }],
104
+ };
105
+ });
106
+ server.tool("webtask_get_task", "Fetch a persisted task run with full step history and artifact paths.", { task_id: z.string().min(1).describe("Task id to fetch") }, async ({ task_id }) => {
107
+ const result = await taskRunner.get(task_id);
108
+ if (!result) {
109
+ throw new Error(`Task not found: ${task_id}`);
110
+ }
111
+ return {
112
+ structuredContent: result,
113
+ content: [{ type: "text", text: renderTask(result) }],
114
+ };
115
+ });
116
+ server.tool("webtask_list_recipes", "List promoted recipes that can guide common web-task flows.", {}, async () => {
117
+ const recipes = await taskRunner.listRecipes();
118
+ return {
119
+ structuredContent: { recipes },
120
+ content: [{ type: "text", text: renderRecipes(recipes) }],
121
+ };
122
+ });
123
+ server.tool("webtask_create_session", "Create a reusable session that carries browser state, default start URL, and planner defaults across tasks.", {
124
+ name: z.string().min(1).describe("Session name"),
125
+ mode: z.enum(["guest", "profile"]).optional().describe("Session mode"),
126
+ profile: z.string().min(1).optional().describe("Optional bound browser profile"),
127
+ start_url: z.string().url().optional().describe("Optional default start URL"),
128
+ agent_kind: AgentKindSchema.optional().describe("Optional default planner backend for the session"),
129
+ agent_model: z.string().optional().describe("Optional default planner model for the session"),
130
+ notes: z.string().optional().describe("Optional session notes"),
131
+ }, async ({ name, mode, profile, start_url, agent_kind, agent_model, notes }) => {
132
+ const session = await taskRunner.createSession(SessionCreateSchema.parse({
133
+ name,
134
+ ...(mode === undefined ? {} : { mode }),
135
+ ...(profile === undefined ? {} : { profile }),
136
+ ...(start_url === undefined ? {} : { startUrl: start_url }),
137
+ ...((agent_kind !== undefined || agent_model !== undefined)
138
+ ? { agent: { kind: agent_kind ?? "auto", ...(agent_model === undefined ? {} : { model: agent_model }) } }
139
+ : {}),
140
+ ...(notes === undefined ? {} : { notes }),
141
+ }));
142
+ return {
143
+ structuredContent: session,
144
+ content: [{ type: "text", text: renderSession(session) }],
145
+ };
146
+ });
147
+ server.tool("webtask_list_sessions", "List saved sessions with browser-state continuity metadata.", {}, async () => {
148
+ const sessions = await taskRunner.listSessions();
149
+ return {
150
+ structuredContent: { sessions },
151
+ content: [{ type: "text", text: renderSessions(sessions) }],
152
+ };
153
+ });
154
+ server.tool("webtask_get_session", "Fetch one saved session including recent task history.", { session_id: z.string().uuid().describe("Session id to fetch") }, async ({ session_id }) => {
155
+ const session = await taskRunner.getSession(session_id);
156
+ if (!session) {
157
+ throw new Error(`Session not found: ${session_id}`);
158
+ }
159
+ return {
160
+ structuredContent: session,
161
+ content: [{ type: "text", text: renderSession(session) }],
162
+ };
163
+ });
164
+ server.tool("webtask_update_session", "Update session metadata like name, profile, notes, or default start URL.", {
165
+ session_id: z.string().uuid().describe("Session id to update"),
166
+ name: z.string().min(1).optional().describe("Updated session name"),
167
+ profile: z.string().min(1).optional().describe("Updated bound profile"),
168
+ start_url: z.string().url().optional().describe("Updated default start URL"),
169
+ notes: z.string().optional().describe("Updated session notes"),
170
+ }, async ({ session_id, name, profile, start_url, notes }) => {
171
+ const session = await taskRunner.updateSession(session_id, SessionUpdateSchema.parse({
172
+ ...(name === undefined ? {} : { name }),
173
+ ...(profile === undefined ? {} : { profile }),
174
+ ...(start_url === undefined ? {} : { startUrl: start_url }),
175
+ ...(notes === undefined ? {} : { notes }),
176
+ }));
177
+ if (!session) {
178
+ throw new Error(`Session not found: ${session_id}`);
179
+ }
180
+ return {
181
+ structuredContent: session,
182
+ content: [{ type: "text", text: renderSession(session) }],
183
+ };
184
+ });
185
+ server.tool("webtask_health", "Quick health check for the MCP runtime.", {}, async () => ({
186
+ structuredContent: { healthy: true },
187
+ content: [{ type: "text", text: "healthy: true" }],
188
+ }));
189
+ return server;
190
+ }
191
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../src/mcp-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "dotenv/config";
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import "dotenv/config";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { createMcpServer } from "./mcp-server.js";
5
+ async function main() {
6
+ const transport = new StdioServerTransport();
7
+ const server = createMcpServer();
8
+ await server.connect(transport);
9
+ }
10
+ main().catch((error) => {
11
+ console.error(error);
12
+ process.exit(1);
13
+ });
14
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/mcp.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAA;AAEtB,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAEhF,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,GAAG,eAAe,EAAE,CAAA;IAChC,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;AACjC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
@@ -0,0 +1,21 @@
1
+ export type RecipeDefinition = {
2
+ id: string;
3
+ name: string;
4
+ description: string;
5
+ urlPatterns?: string[] | undefined;
6
+ browserHints?: {
7
+ preferChrome?: boolean | undefined;
8
+ preferHeadful?: boolean | undefined;
9
+ preferPersistentProfile?: boolean | undefined;
10
+ } | undefined;
11
+ promptHints?: string[] | undefined;
12
+ inputAliases?: Record<string, string[]> | undefined;
13
+ };
14
+ export declare class RecipeRegistry {
15
+ private cache?;
16
+ list(): Promise<RecipeDefinition[]>;
17
+ resolve(options: {
18
+ recipeId?: string | undefined;
19
+ startUrl?: string | undefined;
20
+ }): Promise<RecipeDefinition | undefined>;
21
+ }
@@ -0,0 +1,38 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { RECIPES_DIR } from "../config.js";
4
+ export class RecipeRegistry {
5
+ cache;
6
+ async list() {
7
+ if (this.cache) {
8
+ return this.cache;
9
+ }
10
+ let entries = [];
11
+ try {
12
+ entries = await fs.readdir(RECIPES_DIR);
13
+ }
14
+ catch {
15
+ this.cache = [];
16
+ return this.cache;
17
+ }
18
+ const recipes = await Promise.all(entries
19
+ .filter((entry) => entry.endsWith(".json"))
20
+ .map(async (entry) => {
21
+ const file = await fs.readFile(path.join(RECIPES_DIR, entry), "utf8");
22
+ return JSON.parse(file);
23
+ }));
24
+ this.cache = recipes;
25
+ return recipes;
26
+ }
27
+ async resolve(options) {
28
+ const recipes = await this.list();
29
+ if (options.recipeId) {
30
+ return recipes.find((recipe) => recipe.id === options.recipeId);
31
+ }
32
+ if (!options.startUrl) {
33
+ return recipes.find((recipe) => recipe.id === "generic-search");
34
+ }
35
+ return (recipes.find((recipe) => recipe.urlPatterns?.some((pattern) => options.startUrl?.includes(pattern))) ?? recipes.find((recipe) => recipe.id === "generic-search"));
36
+ }
37
+ }
38
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/recipes/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAkB3C,MAAM,OAAO,cAAc;IACjB,KAAK,CAAsB;IAEnC,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QAED,IAAI,OAAO,GAAa,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,OAAO;aACJ,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;aAC1C,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACnB,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;YACtE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAqB,CAAC;QAC9C,CAAC,CAAC,CACL,CAAC;QAEF,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;QACrB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAGb;QACC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,gBAAgB,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,CACL,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CACtB,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAC3E,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,gBAAgB,CAAC,CAC9D,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ import Fastify from "fastify";
2
+ import { TaskRunner } from "../tasks/runner.js";
3
+ export declare function createApp(taskRunner?: TaskRunner): Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault> & PromiseLike<Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>> & {
4
+ __linterBrands: "SafePromiseLike";
5
+ };
@@ -0,0 +1,89 @@
1
+ import Fastify from "fastify";
2
+ import { TaskRunner } from "../tasks/runner.js";
3
+ import { RequestPreconditionError } from "../tasks/errors.js";
4
+ import { SessionCreateSchema, SessionUpdateSchema, TaskRequestSchema } from "../tasks/schemas.js";
5
+ export function createApp(taskRunner = new TaskRunner()) {
6
+ const app = Fastify({ logger: false });
7
+ app.get("/health", async () => ({ healthy: true }));
8
+ app.get("/v1/recipes", async () => ({ recipes: await taskRunner.listRecipes() }));
9
+ app.get("/v1/sessions", async () => ({ sessions: await taskRunner.listSessions() }));
10
+ app.get("/v1/sessions/:sessionId", async (request, reply) => {
11
+ const { sessionId } = request.params;
12
+ const session = await taskRunner.getSession(sessionId);
13
+ if (!session) {
14
+ reply.code(404);
15
+ return { error: "session_not_found" };
16
+ }
17
+ return session;
18
+ });
19
+ app.post("/v1/sessions", async (request, reply) => {
20
+ const parsed = SessionCreateSchema.safeParse(request.body);
21
+ if (!parsed.success) {
22
+ reply.code(400);
23
+ return { error: "invalid_request", issues: parsed.error.flatten() };
24
+ }
25
+ reply.code(201);
26
+ return taskRunner.createSession(parsed.data);
27
+ });
28
+ app.patch("/v1/sessions/:sessionId", async (request, reply) => {
29
+ const { sessionId } = request.params;
30
+ const parsed = SessionUpdateSchema.safeParse(request.body);
31
+ if (!parsed.success) {
32
+ reply.code(400);
33
+ return { error: "invalid_request", issues: parsed.error.flatten() };
34
+ }
35
+ let updated;
36
+ try {
37
+ updated = await taskRunner.updateSession(sessionId, parsed.data);
38
+ }
39
+ catch (error) {
40
+ if (error instanceof RequestPreconditionError) {
41
+ reply.code(error.statusCode);
42
+ return { error: error.code, message: error.message };
43
+ }
44
+ throw error;
45
+ }
46
+ if (!updated) {
47
+ reply.code(404);
48
+ return { error: "session_not_found" };
49
+ }
50
+ return updated;
51
+ });
52
+ app.get("/v1/tasks/:taskId", async (request, reply) => {
53
+ const { taskId } = request.params;
54
+ const task = await taskRunner.get(taskId);
55
+ if (!task) {
56
+ reply.code(404);
57
+ return { error: "task_not_found" };
58
+ }
59
+ return task;
60
+ });
61
+ app.post("/v1/tasks/run", async (request, reply) => {
62
+ const parsed = TaskRequestSchema.safeParse(request.body);
63
+ if (!parsed.success) {
64
+ reply.code(400);
65
+ return { error: "invalid_request", issues: parsed.error.flatten() };
66
+ }
67
+ if (parsed.data.sessionId) {
68
+ const session = await taskRunner.getSession(parsed.data.sessionId);
69
+ if (!session) {
70
+ reply.code(404);
71
+ return { error: "session_not_found" };
72
+ }
73
+ }
74
+ try {
75
+ const result = await taskRunner.run(parsed.data);
76
+ reply.code(result.status === "completed" ? 200 : 500);
77
+ return result;
78
+ }
79
+ catch (error) {
80
+ if (error instanceof RequestPreconditionError) {
81
+ reply.code(error.statusCode);
82
+ return { error: error.code, message: error.message };
83
+ }
84
+ throw error;
85
+ }
86
+ });
87
+ return app;
88
+ }
89
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/server/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ export type SessionRecord = {
2
+ id: string;
3
+ name: string;
4
+ mode: "guest" | "profile";
5
+ profile?: string | undefined;
6
+ startUrl?: string | undefined;
7
+ agent?: {
8
+ kind: "auto" | "cliproxy" | "opencode" | "mock";
9
+ model?: string | undefined;
10
+ } | undefined;
11
+ notes?: string | undefined;
12
+ createdAt: string;
13
+ updatedAt: string;
14
+ lastTaskAt?: string | undefined;
15
+ taskCount: number;
16
+ history: SessionHistoryEntry[];
17
+ };
18
+ export type SessionHistoryEntry = {
19
+ taskId: string;
20
+ goal: string;
21
+ status: "completed" | "failed";
22
+ startedAt: string;
23
+ finishedAt: string;
24
+ resultSummary: string;
25
+ };
26
+ export type SessionCreateInput = {
27
+ name: string;
28
+ mode?: "guest" | "profile" | undefined;
29
+ profile?: string | undefined;
30
+ startUrl?: string | undefined;
31
+ agent?: SessionRecord["agent"];
32
+ notes?: string | undefined;
33
+ };
34
+ export declare function sessionUserDataDir(sessionId: string): string;
35
+ export declare function sessionStorageStatePath(sessionId: string): string;
36
+ export declare class SessionStore {
37
+ create(input: SessionCreateInput): Promise<SessionRecord>;
38
+ list(): Promise<SessionRecord[]>;
39
+ get(id: string): Promise<SessionRecord | null>;
40
+ update(id: string, patch: {
41
+ name?: string | undefined;
42
+ profile?: string | undefined;
43
+ startUrl?: string | undefined;
44
+ notes?: string | undefined;
45
+ }): Promise<SessionRecord | null>;
46
+ appendHistory(id: string, entry: SessionHistoryEntry): Promise<SessionRecord | null>;
47
+ private save;
48
+ }
@@ -0,0 +1,84 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { PROJECT_ROOT } from "../config.js";
5
+ const SESSIONS_DIR = path.join(PROJECT_ROOT, "sessions");
6
+ export function sessionUserDataDir(sessionId) {
7
+ return path.join(SESSIONS_DIR, sessionId, "user-data-dir");
8
+ }
9
+ export function sessionStorageStatePath(sessionId) {
10
+ return path.join(SESSIONS_DIR, sessionId, "storage-state.json");
11
+ }
12
+ export class SessionStore {
13
+ async create(input) {
14
+ const now = new Date().toISOString();
15
+ const session = {
16
+ id: crypto.randomUUID(),
17
+ name: input.name,
18
+ mode: input.mode ?? (input.profile ? "profile" : "guest"),
19
+ createdAt: now,
20
+ updatedAt: now,
21
+ taskCount: 0,
22
+ history: [],
23
+ ...(input.profile ? { profile: input.profile } : {}),
24
+ ...(input.startUrl ? { startUrl: input.startUrl } : {}),
25
+ ...(input.agent ? { agent: input.agent } : {}),
26
+ ...(input.notes ? { notes: input.notes } : {}),
27
+ };
28
+ await this.save(session);
29
+ return session;
30
+ }
31
+ async list() {
32
+ await fs.mkdir(SESSIONS_DIR, { recursive: true });
33
+ const entries = await fs.readdir(SESSIONS_DIR);
34
+ const sessions = await Promise.all(entries
35
+ .filter((entry) => entry.endsWith(".json"))
36
+ .map(async (entry) => this.get(path.basename(entry, ".json"))));
37
+ return sessions.filter((session) => Boolean(session));
38
+ }
39
+ async get(id) {
40
+ try {
41
+ const file = await fs.readFile(path.join(SESSIONS_DIR, `${id}.json`), "utf8");
42
+ return JSON.parse(file);
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ async update(id, patch) {
49
+ const session = await this.get(id);
50
+ if (!session) {
51
+ return null;
52
+ }
53
+ const updated = {
54
+ ...session,
55
+ updatedAt: new Date().toISOString(),
56
+ ...(patch.name !== undefined ? { name: patch.name } : {}),
57
+ ...(patch.profile !== undefined ? { profile: patch.profile } : {}),
58
+ ...(patch.startUrl !== undefined ? { startUrl: patch.startUrl } : {}),
59
+ ...(patch.notes !== undefined ? { notes: patch.notes } : {}),
60
+ };
61
+ await this.save(updated);
62
+ return updated;
63
+ }
64
+ async appendHistory(id, entry) {
65
+ const session = await this.get(id);
66
+ if (!session) {
67
+ return null;
68
+ }
69
+ const updated = {
70
+ ...session,
71
+ history: [...session.history, entry].slice(-25),
72
+ taskCount: session.taskCount + 1,
73
+ lastTaskAt: entry.finishedAt,
74
+ updatedAt: new Date().toISOString(),
75
+ };
76
+ await this.save(updated);
77
+ return updated;
78
+ }
79
+ async save(session) {
80
+ await fs.mkdir(SESSIONS_DIR, { recursive: true });
81
+ await fs.writeFile(path.join(SESSIONS_DIR, `${session.id}.json`), `${JSON.stringify(session, null, 2)}\n`, "utf8");
82
+ }
83
+ }
84
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/sessions/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { StepRecord, TaskRequest, TaskResult } from "../tasks/schemas.js";
2
+ export type RunHandle = {
3
+ id: string;
4
+ dir: string;
5
+ screenshotsDir: string;
6
+ };
7
+ export declare class RunStore {
8
+ create(request: TaskRequest): Promise<RunHandle>;
9
+ appendStep(run: RunHandle, step: StepRecord): Promise<void>;
10
+ saveResult(run: RunHandle, result: TaskResult): Promise<void>;
11
+ get(taskId: string): Promise<TaskResult | null>;
12
+ }
@@ -0,0 +1,30 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { RUNS_DIR } from "../config.js";
5
+ export class RunStore {
6
+ async create(request) {
7
+ const id = crypto.randomUUID();
8
+ const dir = path.join(RUNS_DIR, id);
9
+ const screenshotsDir = path.join(dir, "screenshots");
10
+ await fs.mkdir(screenshotsDir, { recursive: true });
11
+ await fs.writeFile(path.join(dir, "request.json"), `${JSON.stringify(request, null, 2)}\n`, "utf8");
12
+ return { id, dir, screenshotsDir };
13
+ }
14
+ async appendStep(run, step) {
15
+ await fs.appendFile(path.join(run.dir, "steps.jsonl"), `${JSON.stringify(step)}\n`, "utf8");
16
+ }
17
+ async saveResult(run, result) {
18
+ await fs.writeFile(path.join(run.dir, "task.json"), `${JSON.stringify(result, null, 2)}\n`, "utf8");
19
+ }
20
+ async get(taskId) {
21
+ try {
22
+ const file = await fs.readFile(path.join(RUNS_DIR, taskId, "task.json"), "utf8");
23
+ return JSON.parse(file);
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ }
30
+ //# sourceMappingURL=run-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-store.js","sourceRoot":"","sources":["../../../src/storage/run-store.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AASxC,MAAM,OAAO,QAAQ;IACnB,KAAK,CAAC,MAAM,CAAC,OAAoB;QAC/B,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QACrD,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAC9B,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EACvC,MAAM,CACP,CAAC;QACF,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAc,EAAE,IAAgB;QAC/C,MAAM,EAAE,CAAC,UAAU,CACjB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,EACjC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAC3B,MAAM,CACP,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAc,EAAE,MAAkB;QACjD,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,EAC/B,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EACtC,MAAM,CACP,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAc;QACtB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;YACjF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ export declare class RequestPreconditionError extends Error {
2
+ readonly code: string;
3
+ readonly statusCode: number;
4
+ constructor(code: string, message: string, statusCode?: number);
5
+ }
@@ -0,0 +1,11 @@
1
+ export class RequestPreconditionError extends Error {
2
+ code;
3
+ statusCode;
4
+ constructor(code, message, statusCode = 409) {
5
+ super(message);
6
+ this.code = code;
7
+ this.statusCode = statusCode;
8
+ this.name = "RequestPreconditionError";
9
+ }
10
+ }
11
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/tasks/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAEtC;IAEA;IAHX,YACW,IAAY,EACrB,OAAe,EACN,aAAa,GAAG;QAEzB,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,SAAI,GAAJ,IAAI,CAAQ;QAEZ,eAAU,GAAV,UAAU,CAAM;QAGzB,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export declare function validateOutput(schema: Record<string, unknown> | undefined, result: Record<string, unknown>): void;