donobu 5.37.0 → 5.38.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.
@@ -68,6 +68,7 @@ const merge_1 = require("../reporter/merge");
68
68
  const model_1 = require("../reporter/model");
69
69
  const render_1 = require("../reporter/render");
70
70
  const renderMarkdown_1 = require("../reporter/renderMarkdown");
71
+ const renderPullRequestBody_1 = require("../reporter/renderPullRequestBody");
71
72
  const renderSlack_1 = require("../reporter/renderSlack");
72
73
  const slack_1 = require("../reporter/slack");
73
74
  const Logger_1 = require("../utils/Logger");
@@ -1404,6 +1405,7 @@ async function attemptAutoHealRun(params) {
1404
1405
  }
1405
1406
  if (mergedReport) {
1406
1407
  await regenerateDonobuReports(mergedReport);
1408
+ await writeAutoHealPullRequestBody(mergedReport, params.playwrightOutputDir);
1407
1409
  }
1408
1410
  }
1409
1411
  }
@@ -1412,6 +1414,38 @@ async function attemptAutoHealRun(params) {
1412
1414
  }
1413
1415
  return { attempted: true, exitCode: healExitCode };
1414
1416
  }
1417
+ /**
1418
+ * Filename of the auto-heal PR body artifact. Lands in the Playwright output
1419
+ * directory alongside the merged JSON / HTML / Markdown reports so the
1420
+ * generated GitHub Actions workflow can find it at a stable, well-known path
1421
+ * when preparing the self-healing pull request body.
1422
+ */
1423
+ const AUTO_HEAL_PR_BODY_FILENAME = 'auto-heal-pr-body.md';
1424
+ /**
1425
+ * Emit a PR-shaped markdown body when auto-heal applied fixes. The generated
1426
+ * GitHub Actions workflow points peter-evans/create-pull-request at this file
1427
+ * via `body-path:`, so all PR-body composition (heading, healed list,
1428
+ * reviewer checklist, workflow-run footer) lives here rather than in
1429
+ * customer-facing YAML. Skipped when no tests were healed; peter-evans is
1430
+ * gated by `hashFiles()` in that case so it won't try to read a missing file.
1431
+ * Failures are logged but never surfaced — a missing PR body should not block
1432
+ * the heal run from exiting cleanly.
1433
+ */
1434
+ async function writeAutoHealPullRequestBody(mergedReport, playwrightOutputDir) {
1435
+ try {
1436
+ const body = (0, renderPullRequestBody_1.renderPullRequestBody)(mergedReport);
1437
+ if (!body) {
1438
+ return;
1439
+ }
1440
+ await fs_1.promises.mkdir(playwrightOutputDir, { recursive: true });
1441
+ const outputFile = path.join(playwrightOutputDir, AUTO_HEAL_PR_BODY_FILENAME);
1442
+ await fs_1.promises.writeFile(outputFile, body, 'utf8');
1443
+ Logger_1.appLogger.info(`Donobu auto-heal PR body written to: ${outputFile}`);
1444
+ }
1445
+ catch (error) {
1446
+ Logger_1.appLogger.warn('Failed to write Donobu auto-heal PR body.', error);
1447
+ }
1448
+ }
1415
1449
  /**
1416
1450
  * Copy attachment files that live in a temporary directory (e.g. the auto-heal
1417
1451
  * staging area) into the persistent output directory and rewrite the paths in
@@ -429,17 +429,21 @@ on:
429
429
  const pullRequestCreationSection = options.disablePullRequestCreation
430
430
  ? ''
431
431
  : `
432
- # Create a self-healing PR only when this workflow was not triggered by a pull-request.
432
+ # Open a self-healing PR with whatever auto-heal changed. Donobu writes
433
+ # the PR body to test-results/auto-heal-pr-body.md when it heals tests;
434
+ # the hashFiles() guard skips PR creation when no body is present.
433
435
  - name: Create Pull Request for Test Fixes (if any)
434
- if: \${{ github.event_name != 'pull_request' }}
436
+ if: \${{ github.event_name != 'pull_request' && hashFiles('test-results/auto-heal-pr-body.md') }}
435
437
  uses: peter-evans/create-pull-request@v8
436
438
  with:
437
439
  token: \${{ secrets.GITHUB_TOKEN }}
438
- commit-message: "Fix failing Playwright tests"
439
- title: "[Fixed] Playwright tests"
440
- body: "Fix failing Playwright tests"
440
+ commit-message: "Donobu auto-heal: fix failing tests"
441
+ title: "Donobu auto-heal: Test fixes for \${{ github.ref_name }}"
442
+ body-path: test-results/auto-heal-pr-body.md
441
443
  branch: fix-playwright-tests-for-\${{ github.ref_name }}
442
- base: \${{ github.ref_name }}`;
444
+ base: \${{ github.ref_name }}
445
+ labels: donobu, auto-heal
446
+ delete-branch: true`;
443
447
  return `name: Run Playwright Tests
444
448
  ${triggerSection}
445
449
 
package/dist/envVars.d.ts CHANGED
@@ -42,6 +42,16 @@ export declare const env: Env<{
42
42
  DONOBU_REPORT_URL: z.ZodOptional<z.ZodString>;
43
43
  DONOBU_SLACK_WEBHOOK_URL: z.ZodOptional<z.ZodString>;
44
44
  GITHUB_STEP_SUMMARY: z.ZodOptional<z.ZodString>;
45
+ GITHUB_RUN_ID: z.ZodOptional<z.ZodString>;
46
+ GITHUB_RUN_NUMBER: z.ZodOptional<z.ZodString>;
47
+ GITHUB_SERVER_URL: z.ZodOptional<z.ZodString>;
48
+ GITHUB_REPOSITORY: z.ZodOptional<z.ZodString>;
49
+ GITHUB_ACTOR: z.ZodOptional<z.ZodString>;
50
+ GITHUB_REF_NAME: z.ZodOptional<z.ZodString>;
51
+ CI_PIPELINE_URL: z.ZodOptional<z.ZodString>;
52
+ CI_PIPELINE_IID: z.ZodOptional<z.ZodString>;
53
+ GITLAB_USER_LOGIN: z.ZodOptional<z.ZodString>;
54
+ CI_COMMIT_REF_NAME: z.ZodOptional<z.ZodString>;
45
55
  PLAYWRIGHT_JSON_OUTPUT_DIR: z.ZodOptional<z.ZodString>;
46
56
  DONOBU_PAGE_AI_CLEAR_CACHE: z.ZodOptional<z.ZodEnum<{
47
57
  0: "0";
@@ -92,6 +102,16 @@ export declare const env: Env<{
92
102
  DONOBU_REPORT_URL?: string | undefined;
93
103
  DONOBU_SLACK_WEBHOOK_URL?: string | undefined;
94
104
  GITHUB_STEP_SUMMARY?: string | undefined;
105
+ GITHUB_RUN_ID?: string | undefined;
106
+ GITHUB_RUN_NUMBER?: string | undefined;
107
+ GITHUB_SERVER_URL?: string | undefined;
108
+ GITHUB_REPOSITORY?: string | undefined;
109
+ GITHUB_ACTOR?: string | undefined;
110
+ GITHUB_REF_NAME?: string | undefined;
111
+ CI_PIPELINE_URL?: string | undefined;
112
+ CI_PIPELINE_IID?: string | undefined;
113
+ GITLAB_USER_LOGIN?: string | undefined;
114
+ CI_COMMIT_REF_NAME?: string | undefined;
95
115
  PLAYWRIGHT_JSON_OUTPUT_DIR?: string | undefined;
96
116
  DONOBU_PAGE_AI_CLEAR_CACHE?: "0" | "1" | "true" | "false" | undefined;
97
117
  GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
package/dist/envVars.js CHANGED
@@ -79,6 +79,46 @@ network call.`),
79
79
  .describe(`Set by the GitHub Actions runner to the path of a per-step Markdown file. Anything
80
80
  written here is concatenated into the workflow run's job summary. The Donobu Markdown reporter writes
81
81
  to this automatically when running inside a GHA step so no separate workflow step is needed.`),
82
+ GITHUB_RUN_ID: v4_1.z
83
+ .string()
84
+ .optional()
85
+ .describe(`Set by the GitHub Actions runner. Used by the auto-heal PR body footer to link back to the workflow run that produced the heal.`),
86
+ GITHUB_RUN_NUMBER: v4_1.z
87
+ .string()
88
+ .optional()
89
+ .describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as a human-friendly run number.`),
90
+ GITHUB_SERVER_URL: v4_1.z
91
+ .string()
92
+ .optional()
93
+ .describe(`Set by the GitHub Actions runner (e.g. https://github.com). Combined with GITHUB_REPOSITORY and GITHUB_RUN_ID to build the auto-heal PR body footer link.`),
94
+ GITHUB_REPOSITORY: v4_1.z
95
+ .string()
96
+ .optional()
97
+ .describe(`Set by the GitHub Actions runner (owner/repo). Used by the auto-heal PR body footer link.`),
98
+ GITHUB_ACTOR: v4_1.z
99
+ .string()
100
+ .optional()
101
+ .describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as the user who triggered the run.`),
102
+ GITHUB_REF_NAME: v4_1.z
103
+ .string()
104
+ .optional()
105
+ .describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as the source branch.`),
106
+ CI_PIPELINE_URL: v4_1.z
107
+ .string()
108
+ .optional()
109
+ .describe(`Set by the GitLab CI runner. Used by the auto-heal MR body footer to link back to the pipeline that produced the heal.`),
110
+ CI_PIPELINE_IID: v4_1.z
111
+ .string()
112
+ .optional()
113
+ .describe(`Set by the GitLab CI runner — the per-project pipeline number GitLab shows in its UI. Embedded in the auto-heal MR body footer.`),
114
+ GITLAB_USER_LOGIN: v4_1.z
115
+ .string()
116
+ .optional()
117
+ .describe(`Set by the GitLab CI runner. Embedded in the auto-heal MR body footer as the user who triggered the pipeline.`),
118
+ CI_COMMIT_REF_NAME: v4_1.z
119
+ .string()
120
+ .optional()
121
+ .describe(`Set by the GitLab CI runner. Embedded in the auto-heal MR body footer as the source branch.`),
82
122
  PLAYWRIGHT_JSON_OUTPUT_DIR: v4_1.z.string().optional()
83
123
  .describe(`Directory where the Playwright JSON reporter writes its output (and where the Donobu
84
124
  reporters merge their per-reporter state into a shared sidecar so the auto-heal orchestrator can
@@ -68,6 +68,7 @@ const merge_1 = require("../reporter/merge");
68
68
  const model_1 = require("../reporter/model");
69
69
  const render_1 = require("../reporter/render");
70
70
  const renderMarkdown_1 = require("../reporter/renderMarkdown");
71
+ const renderPullRequestBody_1 = require("../reporter/renderPullRequestBody");
71
72
  const renderSlack_1 = require("../reporter/renderSlack");
72
73
  const slack_1 = require("../reporter/slack");
73
74
  const Logger_1 = require("../utils/Logger");
@@ -1404,6 +1405,7 @@ async function attemptAutoHealRun(params) {
1404
1405
  }
1405
1406
  if (mergedReport) {
1406
1407
  await regenerateDonobuReports(mergedReport);
1408
+ await writeAutoHealPullRequestBody(mergedReport, params.playwrightOutputDir);
1407
1409
  }
1408
1410
  }
1409
1411
  }
@@ -1412,6 +1414,38 @@ async function attemptAutoHealRun(params) {
1412
1414
  }
1413
1415
  return { attempted: true, exitCode: healExitCode };
1414
1416
  }
1417
+ /**
1418
+ * Filename of the auto-heal PR body artifact. Lands in the Playwright output
1419
+ * directory alongside the merged JSON / HTML / Markdown reports so the
1420
+ * generated GitHub Actions workflow can find it at a stable, well-known path
1421
+ * when preparing the self-healing pull request body.
1422
+ */
1423
+ const AUTO_HEAL_PR_BODY_FILENAME = 'auto-heal-pr-body.md';
1424
+ /**
1425
+ * Emit a PR-shaped markdown body when auto-heal applied fixes. The generated
1426
+ * GitHub Actions workflow points peter-evans/create-pull-request at this file
1427
+ * via `body-path:`, so all PR-body composition (heading, healed list,
1428
+ * reviewer checklist, workflow-run footer) lives here rather than in
1429
+ * customer-facing YAML. Skipped when no tests were healed; peter-evans is
1430
+ * gated by `hashFiles()` in that case so it won't try to read a missing file.
1431
+ * Failures are logged but never surfaced — a missing PR body should not block
1432
+ * the heal run from exiting cleanly.
1433
+ */
1434
+ async function writeAutoHealPullRequestBody(mergedReport, playwrightOutputDir) {
1435
+ try {
1436
+ const body = (0, renderPullRequestBody_1.renderPullRequestBody)(mergedReport);
1437
+ if (!body) {
1438
+ return;
1439
+ }
1440
+ await fs_1.promises.mkdir(playwrightOutputDir, { recursive: true });
1441
+ const outputFile = path.join(playwrightOutputDir, AUTO_HEAL_PR_BODY_FILENAME);
1442
+ await fs_1.promises.writeFile(outputFile, body, 'utf8');
1443
+ Logger_1.appLogger.info(`Donobu auto-heal PR body written to: ${outputFile}`);
1444
+ }
1445
+ catch (error) {
1446
+ Logger_1.appLogger.warn('Failed to write Donobu auto-heal PR body.', error);
1447
+ }
1448
+ }
1415
1449
  /**
1416
1450
  * Copy attachment files that live in a temporary directory (e.g. the auto-heal
1417
1451
  * staging area) into the persistent output directory and rewrite the paths in
@@ -429,17 +429,21 @@ on:
429
429
  const pullRequestCreationSection = options.disablePullRequestCreation
430
430
  ? ''
431
431
  : `
432
- # Create a self-healing PR only when this workflow was not triggered by a pull-request.
432
+ # Open a self-healing PR with whatever auto-heal changed. Donobu writes
433
+ # the PR body to test-results/auto-heal-pr-body.md when it heals tests;
434
+ # the hashFiles() guard skips PR creation when no body is present.
433
435
  - name: Create Pull Request for Test Fixes (if any)
434
- if: \${{ github.event_name != 'pull_request' }}
436
+ if: \${{ github.event_name != 'pull_request' && hashFiles('test-results/auto-heal-pr-body.md') }}
435
437
  uses: peter-evans/create-pull-request@v8
436
438
  with:
437
439
  token: \${{ secrets.GITHUB_TOKEN }}
438
- commit-message: "Fix failing Playwright tests"
439
- title: "[Fixed] Playwright tests"
440
- body: "Fix failing Playwright tests"
440
+ commit-message: "Donobu auto-heal: fix failing tests"
441
+ title: "Donobu auto-heal: Test fixes for \${{ github.ref_name }}"
442
+ body-path: test-results/auto-heal-pr-body.md
441
443
  branch: fix-playwright-tests-for-\${{ github.ref_name }}
442
- base: \${{ github.ref_name }}`;
444
+ base: \${{ github.ref_name }}
445
+ labels: donobu, auto-heal
446
+ delete-branch: true`;
443
447
  return `name: Run Playwright Tests
444
448
  ${triggerSection}
445
449
 
@@ -42,6 +42,16 @@ export declare const env: Env<{
42
42
  DONOBU_REPORT_URL: z.ZodOptional<z.ZodString>;
43
43
  DONOBU_SLACK_WEBHOOK_URL: z.ZodOptional<z.ZodString>;
44
44
  GITHUB_STEP_SUMMARY: z.ZodOptional<z.ZodString>;
45
+ GITHUB_RUN_ID: z.ZodOptional<z.ZodString>;
46
+ GITHUB_RUN_NUMBER: z.ZodOptional<z.ZodString>;
47
+ GITHUB_SERVER_URL: z.ZodOptional<z.ZodString>;
48
+ GITHUB_REPOSITORY: z.ZodOptional<z.ZodString>;
49
+ GITHUB_ACTOR: z.ZodOptional<z.ZodString>;
50
+ GITHUB_REF_NAME: z.ZodOptional<z.ZodString>;
51
+ CI_PIPELINE_URL: z.ZodOptional<z.ZodString>;
52
+ CI_PIPELINE_IID: z.ZodOptional<z.ZodString>;
53
+ GITLAB_USER_LOGIN: z.ZodOptional<z.ZodString>;
54
+ CI_COMMIT_REF_NAME: z.ZodOptional<z.ZodString>;
45
55
  PLAYWRIGHT_JSON_OUTPUT_DIR: z.ZodOptional<z.ZodString>;
46
56
  DONOBU_PAGE_AI_CLEAR_CACHE: z.ZodOptional<z.ZodEnum<{
47
57
  0: "0";
@@ -92,6 +102,16 @@ export declare const env: Env<{
92
102
  DONOBU_REPORT_URL?: string | undefined;
93
103
  DONOBU_SLACK_WEBHOOK_URL?: string | undefined;
94
104
  GITHUB_STEP_SUMMARY?: string | undefined;
105
+ GITHUB_RUN_ID?: string | undefined;
106
+ GITHUB_RUN_NUMBER?: string | undefined;
107
+ GITHUB_SERVER_URL?: string | undefined;
108
+ GITHUB_REPOSITORY?: string | undefined;
109
+ GITHUB_ACTOR?: string | undefined;
110
+ GITHUB_REF_NAME?: string | undefined;
111
+ CI_PIPELINE_URL?: string | undefined;
112
+ CI_PIPELINE_IID?: string | undefined;
113
+ GITLAB_USER_LOGIN?: string | undefined;
114
+ CI_COMMIT_REF_NAME?: string | undefined;
95
115
  PLAYWRIGHT_JSON_OUTPUT_DIR?: string | undefined;
96
116
  DONOBU_PAGE_AI_CLEAR_CACHE?: "0" | "1" | "true" | "false" | undefined;
97
117
  GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
@@ -79,6 +79,46 @@ network call.`),
79
79
  .describe(`Set by the GitHub Actions runner to the path of a per-step Markdown file. Anything
80
80
  written here is concatenated into the workflow run's job summary. The Donobu Markdown reporter writes
81
81
  to this automatically when running inside a GHA step so no separate workflow step is needed.`),
82
+ GITHUB_RUN_ID: v4_1.z
83
+ .string()
84
+ .optional()
85
+ .describe(`Set by the GitHub Actions runner. Used by the auto-heal PR body footer to link back to the workflow run that produced the heal.`),
86
+ GITHUB_RUN_NUMBER: v4_1.z
87
+ .string()
88
+ .optional()
89
+ .describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as a human-friendly run number.`),
90
+ GITHUB_SERVER_URL: v4_1.z
91
+ .string()
92
+ .optional()
93
+ .describe(`Set by the GitHub Actions runner (e.g. https://github.com). Combined with GITHUB_REPOSITORY and GITHUB_RUN_ID to build the auto-heal PR body footer link.`),
94
+ GITHUB_REPOSITORY: v4_1.z
95
+ .string()
96
+ .optional()
97
+ .describe(`Set by the GitHub Actions runner (owner/repo). Used by the auto-heal PR body footer link.`),
98
+ GITHUB_ACTOR: v4_1.z
99
+ .string()
100
+ .optional()
101
+ .describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as the user who triggered the run.`),
102
+ GITHUB_REF_NAME: v4_1.z
103
+ .string()
104
+ .optional()
105
+ .describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as the source branch.`),
106
+ CI_PIPELINE_URL: v4_1.z
107
+ .string()
108
+ .optional()
109
+ .describe(`Set by the GitLab CI runner. Used by the auto-heal MR body footer to link back to the pipeline that produced the heal.`),
110
+ CI_PIPELINE_IID: v4_1.z
111
+ .string()
112
+ .optional()
113
+ .describe(`Set by the GitLab CI runner — the per-project pipeline number GitLab shows in its UI. Embedded in the auto-heal MR body footer.`),
114
+ GITLAB_USER_LOGIN: v4_1.z
115
+ .string()
116
+ .optional()
117
+ .describe(`Set by the GitLab CI runner. Embedded in the auto-heal MR body footer as the user who triggered the pipeline.`),
118
+ CI_COMMIT_REF_NAME: v4_1.z
119
+ .string()
120
+ .optional()
121
+ .describe(`Set by the GitLab CI runner. Embedded in the auto-heal MR body footer as the source branch.`),
82
122
  PLAYWRIGHT_JSON_OUTPUT_DIR: v4_1.z.string().optional()
83
123
  .describe(`Directory where the Playwright JSON reporter writes its output (and where the Donobu
84
124
  reporters merge their per-reporter state into a shared sidecar so the auto-heal orchestrator can
@@ -0,0 +1,6 @@
1
+ import { DonobuException } from './DonobuException';
2
+ export declare class FlowIdCollisionException extends DonobuException {
3
+ private constructor();
4
+ static forId(flowId: string): FlowIdCollisionException;
5
+ }
6
+ //# sourceMappingURL=FlowIdCollisionException.d.ts.map
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FlowIdCollisionException = void 0;
4
+ const DonobuException_1 = require("./DonobuException");
5
+ class FlowIdCollisionException extends DonobuException_1.DonobuException {
6
+ constructor(message) {
7
+ super(message, undefined, 409);
8
+ }
9
+ static forId(flowId) {
10
+ return new FlowIdCollisionException(`A flow with ID '${flowId}' already exists. Client-supplied flow IDs must be unique.`);
11
+ }
12
+ }
13
+ exports.FlowIdCollisionException = FlowIdCollisionException;
14
+ //# sourceMappingURL=FlowIdCollisionException.js.map
@@ -8,6 +8,7 @@ export { VercelAiGptClient } from './clients/VercelAiGptClient';
8
8
  export { runGenerateSiteTests } from './codegen/runGenerateSiteTests';
9
9
  export { env } from './envVars';
10
10
  export * from './exceptions/DonobuException';
11
+ export * from './exceptions/FlowIdCollisionException';
11
12
  export * from './exceptions/FlowNotFoundException';
12
13
  export * from './exceptions/GptApiKeysNotSetupException';
13
14
  export * from './exceptions/GptPlatformAuthenticationFailedException';
package/dist/esm/main.js CHANGED
@@ -44,6 +44,7 @@ Object.defineProperty(exports, "runGenerateSiteTests", { enumerable: true, get:
44
44
  var envVars_2 = require("./envVars");
45
45
  Object.defineProperty(exports, "env", { enumerable: true, get: function () { return envVars_2.env; } });
46
46
  __exportStar(require("./exceptions/DonobuException"), exports);
47
+ __exportStar(require("./exceptions/FlowIdCollisionException"), exports);
47
48
  __exportStar(require("./exceptions/FlowNotFoundException"), exports);
48
49
  __exportStar(require("./exceptions/GptApiKeysNotSetupException"), exports);
49
50
  __exportStar(require("./exceptions/GptPlatformAuthenticationFailedException"), exports);
@@ -186,6 +186,12 @@ export declare class DonobuFlowsManager {
186
186
  * back to the primary layer (the SQLite FK will reject if applicable;
187
187
  * non-DB layers will accept the dangling reference).
188
188
  */
189
+ /**
190
+ * Best-effort check that no flow with the given ID exists in any persistence
191
+ * layer. Throws {@link FlowIdCollisionException} on hit. Note: this is RACY
192
+ * — concurrent callers with the same ID can both pass the check.
193
+ */
194
+ private assertFlowIdAvailable;
189
195
  private resolveLayerForFlowCreate;
190
196
  private findTestLayerKey;
191
197
  private isLocallyRunning;
@@ -45,6 +45,7 @@ const CodeGenerator_1 = require("../codegen/CodeGenerator");
45
45
  const ActiveFlowNotFoundException_1 = require("../exceptions/ActiveFlowNotFoundException");
46
46
  const BrowserStateNotFoundException_1 = require("../exceptions/BrowserStateNotFoundException");
47
47
  const CannotDeleteRunningFlowException_1 = require("../exceptions/CannotDeleteRunningFlowException");
48
+ const FlowIdCollisionException_1 = require("../exceptions/FlowIdCollisionException");
48
49
  const FlowNotFoundException_1 = require("../exceptions/FlowNotFoundException");
49
50
  const InvalidParamValueException_1 = require("../exceptions/InvalidParamValueException");
50
51
  const TestNotFoundException_1 = require("../exceptions/TestNotFoundException");
@@ -96,7 +97,10 @@ class DonobuFlowsManager {
96
97
  * related parameters are will be ignored.
97
98
  */
98
99
  async createFlow(flowParams, gptClient, browserContextOverride) {
99
- const flowId = (0, crypto_1.randomUUID)();
100
+ if (flowParams.id) {
101
+ await this.assertFlowIdAvailable(flowParams.id);
102
+ }
103
+ const flowId = flowParams.id ?? (0, crypto_1.randomUUID)();
100
104
  const logBuffer = new FlowLogBuffer_1.FlowLogBuffer();
101
105
  return Logger_1.loggingContext.run({ flowId, logBuffer }, async () => {
102
106
  const messageDuration = flowParams.defaultMessageDuration ??
@@ -670,6 +674,27 @@ class DonobuFlowsManager {
670
674
  * back to the primary layer (the SQLite FK will reject if applicable;
671
675
  * non-DB layers will accept the dangling reference).
672
676
  */
677
+ /**
678
+ * Best-effort check that no flow with the given ID exists in any persistence
679
+ * layer. Throws {@link FlowIdCollisionException} on hit. Note: this is RACY
680
+ * — concurrent callers with the same ID can both pass the check.
681
+ */
682
+ async assertFlowIdAvailable(flowId) {
683
+ for (const persistence of await this.flowsPersistenceRegistry.getAll()) {
684
+ try {
685
+ await persistence.getFlowMetadataById(flowId);
686
+ throw FlowIdCollisionException_1.FlowIdCollisionException.forId(flowId);
687
+ }
688
+ catch (error) {
689
+ if (error instanceof FlowIdCollisionException_1.FlowIdCollisionException) {
690
+ throw error;
691
+ }
692
+ if (!(error instanceof FlowNotFoundException_1.FlowNotFoundException)) {
693
+ throw error;
694
+ }
695
+ }
696
+ }
697
+ }
673
698
  async resolveLayerForFlowCreate(testId) {
674
699
  if (!testId) {
675
700
  return this.flowsPersistenceRegistry.get();
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod/v4';
2
2
  export declare const CreateDonobuFlowSchema: z.ZodObject<{
3
+ id: z.ZodOptional<z.ZodString>;
3
4
  target: z.ZodString;
4
5
  web: z.ZodOptional<z.ZodObject<{
5
6
  browser: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -8,6 +8,19 @@ const ProposedToolCall_1 = require("./ProposedToolCall");
8
8
  const RunMode_1 = require("./RunMode");
9
9
  exports.CreateDonobuFlowSchema = v4_1.z
10
10
  .object({
11
+ id: v4_1.z
12
+ .string()
13
+ .uuid()
14
+ .optional()
15
+ .describe('⚠️ ADVANCED — DO NOT USE unless you have a specific reason. ' +
16
+ 'Pre-assigned flow ID (UUID). Useful only when the caller must know ' +
17
+ 'the ID before flow creation completes (e.g. orchestrators that ' +
18
+ 'pre-allocate IDs to track an in-flight execution). The SDK does a ' +
19
+ 'best-effort collision check against the persistence layer and ' +
20
+ 'throws FlowIdCollisionException if the ID already exists, but ' +
21
+ 'concurrent calls with the same ID are RACY: there is no locking, ' +
22
+ 'so two callers can both pass the check and create dueling rows. ' +
23
+ 'If you do not need this, omit it and let the SDK mint a UUID.'),
11
24
  target: v4_1.z
12
25
  .string()
13
26
  .describe('The target type: "web", "mobile", or a plugin-provided target.'),
@@ -0,0 +1,16 @@
1
+ import type { DonobuReport } from './model';
2
+ type FooterEnv = {
3
+ readonly GITHUB_RUN_ID?: string;
4
+ readonly GITHUB_RUN_NUMBER?: string;
5
+ readonly GITHUB_SERVER_URL?: string;
6
+ readonly GITHUB_REPOSITORY?: string;
7
+ readonly GITHUB_ACTOR?: string;
8
+ readonly GITHUB_REF_NAME?: string;
9
+ readonly CI_PIPELINE_URL?: string;
10
+ readonly CI_PIPELINE_IID?: string;
11
+ readonly GITLAB_USER_LOGIN?: string;
12
+ readonly CI_COMMIT_REF_NAME?: string;
13
+ };
14
+ export declare function renderPullRequestBody(report: DonobuReport, envData?: FooterEnv): string;
15
+ export {};
16
+ //# sourceMappingURL=renderPullRequestBody.d.ts.map
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderPullRequestBody = renderPullRequestBody;
4
+ /**
5
+ * @fileoverview Donobu auto-heal pull request body renderer.
6
+ *
7
+ * Turns the merged auto-heal `DonobuReport` into the markdown body of the
8
+ * PR/MR opened by the surrounding CI job. Pure: callers pass the env subset
9
+ * the footer needs as a plain object, defaulting to the central `env.pick`
10
+ * view of the relevant CI vars when running in production.
11
+ *
12
+ * Returns an empty string when nothing was healed — the CLI uses that to
13
+ * decide whether to write the file at all.
14
+ */
15
+ const envVars_1 = require("../envVars");
16
+ function parseHealedKey(rawKey) {
17
+ // Composite key shape from buildTestKey(): `file::projectName::title`.
18
+ // Titles can themselves contain `::`, so we only split off the first two
19
+ // segments and treat the remainder as the title.
20
+ const firstSep = rawKey.indexOf('::');
21
+ if (firstSep < 0) {
22
+ return { file: 'unknown-file', projectName: 'default', title: rawKey };
23
+ }
24
+ const file = rawKey.slice(0, firstSep);
25
+ const rest = rawKey.slice(firstSep + 2);
26
+ const secondSep = rest.indexOf('::');
27
+ if (secondSep < 0) {
28
+ return { file, projectName: 'default', title: rest };
29
+ }
30
+ return {
31
+ file,
32
+ projectName: rest.slice(0, secondSep),
33
+ title: rest.slice(secondSep + 2),
34
+ };
35
+ }
36
+ function renderPullRequestBody(report, envData = envVars_1.env.pick('GITHUB_RUN_ID', 'GITHUB_RUN_NUMBER', 'GITHUB_SERVER_URL', 'GITHUB_REPOSITORY', 'GITHUB_ACTOR', 'GITHUB_REF_NAME', 'CI_PIPELINE_URL', 'CI_PIPELINE_IID', 'GITLAB_USER_LOGIN', 'CI_COMMIT_REF_NAME').data) {
37
+ const healedKeys = report.metadata?.donobuHealedTests ?? [];
38
+ if (healedKeys.length === 0) {
39
+ return '';
40
+ }
41
+ const parsed = healedKeys.map(parseHealedKey);
42
+ const noun = parsed.length === 1 ? 'test' : 'tests';
43
+ let body = `🩹 **Donobu auto-heal applied fixes to ${parsed.length} failing ${noun}** in this branch.\n\n`;
44
+ body += `The auto-heal rerun applied a treatment plan to the failing ${noun}.\n\n`;
45
+ body += `## Healed ${noun}\n\n`;
46
+ for (const entry of parsed) {
47
+ const projectSuffix = entry.projectName && entry.projectName !== 'default'
48
+ ? ` _(project: \`${entry.projectName}\`)_`
49
+ : '';
50
+ body += `- ❤️‍🩹 \`${entry.file}\` — ${entry.title}${projectSuffix}\n`;
51
+ }
52
+ const footer = buildCiFooter(envData);
53
+ if (footer) {
54
+ body += `\n---\n\n${footer}\n`;
55
+ }
56
+ return body;
57
+ }
58
+ function buildCiFooter(e) {
59
+ if (e.GITHUB_RUN_ID && e.GITHUB_SERVER_URL && e.GITHUB_REPOSITORY) {
60
+ const url = `${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`;
61
+ const label = e.GITHUB_RUN_NUMBER
62
+ ? `workflow run #${e.GITHUB_RUN_NUMBER}`
63
+ : 'workflow run';
64
+ return assembleFooter(label, url, e.GITHUB_ACTOR, e.GITHUB_REF_NAME);
65
+ }
66
+ else if (e.CI_PIPELINE_URL) {
67
+ // `CI_PIPELINE_IID` is the per-project pipeline number GitLab shows in
68
+ // its UI ("#42") — far more useful in a footer than the global numeric
69
+ // `CI_PIPELINE_ID` reviewers don't recognize.
70
+ const label = e.CI_PIPELINE_IID
71
+ ? `pipeline #${e.CI_PIPELINE_IID}`
72
+ : 'pipeline';
73
+ return assembleFooter(label, e.CI_PIPELINE_URL, e.GITLAB_USER_LOGIN, e.CI_COMMIT_REF_NAME);
74
+ }
75
+ else {
76
+ return undefined;
77
+ }
78
+ }
79
+ function assembleFooter(label, url, actor, refName) {
80
+ let footer = `🤖 Generated by Donobu auto-heal · [${label}](${url})`;
81
+ if (actor) {
82
+ footer += ` · triggered by @${actor}`;
83
+ }
84
+ if (refName) {
85
+ footer += ` · on \`${refName}\``;
86
+ }
87
+ return footer;
88
+ }
89
+ //# sourceMappingURL=renderPullRequestBody.js.map
@@ -4,6 +4,7 @@ import type { ToolCallResult } from '../models/ToolCallResult';
4
4
  import { Tool } from './Tool';
5
5
  export declare const TriggerDonobuFlowCoreSchema: z.ZodObject<{
6
6
  donobuFlowParameters: z.ZodObject<{
7
+ id: z.ZodOptional<z.ZodString>;
7
8
  target: z.ZodString;
8
9
  web: z.ZodOptional<z.ZodObject<{
9
10
  browser: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -151,6 +152,7 @@ export declare const TriggerDonobuFlowCoreSchema: z.ZodObject<{
151
152
  }, z.core.$strip>;
152
153
  export declare const TriggerDonobuFlowGptSchema: z.ZodObject<{
153
154
  donobuFlowParameters: z.ZodObject<{
155
+ id: z.ZodOptional<z.ZodString>;
154
156
  target: z.ZodString;
155
157
  web: z.ZodOptional<z.ZodObject<{
156
158
  browser: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -0,0 +1,6 @@
1
+ import { DonobuException } from './DonobuException';
2
+ export declare class FlowIdCollisionException extends DonobuException {
3
+ private constructor();
4
+ static forId(flowId: string): FlowIdCollisionException;
5
+ }
6
+ //# sourceMappingURL=FlowIdCollisionException.d.ts.map
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FlowIdCollisionException = void 0;
4
+ const DonobuException_1 = require("./DonobuException");
5
+ class FlowIdCollisionException extends DonobuException_1.DonobuException {
6
+ constructor(message) {
7
+ super(message, undefined, 409);
8
+ }
9
+ static forId(flowId) {
10
+ return new FlowIdCollisionException(`A flow with ID '${flowId}' already exists. Client-supplied flow IDs must be unique.`);
11
+ }
12
+ }
13
+ exports.FlowIdCollisionException = FlowIdCollisionException;
14
+ //# sourceMappingURL=FlowIdCollisionException.js.map
package/dist/main.d.ts CHANGED
@@ -8,6 +8,7 @@ export { VercelAiGptClient } from './clients/VercelAiGptClient';
8
8
  export { runGenerateSiteTests } from './codegen/runGenerateSiteTests';
9
9
  export { env } from './envVars';
10
10
  export * from './exceptions/DonobuException';
11
+ export * from './exceptions/FlowIdCollisionException';
11
12
  export * from './exceptions/FlowNotFoundException';
12
13
  export * from './exceptions/GptApiKeysNotSetupException';
13
14
  export * from './exceptions/GptPlatformAuthenticationFailedException';
package/dist/main.js CHANGED
@@ -44,6 +44,7 @@ Object.defineProperty(exports, "runGenerateSiteTests", { enumerable: true, get:
44
44
  var envVars_2 = require("./envVars");
45
45
  Object.defineProperty(exports, "env", { enumerable: true, get: function () { return envVars_2.env; } });
46
46
  __exportStar(require("./exceptions/DonobuException"), exports);
47
+ __exportStar(require("./exceptions/FlowIdCollisionException"), exports);
47
48
  __exportStar(require("./exceptions/FlowNotFoundException"), exports);
48
49
  __exportStar(require("./exceptions/GptApiKeysNotSetupException"), exports);
49
50
  __exportStar(require("./exceptions/GptPlatformAuthenticationFailedException"), exports);
@@ -186,6 +186,12 @@ export declare class DonobuFlowsManager {
186
186
  * back to the primary layer (the SQLite FK will reject if applicable;
187
187
  * non-DB layers will accept the dangling reference).
188
188
  */
189
+ /**
190
+ * Best-effort check that no flow with the given ID exists in any persistence
191
+ * layer. Throws {@link FlowIdCollisionException} on hit. Note: this is RACY
192
+ * — concurrent callers with the same ID can both pass the check.
193
+ */
194
+ private assertFlowIdAvailable;
189
195
  private resolveLayerForFlowCreate;
190
196
  private findTestLayerKey;
191
197
  private isLocallyRunning;
@@ -45,6 +45,7 @@ const CodeGenerator_1 = require("../codegen/CodeGenerator");
45
45
  const ActiveFlowNotFoundException_1 = require("../exceptions/ActiveFlowNotFoundException");
46
46
  const BrowserStateNotFoundException_1 = require("../exceptions/BrowserStateNotFoundException");
47
47
  const CannotDeleteRunningFlowException_1 = require("../exceptions/CannotDeleteRunningFlowException");
48
+ const FlowIdCollisionException_1 = require("../exceptions/FlowIdCollisionException");
48
49
  const FlowNotFoundException_1 = require("../exceptions/FlowNotFoundException");
49
50
  const InvalidParamValueException_1 = require("../exceptions/InvalidParamValueException");
50
51
  const TestNotFoundException_1 = require("../exceptions/TestNotFoundException");
@@ -96,7 +97,10 @@ class DonobuFlowsManager {
96
97
  * related parameters are will be ignored.
97
98
  */
98
99
  async createFlow(flowParams, gptClient, browserContextOverride) {
99
- const flowId = (0, crypto_1.randomUUID)();
100
+ if (flowParams.id) {
101
+ await this.assertFlowIdAvailable(flowParams.id);
102
+ }
103
+ const flowId = flowParams.id ?? (0, crypto_1.randomUUID)();
100
104
  const logBuffer = new FlowLogBuffer_1.FlowLogBuffer();
101
105
  return Logger_1.loggingContext.run({ flowId, logBuffer }, async () => {
102
106
  const messageDuration = flowParams.defaultMessageDuration ??
@@ -670,6 +674,27 @@ class DonobuFlowsManager {
670
674
  * back to the primary layer (the SQLite FK will reject if applicable;
671
675
  * non-DB layers will accept the dangling reference).
672
676
  */
677
+ /**
678
+ * Best-effort check that no flow with the given ID exists in any persistence
679
+ * layer. Throws {@link FlowIdCollisionException} on hit. Note: this is RACY
680
+ * — concurrent callers with the same ID can both pass the check.
681
+ */
682
+ async assertFlowIdAvailable(flowId) {
683
+ for (const persistence of await this.flowsPersistenceRegistry.getAll()) {
684
+ try {
685
+ await persistence.getFlowMetadataById(flowId);
686
+ throw FlowIdCollisionException_1.FlowIdCollisionException.forId(flowId);
687
+ }
688
+ catch (error) {
689
+ if (error instanceof FlowIdCollisionException_1.FlowIdCollisionException) {
690
+ throw error;
691
+ }
692
+ if (!(error instanceof FlowNotFoundException_1.FlowNotFoundException)) {
693
+ throw error;
694
+ }
695
+ }
696
+ }
697
+ }
673
698
  async resolveLayerForFlowCreate(testId) {
674
699
  if (!testId) {
675
700
  return this.flowsPersistenceRegistry.get();
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod/v4';
2
2
  export declare const CreateDonobuFlowSchema: z.ZodObject<{
3
+ id: z.ZodOptional<z.ZodString>;
3
4
  target: z.ZodString;
4
5
  web: z.ZodOptional<z.ZodObject<{
5
6
  browser: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -8,6 +8,19 @@ const ProposedToolCall_1 = require("./ProposedToolCall");
8
8
  const RunMode_1 = require("./RunMode");
9
9
  exports.CreateDonobuFlowSchema = v4_1.z
10
10
  .object({
11
+ id: v4_1.z
12
+ .string()
13
+ .uuid()
14
+ .optional()
15
+ .describe('⚠️ ADVANCED — DO NOT USE unless you have a specific reason. ' +
16
+ 'Pre-assigned flow ID (UUID). Useful only when the caller must know ' +
17
+ 'the ID before flow creation completes (e.g. orchestrators that ' +
18
+ 'pre-allocate IDs to track an in-flight execution). The SDK does a ' +
19
+ 'best-effort collision check against the persistence layer and ' +
20
+ 'throws FlowIdCollisionException if the ID already exists, but ' +
21
+ 'concurrent calls with the same ID are RACY: there is no locking, ' +
22
+ 'so two callers can both pass the check and create dueling rows. ' +
23
+ 'If you do not need this, omit it and let the SDK mint a UUID.'),
11
24
  target: v4_1.z
12
25
  .string()
13
26
  .describe('The target type: "web", "mobile", or a plugin-provided target.'),
@@ -0,0 +1,16 @@
1
+ import type { DonobuReport } from './model';
2
+ type FooterEnv = {
3
+ readonly GITHUB_RUN_ID?: string;
4
+ readonly GITHUB_RUN_NUMBER?: string;
5
+ readonly GITHUB_SERVER_URL?: string;
6
+ readonly GITHUB_REPOSITORY?: string;
7
+ readonly GITHUB_ACTOR?: string;
8
+ readonly GITHUB_REF_NAME?: string;
9
+ readonly CI_PIPELINE_URL?: string;
10
+ readonly CI_PIPELINE_IID?: string;
11
+ readonly GITLAB_USER_LOGIN?: string;
12
+ readonly CI_COMMIT_REF_NAME?: string;
13
+ };
14
+ export declare function renderPullRequestBody(report: DonobuReport, envData?: FooterEnv): string;
15
+ export {};
16
+ //# sourceMappingURL=renderPullRequestBody.d.ts.map
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderPullRequestBody = renderPullRequestBody;
4
+ /**
5
+ * @fileoverview Donobu auto-heal pull request body renderer.
6
+ *
7
+ * Turns the merged auto-heal `DonobuReport` into the markdown body of the
8
+ * PR/MR opened by the surrounding CI job. Pure: callers pass the env subset
9
+ * the footer needs as a plain object, defaulting to the central `env.pick`
10
+ * view of the relevant CI vars when running in production.
11
+ *
12
+ * Returns an empty string when nothing was healed — the CLI uses that to
13
+ * decide whether to write the file at all.
14
+ */
15
+ const envVars_1 = require("../envVars");
16
+ function parseHealedKey(rawKey) {
17
+ // Composite key shape from buildTestKey(): `file::projectName::title`.
18
+ // Titles can themselves contain `::`, so we only split off the first two
19
+ // segments and treat the remainder as the title.
20
+ const firstSep = rawKey.indexOf('::');
21
+ if (firstSep < 0) {
22
+ return { file: 'unknown-file', projectName: 'default', title: rawKey };
23
+ }
24
+ const file = rawKey.slice(0, firstSep);
25
+ const rest = rawKey.slice(firstSep + 2);
26
+ const secondSep = rest.indexOf('::');
27
+ if (secondSep < 0) {
28
+ return { file, projectName: 'default', title: rest };
29
+ }
30
+ return {
31
+ file,
32
+ projectName: rest.slice(0, secondSep),
33
+ title: rest.slice(secondSep + 2),
34
+ };
35
+ }
36
+ function renderPullRequestBody(report, envData = envVars_1.env.pick('GITHUB_RUN_ID', 'GITHUB_RUN_NUMBER', 'GITHUB_SERVER_URL', 'GITHUB_REPOSITORY', 'GITHUB_ACTOR', 'GITHUB_REF_NAME', 'CI_PIPELINE_URL', 'CI_PIPELINE_IID', 'GITLAB_USER_LOGIN', 'CI_COMMIT_REF_NAME').data) {
37
+ const healedKeys = report.metadata?.donobuHealedTests ?? [];
38
+ if (healedKeys.length === 0) {
39
+ return '';
40
+ }
41
+ const parsed = healedKeys.map(parseHealedKey);
42
+ const noun = parsed.length === 1 ? 'test' : 'tests';
43
+ let body = `🩹 **Donobu auto-heal applied fixes to ${parsed.length} failing ${noun}** in this branch.\n\n`;
44
+ body += `The auto-heal rerun applied a treatment plan to the failing ${noun}.\n\n`;
45
+ body += `## Healed ${noun}\n\n`;
46
+ for (const entry of parsed) {
47
+ const projectSuffix = entry.projectName && entry.projectName !== 'default'
48
+ ? ` _(project: \`${entry.projectName}\`)_`
49
+ : '';
50
+ body += `- ❤️‍🩹 \`${entry.file}\` — ${entry.title}${projectSuffix}\n`;
51
+ }
52
+ const footer = buildCiFooter(envData);
53
+ if (footer) {
54
+ body += `\n---\n\n${footer}\n`;
55
+ }
56
+ return body;
57
+ }
58
+ function buildCiFooter(e) {
59
+ if (e.GITHUB_RUN_ID && e.GITHUB_SERVER_URL && e.GITHUB_REPOSITORY) {
60
+ const url = `${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`;
61
+ const label = e.GITHUB_RUN_NUMBER
62
+ ? `workflow run #${e.GITHUB_RUN_NUMBER}`
63
+ : 'workflow run';
64
+ return assembleFooter(label, url, e.GITHUB_ACTOR, e.GITHUB_REF_NAME);
65
+ }
66
+ else if (e.CI_PIPELINE_URL) {
67
+ // `CI_PIPELINE_IID` is the per-project pipeline number GitLab shows in
68
+ // its UI ("#42") — far more useful in a footer than the global numeric
69
+ // `CI_PIPELINE_ID` reviewers don't recognize.
70
+ const label = e.CI_PIPELINE_IID
71
+ ? `pipeline #${e.CI_PIPELINE_IID}`
72
+ : 'pipeline';
73
+ return assembleFooter(label, e.CI_PIPELINE_URL, e.GITLAB_USER_LOGIN, e.CI_COMMIT_REF_NAME);
74
+ }
75
+ else {
76
+ return undefined;
77
+ }
78
+ }
79
+ function assembleFooter(label, url, actor, refName) {
80
+ let footer = `🤖 Generated by Donobu auto-heal · [${label}](${url})`;
81
+ if (actor) {
82
+ footer += ` · triggered by @${actor}`;
83
+ }
84
+ if (refName) {
85
+ footer += ` · on \`${refName}\``;
86
+ }
87
+ return footer;
88
+ }
89
+ //# sourceMappingURL=renderPullRequestBody.js.map
@@ -4,6 +4,7 @@ import type { ToolCallResult } from '../models/ToolCallResult';
4
4
  import { Tool } from './Tool';
5
5
  export declare const TriggerDonobuFlowCoreSchema: z.ZodObject<{
6
6
  donobuFlowParameters: z.ZodObject<{
7
+ id: z.ZodOptional<z.ZodString>;
7
8
  target: z.ZodString;
8
9
  web: z.ZodOptional<z.ZodObject<{
9
10
  browser: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -151,6 +152,7 @@ export declare const TriggerDonobuFlowCoreSchema: z.ZodObject<{
151
152
  }, z.core.$strip>;
152
153
  export declare const TriggerDonobuFlowGptSchema: z.ZodObject<{
153
154
  donobuFlowParameters: z.ZodObject<{
155
+ id: z.ZodOptional<z.ZodString>;
154
156
  target: z.ZodString;
155
157
  web: z.ZodOptional<z.ZodObject<{
156
158
  browser: z.ZodOptional<z.ZodNullable<z.ZodObject<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "donobu",
3
- "version": "5.37.0",
3
+ "version": "5.38.0",
4
4
  "description": "Create browser automations with an LLM agent and replay them as Playwright scripts.",
5
5
  "main": "dist/main.js",
6
6
  "module": "dist/esm/main.js",