@bridge_gpt/mcp-server 0.1.12 → 0.1.14

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.
@@ -79,6 +79,28 @@ export function validatePipelineSchema(json) {
79
79
  return { valid: errors.length === 0, errors };
80
80
  }
81
81
  // ---------------------------------------------------------------------------
82
+ // Instruction-File Content Helpers
83
+ // ---------------------------------------------------------------------------
84
+ /**
85
+ * True when markdown contains a terminal ``## Return`` H2 heading — i.e. the
86
+ * heading appears and no later H2 heading follows. Used by the build-time
87
+ * bundler and the custom-pipeline loader to enforce the
88
+ * ``agent_result``-contract for ``agent_task`` instruction files.
89
+ */
90
+ export function hasTerminalReturnSection(markdown) {
91
+ if (typeof markdown !== "string" || markdown.length === 0)
92
+ return false;
93
+ const h2Pattern = /^##\s+(.+?)\s*$/gm;
94
+ let match;
95
+ let lastHeading = null;
96
+ while ((match = h2Pattern.exec(markdown)) !== null) {
97
+ lastHeading = match[1].trim();
98
+ }
99
+ if (lastHeading === null)
100
+ return false;
101
+ return /^return\b/i.test(lastHeading);
102
+ }
103
+ // ---------------------------------------------------------------------------
82
104
  // Variable Handling
83
105
  // ---------------------------------------------------------------------------
84
106
  const variablePattern = () => /\{([a-zA-Z_][a-zA-Z0-9_]*)}/g;
@@ -123,7 +145,7 @@ function substituteInParams(params, variables) {
123
145
  // ---------------------------------------------------------------------------
124
146
  // Recipe Resolution
125
147
  // ---------------------------------------------------------------------------
126
- export function resolveRecipe(pipeline, instructions, variables, skipSteps) {
148
+ export function resolveRecipe(pipeline, instructions, variables, skipSteps, autoApprove) {
127
149
  // Validate required variables are provided
128
150
  const declared = pipeline.variables ?? [];
129
151
  const missing = declared.filter((v) => !(v in variables));
@@ -140,13 +162,18 @@ export function resolveRecipe(pipeline, instructions, variables, skipSteps) {
140
162
  const skipKey = step.type === "mcp_call" ? step.tool : step.description;
141
163
  if (skip.has(skipKey))
142
164
  continue;
165
+ const declaredApproval = step.requires_approval ?? false;
166
+ const effectiveApproval = declaredApproval && !autoApprove;
143
167
  const base = {
144
168
  step: stepIndex++,
145
169
  type: step.type,
146
- description: step.description,
170
+ description: substituteVariables(step.description, variables),
147
171
  on_error: step.on_error ?? "halt",
148
- requires_approval: step.requires_approval ?? false,
172
+ requires_approval: effectiveApproval,
149
173
  };
174
+ if (declaredApproval !== effectiveApproval) {
175
+ base.requires_approval_declared = declaredApproval;
176
+ }
150
177
  if (step.type === "mcp_call") {
151
178
  base.tool = step.tool;
152
179
  base.params = substituteInParams(step.params, variables);
@@ -168,17 +195,22 @@ export function resolveRecipe(pipeline, instructions, variables, skipSteps) {
168
195
  }
169
196
  resolvedSteps.push(base);
170
197
  }
198
+ const baseInstructions = "IMPORTANT: Execute every step below in exact sequential order. " +
199
+ "For mcp_call steps, call the specified tool with the provided params. " +
200
+ "For agent_task steps, follow the instruction text using any tools it specifies. " +
201
+ "If requires_approval is true, pause before executing. For agent_task steps, the instruction file's own approval format is authoritative — follow it verbatim and do not substitute your own short confirmation prompt. For mcp_call steps with no instruction file, present the resolved params as bullet points and ask for approval. " +
202
+ 'For on_error "halt", stop the pipeline immediately on failure. ' +
203
+ 'For on_error "warn_and_continue", log a warning and proceed. ' +
204
+ "Do not skip steps, reorder them, or substitute your own tool calls.";
205
+ const autoApproveSuffix = autoApprove
206
+ ? " Auto-approve mode is ACTIVE: every approval gate has been pre-approved by the user via the auto_approve flag — proceed without pausing for confirmation, applying the default branching, file-staging, and recommendation choices documented in each instruction file's auto-approve branch."
207
+ : "";
171
208
  return {
172
209
  pipeline: pipeline.name,
173
210
  description: pipeline.description ?? "",
174
211
  total_steps: resolvedSteps.length,
175
- agent_instructions: "IMPORTANT: Execute every step below in exact sequential order. " +
176
- "For mcp_call steps, call the specified tool with the provided params. " +
177
- "For agent_task steps, follow the instruction text using any tools it specifies. " +
178
- "If requires_approval is true, pause before executing. For agent_task steps, the instruction file's own approval format is authoritative — follow it verbatim and do not substitute your own short confirmation prompt. For mcp_call steps with no instruction file, present the resolved params as bullet points and ask for approval. " +
179
- 'For on_error "halt", stop the pipeline immediately on failure. ' +
180
- 'For on_error "warn_and_continue", log a warning and proceed. ' +
181
- "Do not skip steps, reorder them, or substitute your own tool calls.",
212
+ agent_instructions: baseInstructions + autoApproveSuffix,
213
+ auto_approve: !!autoApprove,
182
214
  steps: resolvedSteps,
183
215
  };
184
216
  }
@@ -237,15 +269,21 @@ export async function loadCustomPipelines(pipelinesDir, instructionsDir, bundled
237
269
  }
238
270
  const pipeline = parsed;
239
271
  const key = file.replace(/\.json$/, "");
240
- // Validate instruction_file references
272
+ // Validate instruction_file references and terminal ## Return contract.
241
273
  let hasInvalidRef = false;
242
274
  for (const step of pipeline.steps) {
243
275
  if (step.type === "agent_task" && step.instruction_file) {
244
- if (!(step.instruction_file in mergedInstructions)) {
276
+ const content = mergedInstructions[step.instruction_file];
277
+ if (content === undefined) {
245
278
  console.error(`Warning: skipping "${file}" — instruction_file "${step.instruction_file}" not found.`);
246
279
  hasInvalidRef = true;
247
280
  break;
248
281
  }
282
+ if (!hasTerminalReturnSection(content)) {
283
+ console.error(`Warning: skipping "${file}" — instruction_file "${step.instruction_file}" is missing a terminal "## Return" section (required by BAPI-275 agent_result contract).`);
284
+ hasInvalidRef = true;
285
+ break;
286
+ }
249
287
  }
250
288
  }
251
289
  if (hasInvalidRef)