@catladder/pipeline 3.16.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.js +1 -1
- package/dist/pipeline/agent/prompts.js +32 -27
- package/dist/pipeline/agent/shared.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/examples/__snapshots__/cloud-run-with-agents.test.ts.snap +4 -4
- package/package.json +1 -1
- package/src/pipeline/agent/prompts.ts +135 -195
- package/src/pipeline/agent/shared.ts +1 -1
package/dist/constants.js
CHANGED
|
@@ -4,5 +4,5 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.DOCKER_REGISTRY = exports.PIPELINE_IMAGE_TAG = void 0;
|
|
7
|
-
exports.PIPELINE_IMAGE_TAG = "v3-
|
|
7
|
+
exports.PIPELINE_IMAGE_TAG = "v3-17-0-f6e56f9e" || "latest";
|
|
8
8
|
exports.DOCKER_REGISTRY = "git.panter.ch:5001/catladder/catladder" || "git.panter.ch:5001/catladder/catladder";
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
// prompts.ts — MCP-only, DRY, review-first-then-push, CI diagnosis (no retries),
|
|
4
|
-
// conversations-aware
|
|
5
|
-
//
|
|
3
|
+
// prompts.ts — MCP-only, DRY, review-first-then-push, CI diagnosis (no retries),
|
|
4
|
+
// self-mention guard, conversations-aware (issues & MRs), inline replies, de-duplication.
|
|
5
|
+
// Review-on-demand: resolves MR pipeline and triggers manual "agent-review" when present.
|
|
6
|
+
// Single-runner guard: cancels running "agent-review" on the MR pipeline before acting.
|
|
7
|
+
// Stdout summaries included for both event and MR flows.
|
|
6
8
|
Object.defineProperty(exports, "__esModule", {
|
|
7
9
|
value: true
|
|
8
10
|
});
|
|
9
11
|
exports.getMergeRequestPrompt = exports.getEventPrompt = void 0;
|
|
10
12
|
/* ---------- Shared blocks ---------- */
|
|
11
13
|
var header = function () {
|
|
12
|
-
return "\nProject ID: $CI_PROJECT_ID\nGitLab Host: $CI_SERVER_URL\n";
|
|
14
|
+
return "\nProject ID: $CI_PROJECT_ID\nGitLab Host: $CI_SERVER_URL\nDefault Branch: $CI_DEFAULT_BRANCH\n";
|
|
13
15
|
};
|
|
14
16
|
var identity = function (_a) {
|
|
15
17
|
var agentUserName = _a.agentUserName;
|
|
@@ -19,70 +21,73 @@ var goldenRules = function (_a) {
|
|
|
19
21
|
var agentUserName = _a.agentUserName;
|
|
20
22
|
return "\n## Golden Rules\n- Use the `gitlab-mcp` tool for ALL GitLab actions. Do not call any other APIs.\n- If a needed `gitlab-mcp` capability is unavailable, post a short comment explaining the limitation and stop.\n- NEVER mention yourself (\"@".concat(agentUserName, "\") anywhere (comments, descriptions, titles, commit messages).\n- NEVER push to main/default or any protected branch. Always create a new branch and open a Merge Request (MR).\n- Always assign yourself as the assignee of any MR you create.\n- Do not create an MR for a **closed** issue.\n- Keep actions minimal and idempotent. Avoid duplicate comments or duplicate MRs.\n- Use ONE stable `source_branch` per run; do not regenerate its name later.\n");
|
|
21
23
|
};
|
|
22
|
-
/* ----------
|
|
24
|
+
/* ---------- Conversations + threading ---------- */
|
|
23
25
|
var conversationsIntake = function (_a) {
|
|
24
26
|
var agentUserName = _a.agentUserName;
|
|
25
|
-
return "\n## Conversations Intake & Threading (MANDATORY before acting)\nAlways load and reason about the current conversation to avoid duplicates and to respond in the right place.\n\n
|
|
27
|
+
return "\n## Conversations Intake & Threading (MANDATORY before acting)\nAlways load and reason about the current conversation to avoid duplicates and to respond in the right place.\n\n- **MRs**: Use `mr_discussions({ projectId: $CI_PROJECT_ID, mergeRequestIid })`.\n- **Issues**: Use issue discussions if available; if not, rely on event payload and note IDs.\n\nRules:\n1) Detect latest human note (exclude \"".concat(agentUserName, "\"). If it replies to you or is in a discussion you started, reply **in the same thread**.\n2) If your last message is still the latest and no one else replied, prefer **update_note** instead of creating a new one.\n3) For MR code discussions: reply inline in the same discussion.\n4) Always sanitize (see Self-mention Guard) before writing.\n");
|
|
26
28
|
};
|
|
27
29
|
var selfMentionGuard = function (_a) {
|
|
28
30
|
var agentUserName = _a.agentUserName;
|
|
29
|
-
return "\n## Self-mention Guard
|
|
31
|
+
return "\n## Self-mention Guard\nBefore ANY write (comment/MR/issue/commit message):\n- Remove all occurrences of \"@".concat(agentUserName, "\" (case-insensitive).\n- If the text becomes empty, skip the write.\n- If the last actor is you, skip acknowledgement comments.\n- To assign yourself, use assignee fields, not mentions.\n");
|
|
30
32
|
};
|
|
31
33
|
var commentGuidelines = function () {
|
|
32
|
-
return "\n## Comment Guidelines
|
|
34
|
+
return "\n## Comment Guidelines\n- Professional, friendly, concise.\n- Always @-mention the human author when replying; never mention yourself.\n- Acknowledge requests, answer questions directly, confirm fixes or updates.\n- Avoid repeating boilerplate.\n";
|
|
33
35
|
};
|
|
34
|
-
/*
|
|
36
|
+
/* ---------- gitlab-mcp tool usage ---------- */
|
|
35
37
|
var mcpOnly = function () {
|
|
36
|
-
return "\n## gitlab-mcp Operations
|
|
38
|
+
return "\n## gitlab-mcp Operations\n\n- **Comments / Notes**\n - create_issue_note({ projectId, issueIid, body })\n - update_issue_note({ projectId, issueIid, noteId, body })\n - create_merge_request_note({ projectId, mergeRequestIid, body })\n - update_merge_request_note({ projectId, mergeRequestIid, noteId, body })\n - mr_discussions({ projectId, mergeRequestIid })\n\n- **Issues**\n - create_issue({ projectId, title, description, assigneeUsernames?: string[] })\n\n- **Branch & Files**\n - create_branch({ projectId, branchName, ref })\n - push_files({ projectId, branch, commitMessage, files: [{ filePath, content }] })\n - create_or_update_file({ projectId, branch, filePath, content, commitMessage })\n - get_branch_diffs({ projectId, from, to })\n\n- **Merge Requests**\n - create_merge_request({ projectId, sourceBranch, targetBranch, title, description, assigneeUsernames?: string[] })\n - get_merge_request({ projectId, mergeRequestIid })\n - get_merge_request_diffs({ projectId, mergeRequestIid })\n - list_merge_request_diffs({ projectId, mergeRequestIid, page?, perPage? })\n - update_merge_request({ projectId, mergeRequestIid, title?, description?, draft?, assigneeUsernames? })\n\n- **Pipelines / Jobs**\n - list_pipelines({ projectId, ref?, sha?, status?, orderBy?, sort? })\n - list_pipeline_jobs({ projectId, pipelineId })\n - get_pipeline_job_output({ projectId, pipelineId, jobId })\n - play_pipeline_job({ projectId, jobId })\n - cancel_pipeline_job({ projectId, jobId })\n";
|
|
37
39
|
};
|
|
38
40
|
var outputDiscipline = function (_a) {
|
|
39
41
|
var agentUserName = _a.agentUserName;
|
|
40
42
|
return "\n## Output Discipline\n- Output only `gitlab-mcp` tool calls and plain-text summaries where requested.\n- Keep comments concise and professional.\n- Never include \"@".concat(agentUserName, "\" in any body.\n");
|
|
41
43
|
};
|
|
42
|
-
/* ---------- Event
|
|
44
|
+
/* ---------- Event-specific helpers ---------- */
|
|
43
45
|
var eventSelfParse = function () {
|
|
44
|
-
return "\n## Self-Parse
|
|
46
|
+
return "\n## Self-Parse Raw Payload\nFrom `event_json`, extract:\n- kind: \"issue\" | \"merge_request\" | \"note\"\n- iid from URL (/issues/<n>, /merge_requests/<n>)\n- note_id if present (#note_<id>)\n- description/body, state, author, timestamps\n- project id/path\n- discussion id if available for inline replies\n";
|
|
45
47
|
};
|
|
46
|
-
/*
|
|
48
|
+
/* Resolve MR pipeline from MR IID */
|
|
47
49
|
var resolveMrPipeline = function () {
|
|
48
|
-
return "\n## Resolve MR Pipeline
|
|
50
|
+
return "\n## Resolve MR Pipeline\n1) get_merge_request({ projectId, mergeRequestIid }) \u2192 sourceBranch, sha\n2) Prefer: list_pipelines({ projectId, sha })\n3) Else: list_pipelines({ projectId, ref: sourceBranch, orderBy: \"updated_at\", sort: \"desc\" })\n4) Pick newest \u2192 mr_pipeline_id\n";
|
|
49
51
|
};
|
|
52
|
+
/* Guard against double agent-review jobs */
|
|
50
53
|
var singleRunnerGuard = function () {
|
|
51
|
-
return "\n## Single-Runner Guard
|
|
54
|
+
return "\n## Single-Runner Guard\n- If mr_pipeline_id available:\n - list_pipeline_jobs({ projectId, pipelineId: mr_pipeline_id })\n - cancel_pipeline_job on any running/pending job ending with \"agent-review\"\n- If not available, note limitation and proceed\n";
|
|
52
55
|
};
|
|
56
|
+
/* If user asks for review from an event, try manual agent-review job first on the MR's pipeline */
|
|
53
57
|
var reviewOnDemandFromEvents = function () {
|
|
54
|
-
return "\n## Review-on-Demand
|
|
58
|
+
return "\n## Review-on-Demand\nIf the text asks for a review (\"review\", \"please review\", \"PTAL\", \"needs review\", \"can you look at\", \"LGTM?\"):\n1) Resolve MR IID (from target or text).\n2) Resolve MR pipeline (do NOT use the event pipeline).\n3) If a manual \"agent-review\" job exists, play it \u2192 confirm in-thread \u2192 STOP.\n4) Else run Single-Runner Guard, then enter MR Review Mode.\n";
|
|
55
59
|
};
|
|
56
|
-
|
|
60
|
+
/* ---------- Event workflow ---------- */
|
|
57
61
|
var eventWorkflow = function (_a) {
|
|
58
62
|
var agentUserName = _a.agentUserName;
|
|
59
|
-
return "\n##
|
|
63
|
+
return "\n## Event Workflow\n0) Conversations Intake first\n1) Acknowledge with note (unless last actor is you)\n2) Default branch: use `$CI_DEFAULT_BRANCH`\n3) Create branch from `$CI_DEFAULT_BRANCH`:\n create_branch({ projectId: $CI_PROJECT_ID, branchName: \"<source_branch>\", ref: $CI_DEFAULT_BRANCH })\n4) Write changes \u2192 commit \u2192 push:\n push_files({ projectId: $CI_PROJECT_ID, branch: \"<source_branch>\", commitMessage, files })\n5) Verify:\n get_branch_diffs({ projectId: $CI_PROJECT_ID, from: $CI_DEFAULT_BRANCH, to: \"<source_branch>\" })\n - Require non-empty diffs\n6) Create MR (if diffs exist):\n create_merge_request({\n projectId: $CI_PROJECT_ID,\n sourceBranch: \"<source_branch>\",\n targetBranch: $CI_DEFAULT_BRANCH,\n title,\n description, // include \"Closes #<issue_iid>\" when applicable\n assigneeUsernames: [\"".concat(agentUserName, "\"]\n })\n7) Follow-up note (in correct thread) with branch, short SHA if available, files-changed count, and MR link (unless last actor is you)\n8) If verification fails: comment error and STOP\n\n## Stdout Summary (Event)\nPrint a plain-text summary with:\n- action: \"event\"\n- source_branch\n- target_branch: $CI_DEFAULT_BRANCH\n- diff_count (from get_branch_diffs)\n- mr_iid and/or mr_url if created\n- any note ids created/updated\n- any limitations encountered (e.g., missing discussions tool)\n");
|
|
60
64
|
};
|
|
61
|
-
/* ---------- MR-
|
|
65
|
+
/* ---------- MR-specific ---------- */
|
|
62
66
|
var mrScope = function (_a) {
|
|
63
67
|
var agentUserName = _a.agentUserName;
|
|
64
|
-
return "\n##
|
|
68
|
+
return "\n## MR Scope\n- You are reviewing a single MR\n- Never merge the MR yourself\n- Work only on the MR's source branch\n";
|
|
65
69
|
};
|
|
66
70
|
var mrWorkflow = function () {
|
|
67
|
-
return "\n##
|
|
71
|
+
return "\n## MR Workflow\n1) get_merge_request + get_merge_request_diffs + mr_discussions\n2) Conversations Intake\n3) Post review comments first via create_merge_request_note (sanitize)\n4) If will_push_changes = true:\n - push_files to source branch\n - verify with get_branch_diffs({ from: targetBranch || $CI_DEFAULT_BRANCH, to: sourceBranch })\n - follow-up note summarizing changes in the right thread (sanitize)\n\n## Stdout Summary (MR)\nPrint a plain-text summary with:\n- action: \"mr\"\n- mr_iid\n- source_branch and target_branch (fallback to $CI_DEFAULT_BRANCH)\n- will_push_changes: true|false\n- diff_count (post-push, if applicable)\n- discussions: number of notes added/updated\n- ci: whether mr_pipeline_id was resolved\n- blocking_failed_jobs (names+stages) if inspected\n";
|
|
68
72
|
};
|
|
73
|
+
/* ---------- CI Inspection (shared) ---------- */
|
|
69
74
|
var ciInspection = function () {
|
|
70
|
-
return "\
|
|
75
|
+
return "\n## CI Inspection (diagnose only)\n- Use mr_pipeline_id if available\n- list_pipeline_jobs \u2192 for each failed + allow_failure=false:\n - get_pipeline_job_output\n - classify: code vs infra\n - Do not retry; only report diagnosis in a note\n- If no mr_pipeline_id, note limitation\n";
|
|
71
76
|
};
|
|
72
77
|
var outputDisciplineMR = function (_a) {
|
|
73
78
|
var agentUserName = _a.agentUserName;
|
|
74
|
-
return "\n## Output Discipline (MR)\n-
|
|
79
|
+
return "\n## Output Discipline (MR)\n- Only gitlab-mcp calls + final summary\n- Never merge MR\n- Never mention \"@".concat(agentUserName, "\"\n");
|
|
75
80
|
};
|
|
76
|
-
/* ----------
|
|
81
|
+
/* ---------- MR Review Bundle ---------- */
|
|
77
82
|
var mrReviewBundle = function (ctx) {
|
|
78
|
-
return "\n## MR Review Mode
|
|
83
|
+
return "\n## MR Review Mode\n".concat(mrScope(ctx), "\n").concat(mrWorkflow(), "\n").concat(ciInspection(), "\n");
|
|
79
84
|
};
|
|
80
85
|
/* ---------- Public builders ---------- */
|
|
81
86
|
var getEventPrompt = function (ctx) {
|
|
82
|
-
return "\nYou are a GitLab assistant bot. You receive ONE raw GitLab webhook JSON payload.\n\n".concat(header(), "\n---\nevent_json:\n$(cat $TRIGGER_PAYLOAD)\n---\n\n").concat(identity(ctx), "\n").concat(goldenRules(ctx), "\n").concat(selfMentionGuard(ctx), "\n").concat(conversationsIntake(ctx), "
|
|
87
|
+
return "\nYou are a GitLab assistant bot. You receive ONE raw GitLab webhook JSON payload.\n\n".concat(header(), "\n---\nevent_json:\n$(cat $TRIGGER_PAYLOAD)\n---\n\n").concat(identity(ctx), "\n").concat(goldenRules(ctx), "\n").concat(selfMentionGuard(ctx), "\n").concat(conversationsIntake(ctx), "\n").concat(eventSelfParse(), "\n").concat(resolveMrPipeline(), "\n").concat(singleRunnerGuard(), "\n").concat(reviewOnDemandFromEvents(), "\n").concat(mrReviewBundle(ctx), "\n").concat(eventWorkflow(ctx), "\n").concat(commentGuidelines(), "\n").concat(mcpOnly(), "\n").concat(outputDiscipline(ctx), "\n");
|
|
83
88
|
};
|
|
84
89
|
exports.getEventPrompt = getEventPrompt;
|
|
85
90
|
var getMergeRequestPrompt = function (ctx) {
|
|
86
|
-
return "\nYou are a GitLab assistant bot reviewing and updating a single Merge Request (MR).\n\n".concat(header(), "\n---\nmerge_request_iid: $CI_MERGE_REQUEST_IID\ntitle: $CI_MERGE_REQUEST_TITLE\ndescription: $CI_MERGE_REQUEST_DESCRIPTION\n---\n\n").concat(mrScope(ctx), "\n").concat(goldenRules(ctx), "\n").concat(selfMentionGuard(ctx), "\n").concat(conversationsIntake(ctx), "
|
|
91
|
+
return "\nYou are a GitLab assistant bot reviewing and updating a single Merge Request (MR).\n\n".concat(header(), "\n---\nmerge_request_iid: $CI_MERGE_REQUEST_IID\ntitle: $CI_MERGE_REQUEST_TITLE\ndescription: $CI_MERGE_REQUEST_DESCRIPTION\n---\n\n").concat(mrScope(ctx), "\n").concat(goldenRules(ctx), "\n").concat(selfMentionGuard(ctx), "\n").concat(conversationsIntake(ctx), "\n").concat(mrWorkflow(), "\n").concat(ciInspection(), "\n").concat(commentGuidelines(), "\n").concat(mcpOnly(), "\n").concat(outputDisciplineMR(ctx), "\n");
|
|
87
92
|
};
|
|
88
93
|
exports.getMergeRequestPrompt = getMergeRequestPrompt;
|
|
@@ -31,6 +31,6 @@ var callClaude = function (_a) {
|
|
|
31
31
|
var prompt = _a.prompt;
|
|
32
32
|
return ["export PROMPT=\"".concat((0, bashEscape_1.escapeNewlines)((0, bashEscape_1.escapeDoubleQuotes)((0, bashEscape_1.escapeBackTicks)(prompt))), "\""),
|
|
33
33
|
//'echo "$PROMPT"',
|
|
34
|
-
"claude -p \"$PROMPT\" --permission-mode acceptEdits --allowedTools \"Bash
|
|
34
|
+
"claude -p \"$PROMPT\" --permission-mode acceptEdits --allowedTools \"Bash Read(*) Edit(*) Write(*) mcp__gitlab\" --verbose --debug"];
|
|
35
35
|
};
|
|
36
36
|
exports.callClaude = callClaude;
|