@krapht/ork 1.0.0-alpha.3 → 1.0.0-alpha.5
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/dist/{__build_info__-BwrKe6yz.mjs → __build_info__-Dl8yTEu-.mjs} +2 -2
- package/dist/bin.mjs +63 -225
- package/dist/{clean-hXSaN8BT.mjs → clean-DYVmLkd4.mjs} +1 -1
- package/dist/{completion-Cga01yQP.mjs → completion-BVx917Yr.mjs} +5 -5
- package/dist/{context-mCAwzFFM.mjs → context-CepHRoj9.mjs} +3 -3
- package/dist/{decide-BvZnKErW.mjs → decide-CK_-lI5V.mjs} +3 -3
- package/dist/{find-CbetS8I2.mjs → find-DWiDJ5Lc.mjs} +1 -1
- package/dist/{format-D87bY6Ud.mjs → format-yBEAXZhk.mjs} +223 -17
- package/dist/{in-a-run-Bs4Wv-Cz.mjs → in-a-run-CKFIeMpU.mjs} +1 -1
- package/dist/{limits-RzKQ_zPk.mjs → limits-CwzPe9wZ.mjs} +1 -1
- package/dist/{list-DX65Sbu7.mjs → list-BE02pCZ9.mjs} +1 -1
- package/dist/{mcp-DKrrxowo.mjs → mcp-DMuBbUHU.mjs} +6 -6
- package/dist/{output-Q3TZ-Ave.mjs → output-BhYkshYq.mjs} +9 -6
- package/dist/{pause-B5Z41lR3.mjs → pause-C_Q0W6iX.mjs} +4 -4
- package/dist/{relay-BLnjMdjT.mjs → relay-COCvG-0I.mjs} +2 -2
- package/dist/{remove-IbcZOemm.mjs → remove-RVcX1KqP.mjs} +3 -3
- package/dist/{send-CJKEhBL1.mjs → send-OVpRei_5.mjs} +3 -3
- package/dist/{src-LSxjnWDH.mjs → src-CxZr4Bp2.mjs} +16 -8
- package/dist/{src-DnETlJ1r.mjs → src-Do_MhwiV.mjs} +186 -30
- package/dist/{src-XDSRnAZV.mjs → src-HxtJOMRr.mjs} +172 -167
- package/dist/{src-BTDzibW3.mjs → src-QEycKJWk.mjs} +26 -12
- package/dist/ui/THIRD_PARTY_LICENSES.txt +594 -0
- package/dist/ui/assets/app-DzI77WV9.js +75 -0
- package/dist/ui/assets/app-pTYGrAbI.css +1 -0
- package/dist/ui/assets/{index-BkI68sr5.js → index-2G_6XIIv.js} +3 -3
- package/dist/ui/assets/theme-CdXvqTQ6.js +1 -0
- package/dist/ui/index.html +2 -2
- package/dist/{ui-fvrO7Gxd.mjs → ui-Dz_qfUOz.mjs} +4 -4
- package/dist/{usage-bNdcBcj9.mjs → usage-BcLUZ1xw.mjs} +5 -5
- package/dist/{watch-EhlO304A.mjs → watch-Buyn0Mhz.mjs} +6 -6
- package/dist/{workflows-C5hYAVcE.mjs → workflows-1sntXqSd.mjs} +3 -3
- package/dist/{worktrees-BQFcpYz1.mjs → worktrees-B_Go_A9w.mjs} +4 -4
- package/package.json +1 -1
- package/dist/ui/assets/app-BNElhp7Z.js +0 -67
- package/dist/ui/assets/app-BNT0SuIz.css +0 -1
- package/dist/ui/assets/theme-3xH5jxKs.js +0 -1
|
@@ -459,6 +459,7 @@ const PracticesSchema = z.strictObject({
|
|
|
459
459
|
])]).optional().describe("Smallest complete change. `true` is `full`. Default: `full`.")
|
|
460
460
|
});
|
|
461
461
|
const TurnsSchema = z.number().int().positive();
|
|
462
|
+
const McpNamesSchema = z.array(z.string().min(1)).optional().describe("MCP servers from the project's `.mcp.json` this node's sessions load, beside Ork's own. Default: none.");
|
|
462
463
|
const ToolRulesSchema = z.strictObject({
|
|
463
464
|
allow: z.array(z.string()).optional(),
|
|
464
465
|
deny: z.array(z.string()).optional(),
|
|
@@ -612,6 +613,7 @@ const claudeFields = {
|
|
|
612
613
|
const ClaudeLeaderNodeSchema = z.strictObject({
|
|
613
614
|
type: z.literal("claude.leader"),
|
|
614
615
|
...claudeFields,
|
|
616
|
+
mcp: McpNamesSchema,
|
|
615
617
|
...notifyFields,
|
|
616
618
|
...stepFields,
|
|
617
619
|
maxWorkers: z.number().int().nonnegative().optional().describe("Cap on dynamically spawned workers."),
|
|
@@ -620,6 +622,7 @@ const ClaudeLeaderNodeSchema = z.strictObject({
|
|
|
620
622
|
const ClaudeWorkerNodeSchema = z.strictObject({
|
|
621
623
|
type: z.literal("claude.worker"),
|
|
622
624
|
...claudeFields,
|
|
625
|
+
mcp: McpNamesSchema,
|
|
623
626
|
...notifyFields,
|
|
624
627
|
...stepFields
|
|
625
628
|
});
|
|
@@ -658,6 +661,7 @@ const HumanGateNodeSchema = z.strictObject({
|
|
|
658
661
|
...base,
|
|
659
662
|
...notifyFields,
|
|
660
663
|
question: z.string(),
|
|
664
|
+
document: z.string().optional(),
|
|
661
665
|
options: z.array(DecisionOptionSchema).min(2),
|
|
662
666
|
recommended: z.string().optional(),
|
|
663
667
|
timeout: DurationSchema.optional(),
|
|
@@ -922,6 +926,7 @@ const DefaultsSchema = z.strictObject({
|
|
|
922
926
|
maxTurns: TurnsSchema.optional(),
|
|
923
927
|
timeout: TimeoutSchema.optional().describe("For tool and Claude nodes that set none; a gate's own timeout is separate."),
|
|
924
928
|
practices: PracticesSchema.optional(),
|
|
929
|
+
mcp: McpNamesSchema,
|
|
925
930
|
before: stepFields.before
|
|
926
931
|
});
|
|
927
932
|
/** What the placeholders in a git template may name. */
|
|
@@ -1283,7 +1288,7 @@ const renderJsonSchema = () => {
|
|
|
1283
1288
|
* model the serializer follows, so that a document edit puts a new key where
|
|
1284
1289
|
* the serializer would and a canonical file stays canonical (RFC-008).
|
|
1285
1290
|
*/
|
|
1286
|
-
const isRecord$
|
|
1291
|
+
const isRecord$3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1287
1292
|
const unwrapped = (schema) => {
|
|
1288
1293
|
let current = schema;
|
|
1289
1294
|
while (current instanceof z.ZodOptional || current instanceof z.ZodNullable || current instanceof z.ZodDefault) current = current.unwrap();
|
|
@@ -1304,8 +1309,8 @@ const declaresType = (object, type) => {
|
|
|
1304
1309
|
/** The object `value` is, among those `schema` allows. */
|
|
1305
1310
|
const objectFor = (schema, value) => {
|
|
1306
1311
|
const objects = objectsIn(schema);
|
|
1307
|
-
const keys = isRecord$
|
|
1308
|
-
const type = isRecord$
|
|
1312
|
+
const keys = isRecord$3(value) ? Object.keys(value) : [];
|
|
1313
|
+
const type = isRecord$3(value) ? value["type"] : void 0;
|
|
1309
1314
|
return objects.find((object) => declaresType(object, type)) ?? objects.find((object) => keys.every((key) => key in object.shape)) ?? objects[0];
|
|
1310
1315
|
};
|
|
1311
1316
|
/** The keys `schema` declares for `value`, in canonical order. */
|
|
@@ -1321,14 +1326,14 @@ const childOf = (schema, key, value) => {
|
|
|
1321
1326
|
/** `value` with every object's keys in canonical order and no undefined. */
|
|
1322
1327
|
const inCanonicalOrder = (value, schema) => {
|
|
1323
1328
|
if (Array.isArray(value)) return value.map((item, index) => inCanonicalOrder(item, childOf(schema, index, value)));
|
|
1324
|
-
if (!isRecord$
|
|
1329
|
+
if (!isRecord$3(value)) return value;
|
|
1325
1330
|
const order = keysOf(schema, value);
|
|
1326
1331
|
return Object.fromEntries([...order.filter((known) => known in value), ...Object.keys(value).filter((other) => !order.includes(other))].filter((key) => value[key] !== void 0).map((key) => [key, inCanonicalOrder(value[key], childOf(schema, key, value))]));
|
|
1327
1332
|
};
|
|
1328
1333
|
/** Two plain values alike, whatever the order of their keys. */
|
|
1329
1334
|
const sameValue$1 = (a, b) => {
|
|
1330
1335
|
if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((x, i) => sameValue$1(x, b[i]));
|
|
1331
|
-
if (isRecord$
|
|
1336
|
+
if (isRecord$3(a) && isRecord$3(b)) {
|
|
1332
1337
|
const left = Object.entries(a);
|
|
1333
1338
|
return left.length === Object.keys(b).length && left.every(([key, value]) => sameValue$1(value, b[key]));
|
|
1334
1339
|
}
|
|
@@ -1495,7 +1500,7 @@ const entryOf = (doc, raw) => {
|
|
|
1495
1500
|
}
|
|
1496
1501
|
if (!isMap(item)) return void 0;
|
|
1497
1502
|
const value = item.toJS(doc);
|
|
1498
|
-
if (!isRecord$
|
|
1503
|
+
if (!isRecord$3(value)) return void 0;
|
|
1499
1504
|
const { from, to, when, maxRounds, ...rest } = value;
|
|
1500
1505
|
const whenIsText = typeof when === "string";
|
|
1501
1506
|
const roundsIsNumber = typeof maxRounds === "number";
|
|
@@ -1713,7 +1718,7 @@ const withOptions = (doc, item, next) => {
|
|
|
1713
1718
|
const custom = Object.keys(next.extra).length > 0;
|
|
1714
1719
|
if (!isMap(item) || !hasOptions && !custom && !hasComment(item)) return authored(next);
|
|
1715
1720
|
const value = item.toJS(doc);
|
|
1716
|
-
const { when: _when, maxRounds: _rounds, ...rest } = isRecord$
|
|
1721
|
+
const { when: _when, maxRounds: _rounds, ...rest } = isRecord$3(value) ? value : {};
|
|
1717
1722
|
return {
|
|
1718
1723
|
...rest,
|
|
1719
1724
|
...next.when === void 0 ? {} : { when: next.when },
|
|
@@ -3597,6 +3602,26 @@ const writePlugin = (stack, dir, description) => {
|
|
|
3597
3602
|
}
|
|
3598
3603
|
return dir;
|
|
3599
3604
|
};
|
|
3605
|
+
// ../core/src/store/mask.ts
|
|
3606
|
+
/**
|
|
3607
|
+
* @file Masks secrets before anything is stored: tokens and keys in common
|
|
3608
|
+
* formats, anywhere in an event's strings. The store and feedback records use
|
|
3609
|
+
* the same patterns; the terminal is not masked (it is the user's own).
|
|
3610
|
+
*/
|
|
3611
|
+
const PATTERNS = [
|
|
3612
|
+
/sk-ant-[\w-]{20,}/gu,
|
|
3613
|
+
/\bgh[opsur]_[A-Za-z0-9]{20,}/gu,
|
|
3614
|
+
/\bgithub_pat_\w{20,}/gu,
|
|
3615
|
+
/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/gu,
|
|
3616
|
+
/\bxox[abprs]-[\w-]{10,}/gu,
|
|
3617
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/gu,
|
|
3618
|
+
/(?<=\bbearer\s+)[\w.~+/-]{20,}=*/giu,
|
|
3619
|
+
/(?<=aws_secret_access_key\s*[=:]\s*)\S+/giu
|
|
3620
|
+
];
|
|
3621
|
+
const MASK = "[masked]";
|
|
3622
|
+
const maskSecrets = (text) => PATTERNS.reduce((out, pattern) => out.replaceAll(pattern, MASK), text);
|
|
3623
|
+
/** A `JSON.stringify` replacer that masks every string. */
|
|
3624
|
+
const maskReplacer = (_key, value) => typeof value === "string" ? maskSecrets(value) : value;
|
|
3600
3625
|
// ../core/src/control/socket.ts
|
|
3601
3626
|
/**
|
|
3602
3627
|
* @file The per-run local socket (`~/.ork/sockets/<run>.sock`): the fast path
|
|
@@ -4219,27 +4244,39 @@ const stringify$1 = (value) => {
|
|
|
4219
4244
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
4220
4245
|
return JSON.stringify(value);
|
|
4221
4246
|
};
|
|
4222
|
-
const
|
|
4223
|
-
|
|
4247
|
+
const isContainer = (value) => value !== null && typeof value === "object";
|
|
4248
|
+
const depthOf = (value) => isContainer(value) ? 1 + Math.max(0, ...Object.values(value).map((item) => depthOf(item))) : 0;
|
|
4249
|
+
/** Keeps a multi-line value inside its list item or `key:` line. */
|
|
4250
|
+
const hang = (text) => text.replaceAll("\n", "\n ");
|
|
4251
|
+
/** A value at most two levels deep as Markdown list items and `key: value`. */
|
|
4252
|
+
const listed$2 = (value) => {
|
|
4253
|
+
if (!isContainer(value)) return stringify$1(value);
|
|
4254
|
+
if (Array.isArray(value)) return value.map((item) => `- ${hang(listed$2(item))}`).join("\n");
|
|
4255
|
+
return Object.entries(value).map(([key, item]) => isContainer(item) ? `${key}:\n ${hang(listed$2(item))}` : `${key}: ${hang(stringify$1(item))}`).join("\n");
|
|
4256
|
+
};
|
|
4224
4257
|
/**
|
|
4225
|
-
*
|
|
4226
|
-
*
|
|
4227
|
-
*
|
|
4258
|
+
* A value as a person reads it: Markdown, never a line of raw JSON. `before` is
|
|
4259
|
+
* the text so far: a list or object starts on its own line, after a blank one
|
|
4260
|
+
* when text shares its line.
|
|
4228
4261
|
*/
|
|
4229
|
-
const
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
const
|
|
4262
|
+
const readableText = (value, before) => {
|
|
4263
|
+
if (!isContainer(value)) return stringify$1(value);
|
|
4264
|
+
if (depthOf(value) <= 2) {
|
|
4265
|
+
const list = listed$2(value);
|
|
4266
|
+
return list === "" || before === "" || before.endsWith("\n") ? list : `\n\n${list}`;
|
|
4267
|
+
}
|
|
4268
|
+
const code = JSON.stringify(value, void 0, 2).replaceAll(/^/gmu, " ");
|
|
4269
|
+
return before === "" || before.endsWith("\n\n") ? code : `\n\n${code}`;
|
|
4270
|
+
};
|
|
4271
|
+
/**
|
|
4272
|
+
* Fills a parsed template. `readable` is for text a person reads (a gate's
|
|
4273
|
+
* `question` and `document`); scripts and prompts keep JSON (ADR-047).
|
|
4274
|
+
*/
|
|
4275
|
+
const renderTemplate = (parts, scope, { readable = false } = {}) => parts.reduce((text, part) => {
|
|
4276
|
+
if (typeof part === "string") return text + part;
|
|
4277
|
+
const value = evaluate(part.expr, scope);
|
|
4278
|
+
return text + (readable ? readableText(value, text) : stringify$1(value));
|
|
4279
|
+
}, "");
|
|
4243
4280
|
// ../core/src/feedback/fingerprint.ts
|
|
4244
4281
|
/**
|
|
4245
4282
|
* @file Feedback fingerprints: records about the same thing (same target, kind,
|
|
@@ -4563,6 +4600,119 @@ const FEEDBACK_SEVERITIES = [
|
|
|
4563
4600
|
"medium",
|
|
4564
4601
|
"high"
|
|
4565
4602
|
];
|
|
4603
|
+
// ../core/src/project/mcp-file.ts
|
|
4604
|
+
/**
|
|
4605
|
+
* @file The project's `.mcp.json`, the file Claude Code reads too, so a server
|
|
4606
|
+
* is defined in one place: reading its servers, and the compiler's check of
|
|
4607
|
+
* the servers a Claude node names (`mcp:`, ADR-067). A session's servers are
|
|
4608
|
+
* read with the file's text left as written, so no value leaves the file.
|
|
4609
|
+
*/
|
|
4610
|
+
const MCP_FILE = ".mcp.json";
|
|
4611
|
+
/** Ork's own MCP server: a project can't redefine it. */
|
|
4612
|
+
const ORK_MCP_NAME = "ork";
|
|
4613
|
+
const isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4614
|
+
/** The file's `mcpServers`; `{}` when there is no file. */
|
|
4615
|
+
const serversIn = (root) => {
|
|
4616
|
+
const file = path.join(root, MCP_FILE);
|
|
4617
|
+
if (!existsSync(file)) return {
|
|
4618
|
+
ok: true,
|
|
4619
|
+
value: {}
|
|
4620
|
+
};
|
|
4621
|
+
try {
|
|
4622
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
4623
|
+
const servers = isRecord$2(parsed) ? parsed["mcpServers"] : void 0;
|
|
4624
|
+
return {
|
|
4625
|
+
ok: true,
|
|
4626
|
+
value: isRecord$2(servers) ? servers : {}
|
|
4627
|
+
};
|
|
4628
|
+
} catch (error) {
|
|
4629
|
+
const reason = error instanceof SyntaxError ? "it is not valid JSON" : error instanceof Error ? error.message : String(error);
|
|
4630
|
+
return {
|
|
4631
|
+
ok: false,
|
|
4632
|
+
error: `${MCP_FILE} can't be read: ${reason}`
|
|
4633
|
+
};
|
|
4634
|
+
}
|
|
4635
|
+
};
|
|
4636
|
+
/** A server's field that holds something other than text: it would be dropped. */
|
|
4637
|
+
const mcpNotText = (server) => [
|
|
4638
|
+
"args",
|
|
4639
|
+
"env",
|
|
4640
|
+
"headers"
|
|
4641
|
+
].find((field) => {
|
|
4642
|
+
const value = server[field];
|
|
4643
|
+
return (Array.isArray(value) ? value : isRecord$2(value) ? Object.values(value) : []).some((item) => typeof item !== "string");
|
|
4644
|
+
});
|
|
4645
|
+
/** Why an entry can't be loaded, whatever its name; its values aren't quoted. */
|
|
4646
|
+
const entryProblem = (server) => {
|
|
4647
|
+
if (!isRecord$2(server)) return "it is not an object";
|
|
4648
|
+
if (server["args"] !== void 0 && !Array.isArray(server["args"])) return "its args is not a list";
|
|
4649
|
+
const notRecord = ["env", "headers"].find((field) => server[field] !== void 0 && !isRecord$2(server[field]));
|
|
4650
|
+
if (notRecord !== void 0) return `its ${notRecord} is not an object`;
|
|
4651
|
+
const field = mcpNotText(server);
|
|
4652
|
+
if (field !== void 0) return `its ${field} holds a value that isn't text`;
|
|
4653
|
+
return typeof server["command"] === "string" || typeof server["url"] === "string" ? void 0 : "it has neither a command nor a url";
|
|
4654
|
+
};
|
|
4655
|
+
/** What the compiler checks a workflow's `mcp:` names against. */
|
|
4656
|
+
const mcpFileOptions = (root) => {
|
|
4657
|
+
const read = serversIn(root);
|
|
4658
|
+
if (!read.ok) return {
|
|
4659
|
+
mcpServers: [],
|
|
4660
|
+
mcpFileProblem: read.error
|
|
4661
|
+
};
|
|
4662
|
+
if (!existsSync(path.join(root, ".mcp.json"))) return {
|
|
4663
|
+
mcpServers: [],
|
|
4664
|
+
mcpFileProblem: `there is no ${MCP_FILE}`
|
|
4665
|
+
};
|
|
4666
|
+
return {
|
|
4667
|
+
mcpServers: Object.keys(read.value),
|
|
4668
|
+
mcpMalformed: Object.fromEntries(Object.entries(read.value).flatMap(([name, server]) => {
|
|
4669
|
+
const problem = entryProblem(server);
|
|
4670
|
+
return problem === void 0 ? [] : [[name, problem]];
|
|
4671
|
+
}))
|
|
4672
|
+
};
|
|
4673
|
+
};
|
|
4674
|
+
/** The error for one name a node gave, or nothing when it can load. */
|
|
4675
|
+
const nameProblem = (id, name, options, known) => {
|
|
4676
|
+
if (name === ORK_MCP_NAME) return {
|
|
4677
|
+
code: "mcp.reserved",
|
|
4678
|
+
message: `\`${id}\`: \`${ORK_MCP_NAME}\` is Ork's own server, name another`
|
|
4679
|
+
};
|
|
4680
|
+
if (!known.includes(name)) return {
|
|
4681
|
+
code: "mcp.unknown",
|
|
4682
|
+
message: `\`${id}\`: no MCP server \`${name}\`${options.mcpFileProblem === void 0 ? ` in ${MCP_FILE}, which has ${known.length === 0 ? "none" : known.join(", ")}` : `: ${options.mcpFileProblem}`}`
|
|
4683
|
+
};
|
|
4684
|
+
const problem = Object.hasOwn(options.mcpMalformed ?? {}, name) ? options.mcpMalformed?.[name] : void 0;
|
|
4685
|
+
return problem === void 0 ? void 0 : {
|
|
4686
|
+
code: "mcp.malformed",
|
|
4687
|
+
message: `\`${id}\`: MCP server \`${name}\` in ${MCP_FILE} is malformed: ${problem}`
|
|
4688
|
+
};
|
|
4689
|
+
};
|
|
4690
|
+
/** Every server a Claude node's sessions would load exists and can load. */
|
|
4691
|
+
const checkMcpServers = (workflow, options) => {
|
|
4692
|
+
const known = options.mcpServers;
|
|
4693
|
+
if (known === void 0) return [];
|
|
4694
|
+
return Object.entries(workflow.nodes).flatMap(([id, node]) => {
|
|
4695
|
+
if (node.type !== "claude.leader" && node.type !== "claude.worker") return [];
|
|
4696
|
+
const own = node.mcp !== void 0;
|
|
4697
|
+
return (node.mcp ?? workflow.defaults?.mcp ?? []).flatMap((name, index) => {
|
|
4698
|
+
const problem = nameProblem(id, name, options, known);
|
|
4699
|
+
return problem === void 0 ? [] : [{
|
|
4700
|
+
severity: "error",
|
|
4701
|
+
...problem,
|
|
4702
|
+
path: own ? [
|
|
4703
|
+
"nodes",
|
|
4704
|
+
id,
|
|
4705
|
+
"mcp",
|
|
4706
|
+
index
|
|
4707
|
+
] : [
|
|
4708
|
+
"defaults",
|
|
4709
|
+
"mcp",
|
|
4710
|
+
index
|
|
4711
|
+
]
|
|
4712
|
+
}];
|
|
4713
|
+
});
|
|
4714
|
+
});
|
|
4715
|
+
};
|
|
4566
4716
|
// ../core/src/project/templates.ts
|
|
4567
4717
|
/**
|
|
4568
4718
|
* @file Git name templates (`ork/{run}/{node}`, `{inputs.type}/{inputs.slug}`):
|
|
@@ -5776,6 +5926,7 @@ const TEMPLATE_FIELDS = [
|
|
|
5776
5926
|
"command",
|
|
5777
5927
|
"cwd",
|
|
5778
5928
|
"question",
|
|
5929
|
+
"document",
|
|
5779
5930
|
"workflow",
|
|
5780
5931
|
"project",
|
|
5781
5932
|
"ref"
|
|
@@ -5942,6 +6093,7 @@ const compileWorkflow = (authored, options = {}) => {
|
|
|
5942
6093
|
...rules.diagnostics,
|
|
5943
6094
|
...channels.diagnostics,
|
|
5944
6095
|
...checkRules(workflow),
|
|
6096
|
+
...checkMcpServers(workflow, options),
|
|
5945
6097
|
...checkReach(workflow, edges, entries)
|
|
5946
6098
|
];
|
|
5947
6099
|
diagnostics.sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]);
|
|
@@ -9073,7 +9225,8 @@ const checkWorkflowText = (text, { place, workflowDir, registered, home }) => {
|
|
|
9073
9225
|
catalog,
|
|
9074
9226
|
workflowDir,
|
|
9075
9227
|
projectRoot,
|
|
9076
|
-
...loaded.project === void 0 ? {} : { project: loaded.project }
|
|
9228
|
+
...loaded.project === void 0 ? {} : { project: loaded.project },
|
|
9229
|
+
...mcpFileOptions(projectRoot)
|
|
9077
9230
|
});
|
|
9078
9231
|
const { graph } = compiled;
|
|
9079
9232
|
const diagnostics = [];
|
|
@@ -9667,10 +9820,11 @@ const roleSection = (workflow, node) => {
|
|
|
9667
9820
|
return role === void 0 || role === "" ? [] : [`# Your role: ${node.agent}\n\n${role}`];
|
|
9668
9821
|
};
|
|
9669
9822
|
/** The node's own tool rules, the project's and workflow's, and isolation's. */
|
|
9670
|
-
const toolRules = (node, readonly, rules) => ({
|
|
9823
|
+
const toolRules = (node, readonly, rules, mcp) => ({
|
|
9671
9824
|
allow: [.../* @__PURE__ */ new Set([
|
|
9672
9825
|
...rules?.permissions?.allow ?? [],
|
|
9673
9826
|
...node.tools?.allow ?? [],
|
|
9827
|
+
...mcp.map((server) => `mcp__${server.replaceAll(/[^\w-]/gu, "_")}`),
|
|
9674
9828
|
...readonly ? READ_ONLY_COMMANDS : []
|
|
9675
9829
|
])],
|
|
9676
9830
|
deny: [.../* @__PURE__ */ new Set([
|
|
@@ -9700,6 +9854,7 @@ const planNodeSession = (workflow, id, options) => {
|
|
|
9700
9854
|
error: `\`${id}\` is a sub-agent; it runs inside \`${node.parent}\`'s session`
|
|
9701
9855
|
};
|
|
9702
9856
|
const defaults = workflow.defaults ?? {};
|
|
9857
|
+
const mcp = node.mcp ?? defaults.mcp ?? [];
|
|
9703
9858
|
const isolation = node.isolation ?? defaults.isolation ?? "worktree";
|
|
9704
9859
|
const ownWorktree = options.checkout?.own === true;
|
|
9705
9860
|
if ((isolation === "worktree" && !ownWorktree || isolation === "continue" && options.checkout === void 0) && options.inPlace !== true) return {
|
|
@@ -9743,7 +9898,7 @@ const planNodeSession = (workflow, id, options) => {
|
|
|
9743
9898
|
...contextSections(context.files, "node")
|
|
9744
9899
|
].join("\n\n"),
|
|
9745
9900
|
settingSources: ["project", "local"],
|
|
9746
|
-
tools: toolRules(node, isolation === "readonly", workflow.rules),
|
|
9901
|
+
tools: toolRules(node, isolation === "readonly", workflow.rules, mcp),
|
|
9747
9902
|
permissionMode: "default",
|
|
9748
9903
|
reportSchema: reportSchemaFor(node)
|
|
9749
9904
|
};
|
|
@@ -9769,6 +9924,7 @@ const planNodeSession = (workflow, id, options) => {
|
|
|
9769
9924
|
ok: true,
|
|
9770
9925
|
spec,
|
|
9771
9926
|
driver: namedDriver(node, workflow),
|
|
9927
|
+
mcp,
|
|
9772
9928
|
warnings,
|
|
9773
9929
|
context
|
|
9774
9930
|
};
|
|
@@ -13018,4 +13174,4 @@ const createWorkspace = (options) => {
|
|
|
13018
13174
|
close
|
|
13019
13175
|
};
|
|
13020
13176
|
};
|
|
13021
|
-
export { text as $,
|
|
13177
|
+
export { text as $, isToolNode as $n, evaluate as $t, gitOk as A, projectRootOf as An, runScope as At, linkNodes as B, readDocument as Bn, serversIn as Bt, workflowTextHash as C, placeFiles as Cn, walkChecks as Ct, inspectProject as D, shownPath as Dn, userMessageText as Dt, BRANCH_PREFIX as E, runDirOf as En, MESSAGE_LIMIT as Et, declaredProblem as F, writePlainFile as Fn, PROJECT_FILE as Ft, requestContinue as G, EdgeInputSchema as Gn, planPost as Gt, tellNode as H, parseWorkflow as Hn, FEEDBACK_SEVERITIES as Ht, createCalls as I, skillsIn as In, gitRulesOf as It, tellLiveRun as J, expandEdge as Jn, publishPost as Jt, requestPause as K, WorkflowSchema as Kn, runGh as Kt, addressOf as L, WorkflowEditSchema as Ln, loadProject as Lt, clearGitLocalEnv as M, estimateTokens as Mn, envReadsOf as Mt, parseInputPairs as N, guardedBase as Nn, nodeSays as Nt, removeWorktree as O, workflowDirOf as On, heldTimeout as Ot, resolveInputs as P, plainPathInside as Pn, declaredOutputOf as Pt, inTransaction as Q, isClaudeNode as Qn, targetOf as Qt, endLink as R, applyEdits as Rn, MCP_FILE as Rt, readProjectTriggers as S, newProjectId as Sn, checkWorkflowText as St, watchingPid as T, projectsHome as Tn, startRun as Tt, unlinkNodes as U, serializeWorkflow as Un, FEEDBACK_TARGETS as Ut, peerOf as V, renderJsonSchema as Vn, FEEDBACK_KINDS as Vt, flattenTree as W, markValue as Wn, DISCUSSIONS as Wt, usageQueries as X, NodeSchema as Xn, fingerprint as Xt, backfillUsage as Y, settingsOf as Yn, createFeedback as Yt, eventOf as Z, beforeOf as Zn, normalizeTitle as Zt, lateTriggers as _, catalogAgent as _n, runStatus as _t, limitsNow as a, socketRoom as an, integrationFor as ar, DETACHED_ENV as at, triggerStanding as b, hasInRepoFiles as bn, processAlive as bt, usd as c, maskSecrets as cn, CLAUDE_DRIVERS as cr, explainWorkflowText as ct, runningRunIds as d, planMoveInto as dn, experimentsOn as dr, namingNoDriver as dt, parseTemplate as en, programsRunBy as er, adoptedCalls as et, runningScript as f, linkTools as fn, knownExperiments as fr, sessionDriver as ft, parseVersion as g, deleteAgent as gn, pausedOf as gt, isNewer as h, createAgent as hn, liveStatus as ht, NOT_STARTED as i, socketPath as in, TOOL_PREFIX as ir, replayLoopAnswers as it, lines as j, LESSON_CAP_TOKENS as jn, calledWorkflows as jt, git as k, inside as kn, scriptContactsOf as kt, planUpgrade as l, planAgentMigration as ln, firstLine as lr, explainSession as lt, compareVersions as m, toolsInUse as mn, reportSchemaFor as mt, resolveBase as n, readCondition as nn, timeoutMs as nr, resumable as nt, limitsReport as o, wakeRun as on, AGENT_TOOL_LAYOUTS as or, detachRun as ot, detectInstaller as p, toolLinks as pn, parseReport as pt, requestStop as q, CheckReportSchema as qn, sendPost as qt, capsHere as r, serveRun as rn, INTEGRATIONS as rr, createReplay as rt, planReason as s, maskReplacer as sn, ORK_LAYOUT as sr, followEvents as st, createWorkspace as t, renderTemplate as tn, NodeIdSchema as tr, detachResume as tt, releaseNotes as u, applySteps as un, EXPERIMENTS as ur, planNodeSession as ut, triggersReport as v, loadAgents as vn, runTree as vt, takeWatchLock as w, placeFor as wn, walkSummary as wt, declaredTriggers as x, inRepoPlace as xn, stillTheSameProcess as xt, createWatcher as y, PROJECT_MODES as yn, ownProcessStart as yt, endLinksOf as z, newWorkflowText as zn, mcpNotText as zt };
|