@sweny-ai/core 0.1.126 → 0.1.128
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/claude.d.ts +6 -1
- package/dist/claude.js +5 -1
- package/dist/cli/main.js +6 -3
- package/dist/executor.js +28 -2
- package/dist/schema.d.ts +2 -5
- package/dist/schema.js +18 -8
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
package/dist/claude.d.ts
CHANGED
|
@@ -78,7 +78,9 @@ export interface ClaudeClientOptions {
|
|
|
78
78
|
logger?: Logger;
|
|
79
79
|
/** Default tool context for standalone usage (not via executor) */
|
|
80
80
|
defaultContext?: ToolContext;
|
|
81
|
-
/**
|
|
81
|
+
/** Catalog defaults, overridden by per-run skill servers and explicit mcpServers. */
|
|
82
|
+
defaultMcpServers?: Record<string, McpServerConfig>;
|
|
83
|
+
/** Explicit external MCP servers, overriding defaults and per-run skill servers. */
|
|
82
84
|
mcpServers?: Record<string, McpServerConfig>;
|
|
83
85
|
/**
|
|
84
86
|
* Extra env var names passed to the agent subprocess on top of the
|
|
@@ -123,6 +125,7 @@ export declare class ClaudeClient implements Claude {
|
|
|
123
125
|
private logger;
|
|
124
126
|
private defaultContext;
|
|
125
127
|
private mcpServers;
|
|
128
|
+
private defaultMcpServers;
|
|
126
129
|
private envPassthrough;
|
|
127
130
|
private sandboxMode;
|
|
128
131
|
private sandboxAllowedDomains;
|
|
@@ -153,6 +156,8 @@ export declare class ClaudeClient implements Claude {
|
|
|
153
156
|
timeoutMs?: number;
|
|
154
157
|
/** Caller-supplied abort signal. Aborting it interrupts the query. */
|
|
155
158
|
signal?: AbortSignal;
|
|
159
|
+
/** MCP servers declared by the current node's skills. */
|
|
160
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
156
161
|
/** Dry run (#380): no external MCP servers, no write-capable built-ins. */
|
|
157
162
|
readOnly?: boolean;
|
|
158
163
|
/** Env var names + sandbox hosts this node's skills need (#360). */
|
package/dist/claude.js
CHANGED
|
@@ -211,6 +211,7 @@ export class ClaudeClient {
|
|
|
211
211
|
logger;
|
|
212
212
|
defaultContext;
|
|
213
213
|
mcpServers;
|
|
214
|
+
defaultMcpServers;
|
|
214
215
|
envPassthrough;
|
|
215
216
|
sandboxMode;
|
|
216
217
|
sandboxAllowedDomains;
|
|
@@ -224,6 +225,7 @@ export class ClaudeClient {
|
|
|
224
225
|
this.logger = opts.logger ?? consoleLogger;
|
|
225
226
|
this.defaultContext = opts.defaultContext ?? { config: {}, logger: this.logger };
|
|
226
227
|
this.mcpServers = opts.mcpServers ?? {};
|
|
228
|
+
this.defaultMcpServers = opts.defaultMcpServers ?? {};
|
|
227
229
|
this.envPassthrough = opts.envPassthrough;
|
|
228
230
|
this.envScope = opts.envScope;
|
|
229
231
|
this.sandboxMode = opts.sandbox;
|
|
@@ -339,7 +341,9 @@ export class ClaudeClient {
|
|
|
339
341
|
const abort = makeAbort(timeoutMs, signal);
|
|
340
342
|
let stream;
|
|
341
343
|
try {
|
|
342
|
-
const allMcpServers = readOnly
|
|
344
|
+
const allMcpServers = readOnly
|
|
345
|
+
? {}
|
|
346
|
+
: { ...this.defaultMcpServers, ...opts.mcpServers, ...this.mcpServers };
|
|
343
347
|
if (sdkTools.length > 0)
|
|
344
348
|
allMcpServers["sweny-core"] = mcpServer;
|
|
345
349
|
stream = query({
|
package/dist/cli/main.js
CHANGED
|
@@ -204,7 +204,8 @@ triageCmd.action(async (options) => {
|
|
|
204
204
|
maxTurns: config.maxInvestigateTurns || 50,
|
|
205
205
|
cwd: process.cwd(),
|
|
206
206
|
logger: consoleLogger,
|
|
207
|
-
mcpServers,
|
|
207
|
+
defaultMcpServers: mcpServers,
|
|
208
|
+
mcpServers: config.mcpServers,
|
|
208
209
|
});
|
|
209
210
|
// ── Progress display state ─────────────────────────────────
|
|
210
211
|
const FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
@@ -513,7 +514,8 @@ implementCmd.action(async (issueId, options) => {
|
|
|
513
514
|
maxTurns: config.maxImplementTurns || 40,
|
|
514
515
|
cwd: process.cwd(),
|
|
515
516
|
logger: consoleLogger,
|
|
516
|
-
mcpServers,
|
|
517
|
+
defaultMcpServers: mcpServers,
|
|
518
|
+
mcpServers: config.mcpServers,
|
|
517
519
|
});
|
|
518
520
|
console.log(chalk.cyan(`\n sweny implement ${issueId}\n`));
|
|
519
521
|
const implRunStart = Date.now();
|
|
@@ -756,7 +758,8 @@ export async function workflowRunAction(file, options) {
|
|
|
756
758
|
maxTurns: config.maxInvestigateTurns || 50,
|
|
757
759
|
cwd: process.cwd(),
|
|
758
760
|
logger: runLogger,
|
|
759
|
-
mcpServers,
|
|
761
|
+
defaultMcpServers: mcpServers,
|
|
762
|
+
mcpServers: config.mcpServers,
|
|
760
763
|
model: workflow.model,
|
|
761
764
|
});
|
|
762
765
|
// Track per-node entry time to compute elapsed on exit
|
package/dist/executor.js
CHANGED
|
@@ -148,12 +148,16 @@ export async function execute(workflow, input, options) {
|
|
|
148
148
|
logger.info(` dry run: withheld write tools: ${skippedWrites.join(", ")}`, { node: currentId });
|
|
149
149
|
}
|
|
150
150
|
const skillInstructions = resolveSkillInstructions(node.skills, skills);
|
|
151
|
+
const skillMcpServers = resolveSkillMcpServers(node.skills, skills);
|
|
151
152
|
// Runtime guard: if this node declares skills but none resolved, the node
|
|
152
153
|
// cannot do its job (e.g. "create a Linear issue" with no linear skill).
|
|
153
154
|
// The startup validate() warns about this possibility, but only throw when
|
|
154
155
|
// the node is actually reached — unreachable nodes with missing skills are fine.
|
|
155
|
-
// Instruction-only
|
|
156
|
-
if (node.skills.length > 0 &&
|
|
156
|
+
// Instruction-only and resolved MCP-only skills are valid capabilities.
|
|
157
|
+
if (node.skills.length > 0 &&
|
|
158
|
+
resolvedSkillTools.length === 0 &&
|
|
159
|
+
skillInstructions.length === 0 &&
|
|
160
|
+
Object.keys(skillMcpServers).length === 0) {
|
|
157
161
|
throw new Error(`Node "${currentId}" requires skills [${node.skills.join(", ")}] but none are configured. ` +
|
|
158
162
|
`Set the required environment variables and try again.`);
|
|
159
163
|
}
|
|
@@ -241,6 +245,7 @@ export async function execute(workflow, input, options) {
|
|
|
241
245
|
signal,
|
|
242
246
|
timeoutMs,
|
|
243
247
|
agentAccess: resolveAgentAccess(node.skills, skills),
|
|
248
|
+
...(dryRun ? {} : { mcpServers: skillMcpServers }),
|
|
244
249
|
...(dryRun ? { readOnly: true } : {}),
|
|
245
250
|
onProgress: (message) => {
|
|
246
251
|
safeObserve(observer, { type: "node:progress", node: currentId, message }, logger);
|
|
@@ -721,6 +726,13 @@ function dryRunNotice(skippedWrites) {
|
|
|
721
726
|
`Do not create, modify, post, or send anything. Do the analysis, and where this step would ` +
|
|
722
727
|
`normally write, describe exactly what it would have written instead.`);
|
|
723
728
|
}
|
|
729
|
+
/** Only this node's resolved skills contribute external servers. */
|
|
730
|
+
function resolveSkillMcpServers(skillIds, skills) {
|
|
731
|
+
return Object.fromEntries(skillIds.flatMap((id) => {
|
|
732
|
+
const mcp = skills.get(id)?.mcp;
|
|
733
|
+
return mcp ? [[id, { ...mcp, type: mcp.type ?? (mcp.command ? "stdio" : "http") }]] : [];
|
|
734
|
+
}));
|
|
735
|
+
}
|
|
724
736
|
function resolveTools(skillIds, skills) {
|
|
725
737
|
return skillIds
|
|
726
738
|
.map((id) => skills.get(id))
|
|
@@ -1023,6 +1035,14 @@ async function resolveNext(workflow, current, results, input, claude, observer,
|
|
|
1023
1035
|
* Validate a workflow definition before execution.
|
|
1024
1036
|
*/
|
|
1025
1037
|
function validate(workflow, skills) {
|
|
1038
|
+
for (const [id, def] of Object.entries(workflow.skills ?? {})) {
|
|
1039
|
+
if (!def.instruction?.trim()) {
|
|
1040
|
+
throw new Error(`Inline skill "${id}" must provide a non-empty instruction`);
|
|
1041
|
+
}
|
|
1042
|
+
if (id === "sweny-core" && def.mcp) {
|
|
1043
|
+
throw new Error(`Skill "sweny-core" is reserved for the engine MCP server; use a different skill ID`);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1026
1046
|
if (!workflow.nodes[workflow.entry]) {
|
|
1027
1047
|
throw new Error(`Entry node "${workflow.entry}" not found`);
|
|
1028
1048
|
}
|
|
@@ -1036,6 +1056,12 @@ function validate(workflow, skills) {
|
|
|
1036
1056
|
for (const [nodeId, node] of Object.entries(workflow.nodes)) {
|
|
1037
1057
|
if (node.skills.length === 0)
|
|
1038
1058
|
continue;
|
|
1059
|
+
for (const id of node.skills) {
|
|
1060
|
+
const skill = skills.get(id);
|
|
1061
|
+
if (id === "sweny-core" && skill?.mcp) {
|
|
1062
|
+
throw new Error(`Skill "sweny-core" is reserved for the engine MCP server; use a different skill ID (node "${nodeId}")`);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1039
1065
|
const available = node.skills.filter((id) => skills.has(id));
|
|
1040
1066
|
if (available.length === 0) {
|
|
1041
1067
|
consoleLogger.warn(`Node "${nodeId}" has no available skills (needs one of: ${node.skills.join(", ")})`);
|
package/dist/schema.d.ts
CHANGED
|
@@ -3357,11 +3357,7 @@ export declare const workflowJsonSchema: {
|
|
|
3357
3357
|
readonly description: "Inline skill definitions scoped to this workflow";
|
|
3358
3358
|
readonly additionalProperties: {
|
|
3359
3359
|
readonly type: "object";
|
|
3360
|
-
readonly
|
|
3361
|
-
readonly required: readonly ["instruction"];
|
|
3362
|
-
}, {
|
|
3363
|
-
readonly required: readonly ["mcp"];
|
|
3364
|
-
}];
|
|
3360
|
+
readonly required: readonly ["instruction"];
|
|
3365
3361
|
readonly additionalProperties: false;
|
|
3366
3362
|
readonly properties: {
|
|
3367
3363
|
readonly name: {
|
|
@@ -3372,6 +3368,7 @@ export declare const workflowJsonSchema: {
|
|
|
3372
3368
|
};
|
|
3373
3369
|
readonly instruction: {
|
|
3374
3370
|
readonly type: "string";
|
|
3371
|
+
readonly pattern: "\\S";
|
|
3375
3372
|
readonly description: "Natural language expertise injected into the node prompt";
|
|
3376
3373
|
};
|
|
3377
3374
|
readonly mcp: {
|
package/dist/schema.js
CHANGED
|
@@ -63,8 +63,8 @@ export const skillDefinitionZ = z
|
|
|
63
63
|
mcp: mcpServerConfigZ.optional(),
|
|
64
64
|
})
|
|
65
65
|
.strict()
|
|
66
|
-
.refine((s) => s.instruction
|
|
67
|
-
message: "Inline skill must provide
|
|
66
|
+
.refine((s) => Boolean(s.instruction?.trim()), {
|
|
67
|
+
message: "Inline skill must provide a non-empty instruction",
|
|
68
68
|
});
|
|
69
69
|
export const skillZ = z
|
|
70
70
|
.object({
|
|
@@ -489,12 +489,18 @@ export function validateWorkflow(workflow, knownSkills) {
|
|
|
489
489
|
});
|
|
490
490
|
}
|
|
491
491
|
}
|
|
492
|
-
// Inline
|
|
492
|
+
// Inline skills need usage instructions; the engine server name is reserved.
|
|
493
493
|
for (const [skillId, def] of Object.entries(workflow.skills ?? {})) {
|
|
494
|
-
if (!def.instruction
|
|
494
|
+
if (!def.instruction?.trim()) {
|
|
495
495
|
errors.push({
|
|
496
496
|
code: "INVALID_INLINE_SKILL",
|
|
497
|
-
message: `Inline skill "${skillId}" must provide
|
|
497
|
+
message: `Inline skill "${skillId}" must provide a non-empty instruction`,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
if (skillId === "sweny-core" && def.mcp) {
|
|
501
|
+
errors.push({
|
|
502
|
+
code: "INVALID_INLINE_SKILL",
|
|
503
|
+
message: `Skill "sweny-core" is reserved for the engine MCP server; use a different skill ID`,
|
|
498
504
|
});
|
|
499
505
|
}
|
|
500
506
|
}
|
|
@@ -945,14 +951,18 @@ export const workflowJsonSchema = {
|
|
|
945
951
|
description: "Inline skill definitions scoped to this workflow",
|
|
946
952
|
additionalProperties: {
|
|
947
953
|
type: "object",
|
|
948
|
-
//
|
|
949
|
-
|
|
954
|
+
// Inline skills need usable instructions, including when they declare MCP.
|
|
955
|
+
required: ["instruction"],
|
|
950
956
|
// Round 2: reject unknown keys to match Zod skillDefinitionZ.strict().
|
|
951
957
|
additionalProperties: false,
|
|
952
958
|
properties: {
|
|
953
959
|
name: { type: "string" },
|
|
954
960
|
description: { type: "string" },
|
|
955
|
-
instruction: {
|
|
961
|
+
instruction: {
|
|
962
|
+
type: "string",
|
|
963
|
+
pattern: "\\S",
|
|
964
|
+
description: "Natural language expertise injected into the node prompt",
|
|
965
|
+
},
|
|
956
966
|
mcp: {
|
|
957
967
|
type: "object",
|
|
958
968
|
description: "External MCP server definition",
|
package/dist/types.d.ts
CHANGED
|
@@ -604,6 +604,8 @@ export interface Claude {
|
|
|
604
604
|
outputSchema?: JSONSchema;
|
|
605
605
|
/** Called with status messages while Claude is working (tool name, etc.) */
|
|
606
606
|
onProgress?: (message: string) => void;
|
|
607
|
+
/** MCP servers declared by this node's resolved skills. Explicit client configs win. */
|
|
608
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
607
609
|
/** Per-node turn limit. Overrides the client default when set. */
|
|
608
610
|
maxTurns?: number;
|
|
609
611
|
/** Built-in SDK tool names to disallow for this node (e.g. ["Bash"]). */
|