@catladder/pipeline 3.13.1 → 3.14.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.
Files changed (107) hide show
  1. package/dist/bash/bashEscape.d.ts +2 -0
  2. package/dist/bash/bashEscape.js +9 -1
  3. package/dist/constants.js +1 -1
  4. package/dist/pipeline/agent/createAgentContext.d.ts +6 -0
  5. package/dist/pipeline/agent/createAgentContext.js +141 -0
  6. package/dist/pipeline/agent/createAgentEventJob.d.ts +2 -0
  7. package/dist/pipeline/agent/createAgentEventJob.js +74 -0
  8. package/dist/pipeline/agent/createAgentReviewJob.d.ts +2 -0
  9. package/dist/pipeline/agent/createAgentReviewJob.js +69 -0
  10. package/dist/pipeline/agent/createJobsForAgentContext.d.ts +2 -0
  11. package/dist/pipeline/agent/createJobsForAgentContext.js +12 -0
  12. package/dist/pipeline/agent/prompts.d.ts +10 -0
  13. package/dist/pipeline/agent/prompts.js +66 -0
  14. package/dist/pipeline/agent/shared.d.ts +8 -0
  15. package/dist/pipeline/agent/shared.js +29 -0
  16. package/dist/pipeline/agent/utils.d.ts +3 -0
  17. package/dist/pipeline/agent/utils.js +16 -0
  18. package/dist/pipeline/createAllJobs.d.ts +5 -1
  19. package/dist/pipeline/createAllJobs.js +32 -6
  20. package/dist/pipeline/createMainPipeline.js +10 -5
  21. package/dist/pipeline/gitlab/createGitlabJobs.d.ts +3 -3
  22. package/dist/pipeline/gitlab/createGitlabJobs.js +13 -11
  23. package/dist/pipeline/gitlab/createGitlabPipeline.js +6 -0
  24. package/dist/rules/index.d.ts +1 -0
  25. package/dist/rules/index.js +8 -3
  26. package/dist/tsconfig.tsbuildinfo +1 -1
  27. package/dist/types/agent.d.ts +7 -0
  28. package/dist/types/agent.js +5 -0
  29. package/dist/types/config.d.ts +2 -0
  30. package/dist/types/context.d.ts +7 -0
  31. package/dist/types/index.d.ts +2 -1
  32. package/dist/types/index.js +2 -1
  33. package/dist/types/jobs.d.ts +5 -1
  34. package/dist/types/jobs.js +1 -1
  35. package/examples/__snapshots__/cloud-run-health-check-defaults.test.ts.snap +65 -0
  36. package/examples/__snapshots__/cloud-run-health-check-only-startup.test.ts.snap +65 -0
  37. package/examples/__snapshots__/cloud-run-health-check.test.ts.snap +65 -0
  38. package/examples/__snapshots__/cloud-run-http2.test.ts.snap +65 -0
  39. package/examples/__snapshots__/cloud-run-llama.test.ts.snap +29 -0
  40. package/examples/__snapshots__/cloud-run-memory-limit.test.ts.snap +65 -0
  41. package/examples/__snapshots__/cloud-run-meteor-with-worker.test.ts.snap +65 -0
  42. package/examples/__snapshots__/cloud-run-nextjs.test.ts.snap +65 -0
  43. package/examples/__snapshots__/cloud-run-no-cpu-throttling.test.ts.snap +65 -0
  44. package/examples/__snapshots__/cloud-run-no-service.test.ts.snap +65 -0
  45. package/examples/__snapshots__/cloud-run-non-public.test.ts.snap +65 -0
  46. package/examples/__snapshots__/cloud-run-post-stop-job.test.ts.snap +65 -0
  47. package/examples/__snapshots__/cloud-run-service-custom-vpc-connector.test.ts.snap +65 -0
  48. package/examples/__snapshots__/cloud-run-service-custom-vpc.test.ts.snap +65 -0
  49. package/examples/__snapshots__/cloud-run-service-gen2.test.ts.snap +65 -0
  50. package/examples/__snapshots__/cloud-run-service-increase-timout.test.ts.snap +65 -0
  51. package/examples/__snapshots__/cloud-run-service-with-volumes.test.ts.snap +65 -0
  52. package/examples/__snapshots__/cloud-run-storybook.test.ts.snap +53 -0
  53. package/examples/__snapshots__/cloud-run-with-agents.test.ts.snap +1576 -0
  54. package/examples/__snapshots__/cloud-run-with-gpu.test.ts.snap +65 -0
  55. package/examples/__snapshots__/cloud-run-with-ngnix.test.ts.snap +65 -0
  56. package/examples/__snapshots__/cloud-run-with-sql-legacy-jobs.test.ts.snap +65 -0
  57. package/examples/__snapshots__/cloud-run-with-sql-multiple-dbs.test.ts.snap +169 -0
  58. package/examples/__snapshots__/cloud-run-with-sql-reuse-db.test.ts.snap +117 -0
  59. package/examples/__snapshots__/cloud-run-with-sql.test.ts.snap +65 -0
  60. package/examples/__snapshots__/cloud-run-with-worker.test.ts.snap +65 -0
  61. package/examples/__snapshots__/custom-build-job-with-tests.test.ts.snap +65 -0
  62. package/examples/__snapshots__/custom-build-job.test.ts.snap +53 -0
  63. package/examples/__snapshots__/custom-deploy.test.ts.snap +59 -0
  64. package/examples/__snapshots__/custom-envs.test.ts.snap +63 -0
  65. package/examples/__snapshots__/custom-sbom-java.test.ts.snap +53 -0
  66. package/examples/__snapshots__/custom-verify-job.test.ts.snap +73 -0
  67. package/examples/__snapshots__/git-submodule.test.ts.snap +65 -0
  68. package/examples/__snapshots__/kubernetes-application-customization.test.ts.snap +73 -0
  69. package/examples/__snapshots__/kubernetes-with-cloud-sql.test.ts.snap +73 -0
  70. package/examples/__snapshots__/kubernetes-with-jobs.test.ts.snap +133 -0
  71. package/examples/__snapshots__/kubernetes-with-mongodb.test.ts.snap +73 -0
  72. package/examples/__snapshots__/local-dot-env.test.ts.snap +65 -0
  73. package/examples/__snapshots__/meteor-kubernetes.test.ts.snap +73 -0
  74. package/examples/__snapshots__/multiline-var.test.ts.snap +177 -0
  75. package/examples/__snapshots__/native-app.test.ts.snap +101 -0
  76. package/examples/__snapshots__/node-build-with-custom-image.test.ts.snap +65 -0
  77. package/examples/__snapshots__/node-build-with-docker-additions.test.ts.snap +65 -0
  78. package/examples/__snapshots__/override-secrets.test.ts.snap +65 -0
  79. package/examples/__snapshots__/rails-k8s-with-worker-dockerfile.test.ts.snap +65 -0
  80. package/examples/__snapshots__/rails-k8s-with-worker.test.ts.snap +65 -0
  81. package/examples/__snapshots__/referencing-other-vars.test.ts.snap +177 -0
  82. package/examples/__snapshots__/wait-for-other-deploy.test.ts.snap +85 -0
  83. package/examples/__snapshots__/workspace-api-www-turbo-cache.test.ts.snap +97 -0
  84. package/examples/__snapshots__/workspace-api-www.test.ts.snap +97 -0
  85. package/examples/cloud-run-with-agents.test.ts +11 -0
  86. package/examples/cloud-run-with-agents.ts +36 -0
  87. package/package.json +1 -1
  88. package/src/bash/bashEscape.ts +6 -0
  89. package/src/pipeline/__tests__/__snapshots__/getPipelineStages.test.ts.snap +9 -0
  90. package/src/pipeline/agent/createAgentContext.ts +19 -0
  91. package/src/pipeline/agent/createAgentEventJob.ts +35 -0
  92. package/src/pipeline/agent/createAgentReviewJob.ts +33 -0
  93. package/src/pipeline/agent/createJobsForAgentContext.ts +7 -0
  94. package/src/pipeline/agent/prompts.ts +233 -0
  95. package/src/pipeline/agent/shared.ts +36 -0
  96. package/src/pipeline/agent/utils.ts +9 -0
  97. package/src/pipeline/createAllJobs.ts +20 -1
  98. package/src/pipeline/createJobsForComponent.ts +1 -0
  99. package/src/pipeline/createMainPipeline.ts +19 -4
  100. package/src/pipeline/gitlab/createGitlabJobs.ts +39 -30
  101. package/src/pipeline/gitlab/createGitlabPipeline.ts +8 -0
  102. package/src/rules/index.ts +7 -0
  103. package/src/types/agent.ts +7 -0
  104. package/src/types/config.ts +3 -0
  105. package/src/types/context.ts +8 -0
  106. package/src/types/index.ts +1 -0
  107. package/src/types/jobs.ts +6 -0
@@ -15,6 +15,8 @@ export declare const escapeString: (value: string | null | undefined, {
15
15
  export declare const escapeBashExpression: (value: BashExpression, options: EscapeOptions) => BashExpression;
16
16
  export declare const escapeDoubleQuotes: (value: string | null | undefined) => string | undefined;
17
17
  export declare const escapeSingleQuotes: (value: string | null | undefined) => string | undefined;
18
+ export declare const escapeBackTicks: (value: string | null | undefined) => string | undefined;
19
+ export declare const escapeNewlines: (value: string | null | undefined) => string | undefined;
18
20
  export type EscapeForDotEnvOptions = {
19
21
  quoteMode: "auto" | "always";
20
22
  };
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.escapeForDotEnv = exports.escapeSingleQuotes = exports.escapeDoubleQuotes = exports.escapeBashExpression = exports.escapeString = exports.bashEscape = void 0;
6
+ exports.escapeForDotEnv = exports.escapeNewlines = exports.escapeBackTicks = exports.escapeSingleQuotes = exports.escapeDoubleQuotes = exports.escapeBashExpression = exports.escapeString = exports.bashEscape = void 0;
7
7
  var globalScriptFunctions_1 = require("../globalScriptFunctions");
8
8
  var VariableValueContainingReferences_1 = require("../variables/VariableValueContainingReferences");
9
9
  var BashExpression_1 = require("./BashExpression");
@@ -49,6 +49,14 @@ var escapeSingleQuotes = function (value) {
49
49
  return value === null || value === void 0 ? void 0 : value.toString().replace(/'/g, "\\'");
50
50
  };
51
51
  exports.escapeSingleQuotes = escapeSingleQuotes;
52
+ var escapeBackTicks = function (value) {
53
+ return value === null || value === void 0 ? void 0 : value.toString().replace(/`/g, "\\`");
54
+ };
55
+ exports.escapeBackTicks = escapeBackTicks;
56
+ var escapeNewlines = function (value) {
57
+ return value === null || value === void 0 ? void 0 : value.toString().replace(/\n/g, "\\n");
58
+ };
59
+ exports.escapeNewlines = escapeNewlines;
52
60
  /**
53
61
  *
54
62
  * escape env vars for .env files.
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-13-1-90f03516" || "latest";
7
+ exports.PIPELINE_IMAGE_TAG = "v3-14-0-fd3c74b3" || "latest";
8
8
  exports.DOCKER_REGISTRY = "git.panter.ch:5001/catladder/catladder" || "git.panter.ch:5001/catladder/catladder";
@@ -0,0 +1,6 @@
1
+ import type { Config } from "../../types";
2
+ import type { AgentContext } from "../../types/context";
3
+ export declare const createAgentContext: (ctx: {
4
+ agentName: string;
5
+ config: Config;
6
+ }) => Promise<AgentContext>;
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+
3
+ var __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) {
5
+ return value instanceof P ? value : new P(function (resolve) {
6
+ resolve(value);
7
+ });
8
+ }
9
+ return new (P || (P = Promise))(function (resolve, reject) {
10
+ function fulfilled(value) {
11
+ try {
12
+ step(generator.next(value));
13
+ } catch (e) {
14
+ reject(e);
15
+ }
16
+ }
17
+ function rejected(value) {
18
+ try {
19
+ step(generator["throw"](value));
20
+ } catch (e) {
21
+ reject(e);
22
+ }
23
+ }
24
+ function step(result) {
25
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
26
+ }
27
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
28
+ });
29
+ };
30
+ var __generator = this && this.__generator || function (thisArg, body) {
31
+ var _ = {
32
+ label: 0,
33
+ sent: function () {
34
+ if (t[0] & 1) throw t[1];
35
+ return t[1];
36
+ },
37
+ trys: [],
38
+ ops: []
39
+ },
40
+ f,
41
+ y,
42
+ t,
43
+ g;
44
+ return g = {
45
+ next: verb(0),
46
+ "throw": verb(1),
47
+ "return": verb(2)
48
+ }, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
49
+ return this;
50
+ }), g;
51
+ function verb(n) {
52
+ return function (v) {
53
+ return step([n, v]);
54
+ };
55
+ }
56
+ function step(op) {
57
+ if (f) throw new TypeError("Generator is already executing.");
58
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
59
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
60
+ if (y = 0, t) op = [op[0] & 2, t.value];
61
+ switch (op[0]) {
62
+ case 0:
63
+ case 1:
64
+ t = op;
65
+ break;
66
+ case 4:
67
+ _.label++;
68
+ return {
69
+ value: op[1],
70
+ done: false
71
+ };
72
+ case 5:
73
+ _.label++;
74
+ y = op[1];
75
+ op = [0];
76
+ continue;
77
+ case 7:
78
+ op = _.ops.pop();
79
+ _.trys.pop();
80
+ continue;
81
+ default:
82
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
83
+ _ = 0;
84
+ continue;
85
+ }
86
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
87
+ _.label = op[1];
88
+ break;
89
+ }
90
+ if (op[0] === 6 && _.label < t[1]) {
91
+ _.label = t[1];
92
+ t = op;
93
+ break;
94
+ }
95
+ if (t && _.label < t[2]) {
96
+ _.label = t[2];
97
+ _.ops.push(op);
98
+ break;
99
+ }
100
+ if (t[2]) _.ops.pop();
101
+ _.trys.pop();
102
+ continue;
103
+ }
104
+ op = body.call(thisArg, _);
105
+ } catch (e) {
106
+ op = [6, e];
107
+ y = 0;
108
+ } finally {
109
+ f = t = 0;
110
+ }
111
+ if (op[0] & 5) throw op[1];
112
+ return {
113
+ value: op[0] ? op[1] : void 0,
114
+ done: true
115
+ };
116
+ }
117
+ };
118
+ Object.defineProperty(exports, "__esModule", {
119
+ value: true
120
+ });
121
+ exports.createAgentContext = void 0;
122
+ var createAgentContext = function (ctx) {
123
+ return __awaiter(void 0, void 0, void 0, function () {
124
+ var agentConfig;
125
+ var _a;
126
+ return __generator(this, function (_b) {
127
+ agentConfig = (_a = ctx.config.agents) === null || _a === void 0 ? void 0 : _a[ctx.agentName];
128
+ if (!agentConfig) {
129
+ throw new Error("Agent ".concat(ctx.agentName, " not found in config"));
130
+ }
131
+ return [2 /*return*/, {
132
+ type: "agent",
133
+ name: ctx.agentName,
134
+ //env: ctx.env,
135
+ fullConfig: ctx.config,
136
+ agentConfig: agentConfig
137
+ }];
138
+ });
139
+ });
140
+ };
141
+ exports.createAgentContext = createAgentContext;
@@ -0,0 +1,2 @@
1
+ import type { AgentContext, CatladderJob } from "../../types";
2
+ export declare const createAgentEventJob: (context: AgentContext) => CatladderJob;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ var __assign = this && this.__assign || function () {
4
+ __assign = Object.assign || function (t) {
5
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
6
+ s = arguments[i];
7
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __read = this && this.__read || function (o, n) {
14
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
15
+ if (!m) return o;
16
+ var i = m.call(o),
17
+ r,
18
+ ar = [],
19
+ e;
20
+ try {
21
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
22
+ } catch (error) {
23
+ e = {
24
+ error: error
25
+ };
26
+ } finally {
27
+ try {
28
+ if (r && !r.done && (m = i["return"])) m.call(i);
29
+ } finally {
30
+ if (e) throw e.error;
31
+ }
32
+ }
33
+ return ar;
34
+ };
35
+ var __spreadArray = this && this.__spreadArray || function (to, from, pack) {
36
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
37
+ if (ar || !(i in from)) {
38
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
39
+ ar[i] = from[i];
40
+ }
41
+ }
42
+ return to.concat(ar || Array.prototype.slice.call(from));
43
+ };
44
+ Object.defineProperty(exports, "__esModule", {
45
+ value: true
46
+ });
47
+ exports.createAgentEventJob = void 0;
48
+ var prompts_1 = require("./prompts");
49
+ var shared_1 = require("./shared");
50
+ var utils_1 = require("./utils");
51
+ var createAgentEventJob = function (context) {
52
+ var baseJob = (0, shared_1.createBaseAgentJob)(context);
53
+ // unfortunatly, we need to manage both, because the "@mention"-feature only works with the username
54
+ var agentUserId = (0, utils_1.getAgentUserId)(context);
55
+ var agentUserName = (0, utils_1.getAgentUserName)(context);
56
+ return __assign(__assign({
57
+ interruptible: false
58
+ }, baseJob), {
59
+ variables: __assign({}, baseJob.variables),
60
+ name: context.name + "-agent-event",
61
+ rules: [{
62
+ if: "$CI_PIPELINE_SOURCE == \"trigger\" && ($ASSIGNEE_USER_ID == ".concat(agentUserId, " || $OBJECT_DESCRIPTION =~ /@").concat(agentUserName, "/)"),
63
+ when: "always"
64
+ }, {
65
+ when: "never"
66
+ }],
67
+ script: __spreadArray(__spreadArray([], __read(shared_1.baseSetupScript), false), __read((0, shared_1.callClaude)({
68
+ prompt: (0, prompts_1.getEventPrompt)({
69
+ agentUserName: agentUserName
70
+ })
71
+ })), false)
72
+ });
73
+ };
74
+ exports.createAgentEventJob = createAgentEventJob;
@@ -0,0 +1,2 @@
1
+ import type { AgentContext, CatladderJob } from "../../types";
2
+ export declare const createAgentReviewJob: (context: AgentContext) => CatladderJob;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ var __assign = this && this.__assign || function () {
4
+ __assign = Object.assign || function (t) {
5
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
6
+ s = arguments[i];
7
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __read = this && this.__read || function (o, n) {
14
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
15
+ if (!m) return o;
16
+ var i = m.call(o),
17
+ r,
18
+ ar = [],
19
+ e;
20
+ try {
21
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
22
+ } catch (error) {
23
+ e = {
24
+ error: error
25
+ };
26
+ } finally {
27
+ try {
28
+ if (r && !r.done && (m = i["return"])) m.call(i);
29
+ } finally {
30
+ if (e) throw e.error;
31
+ }
32
+ }
33
+ return ar;
34
+ };
35
+ var __spreadArray = this && this.__spreadArray || function (to, from, pack) {
36
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
37
+ if (ar || !(i in from)) {
38
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
39
+ ar[i] = from[i];
40
+ }
41
+ }
42
+ return to.concat(ar || Array.prototype.slice.call(from));
43
+ };
44
+ Object.defineProperty(exports, "__esModule", {
45
+ value: true
46
+ });
47
+ exports.createAgentReviewJob = void 0;
48
+ var rules_1 = require("../../rules");
49
+ var prompts_1 = require("./prompts");
50
+ var shared_1 = require("./shared");
51
+ var utils_1 = require("./utils");
52
+ var createAgentReviewJob = function (context) {
53
+ var baseJob = (0, shared_1.createBaseAgentJob)(context);
54
+ var agentUserName = (0, utils_1.getAgentUserName)(context);
55
+ return __assign(__assign({}, baseJob), {
56
+ name: context.name + "-agent-review",
57
+ rules: [__assign(__assign({}, rules_1.RULE_IS_MERGE_REQUEST), {
58
+ when: "always"
59
+ }), {
60
+ when: "never"
61
+ }],
62
+ script: __spreadArray(__spreadArray([], __read(shared_1.baseSetupScript), false), __read((0, shared_1.callClaude)({
63
+ prompt: (0, prompts_1.getMergeRequestPrompt)({
64
+ agentUserName: agentUserName
65
+ })
66
+ })), false)
67
+ });
68
+ };
69
+ exports.createAgentReviewJob = createAgentReviewJob;
@@ -0,0 +1,2 @@
1
+ import type { AgentContext } from "../../types";
2
+ export declare const createJobsForAgentContext: (context: AgentContext) => import("../../types").CatladderJob[];
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createJobsForAgentContext = void 0;
7
+ var createAgentEventJob_1 = require("./createAgentEventJob");
8
+ var createAgentReviewJob_1 = require("./createAgentReviewJob");
9
+ var createJobsForAgentContext = function (context) {
10
+ return [(0, createAgentEventJob_1.createAgentEventJob)(context), (0, createAgentReviewJob_1.createAgentReviewJob)(context)];
11
+ };
12
+ exports.createJobsForAgentContext = createJobsForAgentContext;
@@ -0,0 +1,10 @@
1
+ type Ctx = {
2
+ agentUserName: string;
3
+ };
4
+ export declare const getEventPrompt: ({
5
+ agentUserName
6
+ }: Ctx) => string;
7
+ export declare const getMergeRequestPrompt: ({
8
+ agentUserName
9
+ }: Ctx) => string;
10
+ export {};
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getMergeRequestPrompt = exports.getEventPrompt = void 0;
7
+ var header = function () {
8
+ return "\nProject ID: $CI_PROJECT_ID\nGitLab Host: $CI_SERVER_URL\n";
9
+ };
10
+ var identity = function (_a) {
11
+ var agentUserName = _a.agentUserName;
12
+ return "\n## Identity\n- Your GitLab username is \"".concat(agentUserName, "\".\n");
13
+ };
14
+ var goldenRules = function (_a) {
15
+ var agentUserName = _a.agentUserName;
16
+ return "\n## Golden Rules\n- Use the `gitlab-mcp` tool for ALL GitLab actions. If a needed action is missing, use GitLab REST/GraphQL API directly as a fallback.\n- NEVER mention yourself (\"@".concat(agentUserName, "\").\n- NEVER push to main/default or any protected branch. Always create a new branch and open a Merge Request (MR).\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");
17
+ };
18
+ var commentGuidelines = function () {
19
+ return "\n## Comment Guidelines (flexible, not verbatim)\n- Keep tone professional, friendly, and concise.\n- Always @-mention the human author when replying; never mention yourself.\n- Acknowledgements: confirm you saw the request and you\u2019ll handle it.\n- MR updates: acknowledge feedback and say you\u2019ll apply/have applied the change.\n- Q&A: answer directly first; add context/links only if useful.\n- Avoid repeating identical boilerplate across comments.\n";
20
+ };
21
+ var mcpAndApi = function () {
22
+ return "\n## Tools & API (MCP-first, REST/GraphQL fallback)\nUse these `gitlab-mcp` capabilities when available (names illustrative\u2014match the actual tool schema):\n\n- **Comments**\n - `gitlab-mcp.comment.create({ project_id: $CI_PROJECT_ID, target: \"issue\"|\"mr\", iid, body })`\n\n- **Branch**\n - `gitlab-mcp.branch.create({ project_id: $CI_PROJECT_ID, from: \"<default_branch>\", name: \"<source_branch>\" })`\n\n- **Commits & push**\n - `gitlab-mcp.commit.push({ project_id: $CI_PROJECT_ID, branch: \"<source_branch>\", message, files: [{ path, content | patch }] })`\n\n- **Merge Requests**\n - `gitlab-mcp.merge_request.create({ project_id: $CI_PROJECT_ID, source_branch, target_branch: \"<default_branch>\", title, description, assign_to_self: true })`\n - `gitlab-mcp.merge_request.update({ project_id: $CI_PROJECT_ID, mr_iid, ... })`\n - `gitlab-mcp.merge_request.rebase({ project_id: $CI_PROJECT_ID, mr_iid, onto: \"<default_branch>\" })`\n\n- **Read/verify**\n - `gitlab-mcp.project.get({ project_id: $CI_PROJECT_ID })` \u2192 default branch\n - `gitlab-mcp.repo.compare({ project_id: $CI_PROJECT_ID, from: \"<default_branch>\", to: \"<source_branch>\" })`\n - `gitlab-mcp.repo.branch.get({ project_id: $CI_PROJECT_ID, name: \"<source_branch>\" })`\n - `gitlab-mcp.repo.commits.list({ project_id: $CI_PROJECT_ID, ref_name: \"<source_branch>\", per_page: 1 })`\n\n### Fallback: Direct GitLab API\nIf MCP lacks an operation, call GitLab\u2019s REST/GraphQL API directly.\n\n- **Authentication** \n Use the environment variable `GITLAB_PERSONAL_ACCESS_TOKEN`. \n Send it in the HTTP header:\n ```\n Private-Token: $GITLAB_PERSONAL_ACCESS_TOKEN\n ```\n\n- **Host & project variables**\n - API base URL: `$CI_SERVER_URL/api/v4`\n - Project ID: `$CI_PROJECT_ID`\n\n- **Examples**\n - Get project (default branch): \n `GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID`\n - Get/create branch: \n `GET|POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/repository/branches`\n - Compare refs: \n `GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/repository/compare?from=<default>&to=<source>`\n - List commits: \n `GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/repository/commits?ref_name=<branch>&per_page=1`\n - Create comment on issue/MR: \n `POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/issues/:iid/notes` \n `POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests/:iid/notes`\n - Create MR: \n `POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests`\n - Get MR changes: \n `GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests/:iid/changes`\n";
23
+ };
24
+ var outputDiscipline = function (_a) {
25
+ var agentUserName = _a.agentUserName;
26
+ return "\n## Output Discipline\n- Prefer `gitlab-mcp` tool calls. If unavailable, output direct API requests (endpoint, method, headers, JSON body).\n- Keep comments concise and professional.\n- Never include \"@".concat(agentUserName, "\" in any body.\n");
27
+ };
28
+ // --- Event-specific sections ---
29
+ var eventSelfParse = function () {
30
+ return "\n## Self-Parse the Raw Payload (no preprocessing available)\nFrom `event_json`, extract:\n- kind: \"issue\" | \"merge_request\" | \"note\"\n- target + iid from URL:\n - `/-/issues/<n>` \u2192 target=\"issue\", iid=<n>\n - `/-/merge_requests/<n>` \u2192 target=\"mr\", iid=<n>\n- note_id if present (`#note_<id>`)\n- description/body text, state, author `user_username`, timestamps\n- project id/path; detect default branch via tool/API when needed\n\nIf any key is missing, choose the safest minimal action or briefly explain via a comment.\n";
31
+ };
32
+ var eventWorkflow = function () {
33
+ return "\n## High-Reliability Workflow (sequence + postconditions)\nFollow this order for any change work:\n\n1) **Acknowledge** with a short comment on the issue/MR thread.\n2) **Discover default branch** (e.g., \"main\") via MCP or API.\n3) **Create a working branch** from default (stable name, e.g., `fix/issue-<iid>-<slug>` or `feat/issue-<iid>-<slug>`).\n4) **Write changes \u2192 commit \u2192 push to remote branch.**\n5) **Verify push landed**:\n - Fetch latest commit on `source_branch`; record its short SHA.\n - Compare default vs `source_branch` and ensure `diffs.length > 0`.\n6) **Create or update MR** ONLY if there is a non-empty diff.\n - Include `Closes #<issue_iid>` in MR description when applicable.\n - Assign yourself to the MR.\n7) **Follow-up comment** with branch name, commit short SHA, files changed count, and MR link.\n8) **If verification fails**:\n - Do NOT create the MR.\n - Comment the exact failure and retry once with a fresh branch name. If still failing, comment and stop.\n\nFor Q&A-only (no code changes), just post a concise, helpful answer on the same issue/MR.\n";
34
+ };
35
+ // --- MR-specific sections ---
36
+ var mrScope = function (_a) {
37
+ var agentUserName = _a.agentUserName;
38
+ return "\n## Identity & Scope\n- Your GitLab username is \"".concat(agentUserName, "\".\n- This prompt runs in the context of ONE MR (no webhook).\n- You may review, comment, rebase, and push updates **to the MR's source branch**.\n- You must **never merge** the MR yourself.\n");
39
+ };
40
+ var mrWorkflow = function () {
41
+ return "\n## High-Reliability Review Workflow\nFollow this sequence with verification at each step:\n\n1) **Collect context**\n - Get MR metadata (source_branch, target_branch, state, draft/WIP).\n - Fetch the full changeset/diffs and open discussions (notes, threads, unresolved discussions).\n - Read existing reviews/comments to avoid duplication.\n - (Optional) Fetch recent CI pipeline(s) for this MR SHA/branch).\n\n2) **Code review**\n - Identify required changes (bugs, tests, style, security, perf, docs).\n - If no meaningful changes are needed:\n - Post a concise review comment summarizing findings.\n - Ask for review by a **recent active human contributor** (not you).\n\n3) **If changes are needed**\n - Post a short acknowledgment comment on the MR.\n - **Rebase** the MR onto the target/default branch (resolve trivial conflicts).\n - Implement minimal, safe changes; keep commits small and clear.\n - **Push** to the MR's **source_branch**.\n - **Verify push landed** (latest commit short SHA; compare target vs source shows diffs > 0).\n - Comment summarizing what changed and why.\n\n4) **CI pipeline**\n - Check pipeline status for the new commit on the MR branch.\n - Retry/re-run if allowed on flaky failures; fix minimal issues; push again if needed.\n - If still failing, comment with failure summary and next steps.\n\n5) **Assign human reviewer if ready**\n - If discussions are resolved and CI is passing (or running), request review from a recent active human contributor (not you).\n\n6) **Stdout summary**\n - Print concise summary: commits pushed (short SHAs), files changed count, discussions resolved/left, CI status, and requested reviewers.\n";
42
+ };
43
+ var fallbackApiAuth = function () {
44
+ return "\n## Fallback API Auth (if MCP lacks a method)\n- Base URL: `$CI_SERVER_URL/api/v4`\n- Project: `$CI_PROJECT_ID`\n- Header: `Private-Token: $GITLAB_PERSONAL_ACCESS_TOKEN`\n";
45
+ };
46
+ // ---------- Public builders ----------
47
+ var getEventPrompt = function (_a) {
48
+ var agentUserName = _a.agentUserName;
49
+ 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({
50
+ agentUserName: agentUserName
51
+ }), "\n").concat(goldenRules({
52
+ agentUserName: agentUserName
53
+ }), "\n").concat(eventSelfParse(), "\n").concat(eventWorkflow(), "\n").concat(commentGuidelines(), "\n").concat(mcpAndApi(), "\n").concat(outputDiscipline({
54
+ agentUserName: agentUserName
55
+ }), "\n");
56
+ };
57
+ exports.getEventPrompt = getEventPrompt;
58
+ var getMergeRequestPrompt = function (_a) {
59
+ var agentUserName = _a.agentUserName;
60
+ 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({
61
+ agentUserName: agentUserName
62
+ }), "\n").concat(goldenRules({
63
+ agentUserName: agentUserName
64
+ }), "\n").concat(mrWorkflow(), "\n").concat(commentGuidelines(), "\n").concat(mcpAndApi(), "\n").concat(fallbackApiAuth(), "\n## Output Discipline (MR)\n- Prefer `gitlab-mcp` tool calls; if unavailable, provide explicit REST calls (method, url, headers, body).\n- At the end, print a **plain-text** summary to STDOUT including:\n - `source_branch` and `target_branch`\n - commits pushed (short SHAs)\n - number of files changed\n - CI status/result\n - reviewers requested (if any)\n- Do **not** merge the MR yourself under any circumstance.\n");
65
+ };
66
+ exports.getMergeRequestPrompt = getMergeRequestPrompt;
@@ -0,0 +1,8 @@
1
+ import type { AgentContext, CatladderJob } from "../../types";
2
+ export declare const createBaseAgentJob: (context: AgentContext) => Omit<CatladderJob, "name" | "rules" | "script">;
3
+ export declare const baseSetupScript: string[];
4
+ export declare const callClaude: ({
5
+ prompt
6
+ }: {
7
+ prompt: string;
8
+ }) => string[];
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.callClaude = exports.baseSetupScript = exports.createBaseAgentJob = void 0;
7
+ var bashEscape_1 = require("../../bash/bashEscape");
8
+ var createBaseAgentJob = function (context) {
9
+ return {
10
+ stage: "agents",
11
+ envMode: "none",
12
+ image: "node:24-alpine3.21",
13
+ variables: {
14
+ MAX_MCP_OUTPUT_TOKENS: "75000",
15
+ GITLAB_PERSONAL_ACCESS_TOKEN: "$AGENT_GITLAB_PERSONAL_ACCESS_TOKEN",
16
+ // TODO: we don't have global secret keys to configure yet
17
+ GITLAB_API_URL: "$CI_API_V4_URL"
18
+ }
19
+ };
20
+ };
21
+ exports.createBaseAgentJob = createBaseAgentJob;
22
+ exports.baseSetupScript = ["apk update", "apk add --no-cache git curl bash", "npm install -g @anthropic-ai/claude-code", "claude mcp add gitlab --env GITLAB_PERSONAL_ACCESS_TOKEN=$GITLAB_PERSONAL_ACCESS_TOKEN --env GITLAB_API_URL=$GITLAB_API_URL -- npx -y @zereight/mcp-gitlab"];
23
+ var callClaude = function (_a) {
24
+ var prompt = _a.prompt;
25
+ return ["export PROMPT=\"".concat((0, bashEscape_1.escapeNewlines)((0, bashEscape_1.escapeDoubleQuotes)((0, bashEscape_1.escapeBackTicks)(prompt))), "\""),
26
+ //'echo "$PROMPT"',
27
+ "claude -p \"$PROMPT\" --permission-mode acceptEdits --allowedTools \"Bash(*) Read(*) Edit(*) Write(*) mcp__gitlab\" --verbose --debug"];
28
+ };
29
+ exports.callClaude = callClaude;
@@ -0,0 +1,3 @@
1
+ import type { AgentContext } from "../../types";
2
+ export declare const getAgentUserName: (context: AgentContext) => string;
3
+ export declare const getAgentUserId: (context: AgentContext) => string;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getAgentUserId = exports.getAgentUserName = void 0;
7
+ var getAgentUserName = function (context) {
8
+ var _a, _b;
9
+ return (_b = (_a = context.agentConfig.agentUser) === null || _a === void 0 ? void 0 : _a.username) !== null && _b !== void 0 ? _b : "agent.claude";
10
+ };
11
+ exports.getAgentUserName = getAgentUserName;
12
+ var getAgentUserId = function (context) {
13
+ var _a, _b;
14
+ return (_b = (_a = context.agentConfig.agentUser) === null || _a === void 0 ? void 0 : _a.userId) !== null && _b !== void 0 ? _b : "$DEFAULT_AGENT_USER_ID";
15
+ };
16
+ exports.getAgentUserId = getAgentUserId;
@@ -1,5 +1,5 @@
1
1
  import type { CreateAllComponentsContextProps } from "../context/createAllComponentsContext";
2
- import type { ComponentContext, WorkspaceContext } from "../types";
2
+ import type { AgentContext, ComponentContext, WorkspaceContext } from "../types";
3
3
  import type { CatladderJob } from "../types/jobs";
4
4
  export type AllCatladderJobs = {
5
5
  workspaces: Array<{
@@ -10,6 +10,10 @@ export type AllCatladderJobs = {
10
10
  context: ComponentContext;
11
11
  jobs: Array<CatladderJob>;
12
12
  }>;
13
+ agents: Array<{
14
+ context: AgentContext;
15
+ jobs: Array<CatladderJob>;
16
+ }>;
13
17
  };
14
18
  export declare const createAllJobs: ({
15
19
  config,
@@ -155,16 +155,18 @@ var createWorkspaceContext_1 = require("../context/createWorkspaceContext");
155
155
  var types_1 = require("../types");
156
156
  var createJobsForComponent_1 = require("./createJobsForComponent");
157
157
  var createJobsForWorkspace_1 = require("./createJobsForWorkspace");
158
+ var createJobsForAgentContext_1 = require("./agent/createJobsForAgentContext");
159
+ var createAgentContext_1 = require("./agent/createAgentContext");
158
160
  var createAllJobs = function (_a) {
159
161
  return __awaiter(void 0, [_a], void 0, function (_b) {
160
162
  var allComponentsContext;
161
163
  var _c;
162
- var _d;
164
+ var _d, _e;
163
165
  var config = _b.config,
164
166
  trigger = _b.trigger,
165
167
  pipelineType = _b.pipelineType;
166
- return __generator(this, function (_e) {
167
- switch (_e.label) {
168
+ return __generator(this, function (_f) {
169
+ switch (_f.label) {
168
170
  case 0:
169
171
  return [4 /*yield*/, (0, createAllComponentsContext_1.createAllComponentsContext)({
170
172
  config: config,
@@ -172,7 +174,7 @@ var createAllJobs = function (_a) {
172
174
  pipelineType: pipelineType
173
175
  })];
174
176
  case 1:
175
- allComponentsContext = _e.sent();
177
+ allComponentsContext = _f.sent();
176
178
  _c = {};
177
179
  return [4 /*yield*/, Promise.all(Object.keys((_d = config.builds) !== null && _d !== void 0 ? _d : {}).map(function (workspaceName) {
178
180
  return __awaiter(void 0, void 0, void 0, function () {
@@ -223,12 +225,36 @@ var createAllJobs = function (_a) {
223
225
  return f.flat();
224
226
  })];
225
227
  case 2:
226
- return [2 /*return*/, (_c.workspaces = _e.sent(), _c.components = allComponentsContext.map(function (context) {
228
+ _c.workspaces = _f.sent(), _c.components = allComponentsContext.map(function (context) {
227
229
  return {
228
230
  context: context,
229
231
  jobs: (0, createJobsForComponent_1.createJobsForComponentContext)(context)
230
232
  };
231
- }), _c)];
233
+ });
234
+ return [4 /*yield*/, Promise.all(Object.keys((_e = config.agents) !== null && _e !== void 0 ? _e : {}).map(function (agentName) {
235
+ return __awaiter(void 0, void 0, void 0, function () {
236
+ var context;
237
+ return __generator(this, function (_a) {
238
+ switch (_a.label) {
239
+ case 0:
240
+ return [4 /*yield*/, (0, createAgentContext_1.createAgentContext)({
241
+ agentName: agentName,
242
+ config: config
243
+ })];
244
+ case 1:
245
+ context = _a.sent();
246
+ return [2 /*return*/, {
247
+ context: context,
248
+ jobs: (0, createJobsForAgentContext_1.createJobsForAgentContext)(context)
249
+ }];
250
+ }
251
+ });
252
+ });
253
+ })).then(function (f) {
254
+ return f.flat();
255
+ })];
256
+ case 3:
257
+ return [2 /*return*/, (_c.agents = _f.sent(), _c)];
232
258
  }
233
259
  });
234
260
  });
@@ -169,7 +169,7 @@ var createGitlabPipeline_1 = require("./gitlab/createGitlabPipeline");
169
169
  var gitlabReleaseJobs_1 = require("./gitlab/gitlabReleaseJobs");
170
170
  var createMainPipeline = function (pipelineType, config) {
171
171
  return __awaiter(void 0, void 0, void 0, function () {
172
- var stages, allJobsPerTrigger, allWorkspaceJobs, allComponentJobs, allJobs;
172
+ var stages, allJobsPerTrigger, allWorkspaceJobs, allComponentJobs, allGlobalJobs, allJobs;
173
173
  return __generator(this, function (_a) {
174
174
  switch (_a.label) {
175
175
  case 0:
@@ -231,7 +231,11 @@ var createMainPipeline = function (pipelineType, config) {
231
231
  });
232
232
  return aIndex - bIndex;
233
233
  });
234
- allJobs = __spreadArray(__spreadArray([], __read(allWorkspaceJobs), false), __read(allComponentJobs), false).reduce(function (acc, _a) {
234
+ allGlobalJobs = allJobsPerTrigger.filter(function (j) {
235
+ var _a;
236
+ return ((_a = j.context) === null || _a === void 0 ? void 0 : _a.type) === "agent";
237
+ });
238
+ allJobs = __spreadArray(__spreadArray(__spreadArray([], __read(allWorkspaceJobs), false), __read(allComponentJobs), false), __read(allGlobalJobs), false).reduce(function (acc, _a) {
235
239
  var _b, _c;
236
240
  var gitlabJob = _a.gitlabJob,
237
241
  name = _a.name,
@@ -274,10 +278,11 @@ function getGitlabRulesForTrigger(trigger) {
274
278
  // taggedRelease: on tag
275
279
  switch (trigger) {
276
280
  case "mainBranch":
277
- return [rules_1.RULE_IS_MAIN_BRANCH_AND_NOT_RELEASE_COMMIT];
281
+ return [rules_1.RULE_NEVER_ON_AGENT_TRIGGER, rules_1.RULE_IS_MAIN_BRANCH_AND_NOT_RELEASE_COMMIT];
278
282
  case "mr":
279
- return [rules_1.RULE_IS_MERGE_REQUEST];
283
+ return [rules_1.RULE_NEVER_ON_AGENT_TRIGGER, rules_1.RULE_IS_MERGE_REQUEST];
280
284
  case "taggedRelease":
281
- return [rules_1.RULE_IS_TAGGED_RELEASE];
285
+ return [rules_1.RULE_NEVER_ON_AGENT_TRIGGER, rules_1.RULE_IS_TAGGED_RELEASE];
282
286
  }
287
+ throw new Error("".concat(trigger, " is not supported"));
283
288
  }
@@ -1,13 +1,13 @@
1
- import type { Context, GitlabJobDef, GitlabRule } from "../../types";
1
+ import type { AgentContext, Context, GitlabJobDef, GitlabRule } from "../../types";
2
2
  import type { CatladderJob } from "../../types/jobs";
3
3
  import type { AllCatladderJobs } from "../createAllJobs";
4
4
  export type GitlabJobWithContext = {
5
5
  gitlabJob: GitlabJobDef;
6
- context: Context | null;
6
+ context: Context | AgentContext | null;
7
7
  };
8
8
  export type AllGitlabJobs = (GitlabJobWithContext & {
9
9
  name: string;
10
10
  })[];
11
11
  export declare const GITLAB_ENVIRONMENT_URL_VARIABLE = "CL_GITLAB_ENVIRONMENT_URL";
12
- export declare const makeGitlabJob: (context: Context, job: CatladderJob<string>, allJobs: AllCatladderJobs, baseRules?: GitlabRule[]) => [fullName: string, job: GitlabJobDef];
12
+ export declare const makeGitlabJob: (context: Context | AgentContext, job: CatladderJob<string>, allJobs: AllCatladderJobs, baseRules?: GitlabRule[]) => [fullName: string, job: GitlabJobDef];
13
13
  export declare const createGitlabJobs: (allJobs: AllCatladderJobs, baseRules?: GitlabRule[]) => Promise<AllGitlabJobs>;