@engineeros/connector 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -13
- package/bin/engineeros-connector.mjs +132 -1085
- package/package.json +24 -41
- package/src/acp-client.mjs +0 -468
- package/src/agent-harness.mjs +0 -264
- package/src/agent-registry.mjs +0 -643
- package/src/assessment-spool.mjs +0 -315
- package/src/capabilities.mjs +0 -24
- package/src/cli-args.mjs +0 -18
- package/src/codex-app-server.mjs +0 -250
- package/src/config.mjs +0 -109
- package/src/connection.mjs +0 -80
- package/src/mcp-server.mjs +0 -256
- package/src/runner.mjs +0 -2124
- package/src/skills/change-planning/SKILL.md +0 -12
- package/src/skills/change-verification/SKILL.md +0 -12
- package/src/skills/codebase-research/SKILL.md +0 -12
- package/src/skills/goal-execution/SKILL.md +0 -12
package/src/config.mjs
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
|
|
6
|
-
export function configPath(workspace = process.cwd()) {
|
|
7
|
-
const key = createHash("sha256")
|
|
8
|
-
.update(path.resolve(workspace))
|
|
9
|
-
.digest("hex")
|
|
10
|
-
.slice(0, 24);
|
|
11
|
-
return path.join(os.homedir(), ".engineeros", "connectors", `${key}.json`);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function socketUrl(value) {
|
|
15
|
-
const url = new URL(value);
|
|
16
|
-
if (url.protocol === "http:") url.protocol = "ws:";
|
|
17
|
-
if (url.protocol === "https:") url.protocol = "wss:";
|
|
18
|
-
if (!["ws:", "wss:"].includes(url.protocol)) {
|
|
19
|
-
throw new Error("EngineerOS URL must use http, https, ws, or wss.");
|
|
20
|
-
}
|
|
21
|
-
url.pathname = "/api/v1/agent-connectors/ws";
|
|
22
|
-
url.search = "";
|
|
23
|
-
url.hash = "";
|
|
24
|
-
return url.toString();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function connectorResumeCredentials(config, serverUrl) {
|
|
28
|
-
if (
|
|
29
|
-
!config?.connector_id ||
|
|
30
|
-
!config.token ||
|
|
31
|
-
config.server_url !== serverUrl
|
|
32
|
-
) {
|
|
33
|
-
return {};
|
|
34
|
-
}
|
|
35
|
-
return {
|
|
36
|
-
existing_connector_id: config.connector_id,
|
|
37
|
-
existing_token: config.token,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function mergePairedConfig(
|
|
42
|
-
requestedConfig,
|
|
43
|
-
existingConfig,
|
|
44
|
-
connectorId,
|
|
45
|
-
token,
|
|
46
|
-
) {
|
|
47
|
-
const preserved =
|
|
48
|
-
existingConfig?.connector_id === connectorId ? existingConfig : {};
|
|
49
|
-
const sameAgent =
|
|
50
|
-
preserved.agent_protocol === requestedConfig.agent_protocol &&
|
|
51
|
-
(preserved.agent_id || preserved.agent_command || null) ===
|
|
52
|
-
(requestedConfig.agent_id || requestedConfig.agent_command || null) &&
|
|
53
|
-
(preserved.agent_version || null) ===
|
|
54
|
-
(requestedConfig.agent_version || null);
|
|
55
|
-
return {
|
|
56
|
-
...preserved,
|
|
57
|
-
...requestedConfig,
|
|
58
|
-
connector_id: connectorId,
|
|
59
|
-
token,
|
|
60
|
-
sessions: sameAgent ? preserved.sessions || {} : {},
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function resultUrl(websocketUrl, connectorId, runId) {
|
|
65
|
-
const url = new URL(websocketUrl);
|
|
66
|
-
url.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
67
|
-
url.pathname = `/api/v1/agent-connectors/${connectorId}/runs/${runId}/result`;
|
|
68
|
-
return url.toString();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function workspaceUrl(websocketUrl, connectorId) {
|
|
72
|
-
const url = new URL(websocketUrl);
|
|
73
|
-
url.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
74
|
-
url.pathname = `/api/v1/agent-connectors/${connectorId}/workspace`;
|
|
75
|
-
return url.toString();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function assessmentResultUrl(websocketUrl, connectorId, assessmentId) {
|
|
79
|
-
const url = new URL(websocketUrl);
|
|
80
|
-
url.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
81
|
-
url.pathname = `/api/v1/agent-connectors/${connectorId}/assessment/${assessmentId}/result`;
|
|
82
|
-
return url.toString();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function artifactToolUrl(websocketUrl, connectorId) {
|
|
86
|
-
const url = new URL(websocketUrl);
|
|
87
|
-
url.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
88
|
-
url.pathname = `/api/v1/agent-connectors/${connectorId}/artifact-tools`;
|
|
89
|
-
return url.toString();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export async function loadConfig(workspace = process.cwd()) {
|
|
93
|
-
try {
|
|
94
|
-
return JSON.parse(await readFile(configPath(workspace), "utf8"));
|
|
95
|
-
} catch (error) {
|
|
96
|
-
if (error?.code === "ENOENT") return null;
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export async function saveConfig(config) {
|
|
102
|
-
const target = configPath(config.workspace);
|
|
103
|
-
await mkdir(path.dirname(target), { recursive: true });
|
|
104
|
-
await writeFile(target, `${JSON.stringify(config, null, 2)}\n`, {
|
|
105
|
-
encoding: "utf8",
|
|
106
|
-
mode: 0o600,
|
|
107
|
-
});
|
|
108
|
-
if (process.platform !== "win32") await chmod(target, 0o600);
|
|
109
|
-
}
|
package/src/connection.mjs
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
const PROTOCOL_FAILURE_MESSAGE_MAX_LENGTH = 2_000;
|
|
2
|
-
const TRUNCATED_FAILURE_SUFFIX = "\n… [truncated by EngineerOS connector]";
|
|
3
|
-
|
|
4
|
-
export function describeWebSocketError(event) {
|
|
5
|
-
return (
|
|
6
|
-
event?.error?.message ||
|
|
7
|
-
event?.message ||
|
|
8
|
-
"The WebSocket connection failed without providing an error detail."
|
|
9
|
-
);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function sendConnectionMessage(activeSocket, connection, message) {
|
|
13
|
-
if (activeSocket !== connection || connection.readyState !== 1) return false;
|
|
14
|
-
connection.send(JSON.stringify(message));
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function protocolFailureMessage(error) {
|
|
19
|
-
const raw = error instanceof Error ? error.message : String(error ?? "");
|
|
20
|
-
const message =
|
|
21
|
-
raw.trim() || "The connector failed without providing an error detail.";
|
|
22
|
-
const characters = [...message];
|
|
23
|
-
if (characters.length <= PROTOCOL_FAILURE_MESSAGE_MAX_LENGTH) return message;
|
|
24
|
-
const suffix = [...TRUNCATED_FAILURE_SUFFIX];
|
|
25
|
-
return `${characters
|
|
26
|
-
.slice(0, PROTOCOL_FAILURE_MESSAGE_MAX_LENGTH - suffix.length)
|
|
27
|
-
.join("")}${TRUNCATED_FAILURE_SUFFIX}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export async function describeRejectedResponse(response, subject) {
|
|
31
|
-
const responseBody = await response.text();
|
|
32
|
-
const detail = responseDetail(responseBody);
|
|
33
|
-
return protocolFailureMessage(
|
|
34
|
-
`EngineerOS rejected ${subject} (${response.status})${detail ? `: ${detail}` : "."}`,
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function startConnectionWatchdog(
|
|
39
|
-
socket,
|
|
40
|
-
url,
|
|
41
|
-
{ timeoutMs = 15_000, onTimeout = console.error } = {},
|
|
42
|
-
) {
|
|
43
|
-
const timer = setTimeout(() => {
|
|
44
|
-
onTimeout(
|
|
45
|
-
`EngineerOS did not complete the WebSocket handshake at ${url} within ${Math.round(timeoutMs / 1_000)} seconds. Check that the backend is running and the URL is reachable from this machine.`,
|
|
46
|
-
);
|
|
47
|
-
try {
|
|
48
|
-
socket.close();
|
|
49
|
-
} catch {
|
|
50
|
-
// Reconnect scheduling is owned by the caller.
|
|
51
|
-
}
|
|
52
|
-
}, timeoutMs);
|
|
53
|
-
|
|
54
|
-
return () => clearTimeout(timer);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function responseDetail(responseBody) {
|
|
58
|
-
const body = String(responseBody || "").trim();
|
|
59
|
-
if (!body) return "";
|
|
60
|
-
try {
|
|
61
|
-
const parsed = JSON.parse(body);
|
|
62
|
-
if (typeof parsed?.detail === "string") return parsed.detail;
|
|
63
|
-
if (Array.isArray(parsed?.detail)) {
|
|
64
|
-
return parsed.detail.map(validationIssue).filter(Boolean).join("; ");
|
|
65
|
-
}
|
|
66
|
-
} catch {
|
|
67
|
-
// Plain-text server errors are already useful to the operator.
|
|
68
|
-
}
|
|
69
|
-
return body;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function validationIssue(issue) {
|
|
73
|
-
if (typeof issue === "string") return issue;
|
|
74
|
-
if (!issue || typeof issue !== "object") return "";
|
|
75
|
-
const location = Array.isArray(issue.loc) ? issue.loc.join(".") : "";
|
|
76
|
-
const message = typeof issue.msg === "string" ? issue.msg : "";
|
|
77
|
-
const type = typeof issue.type === "string" ? ` (${issue.type})` : "";
|
|
78
|
-
if (!location && !message) return "";
|
|
79
|
-
return `${location ? `${location}: ` : ""}${message}${type}`;
|
|
80
|
-
}
|
package/src/mcp-server.mjs
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
import readline from "node:readline";
|
|
2
|
-
|
|
3
|
-
import { artifactToolUrl } from "./config.mjs";
|
|
4
|
-
|
|
5
|
-
const PROTOCOL_VERSION = "2025-06-18";
|
|
6
|
-
|
|
7
|
-
const ARTIFACT_TYPES = [
|
|
8
|
-
"vision",
|
|
9
|
-
"problem",
|
|
10
|
-
"capability",
|
|
11
|
-
"epic",
|
|
12
|
-
"feature",
|
|
13
|
-
"story",
|
|
14
|
-
"architecture",
|
|
15
|
-
"service",
|
|
16
|
-
"api",
|
|
17
|
-
"data_model",
|
|
18
|
-
"event",
|
|
19
|
-
"task",
|
|
20
|
-
"release",
|
|
21
|
-
"risk",
|
|
22
|
-
"pattern",
|
|
23
|
-
"technology",
|
|
24
|
-
"agent",
|
|
25
|
-
"workflow",
|
|
26
|
-
"review",
|
|
27
|
-
"comment",
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
const artifactTypeSchema = { type: "string", enum: ARTIFACT_TYPES };
|
|
31
|
-
const artifactIdSchema = {
|
|
32
|
-
type: "string",
|
|
33
|
-
format: "uuid",
|
|
34
|
-
description: "The saved EngineerOS artifact ID.",
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const artifactTools = [
|
|
38
|
-
{
|
|
39
|
-
name: "engineeros_list_artifacts",
|
|
40
|
-
description: "List saved artifacts in the current EngineerOS project.",
|
|
41
|
-
inputSchema: {
|
|
42
|
-
type: "object",
|
|
43
|
-
properties: {
|
|
44
|
-
artifact_type: artifactTypeSchema,
|
|
45
|
-
status: { type: "string", enum: ["draft", "active", "archived"] },
|
|
46
|
-
page: { type: "integer", minimum: 1 },
|
|
47
|
-
page_size: { type: "integer", minimum: 1, maximum: 50 },
|
|
48
|
-
},
|
|
49
|
-
additionalProperties: false,
|
|
50
|
-
},
|
|
51
|
-
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: "engineeros_get_artifact",
|
|
55
|
-
description: "Load one saved artifact from the current EngineerOS project.",
|
|
56
|
-
inputSchema: {
|
|
57
|
-
type: "object",
|
|
58
|
-
properties: { artifact_id: artifactIdSchema },
|
|
59
|
-
required: ["artifact_id"],
|
|
60
|
-
additionalProperties: false,
|
|
61
|
-
},
|
|
62
|
-
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
name: "engineeros_create_artifact",
|
|
66
|
-
description:
|
|
67
|
-
"Create a saved EngineerOS artifact during the currently approved writable Goal.",
|
|
68
|
-
inputSchema: {
|
|
69
|
-
type: "object",
|
|
70
|
-
properties: {
|
|
71
|
-
artifact_type: artifactTypeSchema,
|
|
72
|
-
name: { type: "string", minLength: 1, maxLength: 500 },
|
|
73
|
-
content: {
|
|
74
|
-
type: "string",
|
|
75
|
-
minLength: 1,
|
|
76
|
-
description: "Complete artifact content as structured Markdown.",
|
|
77
|
-
},
|
|
78
|
-
metadata_info: { type: "object" },
|
|
79
|
-
},
|
|
80
|
-
required: ["artifact_type", "name", "content"],
|
|
81
|
-
additionalProperties: false,
|
|
82
|
-
},
|
|
83
|
-
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
name: "engineeros_update_artifact",
|
|
87
|
-
description:
|
|
88
|
-
"Update a saved EngineerOS artifact during the currently approved writable Goal.",
|
|
89
|
-
inputSchema: {
|
|
90
|
-
type: "object",
|
|
91
|
-
properties: {
|
|
92
|
-
artifact_id: artifactIdSchema,
|
|
93
|
-
artifact_type: artifactTypeSchema,
|
|
94
|
-
name: { type: "string", minLength: 1, maxLength: 500 },
|
|
95
|
-
content: {
|
|
96
|
-
type: "string",
|
|
97
|
-
minLength: 1,
|
|
98
|
-
description: "Complete replacement content as structured Markdown.",
|
|
99
|
-
},
|
|
100
|
-
metadata_info: { type: "object" },
|
|
101
|
-
},
|
|
102
|
-
required: ["artifact_id"],
|
|
103
|
-
additionalProperties: false,
|
|
104
|
-
},
|
|
105
|
-
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
name: "engineeros_reclassify_artifact",
|
|
109
|
-
description:
|
|
110
|
-
"Move a saved artifact to another EngineerOS classification during the currently approved writable Goal.",
|
|
111
|
-
inputSchema: {
|
|
112
|
-
type: "object",
|
|
113
|
-
properties: {
|
|
114
|
-
artifact_id: artifactIdSchema,
|
|
115
|
-
target_artifact_type: artifactTypeSchema,
|
|
116
|
-
},
|
|
117
|
-
required: ["artifact_id", "target_artifact_type"],
|
|
118
|
-
additionalProperties: false,
|
|
119
|
-
},
|
|
120
|
-
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
name: "engineeros_materialize_product_artifacts",
|
|
124
|
-
description:
|
|
125
|
-
"Materialize structured Product documents into the canonical EngineerOS Vision, Portfolio capabilities, and project graph during the currently approved writable Goal.",
|
|
126
|
-
inputSchema: {
|
|
127
|
-
type: "object",
|
|
128
|
-
properties: {},
|
|
129
|
-
additionalProperties: false,
|
|
130
|
-
},
|
|
131
|
-
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
name: "engineeros_delete_artifact",
|
|
135
|
-
description:
|
|
136
|
-
"Soft-delete a saved EngineerOS artifact during the currently approved writable Goal.",
|
|
137
|
-
inputSchema: {
|
|
138
|
-
type: "object",
|
|
139
|
-
properties: { artifact_id: artifactIdSchema },
|
|
140
|
-
required: ["artifact_id"],
|
|
141
|
-
additionalProperties: false,
|
|
142
|
-
},
|
|
143
|
-
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
144
|
-
},
|
|
145
|
-
];
|
|
146
|
-
|
|
147
|
-
const toolNames = new Map(
|
|
148
|
-
artifactTools.map((tool) => [tool.name, tool.name.replace("engineeros_", "")]),
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
export async function handleMcpRequest(message, context) {
|
|
152
|
-
if (message.method === "notifications/initialized") return null;
|
|
153
|
-
if (message.method === "initialize") {
|
|
154
|
-
return success(message.id, {
|
|
155
|
-
protocolVersion: message.params?.protocolVersion || PROTOCOL_VERSION,
|
|
156
|
-
capabilities: { tools: { listChanged: false } },
|
|
157
|
-
serverInfo: { name: "engineeros-connector", version: context.version },
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
if (message.method === "ping") return success(message.id, {});
|
|
161
|
-
if (message.method === "tools/list") {
|
|
162
|
-
return success(message.id, { tools: artifactTools });
|
|
163
|
-
}
|
|
164
|
-
if (message.method === "tools/call") {
|
|
165
|
-
const tool = toolNames.get(message.params?.name);
|
|
166
|
-
if (!tool) return failure(message.id, -32602, "Unknown EngineerOS artifact tool.");
|
|
167
|
-
try {
|
|
168
|
-
const response = await callArtifactTool(context, tool, message.params?.arguments || {});
|
|
169
|
-
return success(message.id, {
|
|
170
|
-
content: [{ type: "text", text: renderArtifactToolResult(response) }],
|
|
171
|
-
isError: false,
|
|
172
|
-
});
|
|
173
|
-
} catch (error) {
|
|
174
|
-
return success(message.id, {
|
|
175
|
-
content: [
|
|
176
|
-
{
|
|
177
|
-
type: "text",
|
|
178
|
-
text: `# EngineerOS artifact tool failed\n\n${error instanceof Error ? error.message : String(error)}`,
|
|
179
|
-
},
|
|
180
|
-
],
|
|
181
|
-
isError: true,
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return failure(message.id, -32601, `Unsupported MCP method: ${message.method}`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export async function runMcpServer({ config, runId, version, input, output, fetchImpl = fetch }) {
|
|
189
|
-
const context = { config, runId, version, fetchImpl };
|
|
190
|
-
const lines = readline.createInterface({ input, crlfDelay: Infinity });
|
|
191
|
-
for await (const line of lines) {
|
|
192
|
-
if (!line.trim()) continue;
|
|
193
|
-
let response;
|
|
194
|
-
try {
|
|
195
|
-
response = await handleMcpRequest(JSON.parse(line), context);
|
|
196
|
-
} catch (error) {
|
|
197
|
-
response = failure(null, -32700, error instanceof Error ? error.message : String(error));
|
|
198
|
-
}
|
|
199
|
-
if (response) output.write(`${JSON.stringify(response)}\n`);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
async function callArtifactTool(context, tool, arguments_) {
|
|
204
|
-
const response = await context.fetchImpl(
|
|
205
|
-
artifactToolUrl(context.config.server_url, context.config.connector_id),
|
|
206
|
-
{
|
|
207
|
-
method: "POST",
|
|
208
|
-
headers: {
|
|
209
|
-
"Content-Type": "application/json",
|
|
210
|
-
Authorization: `Bearer ${context.config.token}`,
|
|
211
|
-
},
|
|
212
|
-
body: JSON.stringify({ run_id: context.runId, tool, arguments: arguments_ }),
|
|
213
|
-
},
|
|
214
|
-
);
|
|
215
|
-
if (!response.ok) {
|
|
216
|
-
const detail = await response.text();
|
|
217
|
-
throw new Error(`EngineerOS rejected ${tool} (${response.status}): ${detail}`);
|
|
218
|
-
}
|
|
219
|
-
return response.json();
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function renderArtifactToolResult(result) {
|
|
223
|
-
const lines = ["# EngineerOS artifact tool result", "", result.message || "Completed."];
|
|
224
|
-
if (result.vision_id) lines.push("", `- Vision ID: \`${result.vision_id}\``);
|
|
225
|
-
if (Array.isArray(result.capability_ids) && result.capability_ids.length) {
|
|
226
|
-
lines.push(`- Capability IDs: ${result.capability_ids.map((id) => `\`${id}\``).join(", ")}`);
|
|
227
|
-
}
|
|
228
|
-
if (result.artifact) lines.push("", ...artifactMarkdown(result.artifact));
|
|
229
|
-
if (Array.isArray(result.artifacts)) {
|
|
230
|
-
lines.push("", `## Artifacts (${result.total ?? result.artifacts.length})`, "");
|
|
231
|
-
for (const artifact of result.artifacts) {
|
|
232
|
-
lines.push(`- **${artifact.name}** — \`${artifact.artifact_type}\` — \`${artifact.id}\``);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return lines.join("\n");
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function artifactMarkdown(artifact) {
|
|
239
|
-
return [
|
|
240
|
-
`## ${artifact.name}`,
|
|
241
|
-
"",
|
|
242
|
-
`- ID: \`${artifact.id}\``,
|
|
243
|
-
`- Type: \`${artifact.artifact_type}\``,
|
|
244
|
-
`- Status: \`${artifact.status}\``,
|
|
245
|
-
"",
|
|
246
|
-
artifact.content || "",
|
|
247
|
-
];
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
function success(id, result) {
|
|
251
|
-
return { jsonrpc: "2.0", id, result };
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function failure(id, code, message) {
|
|
255
|
-
return { jsonrpc: "2.0", id, error: { code, message } };
|
|
256
|
-
}
|