@cobaltio/cobalt-js 9.3.0-beta.1 → 9.3.0-beta.3

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 (37) hide show
  1. package/.github/pull_request_template.md +48 -0
  2. package/.github/workflows/pr-validation.yml +224 -0
  3. package/CLAUDE.md +10 -0
  4. package/cobalt.d.ts +4 -2
  5. package/cobalt.js +8 -2
  6. package/cobalt.ts +9 -3
  7. package/docs/classes/Cobalt.html +26 -24
  8. package/docs/enums/AuthStatus.html +2 -2
  9. package/docs/enums/AuthType.html +2 -2
  10. package/docs/interfaces/Application.html +14 -14
  11. package/docs/interfaces/AuthConfig.html +5 -5
  12. package/docs/interfaces/CobaltOptions.html +3 -3
  13. package/docs/interfaces/Config.html +2 -2
  14. package/docs/interfaces/ConfigField.html +4 -4
  15. package/docs/interfaces/ConfigPayload.html +4 -4
  16. package/docs/interfaces/ConfigWorkflow.html +2 -2
  17. package/docs/interfaces/ConnectedAccount.html +7 -7
  18. package/docs/interfaces/ExecuteWorkflowPayload.html +5 -5
  19. package/docs/interfaces/Execution.html +2 -2
  20. package/docs/interfaces/ExecutionFilters.html +8 -8
  21. package/docs/interfaces/GetExecutionsParams.html +8 -8
  22. package/docs/interfaces/InputField.html +9 -9
  23. package/docs/interfaces/KeyBasedParams.html +4 -4
  24. package/docs/interfaces/Label.html +3 -3
  25. package/docs/interfaces/OAuthParams.html +5 -5
  26. package/docs/interfaces/PublicWorkflow.html +8 -8
  27. package/docs/interfaces/PublicWorkflowPayload.html +4 -4
  28. package/docs/interfaces/PublicWorkflowsPayload.html +6 -6
  29. package/docs/interfaces/RuleOptions.html +2 -2
  30. package/docs/interfaces/UpdateConfigPayload.html +5 -5
  31. package/docs/interfaces/WorkflowPayload.html +4 -4
  32. package/docs/interfaces/WorkflowPayloadResponse.html +2 -2
  33. package/docs/llms.txt +219 -217
  34. package/docs/types/ExecutionSource.html +1 -1
  35. package/docs/types/ExecutionStatus.html +1 -1
  36. package/docs/types/ExecutionType.html +1 -1
  37. package/package.json +3 -3
@@ -0,0 +1,48 @@
1
+ <!--
2
+ Paste your Linear ticket ID anywhere in this PR.
3
+ Valid formats: DEV-123, closes DEV-123, resolves DEV-456, fixes AIA-789
4
+ -->
5
+ DEV-
6
+
7
+ ### Summary
8
+ <!-- Required. What does this PR do and why? Be specific — mention what changed and the reason for the change. -->
9
+
10
+ ### Approach
11
+ <!--
12
+ Optional — include for new features or large changes.
13
+ - What approach did you take and why?
14
+ - What alternatives did you consider and why were they rejected?
15
+ -->
16
+
17
+ ### Test Plan
18
+ <!--
19
+ Required. Steps for testing these changes — what to do and what to verify.
20
+ At least one checkbox is required.
21
+ -->
22
+
23
+ - [ ]
24
+
25
+ ### Claude Code
26
+ <!--
27
+ If this PR was built with Claude Code, check all that apply.
28
+ Delete this section entirely for PRs not written with Claude Code.
29
+ -->
30
+
31
+ - [ ] Used `superpowers:brainstorming` before starting implementation
32
+ - [ ] Plan file added to `docs/superpowers/plans/`
33
+
34
+ ### Env Changes
35
+ <!--
36
+ Include ONLY if this PR adds, removes, or modifies environment variables.
37
+ Delete this section entirely if there are no env var changes.
38
+
39
+ Format:
40
+ - name: VAR_NAME
41
+ action: add | remove | update
42
+ type: configmap | secret
43
+ value: "example_value" # omit for secrets
44
+ description: What this var does and where it's used
45
+ -->
46
+
47
+ ```yaml
48
+ ```
@@ -0,0 +1,224 @@
1
+ name: PR Validation
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [uat]
6
+ types: [opened, edited, synchronize, reopened]
7
+
8
+ jobs:
9
+ pr-validation:
10
+ name: pr-validation
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ pull-requests: write
14
+ contents: read
15
+
16
+ steps:
17
+ - name: Validate PR template
18
+ uses: actions/github-script@v7
19
+ with:
20
+ script: |
21
+ const pr = context.payload.pull_request;
22
+ const title = pr.title || '';
23
+ const body = pr.body || '';
24
+ const labels = pr.labels.map(l => l.name);
25
+ const isHotfix = labels.includes('hotfix');
26
+
27
+ const errors = [];
28
+ const warnings = [];
29
+
30
+ function section(heading) {
31
+ const esc = heading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
32
+ const re = new RegExp(`#{1,6}\\s+${esc}\\s*\\n([\\s\\S]*?)(?=\\n#{1,6}\\s|$)`, 'i');
33
+ const m = body.match(re);
34
+ if (!m) return null;
35
+ return m[1].replace(/<!--[\s\\S]*?-->/g, '').trim();
36
+ }
37
+
38
+ if (isHotfix) {
39
+ warnings.push(
40
+ 'This PR is labelled **hotfix** — template checks skipped. ' +
41
+ 'Tests are still required.'
42
+ );
43
+ } else {
44
+ const titleRe = /^(feat|fix|chore|refactor|build|perf|breaking|docs|internal)(\(.+\))?: .{3,}/;
45
+ const isInternal = /^internal(\(.+\))?:/.test(title);
46
+ if (!titleRe.test(title)) {
47
+ errors.push(
48
+ '**Title format** — must match `type(scope): short description`\n' +
49
+ ' Valid types: `feat` `fix` `chore` `refactor` `build` `perf` `breaking` `docs` `internal`\n' +
50
+ ' Example: `fix(auth): resolve token expiry on refresh`\n' +
51
+ ' Use `internal` for tooling/process PRs that have no Linear ticket\n' +
52
+ ` Got: \`${title}\``
53
+ );
54
+ }
55
+
56
+ const summary = section('Summary') || '';
57
+ if (summary.length < 20) {
58
+ errors.push(
59
+ `**Summary** — must be at least 20 characters (got ${summary.length})`
60
+ );
61
+ }
62
+
63
+ if (!isInternal && !/^\w+\s+[A-Z]+-\d+\b|^[A-Z]+-\d+\b/m.test(body)) {
64
+ errors.push(
65
+ '**Linear ticket** — a valid ticket ID must appear on its own line in the PR body\n' +
66
+ ' Valid formats: `DEV-123`, `closes DEV-123`, `resolves AIA-456`, `fixes DEV-789`\n' +
67
+ ' If there is no ticket, use `internal` as the title type to skip this check'
68
+ );
69
+ }
70
+
71
+ const testPlan = section('Test Plan') || '';
72
+ if (!/- \[ \] .+/.test(testPlan)) {
73
+ errors.push(
74
+ '**Test Plan** — must include at least one step with text, e.g. `- [ ] Navigate to X and verify Y`'
75
+ );
76
+ }
77
+
78
+ let prFiles = [];
79
+ try {
80
+ const { data: files } = await github.rest.pulls.listFiles({
81
+ owner: context.repo.owner,
82
+ repo: context.repo.repo,
83
+ pull_number: pr.number,
84
+ per_page: 100,
85
+ });
86
+ prFiles = files;
87
+ } catch (e) {
88
+ core.warning(`Could not list PR files: ${e.message}`);
89
+ }
90
+
91
+ const needsPlan = /^(feat|refactor|breaking)(\(.+\))?:/.test(title);
92
+ const hasPlanFile = prFiles.some(f =>
93
+ f.filename.startsWith('docs/superpowers/plans/') ||
94
+ f.filename.startsWith('docs/superpowers/specs/')
95
+ );
96
+ if (needsPlan && !hasPlanFile) {
97
+ warnings.push(
98
+ '**Superpowers plan file missing** — feature PRs should include a plan file in `docs/superpowers/plans/`.\n' +
99
+ ' Run `superpowers:brainstorming` + `superpowers:writing-plans` in Claude Code before implementing.\n' +
100
+ ' If you intentionally skipped planning (trivial change), you can ignore this warning.'
101
+ );
102
+ }
103
+
104
+ const envPatterns = [
105
+ /\.env(\.|$)/i,
106
+ /(^|\/)\.env$/i,
107
+ /(^|\/)env\//i,
108
+ /(^|\/)config\//i,
109
+ /helm\/.*values.*\.ya?ml$/i,
110
+ /docker-compose.*\.ya?ml$/i,
111
+ /kubernetes\/.*\.ya?ml$/i,
112
+ /k8s\/.*\.ya?ml$/i,
113
+ ];
114
+ const touchesEnvFiles = prFiles.some(f =>
115
+ envPatterns.some(p => p.test(f.filename))
116
+ );
117
+
118
+ if (touchesEnvFiles) {
119
+ const envSection = section('Env Changes') || '';
120
+ const hasContent =
121
+ /none/i.test(envSection) ||
122
+ /- name:\s*\S+/.test(envSection);
123
+ if (!hasContent) {
124
+ errors.push(
125
+ '**Env Changes** — this PR modifies config/env files but ' +
126
+ 'the Env Changes section is empty.\n' +
127
+ ' Document all env variable changes, or write `none` if no variables changed.'
128
+ );
129
+ }
130
+ }
131
+ }
132
+
133
+ const MARKER = '<!-- pr-validation-bot -->';
134
+ if (errors.length > 0 || warnings.length > 0) {
135
+ const lines = [MARKER];
136
+ if (isHotfix) {
137
+ lines.push('### ⚠️ PR Validation — Hotfix Mode');
138
+ lines.push('');
139
+ warnings.forEach(w => lines.push(`> ${w}`));
140
+ } else {
141
+ if (errors.length > 0) {
142
+ lines.push('### ⚠️ PR Validation Failed');
143
+ lines.push('');
144
+ lines.push(
145
+ `The following ${errors.length === 1 ? 'field requires' : `${errors.length} fields require`} attention:`
146
+ );
147
+ lines.push('');
148
+ errors.forEach(e => lines.push(`- ${e}`));
149
+ lines.push('');
150
+ lines.push('_Fix the above and the check will re-run automatically._');
151
+ }
152
+ if (warnings.length > 0) {
153
+ if (errors.length > 0) lines.push('');
154
+ lines.push(errors.length > 0 ? '### ⚠️ Warnings' : '### ⚠️ PR Validation — Warnings');
155
+ lines.push('');
156
+ warnings.forEach(w => lines.push(`> ${w}`));
157
+ lines.push('');
158
+ lines.push('_Warnings will not fail the check — address them if applicable._');
159
+ }
160
+ }
161
+
162
+ const commentBody = lines.join('\n');
163
+ const { data: comments } = await github.rest.issues.listComments({
164
+ owner: context.repo.owner,
165
+ repo: context.repo.repo,
166
+ issue_number: pr.number,
167
+ });
168
+ const existing = comments.find(
169
+ c => c.user.type === 'Bot' && c.body.includes(MARKER)
170
+ );
171
+ if (existing) {
172
+ await github.rest.issues.updateComment({
173
+ owner: context.repo.owner,
174
+ repo: context.repo.repo,
175
+ comment_id: existing.id,
176
+ body: commentBody,
177
+ });
178
+ } else {
179
+ await github.rest.issues.createComment({
180
+ owner: context.repo.owner,
181
+ repo: context.repo.repo,
182
+ issue_number: pr.number,
183
+ body: commentBody,
184
+ });
185
+ }
186
+ }
187
+
188
+ if (errors.length > 0) {
189
+ core.setFailed(
190
+ `PR validation failed — ${errors.length} field(s) need attention. ` +
191
+ `See PR comment for details.`
192
+ );
193
+ }
194
+
195
+ - name: Notify Slack on failure
196
+ if: failure()
197
+ env:
198
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
199
+ PR_URL: ${{ github.event.pull_request.html_url }}
200
+ PR_NUMBER: ${{ github.event.pull_request.number }}
201
+ PR_TITLE: ${{ github.event.pull_request.title }}
202
+ PR_BRANCH: ${{ github.head_ref }}
203
+ PR_AUTHOR: ${{ github.event.pull_request.user.login }}
204
+ run: |
205
+ payload=$(jq -n \
206
+ --arg url "$PR_URL" \
207
+ --arg number "$PR_NUMBER" \
208
+ --arg title "$PR_TITLE" \
209
+ --arg branch "$PR_BRANCH" \
210
+ --arg author "$PR_AUTHOR" \
211
+ '{
212
+ text: ":warning: *PR Validation Failed* — cobalt-js",
213
+ attachments: [{
214
+ color: "warning",
215
+ fields: [
216
+ { title: "PR", value: ("<" + $url + "|#" + $number + " " + $title + ">"), short: false },
217
+ { title: "Branch", value: ("`" + $branch + "`"), short: true },
218
+ { title: "Author", value: $author, short: true }
219
+ ]
220
+ }]
221
+ }')
222
+ curl -s -X POST "$SLACK_WEBHOOK" \
223
+ -H "Content-Type: application/json" \
224
+ -d "$payload"
package/CLAUDE.md CHANGED
@@ -115,3 +115,13 @@ All requests include `Authorization: Bearer ${token}`:
115
115
  - **v9.x:** Added `getWorkflowPayload()`, `executeWorkflow()`, multi-auth support
116
116
  - **v8.x:** Introduced `AuthType` enum for multi-auth
117
117
  - Deprecated fields maintained for backward compatibility
118
+
119
+ ## Claude Code Skills
120
+
121
+ All development using Claude Code must use the superpowers skills plugin. Required before every task:
122
+
123
+ - **Before building features or components:** invoke `superpowers:brainstorming` to explore intent and design first
124
+ - **Before multi-step implementation:** invoke `superpowers:writing-plans` — this saves a plan to `docs/superpowers/plans/`
125
+ - **Before claiming work is done:** invoke `superpowers:verification-before-completion` before committing or opening a PR
126
+
127
+ For feature work (`feat/*` branches), include the plan file from `docs/superpowers/plans/` in the PR. PRs without a plan file for feature branches will receive a warning from the PR validation bot.
package/cobalt.d.ts CHANGED
@@ -477,9 +477,10 @@ declare class Cobalt {
477
477
  * Returns the specified config.
478
478
  * @param {String} slug The application slug.
479
479
  * @param {String} [configId] The unique ID of the config.
480
+ * @param {Boolean} [excludeOptions] Whether to exclude the options from the fields in the response.
480
481
  * @returns {Promise<Config>} The specified config.
481
482
  */
482
- getConfig(slug: string, configId: string): Promise<Config>;
483
+ getConfig(slug: string, configId: string, excludeOptions?: boolean): Promise<Config>;
483
484
  /**
484
485
  * Update the specified config.
485
486
  * @param {UpdateConfigPayload} payload The update payload.
@@ -498,9 +499,10 @@ declare class Cobalt {
498
499
  * @param {String} slug The application slug.
499
500
  * @param {String} fieldId The unique ID of the field.
500
501
  * @param {String} [workflowId] The unique ID of the workflow.
502
+ * @param {Record<string, unknown>} [payload] The payload to be sent in the request body.
501
503
  * @returns {Promise<Field>} The specified config field.
502
504
  */
503
- getConfigField(slug: string, fieldId: string, workflowId?: string): Promise<Config>;
505
+ getConfigField(slug: string, fieldId: string, workflowId?: string, payload?: Record<string, unknown>): Promise<Config>;
504
506
  /**
505
507
  * Update the specified config field value.
506
508
  * @param {String} slug The application slug.
package/cobalt.js CHANGED
@@ -314,12 +314,14 @@ class Cobalt {
314
314
  * Returns the specified config.
315
315
  * @param {String} slug The application slug.
316
316
  * @param {String} [configId] The unique ID of the config.
317
+ * @param {Boolean} [excludeOptions] Whether to exclude the options from the fields in the response.
317
318
  * @returns {Promise<Config>} The specified config.
318
319
  */
319
- async getConfig(slug, configId) {
320
+ async getConfig(slug, configId, excludeOptions) {
320
321
  const res = await fetch(`${this.baseUrl}/api/v2/f-sdk/slug/${slug}/config${configId ? `/${configId}` : ""}`, {
321
322
  headers: {
322
323
  authorization: `Bearer ${this.token}`,
324
+ ...(excludeOptions ? { disable_field_options: "true" } : {}),
323
325
  },
324
326
  });
325
327
  if (res.status >= 400 && res.status < 600) {
@@ -372,14 +374,18 @@ class Cobalt {
372
374
  * @param {String} slug The application slug.
373
375
  * @param {String} fieldId The unique ID of the field.
374
376
  * @param {String} [workflowId] The unique ID of the workflow.
377
+ * @param {Record<string, unknown>} [payload] The payload to be sent in the request body.
375
378
  * @returns {Promise<Field>} The specified config field.
376
379
  */
377
- async getConfigField(slug, fieldId, workflowId) {
380
+ async getConfigField(slug, fieldId, workflowId, payload) {
378
381
  const res = await fetch(`${this.baseUrl}/api/v2/public/config/field/${fieldId}${workflowId ? `?workflow_id=${workflowId}` : ""}`, {
382
+ method: "POST",
379
383
  headers: {
380
384
  authorization: `Bearer ${this.token}`,
385
+ "content-type": "application/json",
381
386
  slug,
382
387
  },
388
+ body: JSON.stringify(payload || {}),
383
389
  });
384
390
  if (res.status >= 400 && res.status < 600) {
385
391
  const error = await res.json();
package/cobalt.ts CHANGED
@@ -768,12 +768,14 @@ class Cobalt {
768
768
  * Returns the specified config.
769
769
  * @param {String} slug The application slug.
770
770
  * @param {String} [configId] The unique ID of the config.
771
+ * @param {Boolean} [excludeOptions] Whether to exclude the options from the fields in the response.
771
772
  * @returns {Promise<Config>} The specified config.
772
773
  */
773
- async getConfig(slug: string, configId: string): Promise<Config> {
774
+ async getConfig(slug: string, configId: string, excludeOptions?: boolean): Promise<Config> {
774
775
  const res = await fetch(`${this.baseUrl}/api/v2/f-sdk/slug/${slug}/config${configId ? `/${configId}` : ""}`, {
775
776
  headers: {
776
777
  authorization: `Bearer ${this.token}`,
778
+ ...(excludeOptions ? { disable_field_options: "true" } : {}),
777
779
  },
778
780
  });
779
781
 
@@ -835,14 +837,18 @@ class Cobalt {
835
837
  * @param {String} slug The application slug.
836
838
  * @param {String} fieldId The unique ID of the field.
837
839
  * @param {String} [workflowId] The unique ID of the workflow.
840
+ * @param {Record<string, unknown>} [payload] The payload to be sent in the request body.
838
841
  * @returns {Promise<Field>} The specified config field.
839
842
  */
840
- async getConfigField(slug: string, fieldId: string, workflowId?: string): Promise<Config> {
843
+ async getConfigField(slug: string, fieldId: string, workflowId?: string, payload?: Record<string, unknown>): Promise<Config> {
841
844
  const res = await fetch(`${this.baseUrl}/api/v2/public/config/field/${fieldId}${workflowId ? `?workflow_id=${workflowId}` : ""}`, {
845
+ method: "POST",
842
846
  headers: {
843
847
  authorization: `Bearer ${this.token}`,
848
+ "content-type": "application/json",
844
849
  slug,
845
850
  },
851
+ body: JSON.stringify(payload || {}),
846
852
  });
847
853
 
848
854
  if (res.status >= 400 && res.status < 600) {
@@ -951,7 +957,7 @@ class Cobalt {
951
957
  const value = rest[key];
952
958
  if (value !== undefined && value !== "") query.set(key, String(value));
953
959
  }
954
-
960
+
955
961
  const res = await fetch(`${this.baseUrl}/api/v2/public/workflow?${query}`, {
956
962
  headers: {
957
963
  authorization: `Bearer ${this.token}`,