@smwb/onreel-git-mcp 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/chunk-3YP22YLA.js +50 -0
- package/dist/chunk-3YP22YLA.js.map +1 -0
- package/dist/chunk-4ZGRXIVA.js +259 -0
- package/dist/chunk-4ZGRXIVA.js.map +1 -0
- package/dist/chunk-C6PHNSDC.js +112 -0
- package/dist/chunk-C6PHNSDC.js.map +1 -0
- package/dist/chunk-GPRMI4PG.js +421 -0
- package/dist/chunk-GPRMI4PG.js.map +1 -0
- package/dist/chunk-L7CPE2SO.js +166 -0
- package/dist/chunk-L7CPE2SO.js.map +1 -0
- package/dist/contract/contract.const.d.ts +190 -0
- package/dist/contract/contract.lib.d.ts +22 -0
- package/dist/contract/contract.schema.d.ts +279 -0
- package/dist/contract/contract.types.d.ts +23 -0
- package/dist/files/files.const.d.ts +6 -0
- package/dist/files/files.lib.d.ts +14 -0
- package/dist/files/files.types.d.ts +13 -0
- package/dist/files/index.d.ts +3 -0
- package/dist/files/index.js +163 -0
- package/dist/files/index.js.map +1 -0
- package/dist/git/git.const.d.ts +4 -0
- package/dist/git/git.lib.d.ts +90 -0
- package/dist/git/git.types.d.ts +33 -0
- package/dist/git/index.d.ts +7 -0
- package/dist/git/index.js +97 -0
- package/dist/git/index.js.map +1 -0
- package/dist/git/paths.const.d.ts +5 -0
- package/dist/git/paths.lib.d.ts +39 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/log.types.d.ts +5 -0
- package/dist/kernel/redact.lib.d.ts +25 -0
- package/dist/kernel/store.types.d.ts +109 -0
- package/dist/kernel/umask.lib.d.ts +7 -0
- package/dist/mcp/args.lib.d.ts +17 -0
- package/dist/mcp/envelope.lib.d.ts +20 -0
- package/dist/mcp/index.d.ts +8 -0
- package/dist/mcp/index.js +744 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/mcp.const.d.ts +23 -0
- package/dist/mcp/mcp.schema.d.ts +64 -0
- package/dist/mcp/mcp.types.d.ts +125 -0
- package/dist/mcp/principal.lib.d.ts +22 -0
- package/dist/mcp/server.lib.d.ts +3 -0
- package/dist/mcp/tools.lib.d.ts +16 -0
- package/dist/tracker/builtin.lib.d.ts +1 -0
- package/dist/tracker/github.lib.d.ts +2 -0
- package/dist/tracker/gitlab.lib.d.ts +2 -0
- package/dist/tracker/http.lib.d.ts +4 -0
- package/dist/tracker/index.d.ts +15 -0
- package/dist/tracker/index.js +840 -0
- package/dist/tracker/index.js.map +1 -0
- package/dist/tracker/jira.lib.d.ts +2 -0
- package/dist/tracker/local.lib.d.ts +2 -0
- package/dist/tracker/mapping.const.d.ts +26 -0
- package/dist/tracker/registry.lib.d.ts +5 -0
- package/dist/tracker/secrets.lib.d.ts +7 -0
- package/dist/tracker/sourcecraft.lib.d.ts +2 -0
- package/dist/tracker/tracker.const.d.ts +10 -0
- package/dist/tracker/tracker.lib.d.ts +21 -0
- package/dist/tracker/tracker.types.d.ts +77 -0
- package/dist/worktree/index.d.ts +4 -0
- package/dist/worktree/index.js +203 -0
- package/dist/worktree/index.js.map +1 -0
- package/dist/worktree/lifecycle.const.d.ts +2 -0
- package/dist/worktree/lifecycle.lib.d.ts +30 -0
- package/dist/worktree/lifecycle.types.d.ts +14 -0
- package/package.json +74 -4
- package/README.md +0 -3
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
import {
|
|
2
|
+
contractError,
|
|
3
|
+
formatVersion
|
|
4
|
+
} from "../chunk-3YP22YLA.js";
|
|
5
|
+
import {
|
|
6
|
+
ENV_DISPATCH_ID,
|
|
7
|
+
ENV_HOST_URL,
|
|
8
|
+
ENV_RUN_ID,
|
|
9
|
+
ENV_TASK_ID,
|
|
10
|
+
ENV_TOKEN,
|
|
11
|
+
HOST_CONTRACT_VERSION,
|
|
12
|
+
HOST_DISCOVERY_FILE,
|
|
13
|
+
contractErrorSchema,
|
|
14
|
+
requestIdSchema
|
|
15
|
+
} from "../chunk-4ZGRXIVA.js";
|
|
16
|
+
import {
|
|
17
|
+
redactSecretText
|
|
18
|
+
} from "../chunk-L7CPE2SO.js";
|
|
19
|
+
|
|
20
|
+
// src/mcp/mcp.const.ts
|
|
21
|
+
var MCP_PROTOCOL_VERSIONS = ["2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"];
|
|
22
|
+
var MCP_STRUCTURED_SINCE = "2025-06-18";
|
|
23
|
+
var MCP_SERVER_NAME = "onreel";
|
|
24
|
+
var MCP_SERVER_TITLE = "onreel orch";
|
|
25
|
+
var MCP_PROGRESS_INTERVAL_MS = 15e3;
|
|
26
|
+
var MCP_MAX_LINE_BYTES = 8 * 1024 * 1024;
|
|
27
|
+
var MCP_EOF_GRACE_MS = 5e3;
|
|
28
|
+
var MCP_REQUEST_ID_ARGUMENT = "request-id";
|
|
29
|
+
var DURATION_PATTERN = /^\s*(\d+)(ms|s|m|h)?\s*$/;
|
|
30
|
+
var JSONRPC_PARSE_ERROR = -32700;
|
|
31
|
+
var JSONRPC_INVALID_REQUEST = -32600;
|
|
32
|
+
var JSONRPC_METHOD_NOT_FOUND = -32601;
|
|
33
|
+
var JSONRPC_INVALID_PARAMS = -32602;
|
|
34
|
+
var JSONRPC_INTERNAL_ERROR = -32603;
|
|
35
|
+
var MCP_INSTRUCTIONS = "\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B onreel \u2014 \u0442\u0435 \u0436\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u044B, \u0447\u0442\u043E `onreel orch \u2026`, \u0441 \u0442\u0435\u043C\u0438 \u0436\u0435 \u043F\u0440\u0430\u0432\u0430\u043C\u0438. \u0418\u043C\u044F \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 \u2014 \u043F\u0443\u0442\u044C \u043A\u043E\u043C\u0430\u043D\u0434\u044B \u0447\u0435\u0440\u0435\u0437 `_` (orch_task_create \u2014 \u044D\u0442\u043E onreel orch task create), \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u044B \u2014 \u0444\u043B\u0430\u0433\u0438 \u043A\u043E\u043C\u0430\u043D\u0434\u044B \u0431\u0435\u0437 `--`; request-id \u2014 \u043A\u043B\u044E\u0447 \u0438\u0434\u0435\u043C\u043F\u043E\u0442\u0435\u043D\u0442\u043D\u043E\u0441\u0442\u0438: \u043F\u043E\u0432\u0442\u043E\u0440 \u0441 \u0442\u0435\u043C \u0436\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C \u0432\u0435\u0440\u043D\u0451\u0442 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u043F\u0435\u0440\u0432\u043E\u0433\u043E \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F. \u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u2014 \u043A\u043E\u043D\u0432\u0435\u0440\u0442 \u043A\u0430\u043A \u0443 `--json`: {ok: true, requestId, duplicate, result} \u0438\u043B\u0438 {ok: false, requestId, error: {code, message, nextSteps}}; \u0444\u043B\u0430\u0433 `--x` \u0432 nextSteps \u2014 \u044D\u0442\u043E \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442 x. \u0418\u0441\u0442\u0451\u043A\u0448\u0435\u0435 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0435 orch_check \u0438 orch_ask \u2014 \u043D\u0435 \u043E\u0448\u0438\u0431\u043A\u0430 (timedOut, answered: false): \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 \u0432\u044B\u0437\u043E\u0432; \u0434\u0435\u0440\u0436\u0438\u0442\u0435 timeout \u043A\u043E\u0440\u043E\u0447\u0435 \u0442\u0430\u0439\u043C\u0430\u0443\u0442\u0430 \u0432\u044B\u0437\u043E\u0432\u0430 \u0443 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, 5m). \u041F\u0440\u0430\u0432\u0430 \u2014 \u0443 \u0442\u043E\u043A\u0435\u043D\u0430, \u0441 \u043A\u043E\u0442\u043E\u0440\u044B\u043C \u0437\u0430\u043F\u0443\u0449\u0435\u043D \u0441\u0435\u0440\u0432\u0435\u0440: \u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446 \u0438\u0437 host.json \u0438\u043B\u0438 \u0430\u0433\u0435\u043D\u0442 \u0438\u0437 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445 ONREEL_*.";
|
|
36
|
+
|
|
37
|
+
// src/mcp/mcp.schema.ts
|
|
38
|
+
import { z } from "zod";
|
|
39
|
+
var jsonRpcIdSchema = z.union([z.string(), z.number().int()]);
|
|
40
|
+
var jsonRpcMessageSchema = z.object({
|
|
41
|
+
jsonrpc: z.literal("2.0"),
|
|
42
|
+
id: jsonRpcIdSchema.nullable().optional(),
|
|
43
|
+
method: z.string().optional(),
|
|
44
|
+
params: z.unknown().optional(),
|
|
45
|
+
result: z.unknown().optional(),
|
|
46
|
+
error: z.unknown().optional()
|
|
47
|
+
});
|
|
48
|
+
var initializeParamsSchema = z.object({ protocolVersion: z.string(), capabilities: z.unknown().optional(), clientInfo: z.unknown().optional() }).loose();
|
|
49
|
+
var toolsCallParamsSchema = z.object({
|
|
50
|
+
name: z.string().min(1),
|
|
51
|
+
arguments: z.unknown().optional(),
|
|
52
|
+
_meta: z.object({ progressToken: z.union([z.string(), z.number()]).optional() }).loose().optional()
|
|
53
|
+
}).loose();
|
|
54
|
+
var cancelledParamsSchema = z.object({ requestId: jsonRpcIdSchema, reason: z.string().optional() }).loose();
|
|
55
|
+
var cliSuccessSchema = z.object({
|
|
56
|
+
ok: z.literal(true),
|
|
57
|
+
requestId: requestIdSchema.optional(),
|
|
58
|
+
duplicate: z.boolean().optional(),
|
|
59
|
+
result: z.unknown()
|
|
60
|
+
});
|
|
61
|
+
var cliFailureSchema = z.object({
|
|
62
|
+
ok: z.literal(false),
|
|
63
|
+
requestId: requestIdSchema.nullable(),
|
|
64
|
+
error: contractErrorSchema
|
|
65
|
+
});
|
|
66
|
+
var cliOutputSchema = z.discriminatedUnion("ok", [cliSuccessSchema, cliFailureSchema]);
|
|
67
|
+
|
|
68
|
+
// src/mcp/args.lib.ts
|
|
69
|
+
import { resolve } from "path";
|
|
70
|
+
|
|
71
|
+
// src/mcp/envelope.lib.ts
|
|
72
|
+
var CommandError = class extends Error {
|
|
73
|
+
error;
|
|
74
|
+
origin;
|
|
75
|
+
requestId;
|
|
76
|
+
constructor(error, origin, requestId = null, options) {
|
|
77
|
+
super(error.message, options);
|
|
78
|
+
this.name = "CommandError";
|
|
79
|
+
this.error = error;
|
|
80
|
+
this.origin = origin;
|
|
81
|
+
this.requestId = requestId;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
function usageError(message, nextSteps, data) {
|
|
85
|
+
return new CommandError(contractError("invalid_request", message, nextSteps, data), "local");
|
|
86
|
+
}
|
|
87
|
+
function failureOf(cause) {
|
|
88
|
+
if (cause instanceof CommandError) return cause;
|
|
89
|
+
if (typeof cause !== "object" || cause === null) return void 0;
|
|
90
|
+
const candidate = cause;
|
|
91
|
+
if (!isContractError(candidate.error)) return void 0;
|
|
92
|
+
return {
|
|
93
|
+
error: candidate.error,
|
|
94
|
+
origin: candidate.origin === "host" ? "host" : "local",
|
|
95
|
+
requestId: typeof candidate.requestId === "string" ? candidate.requestId : null
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function isContractError(value) {
|
|
99
|
+
if (typeof value !== "object" || value === null) return false;
|
|
100
|
+
const error = value;
|
|
101
|
+
return typeof error.code === "string" && typeof error.message === "string" && Array.isArray(error.nextSteps) && error.nextSteps.length > 0;
|
|
102
|
+
}
|
|
103
|
+
function internalError(cause) {
|
|
104
|
+
const known = failureOf(cause);
|
|
105
|
+
if (known !== void 0) return new CommandError(known.error, known.origin ?? "local", known.requestId ?? null, { cause });
|
|
106
|
+
const raw = cause instanceof Error ? cause.message : String(cause);
|
|
107
|
+
const detail = redactSecretText(raw);
|
|
108
|
+
const error = contractError(
|
|
109
|
+
"internal",
|
|
110
|
+
`\u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044F\u044F \u043E\u0448\u0438\u0431\u043A\u0430 onreel: ${detail === "" ? "\u0431\u0435\u0437 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u044F" : detail}`,
|
|
111
|
+
["\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u0443; \u0435\u0441\u043B\u0438 \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u043E\u0432\u0442\u043E\u0440\u044F\u0435\u0442\u0441\u044F \u2014 \u0441\u043E\u043E\u0431\u0449\u0438\u0442\u0435 \u043E \u043D\u0435\u0439 \u0441 \u043F\u043E\u043B\u043D\u044B\u043C \u0432\u044B\u0432\u043E\u0434\u043E\u043C \u043A\u043E\u043C\u0430\u043D\u0434\u044B."]
|
|
112
|
+
);
|
|
113
|
+
return new CommandError(error, "local", null, { cause });
|
|
114
|
+
}
|
|
115
|
+
function interruptedError(cause, requestId = null) {
|
|
116
|
+
const sent = requestId ?? failureOf(cause)?.requestId ?? null;
|
|
117
|
+
const error = contractError("internal", "\u041A\u043E\u043C\u0430\u043D\u0434\u0430 \u043F\u0440\u0435\u0440\u0432\u0430\u043D\u0430 (SIGINT).", [
|
|
118
|
+
sent === null ? "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u0443." : `\u0417\u0430\u043F\u0440\u043E\u0441 \u0443\u0436\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u0443 \u0441 --request-id ${sent}, \u043C\u0443\u0442\u0430\u0446\u0438\u044E \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C \u0441 \u0442\u0435\u043C \u0436\u0435 requestId (D-068).`
|
|
119
|
+
]);
|
|
120
|
+
return new CommandError(error, "local", sent, { cause });
|
|
121
|
+
}
|
|
122
|
+
function isDuplicate(outcome) {
|
|
123
|
+
const result = outcome.result;
|
|
124
|
+
const fromResult = typeof result === "object" && result !== null && result.duplicate === true;
|
|
125
|
+
return outcome.duplicate === true || fromResult;
|
|
126
|
+
}
|
|
127
|
+
function successEnvelope(outcome) {
|
|
128
|
+
const duplicate = isDuplicate(outcome);
|
|
129
|
+
return {
|
|
130
|
+
ok: true,
|
|
131
|
+
...outcome.requestId === void 0 ? {} : { requestId: outcome.requestId },
|
|
132
|
+
...outcome.requestId === void 0 && !duplicate ? {} : { duplicate },
|
|
133
|
+
result: outcome.result
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function failureEnvelope(error) {
|
|
137
|
+
return { ok: false, requestId: error.requestId ?? null, error: error.error };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/mcp/args.lib.ts
|
|
141
|
+
var durationUnits = { ms: 1, s: 1e3, m: 6e4, h: 36e5 };
|
|
142
|
+
function parseDuration(text) {
|
|
143
|
+
const match = DURATION_PATTERN.exec(text);
|
|
144
|
+
if (match === null) return void 0;
|
|
145
|
+
const value = Number(match[1]) * (durationUnits[match[2] ?? "ms"] ?? 1);
|
|
146
|
+
return Number.isSafeInteger(value) ? value : void 0;
|
|
147
|
+
}
|
|
148
|
+
function isRecord(value) {
|
|
149
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
150
|
+
}
|
|
151
|
+
function helpStep(path) {
|
|
152
|
+
return `\u0421\u043F\u0440\u0430\u0432\u043A\u0430: onreel ${[...path, "--help"].join(" ")}`;
|
|
153
|
+
}
|
|
154
|
+
function applyTemplate(template, value) {
|
|
155
|
+
return template === void 0 || typeof value !== "string" ? value : template.replaceAll("{value}", value);
|
|
156
|
+
}
|
|
157
|
+
function valueError(flag, what, path) {
|
|
158
|
+
return usageError(`\u041D\u0435\u0432\u0435\u0440\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 --${flag.name}: ${what}.`, [`\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 --${flag.name}: ${flag.help}`, helpStep(path)], {
|
|
159
|
+
flag: flag.name
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function parseOne(flag, text, cwd, path) {
|
|
163
|
+
const fail = (what) => {
|
|
164
|
+
throw valueError(flag, what, path);
|
|
165
|
+
};
|
|
166
|
+
switch (flag.parse) {
|
|
167
|
+
case "string":
|
|
168
|
+
return text;
|
|
169
|
+
case "boolean":
|
|
170
|
+
return text === "true" || text === "1";
|
|
171
|
+
case "int": {
|
|
172
|
+
const value = /^-?\d+$/.test(text.trim()) ? Number(text) : Number.NaN;
|
|
173
|
+
return Number.isSafeInteger(value) ? value : fail(`\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E \xAB${text}\xBB`);
|
|
174
|
+
}
|
|
175
|
+
case "csv":
|
|
176
|
+
return text.split(",").map((part) => part.trim()).filter((part) => part !== "");
|
|
177
|
+
case "json":
|
|
178
|
+
try {
|
|
179
|
+
return JSON.parse(text);
|
|
180
|
+
} catch {
|
|
181
|
+
return fail("\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F JSON");
|
|
182
|
+
}
|
|
183
|
+
case "duration":
|
|
184
|
+
return parseDuration(text) ?? fail(`\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F \u0434\u043B\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C \u0432\u0438\u0434\u0430 30s, 5m, 1h \u0438\u043B\u0438 \u0447\u0438\u0441\u043B\u043E \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E \xAB${text}\xBB`);
|
|
185
|
+
case "path":
|
|
186
|
+
return text === "" ? fail("\u043F\u0443\u0441\u0442\u043E\u0439 \u043F\u0443\u0442\u044C") : resolve(cwd, text);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function expectedOf(flag) {
|
|
190
|
+
switch (flag.parse) {
|
|
191
|
+
case "int":
|
|
192
|
+
return "\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E";
|
|
193
|
+
case "boolean":
|
|
194
|
+
return "\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F true \u0438\u043B\u0438 false";
|
|
195
|
+
case "csv":
|
|
196
|
+
return "\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F \u043C\u0430\u0441\u0441\u0438\u0432 \u0441\u0442\u0440\u043E\u043A \u0438\u043B\u0438 \u0441\u0442\u0440\u043E\u043A\u0430 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043F\u044F\u0442\u0443\u044E";
|
|
197
|
+
case "duration":
|
|
198
|
+
return "\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F \u0434\u043B\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C \u0441\u0442\u0440\u043E\u043A\u043E\u0439 (30s, 5m, 1h) \u0438\u043B\u0438 \u043D\u0435\u043E\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434";
|
|
199
|
+
case "json":
|
|
200
|
+
return "\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F JSON";
|
|
201
|
+
default:
|
|
202
|
+
return "\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F \u0441\u0442\u0440\u043E\u043A\u0430";
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function typeError(flag, path) {
|
|
206
|
+
throw valueError(flag, expectedOf(flag), path);
|
|
207
|
+
}
|
|
208
|
+
function jsonScalar(flag, value, cwd, path) {
|
|
209
|
+
let parsed;
|
|
210
|
+
if (typeof value === "string" && flag.parse !== "boolean") parsed = parseOne(flag, value, cwd, path);
|
|
211
|
+
else if (flag.parse === "boolean" && value === true) parsed = true;
|
|
212
|
+
else if (flag.parse === "int" && Number.isSafeInteger(value)) parsed = value;
|
|
213
|
+
else if (flag.parse === "duration" && Number.isSafeInteger(value) && value >= 0) parsed = value;
|
|
214
|
+
else if (flag.parse === "json" && typeof value !== "string") parsed = value;
|
|
215
|
+
else if (flag.parse === "csv" && Array.isArray(value)) {
|
|
216
|
+
parsed = value.map((item) => typeof item === "string" ? parseOne(flag, item, cwd, path) : typeError(flag, path)).flat();
|
|
217
|
+
} else return typeError(flag, path);
|
|
218
|
+
return applyTemplate(flag.template, parsed);
|
|
219
|
+
}
|
|
220
|
+
function jsonFlagValue(flag, value, cwd, path) {
|
|
221
|
+
if (value === void 0 || value === null || flag.parse === "boolean" && value === false) return void 0;
|
|
222
|
+
if (flag.multiple !== true || flag.parse === "csv") return () => jsonScalar(flag, value, cwd, path);
|
|
223
|
+
const items = Array.isArray(value) ? value : [value];
|
|
224
|
+
if (items.length === 0) return void 0;
|
|
225
|
+
return () => items.map((item) => jsonScalar(flag, item, cwd, path));
|
|
226
|
+
}
|
|
227
|
+
function targetOf(flag) {
|
|
228
|
+
return flag.field === void 0 ? `flag:${flag.name}` : `field:${flag.field}`;
|
|
229
|
+
}
|
|
230
|
+
function implicitlyFilled(flag, env) {
|
|
231
|
+
const fromEnv = flag.env === void 0 ? void 0 : env[flag.env];
|
|
232
|
+
return fromEnv !== void 0 && fromEnv !== "" || flag.default !== void 0;
|
|
233
|
+
}
|
|
234
|
+
function requiredFlagNames(spec, env) {
|
|
235
|
+
return spec.flags.filter((flag) => {
|
|
236
|
+
if (flag.required !== true) return false;
|
|
237
|
+
const target = targetOf(flag);
|
|
238
|
+
return !spec.flags.some((other) => targetOf(other) === target && (other !== flag || implicitlyFilled(other, env)));
|
|
239
|
+
}).map((flag) => flag.name);
|
|
240
|
+
}
|
|
241
|
+
function resolveFlagValues(spec, explicit, env, cwd) {
|
|
242
|
+
const values = {};
|
|
243
|
+
const writers = /* @__PURE__ */ new Map();
|
|
244
|
+
for (const [flag, parse] of explicit) {
|
|
245
|
+
values[flag.name] = parse();
|
|
246
|
+
const target = targetOf(flag);
|
|
247
|
+
const other = writers.get(target);
|
|
248
|
+
if (other !== void 0) {
|
|
249
|
+
const what = flag.field === void 0 ? "\u043E\u0434\u043D\u043E \u0438 \u0442\u043E \u0436\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435" : `\u043E\u0434\u043D\u043E \u0438 \u0442\u043E \u0436\u0435 \u043F\u043E\u043B\u0435 ${flag.field}`;
|
|
250
|
+
throw usageError(`\u0424\u043B\u0430\u0433\u0438 --${other} \u0438 --${flag.name} \u0437\u0430\u0434\u0430\u044E\u0442 ${what}.`, [`\u041E\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u043E\u0434\u0438\u043D \u0438\u0437 \u0444\u043B\u0430\u0433\u043E\u0432: --${other} \u0438\u043B\u0438 --${flag.name}.`]);
|
|
251
|
+
}
|
|
252
|
+
writers.set(target, flag.name);
|
|
253
|
+
}
|
|
254
|
+
for (const flag of spec.flags) {
|
|
255
|
+
if (values[flag.name] !== void 0 || writers.has(targetOf(flag))) continue;
|
|
256
|
+
const fromEnv = flag.env === void 0 ? void 0 : env[flag.env];
|
|
257
|
+
let value;
|
|
258
|
+
if (fromEnv !== void 0 && fromEnv !== "") value = applyTemplate(flag.envTemplate, parseOne(flag, fromEnv, cwd, spec.path));
|
|
259
|
+
else if (flag.default !== void 0) value = flag.default;
|
|
260
|
+
if (value === void 0) continue;
|
|
261
|
+
values[flag.name] = value;
|
|
262
|
+
writers.set(targetOf(flag), flag.name);
|
|
263
|
+
}
|
|
264
|
+
for (const flag of spec.flags) {
|
|
265
|
+
if (flag.required !== true || writers.has(targetOf(flag))) continue;
|
|
266
|
+
const steps = [`\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 --${flag.name} ${flag.placeholder ?? "<\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435>"}: ${flag.help}`];
|
|
267
|
+
if (flag.env !== void 0) steps.push(`\u0418\u043B\u0438 \u0437\u0430\u0434\u0430\u0439\u0442\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0443\u044E ${flag.env}.`);
|
|
268
|
+
steps.push(helpStep(spec.path));
|
|
269
|
+
throw usageError(`\u041D\u0435 \u0437\u0430\u0434\u0430\u043D \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u0444\u043B\u0430\u0433 --${flag.name} \u043A\u043E\u043C\u0430\u043D\u0434\u044B onreel ${spec.path.join(" ")}.`, steps, { flag: flag.name });
|
|
270
|
+
}
|
|
271
|
+
return values;
|
|
272
|
+
}
|
|
273
|
+
function requestIdError(value) {
|
|
274
|
+
return usageError(`\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 --request-id: ${value}.`, [
|
|
275
|
+
"requestId \u2014 \u0434\u043E 128 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432: \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B \u0438 . _ : -, \u043F\u0435\u0440\u0432\u044B\u0439 \u0441\u0438\u043C\u0432\u043E\u043B \u2014 \u0431\u0443\u043A\u0432\u0430 \u0438\u043B\u0438 \u0446\u0438\u0444\u0440\u0430."
|
|
276
|
+
]);
|
|
277
|
+
}
|
|
278
|
+
function resolveJsonArguments(spec, input, env, cwd) {
|
|
279
|
+
const command = `onreel ${spec.path.join(" ")}`;
|
|
280
|
+
const args = input === void 0 || input === null ? {} : input;
|
|
281
|
+
if (!isRecord(args)) {
|
|
282
|
+
throw usageError(`\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0435 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u044B ${command}: \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F \u043E\u0431\u044A\u0435\u043A\u0442 JSON {"\u0444\u043B\u0430\u0433": \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435}.`, [helpStep(spec.path)]);
|
|
283
|
+
}
|
|
284
|
+
const byName = new Map(spec.flags.map((flag) => [flag.name, flag]));
|
|
285
|
+
let requestId;
|
|
286
|
+
for (const [key, value] of Object.entries(args)) {
|
|
287
|
+
if (key === MCP_REQUEST_ID_ARGUMENT) {
|
|
288
|
+
if (value === void 0 || value === null) continue;
|
|
289
|
+
if (typeof value !== "string" || !requestIdSchema.safeParse(value).success) {
|
|
290
|
+
throw requestIdError(typeof value === "string" ? value : JSON.stringify(value));
|
|
291
|
+
}
|
|
292
|
+
requestId = value;
|
|
293
|
+
} else if (!byName.has(key)) {
|
|
294
|
+
const known = [...byName.keys(), MCP_REQUEST_ID_ARGUMENT].join(", ");
|
|
295
|
+
const steps = key === "data-dir" ? ["\u041A\u0430\u0442\u0430\u043B\u043E\u0433 \u0434\u0430\u043D\u043D\u044B\u0445 host \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044F \u043F\u0440\u0438 \u0437\u0430\u043F\u0443\u0441\u043A\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430: onreel orch mcp --data-dir <\u043A\u0430\u0442\u0430\u043B\u043E\u0433>."] : [`\u0410\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u044B ${command}: ${known}.`, helpStep(spec.path)];
|
|
296
|
+
throw usageError(`\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442 ${key} \u043A\u043E\u043C\u0430\u043D\u0434\u044B ${command}.`, steps, { argument: key });
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const explicit = [];
|
|
300
|
+
for (const flag of spec.flags) {
|
|
301
|
+
const parse = jsonFlagValue(flag, args[flag.name], cwd, spec.path);
|
|
302
|
+
if (parse !== void 0) explicit.push([flag, parse]);
|
|
303
|
+
}
|
|
304
|
+
const values = resolveFlagValues(spec, explicit, env, cwd);
|
|
305
|
+
return requestId === void 0 ? { values } : { values, requestId };
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/mcp/principal.lib.ts
|
|
309
|
+
import { readFileSync } from "fs";
|
|
310
|
+
import { join } from "path";
|
|
311
|
+
var MAX_ANCESTORS = 64;
|
|
312
|
+
var AGENT_ENV_NAMES = [ENV_HOST_URL, ENV_TOKEN, ENV_RUN_ID, ENV_TASK_ID, ENV_DISPATCH_ID];
|
|
313
|
+
function nonEmpty(value) {
|
|
314
|
+
return value === void 0 || value === "" ? void 0 : value;
|
|
315
|
+
}
|
|
316
|
+
function readProc(procRoot, pid, file) {
|
|
317
|
+
try {
|
|
318
|
+
return readFileSync(join(procRoot, String(pid), file), "utf8");
|
|
319
|
+
} catch {
|
|
320
|
+
return void 0;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function hasAgentEnv(environ) {
|
|
324
|
+
const names = /* @__PURE__ */ new Set();
|
|
325
|
+
for (const entry of environ.split("\0")) {
|
|
326
|
+
const separator = entry.indexOf("=");
|
|
327
|
+
if (separator > 0 && separator < entry.length - 1) names.add(entry.slice(0, separator));
|
|
328
|
+
}
|
|
329
|
+
return names.has(ENV_HOST_URL) && names.has(ENV_TOKEN);
|
|
330
|
+
}
|
|
331
|
+
function findAgentAncestor(pid = process.ppid, procRoot = "/proc") {
|
|
332
|
+
const seen = /* @__PURE__ */ new Set();
|
|
333
|
+
let current = pid;
|
|
334
|
+
while (current > 0 && !seen.has(current) && seen.size < MAX_ANCESTORS) {
|
|
335
|
+
seen.add(current);
|
|
336
|
+
const environ = readProc(procRoot, current, "environ");
|
|
337
|
+
if (environ !== void 0 && hasAgentEnv(environ)) return current;
|
|
338
|
+
const parent = /^PPid:\s*(\d+)\s*$/m.exec(readProc(procRoot, current, "status") ?? "")?.[1];
|
|
339
|
+
if (parent === void 0) return void 0;
|
|
340
|
+
current = Number(parent);
|
|
341
|
+
}
|
|
342
|
+
return void 0;
|
|
343
|
+
}
|
|
344
|
+
function isAgentInvocation(globals, env) {
|
|
345
|
+
return globals.dataDir === void 0 && nonEmpty(env[ENV_HOST_URL]) !== void 0 && nonEmpty(env[ENV_TOKEN]) !== void 0;
|
|
346
|
+
}
|
|
347
|
+
function mcpPrincipal(globals, env, agentAncestor, discovery) {
|
|
348
|
+
if (isAgentInvocation(globals, env)) {
|
|
349
|
+
const dispatchId = env[ENV_DISPATCH_ID];
|
|
350
|
+
return dispatchId === void 0 || dispatchId === "" ? { kind: "agent" } : { kind: "agent", dispatchId };
|
|
351
|
+
}
|
|
352
|
+
if (globals.dataDir === void 0 && agentAncestor !== void 0) return { kind: "refused", agentPid: agentAncestor };
|
|
353
|
+
const dataDir = globals.dataDir ?? discovery?.(globals, env);
|
|
354
|
+
return dataDir === void 0 ? { kind: "owner" } : { kind: "owner", dataDir };
|
|
355
|
+
}
|
|
356
|
+
function principalText(principal) {
|
|
357
|
+
switch (principal.kind) {
|
|
358
|
+
case "agent":
|
|
359
|
+
return `\u0421\u0435\u0440\u0432\u0435\u0440 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043E\u0442 \u0430\u0433\u0435\u043D\u0442\u0430 onreel: \u0442\u043E\u043A\u0435\u043D \u0438\u0437 ${ENV_TOKEN}${principal.dispatchId === void 0 ? "" : `, \u043F\u043E\u043F\u044B\u0442\u043A\u0430 ${principal.dispatchId}`}.`;
|
|
360
|
+
case "owner":
|
|
361
|
+
return `\u0421\u0435\u0440\u0432\u0435\u0440 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043E\u0442 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430: \u0442\u043E\u043A\u0435\u043D \u0438\u0437 ${HOST_DISCOVERY_FILE}${principal.dataDir === void 0 ? "" : ` \u0432 ${principal.dataDir}`}.`;
|
|
362
|
+
case "refused":
|
|
363
|
+
return `\u0421\u0435\u0440\u0432\u0435\u0440 \u0437\u0430\u043F\u0443\u0449\u0435\u043D \u0438\u0437 \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0430 \u0430\u0433\u0435\u043D\u0442\u0430 onreel (pid ${String(principal.agentPid)}), \u043D\u043E \u0431\u0435\u0437 ${ENV_HOST_URL} \u0438 ${ENV_TOKEN}: \u043E\u0442 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430 \u043F\u043E ${HOST_DISCOVERY_FILE} \u043E\u043D \u043D\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442, \u043A\u0430\u0436\u0434\u044B\u0439 \u0432\u044B\u0437\u043E\u0432 \u0432\u0435\u0440\u043D\u0451\u0442 unauthorized.`;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function principalRefusal(principal) {
|
|
367
|
+
return new CommandError(
|
|
368
|
+
contractError(
|
|
369
|
+
"unauthorized",
|
|
370
|
+
`onreel orch mcp \u0437\u0430\u043F\u0443\u0449\u0435\u043D \u0438\u0437 \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0430 \u0430\u0433\u0435\u043D\u0442\u0430 onreel (pid ${String(principal.agentPid)}) \u0431\u0435\u0437 ${ENV_HOST_URL} \u0438 ${ENV_TOKEN}: \u043A\u043B\u0438\u0435\u043D\u0442 MCP \u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u043B \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0430\u0433\u0435\u043D\u0442\u0430, \u0430 \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C \u043E\u0442 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430 \u043F\u043E ${HOST_DISCOVERY_FILE} \u0432\u043D\u0443\u0442\u0440\u0438 \u0430\u0433\u0435\u043D\u0442\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043E\u0442\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F.`,
|
|
371
|
+
[
|
|
372
|
+
`\u041F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 ${AGENT_ENV_NAMES.join(", ")} \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 MCP (Codex \u2014 env_vars, Claude Code \u2014 env, opencode \u2014 environment).`,
|
|
373
|
+
"\u0414\u043E \u0442\u0435\u0445 \u043F\u043E\u0440 \u0432\u044B\u0437\u044B\u0432\u0430\u0439\u0442\u0435 \u0442\u0435 \u0436\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u044B \u0432 \u043E\u0431\u043E\u043B\u043E\u0447\u043A\u0435: onreel orch \u2026 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0430\u0433\u0435\u043D\u0442\u0430."
|
|
374
|
+
],
|
|
375
|
+
{ agentPid: principal.agentPid }
|
|
376
|
+
),
|
|
377
|
+
"local"
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// src/mcp/tools.lib.ts
|
|
382
|
+
import { z as z2 } from "zod";
|
|
383
|
+
var requestIdPattern;
|
|
384
|
+
function requestIdPatternOf() {
|
|
385
|
+
requestIdPattern ??= { value: z2.toJSONSchema(requestIdSchema).pattern };
|
|
386
|
+
return requestIdPattern.value;
|
|
387
|
+
}
|
|
388
|
+
function toolName(spec) {
|
|
389
|
+
return spec.path.join("_");
|
|
390
|
+
}
|
|
391
|
+
function mcpToolSpecs(specs) {
|
|
392
|
+
return specs.filter((spec) => spec.handler !== "mcp");
|
|
393
|
+
}
|
|
394
|
+
function typeOf(flag) {
|
|
395
|
+
switch (flag.parse) {
|
|
396
|
+
case "int":
|
|
397
|
+
return { type: "integer" };
|
|
398
|
+
case "boolean":
|
|
399
|
+
return { type: "boolean" };
|
|
400
|
+
case "csv":
|
|
401
|
+
return { type: "array", items: { type: "string" } };
|
|
402
|
+
case "json":
|
|
403
|
+
return { type: "object" };
|
|
404
|
+
case "duration":
|
|
405
|
+
return { type: "string", pattern: DURATION_PATTERN.source };
|
|
406
|
+
default:
|
|
407
|
+
return flag.multiple === true ? { type: "array", items: { type: "string" } } : { type: "string" };
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function descriptionOf(flag) {
|
|
411
|
+
const notes = [];
|
|
412
|
+
if (flag.env !== void 0 && !flag.help.includes(flag.env)) notes.push(`\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0438\u0437 ${flag.env}`);
|
|
413
|
+
if (flag.default !== void 0) notes.push(`\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E ${JSON.stringify(flag.default)}`);
|
|
414
|
+
if (flag.parse === "duration") notes.push("\u0434\u043B\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C: 30s, 5m, 1h \u0438\u043B\u0438 \u0447\u0438\u0441\u043B\u043E \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434");
|
|
415
|
+
if (flag.parse === "path") notes.push("\u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u043F\u0443\u0442\u044C \u2014 \u043E\u0442 \u0440\u0430\u0431\u043E\u0447\u0435\u0433\u043E \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430");
|
|
416
|
+
return notes.length === 0 ? flag.help : `${flag.help} (${notes.join("; ")})`;
|
|
417
|
+
}
|
|
418
|
+
function inputSchemaOf(spec, env) {
|
|
419
|
+
const properties = {};
|
|
420
|
+
for (const flag of spec.flags) {
|
|
421
|
+
properties[flag.name] = {
|
|
422
|
+
...typeOf(flag),
|
|
423
|
+
description: descriptionOf(flag),
|
|
424
|
+
...flag.default === void 0 ? {} : { default: flag.default }
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
const pattern = requestIdPatternOf();
|
|
428
|
+
properties[MCP_REQUEST_ID_ARGUMENT] = {
|
|
429
|
+
type: "string",
|
|
430
|
+
...pattern === void 0 ? {} : { pattern },
|
|
431
|
+
description: "requestId \u0437\u0430\u043F\u0440\u043E\u0441\u0430 (\u0444\u043B\u0430\u0433 --request-id): \u043F\u043E\u0432\u0442\u043E\u0440 \u0441 \u0442\u0435\u043C \u0436\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C \u0432\u0435\u0440\u043D\u0451\u0442 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u043F\u0435\u0440\u0432\u043E\u0433\u043E \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F"
|
|
432
|
+
};
|
|
433
|
+
return { type: "object", properties, required: requiredFlagNames(spec, env), additionalProperties: false };
|
|
434
|
+
}
|
|
435
|
+
function toolOf(spec, env) {
|
|
436
|
+
const command = spec.path.join(" ");
|
|
437
|
+
const summary = spec.summary.replace(/\.$/, "");
|
|
438
|
+
const description = `${summary}. \u0422\u043E \u0436\u0435, \u0447\u0442\u043E onreel ${command}.` + (spec.rule === void 0 ? "" : ` \u041F\u0440\u0430\u0432\u0438\u043B\u043E: ${spec.rule}`) + (spec.verb === void 0 ? "" : ` \u0413\u043B\u0430\u0433\u043E\u043B \u043A\u043E\u043D\u0442\u0440\u0430\u043A\u0442\u0430: ${spec.verb}.`);
|
|
439
|
+
return {
|
|
440
|
+
name: toolName(spec),
|
|
441
|
+
title: `onreel ${command}`,
|
|
442
|
+
description,
|
|
443
|
+
inputSchema: inputSchemaOf(spec, env),
|
|
444
|
+
annotations: { readOnlyHint: spec.verb === void 0 ? true : spec.mutation !== true, openWorldHint: false }
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function toolResult(output, structured) {
|
|
448
|
+
return {
|
|
449
|
+
content: [{ type: "text", text: JSON.stringify(output) }],
|
|
450
|
+
...structured ? { structuredContent: output } : {},
|
|
451
|
+
...output.ok ? {} : { isError: true }
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// src/mcp/server.lib.ts
|
|
456
|
+
var RpcError = class extends Error {
|
|
457
|
+
code;
|
|
458
|
+
constructor(code, message) {
|
|
459
|
+
super(message);
|
|
460
|
+
this.name = "RpcError";
|
|
461
|
+
this.code = code;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
function keyOf(id) {
|
|
465
|
+
return `${typeof id}:${String(id)}`;
|
|
466
|
+
}
|
|
467
|
+
function readableId(message) {
|
|
468
|
+
if (typeof message !== "object" || message === null) return null;
|
|
469
|
+
const id = message.id;
|
|
470
|
+
return typeof id === "string" || typeof id === "number" && Number.isInteger(id) ? id : null;
|
|
471
|
+
}
|
|
472
|
+
function readLines(input, maxBytes, onLine, onOverflow, onEnd) {
|
|
473
|
+
let chunks = [];
|
|
474
|
+
let size = 0;
|
|
475
|
+
let skipping = false;
|
|
476
|
+
let closed = false;
|
|
477
|
+
const emit = (tail) => {
|
|
478
|
+
const line = Buffer.concat([...chunks, tail]).toString("utf8");
|
|
479
|
+
chunks = [];
|
|
480
|
+
size = 0;
|
|
481
|
+
onLine(line.endsWith("\r") ? line.slice(0, -1) : line);
|
|
482
|
+
};
|
|
483
|
+
const onData = (data) => {
|
|
484
|
+
let chunk = typeof data === "string" ? Buffer.from(data, "utf8") : data;
|
|
485
|
+
while (!closed) {
|
|
486
|
+
const newline = chunk.indexOf(10);
|
|
487
|
+
const piece = newline === -1 ? chunk : chunk.subarray(0, newline);
|
|
488
|
+
if (!skipping) {
|
|
489
|
+
if (size + piece.length > maxBytes) {
|
|
490
|
+
chunks = [];
|
|
491
|
+
size = 0;
|
|
492
|
+
skipping = true;
|
|
493
|
+
onOverflow();
|
|
494
|
+
} else if (newline === -1) {
|
|
495
|
+
chunks.push(piece);
|
|
496
|
+
size += piece.length;
|
|
497
|
+
} else {
|
|
498
|
+
emit(piece);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (newline === -1) return;
|
|
502
|
+
skipping = false;
|
|
503
|
+
chunk = chunk.subarray(newline + 1);
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
const finish = (reason) => {
|
|
507
|
+
if (closed) return;
|
|
508
|
+
closed = true;
|
|
509
|
+
input.off("data", onData);
|
|
510
|
+
input.off("end", onInputEnd);
|
|
511
|
+
input.off("close", onInputEnd);
|
|
512
|
+
input.pause();
|
|
513
|
+
onEnd(reason);
|
|
514
|
+
};
|
|
515
|
+
const onInputEnd = () => {
|
|
516
|
+
if (closed) return;
|
|
517
|
+
if (!skipping && size > 0) emit(Buffer.alloc(0));
|
|
518
|
+
finish("eof");
|
|
519
|
+
};
|
|
520
|
+
input.on("error", () => {
|
|
521
|
+
});
|
|
522
|
+
input.on("data", onData);
|
|
523
|
+
input.once("end", onInputEnd);
|
|
524
|
+
input.once("close", onInputEnd);
|
|
525
|
+
return () => {
|
|
526
|
+
finish("stop");
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
function negotiate(requested) {
|
|
530
|
+
return MCP_PROTOCOL_VERSIONS.includes(requested) ? requested : MCP_PROTOCOL_VERSIONS[0];
|
|
531
|
+
}
|
|
532
|
+
function serveMcp(options) {
|
|
533
|
+
const { execute, io } = options;
|
|
534
|
+
const specs = mcpToolSpecs(options.specs);
|
|
535
|
+
const byName = new Map(specs.map((spec) => [toolName(spec), spec]));
|
|
536
|
+
const progressIntervalMs = options.progressIntervalMs ?? MCP_PROGRESS_INTERVAL_MS;
|
|
537
|
+
const principal = options.principal ?? mcpPrincipal(options.globals, io.env, void 0, options.discovery);
|
|
538
|
+
const instructions = `${MCP_INSTRUCTIONS} ${principalText(principal)} \u0420\u0430\u0431\u043E\u0447\u0438\u0439 \u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u0441\u0435\u0440\u0432\u0435\u0440\u0430: ${io.cwd}; \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u0443\u0442\u0438 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u2014 \u043E\u0442 \u043D\u0435\u0433\u043E.`;
|
|
539
|
+
let protocolVersion = MCP_PROTOCOL_VERSIONS[0];
|
|
540
|
+
const calls = /* @__PURE__ */ new Map();
|
|
541
|
+
const running = /* @__PURE__ */ new Set();
|
|
542
|
+
const send = (message) => {
|
|
543
|
+
io.stdout(`${JSON.stringify({ jsonrpc: "2.0", ...message })}
|
|
544
|
+
`);
|
|
545
|
+
};
|
|
546
|
+
const sendError = (id, code, message) => {
|
|
547
|
+
send({ id, error: { code, message } });
|
|
548
|
+
};
|
|
549
|
+
const callTool = async (id, spec, params) => {
|
|
550
|
+
const controller = new AbortController();
|
|
551
|
+
const key = keyOf(id);
|
|
552
|
+
calls.set(key, controller);
|
|
553
|
+
const signal = io.signal === void 0 ? controller.signal : AbortSignal.any([io.signal, controller.signal]);
|
|
554
|
+
const progressToken = params._meta?.progressToken;
|
|
555
|
+
let progress = 0;
|
|
556
|
+
const timer = progressToken === void 0 ? void 0 : setInterval(() => {
|
|
557
|
+
progress += 1;
|
|
558
|
+
send({ method: "notifications/progress", params: { progressToken, progress, message: "\u041E\u0436\u0438\u0434\u0430\u043D\u0438\u0435\u2026" } });
|
|
559
|
+
}, progressIntervalMs);
|
|
560
|
+
timer?.unref();
|
|
561
|
+
signal.addEventListener("abort", () => clearInterval(timer), { once: true });
|
|
562
|
+
let output;
|
|
563
|
+
try {
|
|
564
|
+
if (principal.kind === "refused") throw principalRefusal(principal);
|
|
565
|
+
const { values, requestId } = resolveJsonArguments(spec, params.arguments, io.env, io.cwd);
|
|
566
|
+
const globals = {
|
|
567
|
+
json: true,
|
|
568
|
+
help: false,
|
|
569
|
+
...options.globals.dataDir === void 0 ? {} : { dataDir: options.globals.dataDir },
|
|
570
|
+
...requestId === void 0 ? {} : { requestId }
|
|
571
|
+
};
|
|
572
|
+
const callIo = { ...io, stdout: () => {
|
|
573
|
+
}, signal };
|
|
574
|
+
output = successEnvelope(await execute(spec, values, globals, callIo));
|
|
575
|
+
} catch (cause) {
|
|
576
|
+
output = failureEnvelope(signal.aborted ? interruptedError(cause) : internalError(cause));
|
|
577
|
+
} finally {
|
|
578
|
+
clearInterval(timer);
|
|
579
|
+
if (calls.get(key) === controller) calls.delete(key);
|
|
580
|
+
}
|
|
581
|
+
if (signal.aborted) return;
|
|
582
|
+
send({ id, result: toolResult(output, protocolVersion >= MCP_STRUCTURED_SINCE) });
|
|
583
|
+
};
|
|
584
|
+
const handleRequest = (id, method, params) => {
|
|
585
|
+
switch (method) {
|
|
586
|
+
case "initialize": {
|
|
587
|
+
const parsed = initializeParamsSchema.safeParse(params);
|
|
588
|
+
if (!parsed.success) throw new RpcError(JSONRPC_INVALID_PARAMS, "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B initialize: \u043D\u0443\u0436\u0435\u043D protocolVersion.");
|
|
589
|
+
protocolVersion = negotiate(parsed.data.protocolVersion);
|
|
590
|
+
send({
|
|
591
|
+
id,
|
|
592
|
+
result: {
|
|
593
|
+
protocolVersion,
|
|
594
|
+
capabilities: { tools: { listChanged: false } },
|
|
595
|
+
serverInfo: { name: MCP_SERVER_NAME, title: MCP_SERVER_TITLE, version: formatVersion(HOST_CONTRACT_VERSION) },
|
|
596
|
+
instructions
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
case "ping":
|
|
602
|
+
send({ id, result: {} });
|
|
603
|
+
return;
|
|
604
|
+
case "tools/list":
|
|
605
|
+
send({ id, result: { tools: specs.map((spec) => toolOf(spec, io.env)) } });
|
|
606
|
+
return;
|
|
607
|
+
case "tools/call": {
|
|
608
|
+
const parsed = toolsCallParamsSchema.safeParse(params);
|
|
609
|
+
if (!parsed.success) throw new RpcError(JSONRPC_INVALID_PARAMS, "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B tools/call: \u043D\u0443\u0436\u043D\u043E \u0438\u043C\u044F \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 name.");
|
|
610
|
+
const spec = byName.get(parsed.data.name);
|
|
611
|
+
if (spec === void 0) throw new RpcError(JSONRPC_INVALID_PARAMS, `\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442 ${parsed.data.name}.`);
|
|
612
|
+
const call = callTool(id, spec, parsed.data).catch((cause) => {
|
|
613
|
+
reportInternal(id, cause);
|
|
614
|
+
});
|
|
615
|
+
running.add(call);
|
|
616
|
+
void call.finally(() => running.delete(call));
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
default:
|
|
620
|
+
throw new RpcError(JSONRPC_METHOD_NOT_FOUND, `\u041C\u0435\u0442\u043E\u0434 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F: ${method}.`);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
const handleNotification = (method, params) => {
|
|
624
|
+
if (method !== "notifications/cancelled") return;
|
|
625
|
+
const parsed = cancelledParamsSchema.safeParse(params);
|
|
626
|
+
if (parsed.success) calls.get(keyOf(parsed.data.requestId))?.abort();
|
|
627
|
+
};
|
|
628
|
+
const reportInternal = (id, cause) => {
|
|
629
|
+
const detail = redactSecretText(cause instanceof Error ? cause.message : String(cause));
|
|
630
|
+
io.stderr(`onreel orch mcp: \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044F\u044F \u043E\u0448\u0438\u0431\u043A\u0430: ${detail}
|
|
631
|
+
`);
|
|
632
|
+
sendError(id, JSONRPC_INTERNAL_ERROR, `\u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044F\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 MCP onreel: ${detail}`);
|
|
633
|
+
};
|
|
634
|
+
const handleLine = (line) => {
|
|
635
|
+
if (line.trim() === "") return;
|
|
636
|
+
let message;
|
|
637
|
+
try {
|
|
638
|
+
message = JSON.parse(line);
|
|
639
|
+
} catch {
|
|
640
|
+
sendError(null, JSONRPC_PARSE_ERROR, "\u0421\u0442\u0440\u043E\u043A\u0430 \u043D\u0435 JSON: \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 JSON-RPC \u2014 \u043E\u0434\u0438\u043D \u043E\u0431\u044A\u0435\u043A\u0442 JSON \u0432 \u0441\u0442\u0440\u043E\u043A\u0435.");
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
if (Array.isArray(message)) {
|
|
644
|
+
sendError(null, JSONRPC_INVALID_REQUEST, "\u041F\u0430\u043A\u0435\u0442\u044B JSON-RPC \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044E\u0442\u0441\u044F: \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u044F\u0439\u0442\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043F\u043E \u043E\u0434\u043D\u043E\u043C\u0443.");
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
const parsed = jsonRpcMessageSchema.safeParse(message);
|
|
648
|
+
if (!parsed.success) {
|
|
649
|
+
sendError(readableId(message), JSONRPC_INVALID_REQUEST, "\u041D\u0435\u0432\u0435\u0440\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 JSON-RPC 2.0.");
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
const { id, method, params } = parsed.data;
|
|
653
|
+
if (method === void 0) {
|
|
654
|
+
const reply = message;
|
|
655
|
+
if (!("result" in reply) && !("error" in reply)) {
|
|
656
|
+
sendError(id ?? null, JSONRPC_INVALID_REQUEST, "\u041D\u0435\u0432\u0435\u0440\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 JSON-RPC 2.0: \u043D\u0435\u0442 \u043D\u0438 method, \u043D\u0438 result, \u043D\u0438 error.");
|
|
657
|
+
}
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
if (id === void 0) {
|
|
661
|
+
handleNotification(method, params);
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
if (id === null) {
|
|
665
|
+
sendError(null, JSONRPC_INVALID_REQUEST, "id \u0437\u0430\u043F\u0440\u043E\u0441\u0430 JSON-RPC \u2014 \u0441\u0442\u0440\u043E\u043A\u0430 \u0438\u043B\u0438 \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E.");
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
try {
|
|
669
|
+
handleRequest(id, method, params);
|
|
670
|
+
} catch (cause) {
|
|
671
|
+
if (cause instanceof RpcError) sendError(id, cause.code, cause.message);
|
|
672
|
+
else reportInternal(id, cause);
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
const maxLineBytes = options.maxLineBytes ?? MCP_MAX_LINE_BYTES;
|
|
676
|
+
const eofGraceMs = options.eofGraceMs ?? MCP_EOF_GRACE_MS;
|
|
677
|
+
const overflow = () => {
|
|
678
|
+
sendError(null, JSONRPC_INVALID_REQUEST, `\u0421\u0442\u0440\u043E\u043A\u0430 \u0434\u043B\u0438\u043D\u043D\u0435\u0435 ${String(maxLineBytes)} \u0431\u0430\u0439\u0442: \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043E\u0442\u0431\u0440\u043E\u0448\u0435\u043D\u043E.`);
|
|
679
|
+
};
|
|
680
|
+
return new Promise((resolve2) => {
|
|
681
|
+
let stop = () => {
|
|
682
|
+
};
|
|
683
|
+
const onEnd = (reason) => {
|
|
684
|
+
io.signal?.removeEventListener("abort", stop);
|
|
685
|
+
const abortAll = () => {
|
|
686
|
+
for (const controller of calls.values()) controller.abort();
|
|
687
|
+
};
|
|
688
|
+
const grace = reason === "eof" && running.size > 0 ? setTimeout(abortAll, eofGraceMs) : void 0;
|
|
689
|
+
void Promise.allSettled(running).then(() => {
|
|
690
|
+
clearTimeout(grace);
|
|
691
|
+
resolve2();
|
|
692
|
+
});
|
|
693
|
+
};
|
|
694
|
+
stop = readLines(options.input, maxLineBytes, handleLine, overflow, onEnd);
|
|
695
|
+
io.signal?.addEventListener("abort", stop, { once: true });
|
|
696
|
+
if (io.signal?.aborted === true) stop();
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
export {
|
|
700
|
+
CommandError,
|
|
701
|
+
DURATION_PATTERN,
|
|
702
|
+
JSONRPC_INTERNAL_ERROR,
|
|
703
|
+
JSONRPC_INVALID_PARAMS,
|
|
704
|
+
JSONRPC_INVALID_REQUEST,
|
|
705
|
+
JSONRPC_METHOD_NOT_FOUND,
|
|
706
|
+
JSONRPC_PARSE_ERROR,
|
|
707
|
+
MCP_EOF_GRACE_MS,
|
|
708
|
+
MCP_INSTRUCTIONS,
|
|
709
|
+
MCP_MAX_LINE_BYTES,
|
|
710
|
+
MCP_PROGRESS_INTERVAL_MS,
|
|
711
|
+
MCP_PROTOCOL_VERSIONS,
|
|
712
|
+
MCP_REQUEST_ID_ARGUMENT,
|
|
713
|
+
MCP_SERVER_NAME,
|
|
714
|
+
MCP_SERVER_TITLE,
|
|
715
|
+
MCP_STRUCTURED_SINCE,
|
|
716
|
+
cancelledParamsSchema,
|
|
717
|
+
cliFailureSchema,
|
|
718
|
+
cliOutputSchema,
|
|
719
|
+
cliSuccessSchema,
|
|
720
|
+
failureEnvelope,
|
|
721
|
+
findAgentAncestor,
|
|
722
|
+
initializeParamsSchema,
|
|
723
|
+
inputSchemaOf,
|
|
724
|
+
internalError,
|
|
725
|
+
interruptedError,
|
|
726
|
+
isAgentInvocation,
|
|
727
|
+
jsonRpcIdSchema,
|
|
728
|
+
jsonRpcMessageSchema,
|
|
729
|
+
mcpPrincipal,
|
|
730
|
+
mcpToolSpecs,
|
|
731
|
+
parseDuration,
|
|
732
|
+
principalRefusal,
|
|
733
|
+
principalText,
|
|
734
|
+
requiredFlagNames,
|
|
735
|
+
resolveJsonArguments,
|
|
736
|
+
serveMcp,
|
|
737
|
+
successEnvelope,
|
|
738
|
+
toolName,
|
|
739
|
+
toolOf,
|
|
740
|
+
toolResult,
|
|
741
|
+
toolsCallParamsSchema,
|
|
742
|
+
usageError
|
|
743
|
+
};
|
|
744
|
+
//# sourceMappingURL=index.js.map
|