@inkeep/agents-core 0.0.0-dev-20260324095902 → 0.0.0-dev-20260324145046

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 (50) hide show
  1. package/dist/auth/auth-validation-schemas.d.ts +154 -154
  2. package/dist/auth/permissions.d.ts +9 -9
  3. package/dist/data-access/manage/agents.d.ts +10 -10
  4. package/dist/data-access/manage/artifactComponents.d.ts +4 -4
  5. package/dist/data-access/manage/contextConfigs.d.ts +8 -8
  6. package/dist/data-access/manage/credentialReferences.js +1 -1
  7. package/dist/data-access/manage/dataComponents.js +1 -1
  8. package/dist/data-access/manage/functionTools.d.ts +4 -4
  9. package/dist/data-access/manage/skills.d.ts +10 -10
  10. package/dist/data-access/manage/subAgentExternalAgentRelations.d.ts +6 -6
  11. package/dist/data-access/manage/subAgentRelations.d.ts +8 -8
  12. package/dist/data-access/manage/subAgentTeamAgentRelations.d.ts +6 -6
  13. package/dist/data-access/manage/subAgents.d.ts +6 -6
  14. package/dist/data-access/manage/tools.d.ts +12 -12
  15. package/dist/data-access/manage/triggers.d.ts +2 -2
  16. package/dist/data-access/runtime/apiKeys.d.ts +8 -8
  17. package/dist/data-access/runtime/apps.d.ts +14 -14
  18. package/dist/data-access/runtime/conversations.d.ts +20 -20
  19. package/dist/data-access/runtime/messages.d.ts +15 -15
  20. package/dist/data-access/runtime/tasks.d.ts +5 -5
  21. package/dist/db/manage/manage-schema.d.ts +4 -4
  22. package/dist/db/runtime/test-runtime-client.js +1 -1
  23. package/dist/dolt/advisory-lock.d.ts +7 -0
  24. package/dist/dolt/advisory-lock.js +18 -0
  25. package/dist/dolt/branches-api.d.ts +19 -9
  26. package/dist/dolt/branches-api.js +58 -29
  27. package/dist/dolt/index.d.ts +7 -4
  28. package/dist/dolt/index.js +7 -4
  29. package/dist/dolt/merge.d.ts +41 -5
  30. package/dist/dolt/merge.js +161 -24
  31. package/dist/dolt/pk-map.d.ts +6 -0
  32. package/dist/dolt/pk-map.js +27 -0
  33. package/dist/dolt/ref-middleware.d.ts +2 -1
  34. package/dist/dolt/ref-middleware.js +18 -4
  35. package/dist/dolt/resolve-conflicts.d.ts +10 -0
  36. package/dist/dolt/resolve-conflicts.js +100 -0
  37. package/dist/dolt/schema-sync.js +17 -17
  38. package/dist/index.d.ts +8 -5
  39. package/dist/index.js +9 -6
  40. package/dist/middleware/no-auth.d.ts +2 -2
  41. package/dist/utils/error.d.ts +51 -51
  42. package/dist/utils/index.js +1 -1
  43. package/dist/utils/work-app-mcp.js +4 -3
  44. package/dist/validation/dolt-schemas.d.ts +95 -2
  45. package/dist/validation/dolt-schemas.js +54 -2
  46. package/dist/validation/drizzle-schema-helpers.d.ts +3 -3
  47. package/dist/validation/index.d.ts +2 -2
  48. package/dist/validation/index.js +2 -2
  49. package/dist/validation/schemas.d.ts +1886 -1886
  50. package/package.json +1 -1
@@ -1,9 +1,16 @@
1
+ import { doltHashOf } from "./commit.js";
1
2
  import { SCHEMA_SOURCE_BRANCH, ensureSchemaSync, getSchemaDiff, syncSchemaFromMain } from "./schema-sync.js";
2
3
  import { doltBranch, doltCheckout, doltDeleteBranch, doltGetBranchNamespace, doltListBranches } from "./branch.js";
3
4
  import { sql } from "drizzle-orm";
4
5
 
5
6
  //#region src/dolt/branches-api.ts
6
7
  const MAIN_BRANCH_SUFFIX = "main";
8
+ var invalidBranchParamsError = class extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "invalidBranchParamsError";
12
+ }
13
+ };
7
14
  /**
8
15
  * Get the tenant-scoped main branch name
9
16
  */
@@ -14,6 +21,12 @@ const getTenantMainBranch = (tenantId) => `${tenantId}_${MAIN_BRANCH_SUFFIX}`;
14
21
  const isProtectedBranchName = (branchName) => {
15
22
  return branchName === MAIN_BRANCH_SUFFIX;
16
23
  };
24
+ const getTempBranchSuffix = (prefix) => {
25
+ return `temp-${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
26
+ };
27
+ const isTempBranchName = (fullName) => {
28
+ return /temp-[a-z-]+_\d+_[a-z0-9]+$/.test(fullName);
29
+ };
17
30
  /**
18
31
  * Checkout a branch with optional schema synchronization from main.
19
32
  *
@@ -49,6 +62,13 @@ const checkoutBranch = (db) => async (params) => {
49
62
  }
50
63
  };
51
64
  };
65
+ const syncSchemaOnBranch = (db) => async (branchName) => {
66
+ if ((await getSchemaDiff(db)(branchName)).length > 0) {
67
+ await doltCheckout(db)({ branch: branchName });
68
+ const syncResult = await syncSchemaFromMain(db)({ autoCommitPending: true });
69
+ if (syncResult.error && !syncResult.synced) throw new Error(`Failed to sync schema on source branch '${branchName}': ${syncResult.error}`);
70
+ }
71
+ };
52
72
  /**
53
73
  * Create a new branch with optional schema synchronization.
54
74
  *
@@ -58,55 +78,64 @@ const checkoutBranch = (db) => async (params) => {
58
78
  *
59
79
  * By syncing schema on the source branch first, we ensure the new branch
60
80
  * starts with the latest schema, avoiding schema conflicts later.
81
+ * If you want to create a branch from a commit hash, use the fromCommit parameter.
61
82
  */
62
83
  const createBranch = (db) => async (params) => {
63
- const { tenantId, projectId, name, from, syncSchemaOnSource = true } = params;
64
- if (!name || name.trim() === "") throw new Error("Branch name cannot be empty");
84
+ const { tenantId, projectId, name, fromBranch, fromCommit, syncSchemaOnSource = true } = params;
85
+ if (fromBranch && fromCommit) throw new invalidBranchParamsError("Cannot specify both fromBranch and fromCommit");
86
+ if (!name || name.trim() === "") throw new invalidBranchParamsError("Branch name cannot be empty");
65
87
  const fullName = doltGetBranchNamespace({
66
88
  tenantId,
67
89
  projectId,
68
90
  branchName: name
69
91
  })();
70
- if ((await doltListBranches(db)()).some((b) => b.name === fullName)) throw new Error(`Branch '${name}' already exists`);
71
- let fromFullBranchName;
72
- if (from && from !== MAIN_BRANCH_SUFFIX) fromFullBranchName = doltGetBranchNamespace({
73
- tenantId,
74
- projectId,
75
- branchName: from
76
- })();
77
- else fromFullBranchName = getTenantMainBranch(tenantId);
78
- if (syncSchemaOnSource && fromFullBranchName !== SCHEMA_SOURCE_BRANCH) {
79
- if ((await getSchemaDiff(db)(fromFullBranchName)).length > 0) {
80
- await doltCheckout(db)({ branch: fromFullBranchName });
81
- const syncResult = await syncSchemaFromMain(db)({ autoCommitPending: true });
82
- if (syncResult.error && !syncResult.synced) throw new Error(`Failed to sync schema on source branch '${fromFullBranchName}': ${syncResult.error}`);
83
- }
92
+ if ((await doltListBranches(db)()).some((b) => b.name === fullName)) throw new invalidBranchParamsError(`Branch '${name}' already exists`);
93
+ if (fromCommit) {
94
+ await doltBranch(db)({
95
+ name: fullName,
96
+ startPoint: fromCommit
97
+ });
98
+ if (syncSchemaOnSource) await syncSchemaOnBranch(db)(fullName);
99
+ } else {
100
+ let fromFullBranchName;
101
+ if (fromBranch) fromFullBranchName = doltGetBranchNamespace({
102
+ tenantId,
103
+ projectId,
104
+ branchName: fromBranch
105
+ })();
106
+ else fromFullBranchName = doltGetBranchNamespace({
107
+ tenantId,
108
+ projectId,
109
+ branchName: MAIN_BRANCH_SUFFIX
110
+ })();
111
+ if (syncSchemaOnSource && fromFullBranchName !== SCHEMA_SOURCE_BRANCH) await syncSchemaOnBranch(db)(fromFullBranchName);
112
+ await doltBranch(db)({
113
+ name: fullName,
114
+ startPoint: fromFullBranchName
115
+ });
84
116
  }
85
- await doltBranch(db)({
86
- name: fullName,
87
- startPoint: fromFullBranchName
88
- });
89
- const newBranch = (await doltListBranches(db)()).find((b) => b.name === fullName);
90
- if (!newBranch) throw new Error("Failed to create branch");
91
117
  return {
92
118
  baseName: name,
93
119
  fullName,
94
- hash: newBranch.hash
120
+ hash: await doltHashOf(db)({ revision: fullName })
95
121
  };
96
122
  };
97
123
  /**
98
124
  * Delete a branch
99
125
  */
100
126
  const deleteBranch = (db) => async (params) => {
101
- const { tenantId, projectId, name } = params;
102
- if (isProtectedBranchName(name)) throw new Error(`Cannot delete protected branch '${name}'`);
127
+ const { tenantId, projectId, branchName, force } = params;
128
+ if (isProtectedBranchName(branchName)) throw new invalidBranchParamsError(`Cannot delete protected branch '${branchName}'`);
103
129
  const fullName = doltGetBranchNamespace({
104
130
  tenantId,
105
131
  projectId,
106
- branchName: name
132
+ branchName
107
133
  })();
108
- if (!(await doltListBranches(db)()).some((b) => b.name === fullName)) throw new Error(`Branch '${name}' not found`);
109
- await doltDeleteBranch(db)({ name: fullName });
134
+ if (!(await doltListBranches(db)()).some((b) => b.name === fullName)) throw new invalidBranchParamsError(`Branch '${branchName}' not found`);
135
+ await doltDeleteBranch(db)({
136
+ name: fullName,
137
+ force
138
+ });
110
139
  };
111
140
  /**
112
141
  * Get a single branch
@@ -159,4 +188,4 @@ const listBranchesForAgent = (db) => async (params) => {
159
188
  };
160
189
 
161
190
  //#endregion
162
- export { MAIN_BRANCH_SUFFIX, checkoutBranch, createBranch, deleteBranch, getBranch, getTenantMainBranch, isProtectedBranchName, listBranches, listBranchesForAgent };
191
+ export { MAIN_BRANCH_SUFFIX, checkoutBranch, createBranch, deleteBranch, getBranch, getTempBranchSuffix, getTenantMainBranch, invalidBranchParamsError, isProtectedBranchName, isTempBranchName, listBranches, listBranchesForAgent, syncSchemaOnBranch };
@@ -1,10 +1,13 @@
1
+ import { releaseAdvisoryLock, tryAdvisoryLock } from "./advisory-lock.js";
1
2
  import { branchScopes, doltActiveBranch, doltBranch, doltBranchExists, doltCheckout, doltDeleteBranch, doltGetBranchNamespace, doltListBranches, doltRenameBranch, ensureBranchExists } from "./branch.js";
2
- import { CheckoutBranchParams, CheckoutBranchResult, CreateBranchParams, DeleteBranchParams, GetBranchParams, MAIN_BRANCH_SUFFIX, checkoutBranch, createBranch, deleteBranch, getBranch, getTenantMainBranch, isProtectedBranchName, listBranches, listBranchesForAgent } from "./branches-api.js";
3
+ import { CheckoutBranchParams, CheckoutBranchResult, CreateBranchParams, DeleteBranchParams, GetBranchParams, MAIN_BRANCH_SUFFIX, checkoutBranch, createBranch, deleteBranch, getBranch, getTempBranchSuffix, getTenantMainBranch, invalidBranchParamsError, isProtectedBranchName, isTempBranchName, listBranches, listBranchesForAgent, syncSchemaOnBranch } from "./branches-api.js";
3
4
  import { doltAdd, doltAddAndCommit, doltCommit, doltDeleteTag, doltHashOf, doltListTags, doltLog, doltReset, doltStatus, doltTag } from "./commit.js";
4
5
  import { doltDiff, doltDiffSummary } from "./diff.js";
5
- import { doltAbortMerge, doltConflicts, doltMerge, doltMergeStatus, doltResolveConflicts, doltSchemaConflicts, doltTableConflicts } from "./merge.js";
6
+ import { MergeConflictError, doltAbortMerge, doltConflicts, doltMerge, doltMergeStatus, doltPreviewMergeConflicts, doltPreviewMergeConflictsSummary, doltResolveConflicts, doltSchemaConflicts, doltTableConflicts } from "./merge.js";
7
+ import { PkMap, isValidManageTable, managePkMap } from "./pk-map.js";
6
8
  import { RefType, checkoutRef, getCurrentBranchOrCommit, getProjectMainResolvedRef, getProjectScopedRef, getTenantScopedRef, isRefWritable, isValidCommitHash, resolveProjectMainRefs, resolveRef } from "./ref-helpers.js";
7
- import { RefContext, RefMiddlewareOptions, createRefMiddleware, createWriteProtectionMiddleware, refMiddlewareFactory, writeProtectionMiddlewareFactory } from "./ref-middleware.js";
9
+ import { RefContext, RefMiddlewareOptions, createRefMiddleware, createWriteProtectionMiddleware, isMergeRoute, refMiddlewareFactory, writeProtectionMiddlewareFactory } from "./ref-middleware.js";
8
10
  import { NestedRefScopeError, WithRefOptions, getCurrentRefScope, getRefScopedDb, isInRefScope, withRef } from "./ref-scope.js";
11
+ import { ResolutionValidationError, applyResolutions } from "./resolve-conflicts.js";
9
12
  import { EnsureSchemaSyncOptions, SCHEMA_SOURCE_BRANCH, SchemaDiff, SchemaSyncOptions, SchemaSyncResult, areBranchesSchemaCompatible, ensureSchemaSync, formatSchemaDiffSummary, getActiveBranch, getSchemaDiff, hasSchemaDifferences, hasUncommittedChanges, isLocalhostUrl, syncSchemaFromMain } from "./schema-sync.js";
10
- export { CheckoutBranchParams, CheckoutBranchResult, CreateBranchParams, DeleteBranchParams, EnsureSchemaSyncOptions, GetBranchParams, MAIN_BRANCH_SUFFIX, NestedRefScopeError, RefContext, RefMiddlewareOptions, RefType, SCHEMA_SOURCE_BRANCH, SchemaDiff, SchemaSyncOptions, SchemaSyncResult, WithRefOptions, areBranchesSchemaCompatible, branchScopes, checkoutBranch, checkoutRef, createBranch, createRefMiddleware, createWriteProtectionMiddleware, deleteBranch, doltAbortMerge, doltActiveBranch, doltAdd, doltAddAndCommit, doltBranch, doltBranchExists, doltCheckout, doltCommit, doltConflicts, doltDeleteBranch, doltDeleteTag, doltDiff, doltDiffSummary, doltGetBranchNamespace, doltHashOf, doltListBranches, doltListTags, doltLog, doltMerge, doltMergeStatus, doltRenameBranch, doltReset, doltResolveConflicts, doltSchemaConflicts, doltStatus, doltTableConflicts, doltTag, ensureBranchExists, ensureSchemaSync, formatSchemaDiffSummary, getActiveBranch, getBranch, getCurrentBranchOrCommit, getCurrentRefScope, getProjectMainResolvedRef, getProjectScopedRef, getRefScopedDb, getSchemaDiff, getTenantMainBranch, getTenantScopedRef, hasSchemaDifferences, hasUncommittedChanges, isInRefScope, isLocalhostUrl, isProtectedBranchName, isRefWritable, isValidCommitHash, listBranches, listBranchesForAgent, refMiddlewareFactory, resolveProjectMainRefs, resolveRef, syncSchemaFromMain, withRef, writeProtectionMiddlewareFactory };
13
+ export { CheckoutBranchParams, CheckoutBranchResult, CreateBranchParams, DeleteBranchParams, EnsureSchemaSyncOptions, GetBranchParams, MAIN_BRANCH_SUFFIX, MergeConflictError, NestedRefScopeError, PkMap, RefContext, RefMiddlewareOptions, RefType, ResolutionValidationError, SCHEMA_SOURCE_BRANCH, SchemaDiff, SchemaSyncOptions, SchemaSyncResult, WithRefOptions, applyResolutions, areBranchesSchemaCompatible, branchScopes, checkoutBranch, checkoutRef, createBranch, createRefMiddleware, createWriteProtectionMiddleware, deleteBranch, doltAbortMerge, doltActiveBranch, doltAdd, doltAddAndCommit, doltBranch, doltBranchExists, doltCheckout, doltCommit, doltConflicts, doltDeleteBranch, doltDeleteTag, doltDiff, doltDiffSummary, doltGetBranchNamespace, doltHashOf, doltListBranches, doltListTags, doltLog, doltMerge, doltMergeStatus, doltPreviewMergeConflicts, doltPreviewMergeConflictsSummary, doltRenameBranch, doltReset, doltResolveConflicts, doltSchemaConflicts, doltStatus, doltTableConflicts, doltTag, ensureBranchExists, ensureSchemaSync, formatSchemaDiffSummary, getActiveBranch, getBranch, getCurrentBranchOrCommit, getCurrentRefScope, getProjectMainResolvedRef, getProjectScopedRef, getRefScopedDb, getSchemaDiff, getTempBranchSuffix, getTenantMainBranch, getTenantScopedRef, hasSchemaDifferences, hasUncommittedChanges, invalidBranchParamsError, isInRefScope, isLocalhostUrl, isMergeRoute, isProtectedBranchName, isRefWritable, isTempBranchName, isValidCommitHash, isValidManageTable, listBranches, listBranchesForAgent, managePkMap, refMiddlewareFactory, releaseAdvisoryLock, resolveProjectMainRefs, resolveRef, syncSchemaFromMain, syncSchemaOnBranch, tryAdvisoryLock, withRef, writeProtectionMiddlewareFactory };
@@ -1,11 +1,14 @@
1
1
  import { doltAdd, doltAddAndCommit, doltCommit, doltDeleteTag, doltHashOf, doltListTags, doltLog, doltReset, doltStatus, doltTag } from "./commit.js";
2
- import { doltAbortMerge, doltConflicts, doltMerge, doltMergeStatus, doltResolveConflicts, doltSchemaConflicts, doltTableConflicts } from "./merge.js";
2
+ import { isValidManageTable, managePkMap } from "./pk-map.js";
3
+ import { ResolutionValidationError, applyResolutions } from "./resolve-conflicts.js";
4
+ import { MergeConflictError, doltAbortMerge, doltConflicts, doltMerge, doltMergeStatus, doltPreviewMergeConflicts, doltPreviewMergeConflictsSummary, doltResolveConflicts, doltSchemaConflicts, doltTableConflicts } from "./merge.js";
3
5
  import { SCHEMA_SOURCE_BRANCH, areBranchesSchemaCompatible, ensureSchemaSync, formatSchemaDiffSummary, getActiveBranch, getSchemaDiff, hasSchemaDifferences, hasUncommittedChanges, isLocalhostUrl, syncSchemaFromMain } from "./schema-sync.js";
4
- import { MAIN_BRANCH_SUFFIX, checkoutBranch, createBranch, deleteBranch, getBranch, getTenantMainBranch, isProtectedBranchName, listBranches, listBranchesForAgent } from "./branches-api.js";
6
+ import { MAIN_BRANCH_SUFFIX, checkoutBranch, createBranch, deleteBranch, getBranch, getTempBranchSuffix, getTenantMainBranch, invalidBranchParamsError, isProtectedBranchName, isTempBranchName, listBranches, listBranchesForAgent, syncSchemaOnBranch } from "./branches-api.js";
5
7
  import { checkoutRef, getCurrentBranchOrCommit, getProjectMainResolvedRef, getProjectScopedRef, getTenantScopedRef, isRefWritable, isValidCommitHash, resolveProjectMainRefs, resolveRef } from "./ref-helpers.js";
6
8
  import { doltActiveBranch, doltBranch, doltBranchExists, doltCheckout, doltDeleteBranch, doltGetBranchNamespace, doltListBranches, doltRenameBranch, ensureBranchExists } from "./branch.js";
9
+ import { releaseAdvisoryLock, tryAdvisoryLock } from "./advisory-lock.js";
7
10
  import { doltDiff, doltDiffSummary } from "./diff.js";
8
- import { createRefMiddleware, createWriteProtectionMiddleware, refMiddlewareFactory, writeProtectionMiddlewareFactory } from "./ref-middleware.js";
11
+ import { createRefMiddleware, createWriteProtectionMiddleware, isMergeRoute, refMiddlewareFactory, writeProtectionMiddlewareFactory } from "./ref-middleware.js";
9
12
  import { NestedRefScopeError, getCurrentRefScope, getRefScopedDb, isInRefScope, withRef } from "./ref-scope.js";
10
13
 
11
- export { MAIN_BRANCH_SUFFIX, NestedRefScopeError, SCHEMA_SOURCE_BRANCH, areBranchesSchemaCompatible, checkoutBranch, checkoutRef, createBranch, createRefMiddleware, createWriteProtectionMiddleware, deleteBranch, doltAbortMerge, doltActiveBranch, doltAdd, doltAddAndCommit, doltBranch, doltBranchExists, doltCheckout, doltCommit, doltConflicts, doltDeleteBranch, doltDeleteTag, doltDiff, doltDiffSummary, doltGetBranchNamespace, doltHashOf, doltListBranches, doltListTags, doltLog, doltMerge, doltMergeStatus, doltRenameBranch, doltReset, doltResolveConflicts, doltSchemaConflicts, doltStatus, doltTableConflicts, doltTag, ensureBranchExists, ensureSchemaSync, formatSchemaDiffSummary, getActiveBranch, getBranch, getCurrentBranchOrCommit, getCurrentRefScope, getProjectMainResolvedRef, getProjectScopedRef, getRefScopedDb, getSchemaDiff, getTenantMainBranch, getTenantScopedRef, hasSchemaDifferences, hasUncommittedChanges, isInRefScope, isLocalhostUrl, isProtectedBranchName, isRefWritable, isValidCommitHash, listBranches, listBranchesForAgent, refMiddlewareFactory, resolveProjectMainRefs, resolveRef, syncSchemaFromMain, withRef, writeProtectionMiddlewareFactory };
14
+ export { MAIN_BRANCH_SUFFIX, MergeConflictError, NestedRefScopeError, ResolutionValidationError, SCHEMA_SOURCE_BRANCH, applyResolutions, areBranchesSchemaCompatible, checkoutBranch, checkoutRef, createBranch, createRefMiddleware, createWriteProtectionMiddleware, deleteBranch, doltAbortMerge, doltActiveBranch, doltAdd, doltAddAndCommit, doltBranch, doltBranchExists, doltCheckout, doltCommit, doltConflicts, doltDeleteBranch, doltDeleteTag, doltDiff, doltDiffSummary, doltGetBranchNamespace, doltHashOf, doltListBranches, doltListTags, doltLog, doltMerge, doltMergeStatus, doltPreviewMergeConflicts, doltPreviewMergeConflictsSummary, doltRenameBranch, doltReset, doltResolveConflicts, doltSchemaConflicts, doltStatus, doltTableConflicts, doltTag, ensureBranchExists, ensureSchemaSync, formatSchemaDiffSummary, getActiveBranch, getBranch, getCurrentBranchOrCommit, getCurrentRefScope, getProjectMainResolvedRef, getProjectScopedRef, getRefScopedDb, getSchemaDiff, getTempBranchSuffix, getTenantMainBranch, getTenantScopedRef, hasSchemaDifferences, hasUncommittedChanges, invalidBranchParamsError, isInRefScope, isLocalhostUrl, isMergeRoute, isProtectedBranchName, isRefWritable, isTempBranchName, isValidCommitHash, isValidManageTable, listBranches, listBranchesForAgent, managePkMap, refMiddlewareFactory, releaseAdvisoryLock, resolveProjectMainRefs, resolveRef, syncSchemaFromMain, syncSchemaOnBranch, tryAdvisoryLock, withRef, writeProtectionMiddlewareFactory };
@@ -1,10 +1,24 @@
1
+ import { ConflictResolution } from "../validation/dolt-schemas.js";
1
2
  import { AgentsManageDatabaseClient } from "../db/manage/manage-client.js";
2
3
 
3
4
  //#region src/dolt/merge.d.ts
4
-
5
+ declare class MergeConflictError extends Error {
6
+ readonly conflictCount: number;
7
+ readonly fromBranch: string;
8
+ readonly toBranch: string;
9
+ constructor(message: string, conflictCount: number, fromBranch: string, toBranch: string);
10
+ }
5
11
  /**
6
- * Merge another branch into the current branch
7
- * Returns merge status and handles conflicts by allowing commit with conflicts
12
+ * Merge a branch into the currently checked out branch.
13
+ *
14
+ * Runs inside an explicit transaction so that conflicts and
15
+ * constraint-violations are surfaced to the caller instead of being
16
+ * auto-rolled-back by Dolt's AUTOCOMMIT mode.
17
+ *
18
+ * If conflicts arise and `resolutions` are provided, they are applied
19
+ * and the merge is committed. If conflicts arise without resolutions
20
+ * (or with insufficient resolutions), the transaction is rolled back
21
+ * and a `MergeConflictError` is thrown.
8
22
  */
9
23
  declare const doltMerge: (db: AgentsManageDatabaseClient) => (params: {
10
24
  fromBranch: string;
@@ -15,8 +29,9 @@ declare const doltMerge: (db: AgentsManageDatabaseClient) => (params: {
15
29
  name: string;
16
30
  email: string;
17
31
  };
32
+ resolutions?: ConflictResolution[];
18
33
  }) => Promise<{
19
- status: "success" | "conflicts";
34
+ status: "success";
20
35
  from: string;
21
36
  to: string;
22
37
  toHead?: string;
@@ -52,6 +67,27 @@ declare const doltTableConflicts: (db: AgentsManageDatabaseClient) => (params: {
52
67
  * Get schema conflicts
53
68
  */
54
69
  declare const doltSchemaConflicts: (db: AgentsManageDatabaseClient) => () => Promise<any[]>;
70
+ /**
71
+ * Preview merge conflicts without modifying the database (dry-run).
72
+ * Returns a summary of which tables have conflicts.
73
+ */
74
+ declare const doltPreviewMergeConflictsSummary: (db: AgentsManageDatabaseClient) => (params: {
75
+ baseBranch: string;
76
+ mergeBranch: string;
77
+ }) => Promise<{
78
+ table: string;
79
+ numDataConflicts: number;
80
+ numSchemaConflicts: number;
81
+ }[]>;
82
+ /**
83
+ * Preview detailed merge conflicts for a specific table without modifying the database (dry-run).
84
+ * Returns the same column shape as dolt_conflicts_$table.
85
+ */
86
+ declare const doltPreviewMergeConflicts: (db: AgentsManageDatabaseClient) => (params: {
87
+ baseBranch: string;
88
+ mergeBranch: string;
89
+ tableName: string;
90
+ }) => Promise<Record<string, unknown>[]>;
55
91
  /**
56
92
  * Resolve conflicts for a table using a strategy
57
93
  */
@@ -60,4 +96,4 @@ declare const doltResolveConflicts: (db: AgentsManageDatabaseClient) => (params:
60
96
  strategy: "ours" | "theirs";
61
97
  }) => Promise<void>;
62
98
  //#endregion
63
- export { doltAbortMerge, doltConflicts, doltMerge, doltMergeStatus, doltResolveConflicts, doltSchemaConflicts, doltTableConflicts };
99
+ export { MergeConflictError, doltAbortMerge, doltConflicts, doltMerge, doltMergeStatus, doltPreviewMergeConflicts, doltPreviewMergeConflictsSummary, doltResolveConflicts, doltSchemaConflicts, doltTableConflicts };
@@ -1,36 +1,150 @@
1
+ import { getLogger } from "../utils/logger.js";
2
+ import { doltAddAndCommit } from "./commit.js";
3
+ import { createApiError } from "../utils/error.js";
4
+ import { managePkMap } from "./pk-map.js";
5
+ import { ResolutionValidationError, applyResolutions } from "./resolve-conflicts.js";
1
6
  import { doltCheckout } from "./branch.js";
2
7
  import { sql } from "drizzle-orm";
3
8
 
4
9
  //#region src/dolt/merge.ts
10
+ const logger = getLogger("dolt-merge");
11
+ const TIMESTAMP_COLUMNS = new Set(["created_at", "updated_at"]);
12
+ var MergeConflictError = class extends Error {
13
+ constructor(message, conflictCount, fromBranch, toBranch) {
14
+ super(message);
15
+ this.conflictCount = conflictCount;
16
+ this.fromBranch = fromBranch;
17
+ this.toBranch = toBranch;
18
+ this.name = "MergeConflictError";
19
+ }
20
+ };
21
+ function extractConflictCount(row) {
22
+ if (typeof row.conflicts === "number" || typeof row.conflicts === "string") return Number(row.conflicts);
23
+ const doltMerge$1 = row.dolt_merge;
24
+ if (Array.isArray(doltMerge$1)) return Number(doltMerge$1[2] ?? 0);
25
+ throw new Error(`Unexpected DOLT_MERGE result format: ${JSON.stringify(row)}`);
26
+ }
27
+ function isTimestampOnlyConflictRow(row, pkColumns) {
28
+ if (row.our_diff_type !== "modified" || row.their_diff_type !== "modified") return false;
29
+ const pkSet = new Set(pkColumns);
30
+ for (const key of Object.keys(row)) {
31
+ if (!key.startsWith("base_")) continue;
32
+ const col = key.slice(5);
33
+ if (col === "diff_type" || pkSet.has(col) || TIMESTAMP_COLUMNS.has(col)) continue;
34
+ if (String(row[`base_${col}`] ?? "") !== String(row[`our_${col}`] ?? "") || String(row[`base_${col}`] ?? "") !== String(row[`their_${col}`] ?? "")) return false;
35
+ }
36
+ return true;
37
+ }
38
+ function buildTimestampAutoResolution(tableName, row, pkColumns) {
39
+ const primaryKey = {};
40
+ for (const col of pkColumns) primaryKey[col] = String(row[`base_${col}`] ?? row[`our_${col}`] ?? row[`their_${col}`]);
41
+ return {
42
+ table: tableName,
43
+ primaryKey,
44
+ rowDefaultPick: (row.our_updated_at ? new Date(String(row.our_updated_at)) : /* @__PURE__ */ new Date(0)) >= (row.their_updated_at ? new Date(String(row.their_updated_at)) : /* @__PURE__ */ new Date(0)) ? "ours" : "theirs"
45
+ };
46
+ }
5
47
  /**
6
- * Merge another branch into the current branch
7
- * Returns merge status and handles conflicts by allowing commit with conflicts
48
+ * Merge a branch into the currently checked out branch.
49
+ *
50
+ * Runs inside an explicit transaction so that conflicts and
51
+ * constraint-violations are surfaced to the caller instead of being
52
+ * auto-rolled-back by Dolt's AUTOCOMMIT mode.
53
+ *
54
+ * If conflicts arise and `resolutions` are provided, they are applied
55
+ * and the merge is committed. If conflicts arise without resolutions
56
+ * (or with insufficient resolutions), the transaction is rolled back
57
+ * and a `MergeConflictError` is thrown.
8
58
  */
9
59
  const doltMerge = (db) => async (params) => {
10
- console.log("merging branch", params.fromBranch, "into", params.toBranch);
60
+ logger.info({
61
+ fromBranch: params.fromBranch,
62
+ toBranch: params.toBranch
63
+ }, "Merging branch");
11
64
  await doltCheckout(db)({ branch: params.toBranch });
12
65
  const toHead = (await db.execute(sql`SELECT HASHOF('HEAD') as hash`)).rows[0]?.hash;
13
- const args = [`'${params.fromBranch}'`];
66
+ const args = [`'${params.fromBranch.replace(/'/g, "''")}'`];
14
67
  if (params.noFastForward) args.push("'--no-ff'");
15
- if (params.message) args.push("'-m'", `'${params.message.replace(/'/g, "''")}'`);
16
- if (params.author) args.push("'--author'", `'${params.author.name} <${params.author.email}>'`);
17
- const firstRow = (await db.execute(sql.raw(`SELECT DOLT_MERGE(${args.join(", ")})`))).rows[0] ?? {};
18
- const mergeResult = typeof firstRow.conflicts === "number" || typeof firstRow.conflicts === "string" || firstRow.conflicts == null ? firstRow : Object.values(firstRow)[0] ?? {};
19
- const conflicts = Number(mergeResult.conflicts ?? 0);
20
- if (Number.isFinite(conflicts) && conflicts > 0) return {
21
- status: "conflicts",
22
- from: params.fromBranch,
23
- to: params.toBranch,
24
- toHead,
25
- hasConflicts: true
26
- };
27
- return {
28
- status: "success",
29
- from: params.fromBranch,
30
- to: params.toBranch,
31
- toHead,
32
- hasConflicts: false
33
- };
68
+ if (params.message) {
69
+ const cleanedMessage = params.message.replace(/'/g, "''");
70
+ args.push("'-m'", `'${cleanedMessage}'`);
71
+ }
72
+ const cleanedAuthor = params.author?.name?.replace(/'/g, "''");
73
+ const cleanedEmail = params.author?.email?.replace(/'/g, "''");
74
+ if (params.author) args.push("'--author'", `'${cleanedAuthor} <${cleanedEmail}>'`);
75
+ await db.execute(sql.raw("START TRANSACTION"));
76
+ let txFinalized = false;
77
+ try {
78
+ let result;
79
+ try {
80
+ result = await db.execute(sql.raw(`SELECT DOLT_MERGE(${args.join(", ")})`));
81
+ logger.info({ result }, "DOLT_MERGE result");
82
+ } catch (error) {
83
+ const cause = error?.cause;
84
+ logger.error({
85
+ message: error?.message,
86
+ code: cause?.code,
87
+ severity: cause?.severity,
88
+ detail: cause?.detail,
89
+ hint: cause?.hint,
90
+ query: error?.query,
91
+ fromBranch: params.fromBranch,
92
+ toBranch: params.toBranch
93
+ }, "Error merging branch");
94
+ throw error;
95
+ }
96
+ const conflicts = extractConflictCount(result.rows[0] ?? {});
97
+ if (Number.isFinite(conflicts) && conflicts > 0) {
98
+ const userResolutions = params.resolutions ?? [];
99
+ const autoResolutions = [];
100
+ const conflictTables = await doltConflicts(db)();
101
+ let manualConflicts = 0;
102
+ for (const ct of conflictTables) {
103
+ const tableConflicts = await doltTableConflicts(db)({ tableName: ct.table });
104
+ const pkColumns = managePkMap[ct.table] ?? [];
105
+ for (const row of tableConflicts) if (isTimestampOnlyConflictRow(row, pkColumns)) autoResolutions.push(buildTimestampAutoResolution(ct.table, row, pkColumns));
106
+ else manualConflicts++;
107
+ }
108
+ if (manualConflicts > 0 && userResolutions.length < manualConflicts) throw new MergeConflictError(manualConflicts > 0 && userResolutions.length === 0 ? "Merge has conflicts but no resolutions were provided." : `Resolutions provided (${userResolutions.length}) do not cover all conflicts (${manualConflicts}). All conflicts must be resolved.`, manualConflicts, params.fromBranch, params.toBranch);
109
+ const allResolutions = [...autoResolutions, ...userResolutions];
110
+ try {
111
+ await applyResolutions(db)(allResolutions);
112
+ } catch (error) {
113
+ if (error instanceof ResolutionValidationError) throw createApiError({
114
+ code: "bad_request",
115
+ message: `Invalid resolution: ${error.message}`
116
+ });
117
+ throw error;
118
+ }
119
+ await doltAddAndCommit(db)({
120
+ message: params.message ? `${params.message} (with conflict resolution)` : `Merge ${params.fromBranch} into ${params.toBranch} (with conflict resolution)`,
121
+ author: params.author
122
+ });
123
+ txFinalized = true;
124
+ return {
125
+ status: "success",
126
+ from: params.fromBranch,
127
+ to: params.toBranch,
128
+ toHead,
129
+ hasConflicts: true
130
+ };
131
+ }
132
+ await db.execute(sql.raw("COMMIT"));
133
+ txFinalized = true;
134
+ return {
135
+ status: "success",
136
+ from: params.fromBranch,
137
+ to: params.toBranch,
138
+ toHead,
139
+ hasConflicts: false
140
+ };
141
+ } finally {
142
+ if (!txFinalized) try {
143
+ await db.execute(sql.raw("ROLLBACK"));
144
+ } catch (rollbackError) {
145
+ logger.error({ error: rollbackError }, "Failed to rollback transaction");
146
+ }
147
+ }
34
148
  };
35
149
  /**
36
150
  * Abort a merge
@@ -70,6 +184,29 @@ const doltSchemaConflicts = (db) => async () => {
70
184
  return (await db.execute(sql`SELECT * FROM dolt_schema_conflicts`)).rows;
71
185
  };
72
186
  /**
187
+ * Preview merge conflicts without modifying the database (dry-run).
188
+ * Returns a summary of which tables have conflicts.
189
+ */
190
+ const doltPreviewMergeConflictsSummary = (db) => async (params) => {
191
+ const escapedBaseBranch = params.baseBranch.replace(/'/g, "''");
192
+ const escapedMergeBranch = params.mergeBranch.replace(/'/g, "''");
193
+ return (await db.execute(sql.raw(`SELECT * FROM DOLT_PREVIEW_MERGE_CONFLICTS_SUMMARY('${escapedBaseBranch}', '${escapedMergeBranch}')`))).rows.map((row) => ({
194
+ table: row.table.replace("public.", ""),
195
+ numDataConflicts: Number(row.num_data_conflicts ?? 0),
196
+ numSchemaConflicts: Number(row.num_schema_conflicts ?? 0)
197
+ }));
198
+ };
199
+ /**
200
+ * Preview detailed merge conflicts for a specific table without modifying the database (dry-run).
201
+ * Returns the same column shape as dolt_conflicts_$table.
202
+ */
203
+ const doltPreviewMergeConflicts = (db) => async (params) => {
204
+ const escapedBaseBranch = params.baseBranch.replace(/'/g, "''");
205
+ const escapedMergeBranch = params.mergeBranch.replace(/'/g, "''");
206
+ const escapedTableName = params.tableName.replace(/'/g, "''");
207
+ return (await db.execute(sql.raw(`SELECT * FROM DOLT_PREVIEW_MERGE_CONFLICTS('${escapedBaseBranch}', '${escapedMergeBranch}', '${escapedTableName}')`))).rows;
208
+ };
209
+ /**
73
210
  * Resolve conflicts for a table using a strategy
74
211
  */
75
212
  const doltResolveConflicts = (db) => async (params) => {
@@ -78,4 +215,4 @@ const doltResolveConflicts = (db) => async (params) => {
78
215
  };
79
216
 
80
217
  //#endregion
81
- export { doltAbortMerge, doltConflicts, doltMerge, doltMergeStatus, doltResolveConflicts, doltSchemaConflicts, doltTableConflicts };
218
+ export { MergeConflictError, doltAbortMerge, doltConflicts, doltMerge, doltMergeStatus, doltPreviewMergeConflicts, doltPreviewMergeConflictsSummary, doltResolveConflicts, doltSchemaConflicts, doltTableConflicts };
@@ -0,0 +1,6 @@
1
+ //#region src/dolt/pk-map.d.ts
2
+ type PkMap = Record<string, string[]>;
3
+ declare const managePkMap: PkMap;
4
+ declare const isValidManageTable: (tableName: string) => boolean;
5
+ //#endregion
6
+ export { PkMap, isValidManageTable, managePkMap };
@@ -0,0 +1,27 @@
1
+ import { manage_schema_exports } from "../db/manage/manage-schema.js";
2
+ import { getTableConfig } from "drizzle-orm/pg-core";
3
+
4
+ //#region src/dolt/pk-map.ts
5
+ function buildPkMapFromSchema() {
6
+ const pkMap = {};
7
+ for (const value of Object.values(manage_schema_exports)) {
8
+ if (value == null || typeof value !== "object") continue;
9
+ let config;
10
+ try {
11
+ config = getTableConfig(value);
12
+ } catch {
13
+ continue;
14
+ }
15
+ if (!config?.name || !config.primaryKeys?.length) continue;
16
+ const pkColumns = config.primaryKeys[0]?.columns.map((col) => col.name);
17
+ if (pkColumns && pkColumns.length > 0) pkMap[config.name] = pkColumns;
18
+ }
19
+ return pkMap;
20
+ }
21
+ const managePkMap = buildPkMapFromSchema();
22
+ const isValidManageTable = (tableName) => {
23
+ return tableName in managePkMap;
24
+ };
25
+
26
+ //#endregion
27
+ export { isValidManageTable, managePkMap };
@@ -3,6 +3,7 @@ import { AgentsManageDatabaseClient } from "../db/manage/manage-client.js";
3
3
  import { Context, Next } from "hono";
4
4
 
5
5
  //#region src/dolt/ref-middleware.d.ts
6
+ declare function isMergeRoute(path: string): boolean;
6
7
  type RefContext = {
7
8
  resolvedRef?: ResolvedRef;
8
9
  };
@@ -79,4 +80,4 @@ declare const refMiddlewareFactory: (db: AgentsManageDatabaseClient, options?: R
79
80
  */
80
81
  declare const writeProtectionMiddlewareFactory: () => (c: Context, next: Next) => Promise<void>;
81
82
  //#endregion
82
- export { RefContext, RefMiddlewareOptions, createRefMiddleware, createWriteProtectionMiddleware, refMiddlewareFactory, writeProtectionMiddlewareFactory };
83
+ export { RefContext, RefMiddlewareOptions, createRefMiddleware, createWriteProtectionMiddleware, isMergeRoute, refMiddlewareFactory, writeProtectionMiddlewareFactory };
@@ -1,10 +1,14 @@
1
1
  import { getLogger } from "../utils/logger.js";
2
+ import { createApiError } from "../utils/error.js";
2
3
  import { isRefWritable, resolveRef } from "./ref-helpers.js";
3
4
  import { ensureBranchExists } from "./branch.js";
4
- import { createApiError } from "../utils/error.js";
5
5
 
6
6
  //#region src/dolt/ref-middleware.ts
7
7
  const logger = getLogger("ref-middleware");
8
+ const MERGE_ROUTE_PATTERN = /\/branches\/merge(\/preview)?$/;
9
+ function isMergeRoute(path) {
10
+ return MERGE_ROUTE_PATTERN.test(path);
11
+ }
8
12
  /**
9
13
  * Default tenant ID extractor - extracts from /tenants/{tenantId} path pattern
10
14
  */
@@ -43,8 +47,18 @@ const defaultExtractProjectId = (c) => {
43
47
  const createRefMiddleware = (db, options = {}) => {
44
48
  const { extractTenantId = defaultExtractTenantId, extractProjectId = defaultExtractProjectId, allowProjectIdFromBody = true } = options;
45
49
  return async (c, next) => {
46
- const ref = c.req.query("ref");
47
- const pathSplit = c.req.path.split("/");
50
+ let ref = c.req.query("ref");
51
+ const path = c.req.path;
52
+ const pathSplit = path.split("/");
53
+ if (!ref && isMergeRoute(path) && c.req.method === "POST") try {
54
+ const body = await c.req.json();
55
+ if (body && typeof body.targetBranch === "string") {
56
+ ref = body.targetBranch;
57
+ logger.debug({ ref }, "Extracted targetBranch from merge route body as ref");
58
+ }
59
+ } catch {
60
+ logger.debug({}, "Could not extract targetBranch from merge route body");
61
+ }
48
62
  const tenantId = extractTenantId(c);
49
63
  let projectId = extractProjectId(c);
50
64
  if (!projectId && allowProjectIdFromBody && [
@@ -214,4 +228,4 @@ const refMiddlewareFactory = createRefMiddleware;
214
228
  const writeProtectionMiddlewareFactory = createWriteProtectionMiddleware;
215
229
 
216
230
  //#endregion
217
- export { createRefMiddleware, createWriteProtectionMiddleware, refMiddlewareFactory, writeProtectionMiddlewareFactory };
231
+ export { createRefMiddleware, createWriteProtectionMiddleware, isMergeRoute, refMiddlewareFactory, writeProtectionMiddlewareFactory };
@@ -0,0 +1,10 @@
1
+ import { ConflictResolution } from "../validation/dolt-schemas.js";
2
+ import { AgentsManageDatabaseClient } from "../db/manage/manage-client.js";
3
+
4
+ //#region src/dolt/resolve-conflicts.d.ts
5
+ declare class ResolutionValidationError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ declare const applyResolutions: (db: AgentsManageDatabaseClient) => (resolutions: ConflictResolution[]) => Promise<void>;
9
+ //#endregion
10
+ export { ResolutionValidationError, applyResolutions };