@remixhq/core 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.ts CHANGED
@@ -406,6 +406,8 @@ type ApiClient = {
406
406
  getChangeStep(appId: string, changeStepId: string): Promise<Json>;
407
407
  getChangeStepDiff(appId: string, changeStepId: string): Promise<Json>;
408
408
  listMergeRequests(params?: {
409
+ queue?: string;
410
+ appId?: string;
409
411
  sourceAppId?: string;
410
412
  targetAppId?: string;
411
413
  status?: string | string[];
package/dist/api.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApiClient
3
- } from "./chunk-OJMTW22J.js";
3
+ } from "./chunk-R44EOUS4.js";
4
4
  import "./chunk-YZ34ICNN.js";
5
5
  export {
6
6
  createApiClient
@@ -0,0 +1,46 @@
1
+ import {
2
+ RemixError
3
+ } from "./chunk-YZ34ICNN.js";
4
+
5
+ // src/config/model.ts
6
+ import { z } from "zod";
7
+ var DEFAULT_API_URL = "http://localhost:8080";
8
+ var DEFAULT_SUPABASE_URL = "https://xtfxwbckjpfmqubnsusu.supabase.co";
9
+ var DEFAULT_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh0Znh3YmNranBmbXF1Ym5zdXN1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA2MDEyMzAsImV4cCI6MjA3NjE3NzIzMH0.dzWGAWrK4CvrmHVHzf8w7JlUZohdap0ZPnLZnABMV8s";
10
+ function isValidUrl(value) {
11
+ try {
12
+ new URL(value);
13
+ return true;
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+ var urlSchema = z.string().min(1).transform((s) => s.trim()).refine((s) => isValidUrl(s), "Invalid URL.").transform((s) => s.replace(/\/+$/, ""));
19
+ var configSchema = z.object({
20
+ apiUrl: urlSchema,
21
+ supabaseUrl: urlSchema,
22
+ supabaseAnonKey: z.string().min(1)
23
+ });
24
+ var cachedConfig = null;
25
+ async function resolveConfig(_opts) {
26
+ if (cachedConfig) return cachedConfig;
27
+ const cfgRaw = {
28
+ apiUrl: DEFAULT_API_URL,
29
+ supabaseUrl: DEFAULT_SUPABASE_URL,
30
+ supabaseAnonKey: DEFAULT_SUPABASE_ANON_KEY
31
+ };
32
+ const parsedCfg = configSchema.safeParse(cfgRaw);
33
+ if (!parsedCfg.success) {
34
+ throw new RemixError("Invalid core configuration.", {
35
+ exitCode: 1,
36
+ hint: parsedCfg.error.issues.map((i) => `${i.path.join(".") || "config"}: ${i.message}`).join("; ")
37
+ });
38
+ }
39
+ cachedConfig = parsedCfg.data;
40
+ return parsedCfg.data;
41
+ }
42
+
43
+ export {
44
+ configSchema,
45
+ resolveConfig
46
+ };
@@ -0,0 +1,288 @@
1
+ import {
2
+ RemixError
3
+ } from "./chunk-YZ34ICNN.js";
4
+
5
+ // src/api/client.ts
6
+ async function readJsonSafe(res) {
7
+ const ct = res.headers.get("content-type") ?? "";
8
+ if (!ct.toLowerCase().includes("application/json")) return null;
9
+ try {
10
+ return await res.json();
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
15
+ function createApiClient(config, opts) {
16
+ const apiKey = (opts?.apiKey ?? "").trim();
17
+ const tokenProvider = opts?.tokenProvider;
18
+ const CLIENT_KEY_HEADER = "x-comerge-api-key";
19
+ async function request(path, init) {
20
+ if (!tokenProvider) {
21
+ throw new RemixError("API client is missing a token provider.", {
22
+ exitCode: 1,
23
+ hint: "Configure auth before creating the Remix API client."
24
+ });
25
+ }
26
+ const auth = await tokenProvider();
27
+ const url = new URL(path, config.apiUrl).toString();
28
+ const doFetch = async (bearer) => fetch(url, {
29
+ ...init,
30
+ headers: {
31
+ Accept: "application/json",
32
+ "Content-Type": "application/json",
33
+ ...init?.headers ?? {},
34
+ Authorization: `Bearer ${bearer}`,
35
+ ...apiKey ? { [CLIENT_KEY_HEADER]: apiKey } : {}
36
+ }
37
+ });
38
+ let res = await doFetch(auth.token);
39
+ if (res.status === 401 && !auth.fromEnv && auth.session?.refresh_token) {
40
+ const refreshed = await tokenProvider({ forceRefresh: true });
41
+ res = await doFetch(refreshed.token);
42
+ }
43
+ if (!res.ok) {
44
+ const body = await readJsonSafe(res);
45
+ const msg = (body && typeof body === "object" && body && "message" in body && typeof body.message === "string" ? body.message : null) ?? `Request failed (status ${res.status})`;
46
+ throw new RemixError(msg, { exitCode: 1, hint: body ? JSON.stringify(body, null, 2) : null });
47
+ }
48
+ const json = await readJsonSafe(res);
49
+ return json ?? null;
50
+ }
51
+ async function requestBinary(path, init) {
52
+ if (!tokenProvider) {
53
+ throw new RemixError("API client is missing a token provider.", {
54
+ exitCode: 1,
55
+ hint: "Configure auth before creating the Remix API client."
56
+ });
57
+ }
58
+ const auth = await tokenProvider();
59
+ const url = new URL(path, config.apiUrl).toString();
60
+ const doFetch = async (bearer) => fetch(url, {
61
+ ...init,
62
+ headers: {
63
+ Accept: "*/*",
64
+ ...init?.headers ?? {},
65
+ Authorization: `Bearer ${bearer}`,
66
+ ...apiKey ? { [CLIENT_KEY_HEADER]: apiKey } : {}
67
+ }
68
+ });
69
+ let res = await doFetch(auth.token);
70
+ if (res.status === 401 && !auth.fromEnv && auth.session?.refresh_token) {
71
+ const refreshed = await tokenProvider({ forceRefresh: true });
72
+ res = await doFetch(refreshed.token);
73
+ }
74
+ if (!res.ok) {
75
+ const body = await readJsonSafe(res);
76
+ const msg = (body && typeof body === "object" && body && "message" in body && typeof body.message === "string" ? body.message : null) ?? `Request failed (status ${res.status})`;
77
+ throw new RemixError(msg, { exitCode: 1, hint: body ? JSON.stringify(body, null, 2) : null });
78
+ }
79
+ const contentDisposition = res.headers.get("content-disposition") ?? "";
80
+ const fileNameMatch = contentDisposition.match(/filename=\"([^\"]+)\"/i);
81
+ return {
82
+ data: Buffer.from(await res.arrayBuffer()),
83
+ fileName: fileNameMatch?.[1] ?? null,
84
+ contentType: res.headers.get("content-type")
85
+ };
86
+ }
87
+ return {
88
+ getMe: () => request("/v1/me", { method: "GET" }),
89
+ listOrganizations: () => request("/v1/organizations", { method: "GET" }),
90
+ getOrganization: (orgId) => request(`/v1/organizations/${encodeURIComponent(orgId)}`, { method: "GET" }),
91
+ listProjects: (params) => {
92
+ const qs = new URLSearchParams();
93
+ if (params?.organizationId) qs.set("organizationId", params.organizationId);
94
+ if (params?.clientAppId) qs.set("clientAppId", params.clientAppId);
95
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
96
+ return request(`/v1/projects${suffix}`, { method: "GET" });
97
+ },
98
+ getProject: (projectId) => request(`/v1/projects/${encodeURIComponent(projectId)}`, { method: "GET" }),
99
+ resolveProjectBinding: (params) => {
100
+ const qs = new URLSearchParams();
101
+ if (params.repoFingerprint) qs.set("repoFingerprint", params.repoFingerprint);
102
+ if (params.remoteUrl) qs.set("remoteUrl", params.remoteUrl);
103
+ return request(`/v1/projects/bindings/resolve?${qs.toString()}`, { method: "GET" });
104
+ },
105
+ autoEnableDeveloper: () => request("/v1/developer/auto-enable", { method: "POST" }),
106
+ listClientApps: (params) => {
107
+ const qs = params?.orgId ? `?orgId=${encodeURIComponent(params.orgId)}` : "";
108
+ return request(`/v1/developer/client-apps${qs}`, { method: "GET" });
109
+ },
110
+ createClientApp: (payload) => request("/v1/developer/client-apps", { method: "POST", body: JSON.stringify(payload) }),
111
+ createClientAppKey: (clientAppId, payload) => request(`/v1/developer/client-apps/${encodeURIComponent(clientAppId)}/keys`, {
112
+ method: "POST",
113
+ body: JSON.stringify(payload ?? {})
114
+ }),
115
+ listApps: (params) => {
116
+ const qs = new URLSearchParams();
117
+ if (params?.projectId) qs.set("projectId", params.projectId);
118
+ if (params?.organizationId) qs.set("organizationId", params.organizationId);
119
+ if (params?.forked) qs.set("forked", params.forked);
120
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
121
+ return request(`/v1/apps${suffix}`, { method: "GET" });
122
+ },
123
+ getApp: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}`, { method: "GET" }),
124
+ getMergeRequest: (mrId) => request(`/v1/merge-requests/${encodeURIComponent(mrId)}`, { method: "GET" }),
125
+ presignImportUpload: (payload) => request("/v1/apps/import/upload/presign", { method: "POST", body: JSON.stringify(payload) }),
126
+ importFromUpload: (payload) => request("/v1/apps/import/upload", { method: "POST", body: JSON.stringify(payload) }),
127
+ presignImportUploadFirstParty: (payload) => request("/v1/apps/import/upload/presign/first-party", { method: "POST", body: JSON.stringify(payload) }),
128
+ importFromUploadFirstParty: (payload) => request("/v1/apps/import/upload/first-party", { method: "POST", body: JSON.stringify(payload) }),
129
+ importFromGithubFirstParty: (payload) => request("/v1/apps/import/github/first-party", { method: "POST", body: JSON.stringify(payload) }),
130
+ forkApp: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/fork`, { method: "POST", body: JSON.stringify(payload ?? {}) }),
131
+ downloadAppBundle: (appId) => requestBinary(`/v1/apps/${encodeURIComponent(appId)}/download.bundle`, { method: "GET" }),
132
+ createChangeStep: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/change-steps`, {
133
+ method: "POST",
134
+ body: JSON.stringify(payload)
135
+ }),
136
+ createCollabTurn: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/collab-turns`, {
137
+ method: "POST",
138
+ body: JSON.stringify(payload)
139
+ }),
140
+ listCollabTurns: (appId, params) => {
141
+ const qs = new URLSearchParams();
142
+ if (params?.limit !== void 0) qs.set("limit", String(params.limit));
143
+ if (params?.offset !== void 0) qs.set("offset", String(params.offset));
144
+ if (params?.changeStepId) qs.set("changeStepId", params.changeStepId);
145
+ if (params?.threadId) qs.set("threadId", params.threadId);
146
+ if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
147
+ if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
148
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
149
+ return request(`/v1/apps/${encodeURIComponent(appId)}/collab-turns${suffix}`, { method: "GET" });
150
+ },
151
+ getCollabTurn: (appId, collabTurnId) => request(`/v1/apps/${encodeURIComponent(appId)}/collab-turns/${encodeURIComponent(collabTurnId)}`, {
152
+ method: "GET"
153
+ }),
154
+ getAgentMemorySummary: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/agent-memory/summary`, { method: "GET" }),
155
+ listAgentMemoryTimeline: (appId, params) => {
156
+ const qs = new URLSearchParams();
157
+ if (params?.limit !== void 0) qs.set("limit", String(params.limit));
158
+ if (params?.offset !== void 0) qs.set("offset", String(params.offset));
159
+ if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
160
+ if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
161
+ if (params?.kinds?.length) {
162
+ for (const kind of params.kinds) qs.append("kinds", kind);
163
+ }
164
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
165
+ return request(`/v1/apps/${encodeURIComponent(appId)}/agent-memory/timeline${suffix}`, { method: "GET" });
166
+ },
167
+ searchAgentMemory: (appId, params) => {
168
+ const qs = new URLSearchParams();
169
+ qs.set("q", params.q);
170
+ if (params.limit !== void 0) qs.set("limit", String(params.limit));
171
+ if (params.offset !== void 0) qs.set("offset", String(params.offset));
172
+ if (params.createdAfter) qs.set("createdAfter", params.createdAfter);
173
+ if (params.createdBefore) qs.set("createdBefore", params.createdBefore);
174
+ if (params.kinds?.length) {
175
+ for (const kind of params.kinds) qs.append("kinds", kind);
176
+ }
177
+ return request(`/v1/apps/${encodeURIComponent(appId)}/agent-memory/search?${qs.toString()}`, { method: "GET" });
178
+ },
179
+ getChangeStep: (appId, changeStepId) => request(`/v1/apps/${encodeURIComponent(appId)}/change-steps/${encodeURIComponent(changeStepId)}`, { method: "GET" }),
180
+ getChangeStepDiff: (appId, changeStepId) => request(`/v1/apps/${encodeURIComponent(appId)}/change-steps/${encodeURIComponent(changeStepId)}/diff`, {
181
+ method: "GET"
182
+ }),
183
+ startChangeStepReplay: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/change-steps/replays`, {
184
+ method: "POST",
185
+ body: JSON.stringify(payload)
186
+ }),
187
+ getChangeStepReplay: (appId, replayId) => request(`/v1/apps/${encodeURIComponent(appId)}/change-steps/replays/${encodeURIComponent(replayId)}`, {
188
+ method: "GET"
189
+ }),
190
+ getChangeStepReplayDiff: (appId, replayId) => request(`/v1/apps/${encodeURIComponent(appId)}/change-steps/replays/${encodeURIComponent(replayId)}/diff`, {
191
+ method: "GET"
192
+ }),
193
+ listMergeRequests: (params) => {
194
+ const qs = new URLSearchParams();
195
+ if (params?.queue) qs.set("queue", params.queue);
196
+ if (params?.appId) qs.set("appId", params.appId);
197
+ if (params?.sourceAppId) qs.set("sourceAppId", params.sourceAppId);
198
+ if (params?.targetAppId) qs.set("targetAppId", params.targetAppId);
199
+ if (Array.isArray(params?.status)) {
200
+ for (const status of params.status) qs.append("status", status);
201
+ } else if (typeof params?.status === "string") {
202
+ qs.set("status", params.status);
203
+ }
204
+ if (params?.kind) qs.set("kind", params.kind);
205
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
206
+ return request(`/v1/merge-requests${suffix}`, { method: "GET" });
207
+ },
208
+ openMergeRequest: (sourceAppId) => request("/v1/merge-requests", { method: "POST", body: JSON.stringify({ sourceAppId }) }),
209
+ getMergeRequestReview: (mrId) => request(`/v1/merge-requests/${encodeURIComponent(mrId)}/review`, { method: "GET" }),
210
+ updateMergeRequest: (mrId, payload) => request(`/v1/merge-requests/${encodeURIComponent(mrId)}`, { method: "PATCH", body: JSON.stringify(payload) }),
211
+ createOrganizationInvite: (orgId, payload) => request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations`, {
212
+ method: "POST",
213
+ body: JSON.stringify(payload)
214
+ }),
215
+ createProjectInvite: (projectId, payload) => request(`/v1/projects/${encodeURIComponent(projectId)}/invitations`, {
216
+ method: "POST",
217
+ body: JSON.stringify(payload)
218
+ }),
219
+ createAppInvite: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/invitations`, {
220
+ method: "POST",
221
+ body: JSON.stringify(payload)
222
+ }),
223
+ listOrganizationInvites: (orgId) => request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations`, { method: "GET" }),
224
+ listProjectInvites: (projectId) => request(`/v1/projects/${encodeURIComponent(projectId)}/invitations`, { method: "GET" }),
225
+ listAppInvites: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/invitations`, { method: "GET" }),
226
+ resendOrganizationInvite: (orgId, inviteId, payload) => request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations/${encodeURIComponent(inviteId)}/resend`, {
227
+ method: "POST",
228
+ body: JSON.stringify(payload ?? {})
229
+ }),
230
+ resendProjectInvite: (projectId, inviteId, payload) => request(`/v1/projects/${encodeURIComponent(projectId)}/invitations/${encodeURIComponent(inviteId)}/resend`, {
231
+ method: "POST",
232
+ body: JSON.stringify(payload ?? {})
233
+ }),
234
+ resendAppInvite: (appId, inviteId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/invitations/${encodeURIComponent(inviteId)}/resend`, {
235
+ method: "POST",
236
+ body: JSON.stringify(payload ?? {})
237
+ }),
238
+ revokeOrganizationInvite: (orgId, inviteId) => request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations/${encodeURIComponent(inviteId)}`, {
239
+ method: "DELETE"
240
+ }),
241
+ revokeProjectInvite: (projectId, inviteId) => request(`/v1/projects/${encodeURIComponent(projectId)}/invitations/${encodeURIComponent(inviteId)}`, {
242
+ method: "DELETE"
243
+ }),
244
+ revokeAppInvite: (appId, inviteId) => request(`/v1/apps/${encodeURIComponent(appId)}/invitations/${encodeURIComponent(inviteId)}`, {
245
+ method: "DELETE"
246
+ }),
247
+ syncUpstreamApp: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/sync-upstream`, {
248
+ method: "POST",
249
+ body: JSON.stringify({})
250
+ }),
251
+ preflightAppReconcile: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/reconcile/preflight`, {
252
+ method: "POST",
253
+ body: JSON.stringify(payload)
254
+ }),
255
+ startAppReconcile: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/reconcile/start`, {
256
+ method: "POST",
257
+ body: JSON.stringify(payload)
258
+ }),
259
+ getAppReconcile: (appId, reconcileId) => request(`/v1/apps/${encodeURIComponent(appId)}/reconcile/${encodeURIComponent(reconcileId)}`, { method: "GET" }),
260
+ downloadAppReconcileBundle: (appId, reconcileId) => requestBinary(`/v1/apps/${encodeURIComponent(appId)}/reconcile/${encodeURIComponent(reconcileId)}/download.bundle`, {
261
+ method: "GET"
262
+ }),
263
+ syncLocalApp: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/sync-local`, {
264
+ method: "POST",
265
+ body: JSON.stringify(payload)
266
+ }),
267
+ initiateBundle: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/bundles`, { method: "POST", body: JSON.stringify(payload) }),
268
+ getBundle: (appId, bundleId) => request(`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}`, { method: "GET" }),
269
+ getBundleDownloadUrl: (appId, bundleId, options) => request(
270
+ `/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/download?redirect=${options?.redirect ?? false}`,
271
+ { method: "GET" }
272
+ ),
273
+ getBundleAssetsDownloadUrl: (appId, bundleId, options) => {
274
+ const qs = new URLSearchParams({
275
+ redirect: String(options?.redirect ?? false),
276
+ kind: options?.kind ?? "metro-assets"
277
+ });
278
+ return request(
279
+ `/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/assets/download?${qs.toString()}`,
280
+ { method: "GET" }
281
+ );
282
+ }
283
+ };
284
+ }
285
+
286
+ export {
287
+ createApiClient
288
+ };
package/dist/collab.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  type JsonObject = Record<string, any>;
2
2
  type MergeRequestStatus = "open" | "approved" | "rejected" | "merged" | "closed";
3
+ type MergeRequestQueue = "reviewable" | "created_by_me" | "app_reviewable" | "app_outgoing" | "app_related_visible";
3
4
  type MergeRequest = {
4
5
  id: string;
5
6
  sourceAppId: string;
@@ -63,7 +64,7 @@ type MergeRequestReview = {
63
64
  };
64
65
  type CollabApproveMode = "remote-only" | "sync-target-repo";
65
66
  type CollabStatusBlockedReason = "not_git_repo" | "not_bound" | "missing_head" | "detached_head" | "branch_mismatch" | "dirty_worktree" | "metadata_conflict" | "remote_error";
66
- type CollabStatusRecommendedAction = "init" | "sync" | "reconcile" | "review_inbox" | "no_action";
67
+ type CollabStatusRecommendedAction = "init" | "sync" | "reconcile" | "review_queue" | "no_action";
67
68
  type CollabStatus = {
68
69
  schemaVersion: 1;
69
70
  repo: {
@@ -144,6 +145,23 @@ type SyncUpstreamResponse = {
144
145
  status: "up-to-date" | "queued";
145
146
  mergeRequestId?: string;
146
147
  };
148
+ type CollabRecordingPreflightStatus = "not_git_repo" | "not_bound" | "missing_head" | "branch_mismatch" | "metadata_conflict" | "up_to_date" | "ready_to_fast_forward" | "reconcile_required";
149
+ type CollabRecordingPreflight = {
150
+ status: CollabRecordingPreflightStatus;
151
+ repoRoot: string | null;
152
+ appId: string | null;
153
+ currentBranch: string | null;
154
+ preferredBranch: string | null;
155
+ headCommitHash: string | null;
156
+ worktreeClean: boolean;
157
+ syncStatus: SyncLocalResponse["status"] | null;
158
+ syncTargetCommitHash: string | null;
159
+ syncTargetCommitId: string | null;
160
+ reconcileTargetHeadCommitHash: string | null;
161
+ reconcileTargetHeadCommitId: string | null;
162
+ warnings: string[];
163
+ hint: string | null;
164
+ };
147
165
  type ReconcilePreflightResponse = {
148
166
  status: "up_to_date" | "ready_to_reconcile" | "metadata_conflict";
149
167
  localHeadCommitHash: string;
@@ -319,6 +337,8 @@ type CollabApiClient = {
319
337
  }): Promise<unknown>;
320
338
  getChangeStep(appId: string, changeStepId: string): Promise<unknown>;
321
339
  listMergeRequests(params?: {
340
+ queue?: MergeRequestQueue;
341
+ appId?: string;
322
342
  sourceAppId?: string;
323
343
  targetAppId?: string;
324
344
  status?: string | string[];
@@ -409,6 +429,12 @@ declare function collabAdd(params: {
409
429
  };
410
430
  }): Promise<JsonObject>;
411
431
 
432
+ declare function collabRecordingPreflight(params: {
433
+ api: CollabApiClient;
434
+ cwd: string;
435
+ allowBranchMismatch?: boolean;
436
+ }): Promise<CollabRecordingPreflight>;
437
+
412
438
  declare function collabRecordTurn(params: {
413
439
  api: CollabApiClient;
414
440
  cwd: string;
@@ -435,7 +461,20 @@ declare function collabApprove(params: {
435
461
  declare function collabInbox(params: {
436
462
  api: CollabApiClient;
437
463
  }): Promise<{
438
- mergeRequests: any;
464
+ mergeRequests: MergeRequest[];
465
+ }>;
466
+
467
+ declare function collabListMergeRequests(params: {
468
+ api: CollabApiClient;
469
+ queue: MergeRequestQueue;
470
+ cwd?: string | null;
471
+ appId?: string | null;
472
+ status?: string | string[];
473
+ kind?: string | null;
474
+ }): Promise<{
475
+ queue: MergeRequestQueue;
476
+ appId: string | null;
477
+ mergeRequests: MergeRequest[];
439
478
  }>;
440
479
 
441
480
  declare function collabInit(params: {
@@ -677,4 +716,4 @@ declare function collabView(params: {
677
716
  mrId: string;
678
717
  }): Promise<MergeRequestReview>;
679
718
 
680
- export { type AppReconcileResponse, type CollabApiClient, type CollabApproveMode, type CollabApproveResult, type CollabStatus, type CollabStatusBlockedReason, type CollabStatusRecommendedAction, type CollabTurn, type InvitationScopeType, type JsonObject, type MergeRequest, type MergeRequestReview, type MergeRequestStatus, type ReconcilePreflightResponse, type SyncLocalResponse, type SyncUpstreamResponse, collabAdd, collabApprove, collabInbox, collabInit, collabInvite, collabList, collabReconcile, collabRecordTurn, collabReject, collabRemix, collabRequestMerge, collabStatus, collabSync, collabSyncUpstream, collabView };
719
+ export { type AppReconcileResponse, type CollabApiClient, type CollabApproveMode, type CollabApproveResult, type CollabRecordingPreflight, type CollabRecordingPreflightStatus, type CollabStatus, type CollabStatusBlockedReason, type CollabStatusRecommendedAction, type CollabTurn, type InvitationScopeType, type JsonObject, type MergeRequest, type MergeRequestQueue, type MergeRequestReview, type MergeRequestStatus, type ReconcilePreflightResponse, type SyncLocalResponse, type SyncUpstreamResponse, collabAdd, collabApprove, collabInbox, collabInit, collabInvite, collabList, collabListMergeRequests, collabReconcile, collabRecordTurn, collabRecordingPreflight, collabReject, collabRemix, collabRequestMerge, collabStatus, collabSync, collabSyncUpstream, collabView };
package/dist/collab.js CHANGED
@@ -260,6 +260,199 @@ async function pollMergeRequestCompletion(api, mrId, params) {
260
260
  throw new RemixError("Timed out waiting for merge approval to complete.", { exitCode: 1 });
261
261
  }
262
262
 
263
+ // src/application/collab/recordingPreflight.ts
264
+ async function collabRecordingPreflight(params) {
265
+ let repoRoot;
266
+ try {
267
+ repoRoot = await findGitRoot(params.cwd);
268
+ } catch (error) {
269
+ const message = error instanceof Error ? error.message : "Not inside a git repository.";
270
+ return {
271
+ status: "not_git_repo",
272
+ repoRoot: null,
273
+ appId: null,
274
+ currentBranch: null,
275
+ preferredBranch: null,
276
+ headCommitHash: null,
277
+ worktreeClean: false,
278
+ syncStatus: null,
279
+ syncTargetCommitHash: null,
280
+ syncTargetCommitId: null,
281
+ reconcileTargetHeadCommitHash: null,
282
+ reconcileTargetHeadCommitId: null,
283
+ warnings: [],
284
+ hint: message
285
+ };
286
+ }
287
+ const binding = await readCollabBinding(repoRoot);
288
+ if (!binding) {
289
+ return {
290
+ status: "not_bound",
291
+ repoRoot,
292
+ appId: null,
293
+ currentBranch: null,
294
+ preferredBranch: null,
295
+ headCommitHash: null,
296
+ worktreeClean: false,
297
+ syncStatus: null,
298
+ syncTargetCommitHash: null,
299
+ syncTargetCommitId: null,
300
+ reconcileTargetHeadCommitHash: null,
301
+ reconcileTargetHeadCommitId: null,
302
+ warnings: [],
303
+ hint: "Run `remix collab init` first."
304
+ };
305
+ }
306
+ const [currentBranch, headCommitHash, worktreeStatus] = await Promise.all([
307
+ getCurrentBranch(repoRoot),
308
+ getHeadCommitHash(repoRoot),
309
+ getWorktreeStatus(repoRoot)
310
+ ]);
311
+ const preferredBranch = binding.preferredBranch ?? null;
312
+ if (!headCommitHash) {
313
+ return {
314
+ status: "missing_head",
315
+ repoRoot,
316
+ appId: binding.currentAppId,
317
+ currentBranch,
318
+ preferredBranch,
319
+ headCommitHash: null,
320
+ worktreeClean: worktreeStatus.isClean,
321
+ syncStatus: null,
322
+ syncTargetCommitHash: null,
323
+ syncTargetCommitId: null,
324
+ reconcileTargetHeadCommitHash: null,
325
+ reconcileTargetHeadCommitId: null,
326
+ warnings: [],
327
+ hint: "Failed to resolve local HEAD commit."
328
+ };
329
+ }
330
+ if (!params.allowBranchMismatch && !isPreferredBranchMatch(currentBranch, preferredBranch)) {
331
+ return {
332
+ status: "branch_mismatch",
333
+ repoRoot,
334
+ appId: binding.currentAppId,
335
+ currentBranch,
336
+ preferredBranch,
337
+ headCommitHash,
338
+ worktreeClean: worktreeStatus.isClean,
339
+ syncStatus: null,
340
+ syncTargetCommitHash: null,
341
+ syncTargetCommitId: null,
342
+ reconcileTargetHeadCommitHash: null,
343
+ reconcileTargetHeadCommitId: null,
344
+ warnings: [],
345
+ hint: buildPreferredBranchMismatchHint({
346
+ currentBranch,
347
+ preferredBranch
348
+ })
349
+ };
350
+ }
351
+ const syncResp = await params.api.syncLocalApp(binding.currentAppId, {
352
+ baseCommitHash: headCommitHash,
353
+ repoFingerprint: binding.repoFingerprint ?? void 0,
354
+ remoteUrl: binding.remoteUrl ?? void 0,
355
+ defaultBranch: binding.defaultBranch ?? void 0,
356
+ dryRun: true
357
+ });
358
+ const sync = unwrapResponseObject(syncResp, "sync result");
359
+ if (sync.status === "conflict_risk") {
360
+ return {
361
+ status: "metadata_conflict",
362
+ repoRoot,
363
+ appId: binding.currentAppId,
364
+ currentBranch,
365
+ preferredBranch,
366
+ headCommitHash,
367
+ worktreeClean: worktreeStatus.isClean,
368
+ syncStatus: sync.status,
369
+ syncTargetCommitHash: sync.targetCommitHash,
370
+ syncTargetCommitId: sync.targetCommitId,
371
+ reconcileTargetHeadCommitHash: null,
372
+ reconcileTargetHeadCommitId: null,
373
+ warnings: sync.warnings,
374
+ hint: sync.warnings.join("\n") || "Run the command from the correct bound repository."
375
+ };
376
+ }
377
+ if (sync.status === "up_to_date" || sync.status === "ready_to_fast_forward") {
378
+ return {
379
+ status: sync.status,
380
+ repoRoot,
381
+ appId: binding.currentAppId,
382
+ currentBranch,
383
+ preferredBranch,
384
+ headCommitHash,
385
+ worktreeClean: worktreeStatus.isClean,
386
+ syncStatus: sync.status,
387
+ syncTargetCommitHash: sync.targetCommitHash,
388
+ syncTargetCommitId: sync.targetCommitId,
389
+ reconcileTargetHeadCommitHash: null,
390
+ reconcileTargetHeadCommitId: null,
391
+ warnings: sync.warnings,
392
+ hint: null
393
+ };
394
+ }
395
+ const reconcileResp = await params.api.preflightAppReconcile(binding.currentAppId, {
396
+ localHeadCommitHash: headCommitHash,
397
+ repoFingerprint: binding.repoFingerprint ?? void 0,
398
+ remoteUrl: binding.remoteUrl ?? void 0,
399
+ defaultBranch: binding.defaultBranch ?? void 0
400
+ });
401
+ const reconcile = unwrapResponseObject(reconcileResp, "reconcile preflight");
402
+ if (reconcile.status === "metadata_conflict") {
403
+ return {
404
+ status: "metadata_conflict",
405
+ repoRoot,
406
+ appId: binding.currentAppId,
407
+ currentBranch,
408
+ preferredBranch,
409
+ headCommitHash,
410
+ worktreeClean: worktreeStatus.isClean,
411
+ syncStatus: sync.status,
412
+ syncTargetCommitHash: sync.targetCommitHash,
413
+ syncTargetCommitId: sync.targetCommitId,
414
+ reconcileTargetHeadCommitHash: reconcile.targetHeadCommitHash,
415
+ reconcileTargetHeadCommitId: reconcile.targetHeadCommitId,
416
+ warnings: reconcile.warnings,
417
+ hint: reconcile.warnings.join("\n") || "Run the command from the correct bound repository."
418
+ };
419
+ }
420
+ if (reconcile.status === "up_to_date") {
421
+ return {
422
+ status: "up_to_date",
423
+ repoRoot,
424
+ appId: binding.currentAppId,
425
+ currentBranch,
426
+ preferredBranch,
427
+ headCommitHash,
428
+ worktreeClean: worktreeStatus.isClean,
429
+ syncStatus: sync.status,
430
+ syncTargetCommitHash: sync.targetCommitHash,
431
+ syncTargetCommitId: sync.targetCommitId,
432
+ reconcileTargetHeadCommitHash: reconcile.targetHeadCommitHash,
433
+ reconcileTargetHeadCommitId: reconcile.targetHeadCommitId,
434
+ warnings: reconcile.warnings,
435
+ hint: null
436
+ };
437
+ }
438
+ return {
439
+ status: "reconcile_required",
440
+ repoRoot,
441
+ appId: binding.currentAppId,
442
+ currentBranch,
443
+ preferredBranch,
444
+ headCommitHash,
445
+ worktreeClean: worktreeStatus.isClean,
446
+ syncStatus: sync.status,
447
+ syncTargetCommitHash: sync.targetCommitHash,
448
+ syncTargetCommitId: sync.targetCommitId,
449
+ reconcileTargetHeadCommitHash: reconcile.targetHeadCommitHash,
450
+ reconcileTargetHeadCommitId: reconcile.targetHeadCommitId,
451
+ warnings: reconcile.warnings,
452
+ hint: reconcile.warnings.join("\n") || "Run `remix collab reconcile` first because the local history is no longer fast-forward compatible with the app."
453
+ };
454
+ }
455
+
263
456
  // src/infrastructure/locking/repoMutationLock.ts
264
457
  import fs from "fs/promises";
265
458
  import os from "os";
@@ -595,27 +788,43 @@ async function collabSync(params) {
595
788
  }
596
789
 
597
790
  // src/application/collab/collabAdd.ts
598
- async function preflightSyncStatus(params) {
599
- const resp = await params.api.syncLocalApp(params.appId, {
600
- baseCommitHash: params.headCommitHash,
601
- repoFingerprint: params.repoFingerprint ?? void 0,
602
- remoteUrl: params.remoteUrl ?? void 0,
603
- defaultBranch: params.defaultBranch ?? void 0,
604
- dryRun: true
605
- });
606
- return unwrapResponseObject(resp, "sync result");
607
- }
608
- function assertSupportedSyncStatus(sync) {
609
- if (sync.status === "conflict_risk") {
791
+ function assertSupportedRecordingPreflight(preflight) {
792
+ if (preflight.status === "not_bound") {
793
+ throw new RemixError("Repository is not bound to Remix.", {
794
+ exitCode: 2,
795
+ hint: preflight.hint
796
+ });
797
+ }
798
+ if (preflight.status === "not_git_repo") {
799
+ throw new RemixError(preflight.hint || "Not inside a git repository.", {
800
+ exitCode: 2,
801
+ hint: preflight.hint
802
+ });
803
+ }
804
+ if (preflight.status === "missing_head") {
805
+ throw new RemixError("Failed to resolve local HEAD commit.", {
806
+ exitCode: 1,
807
+ hint: preflight.hint
808
+ });
809
+ }
810
+ if (preflight.status === "branch_mismatch") {
811
+ assertPreferredBranchMatch({
812
+ currentBranch: preflight.currentBranch,
813
+ preferredBranch: preflight.preferredBranch,
814
+ allowBranchMismatch: false,
815
+ operation: "`remix collab add`"
816
+ });
817
+ }
818
+ if (preflight.status === "metadata_conflict") {
610
819
  throw new RemixError("Local repository metadata conflicts with the bound Remix app.", {
611
820
  exitCode: 2,
612
- hint: sync.warnings.join("\n") || "Run the command from the correct bound repository."
821
+ hint: preflight.hint
613
822
  });
614
823
  }
615
- if (sync.status === "base_unknown") {
824
+ if (preflight.status === "reconcile_required") {
616
825
  throw new RemixError("Local repository cannot be fast-forward synced.", {
617
826
  exitCode: 2,
618
- hint: "Run `remix collab reconcile` first because the local history is no longer fast-forward compatible with the app."
827
+ hint: preflight.hint
619
828
  });
620
829
  }
621
830
  }
@@ -635,28 +844,25 @@ async function collabAdd(params) {
635
844
  const diffSource = params.diffSource ?? (params.diff ? "external" : "worktree");
636
845
  const autoSyncEnabled = params.sync !== false;
637
846
  const run = async (lockWarnings = []) => {
638
- const branch = await getCurrentBranch(repoRoot);
847
+ const preflight = await collabRecordingPreflight({
848
+ api: params.api,
849
+ cwd: repoRoot,
850
+ allowBranchMismatch: params.allowBranchMismatch
851
+ });
852
+ assertSupportedRecordingPreflight(preflight);
853
+ const branch = preflight.currentBranch;
639
854
  assertPreferredBranchMatch({
640
855
  currentBranch: branch,
641
856
  preferredBranch: binding.preferredBranch,
642
857
  allowBranchMismatch: params.allowBranchMismatch,
643
858
  operation: "`remix collab add`"
644
859
  });
645
- let headCommitHash = await getHeadCommitHash(repoRoot);
860
+ let headCommitHash = preflight.headCommitHash;
646
861
  if (!headCommitHash) {
647
862
  throw new RemixError("Failed to resolve local HEAD commit.", { exitCode: 1 });
648
863
  }
649
864
  const worktreeStatus = await getWorktreeStatus(repoRoot);
650
- const syncPreview = await preflightSyncStatus({
651
- api: params.api,
652
- appId: binding.currentAppId,
653
- headCommitHash,
654
- repoFingerprint: binding.repoFingerprint ?? void 0,
655
- remoteUrl: binding.remoteUrl ?? void 0,
656
- defaultBranch: binding.defaultBranch ?? void 0
657
- });
658
- assertSupportedSyncStatus(syncPreview);
659
- if (syncPreview.status === "ready_to_fast_forward") {
865
+ if (preflight.status === "ready_to_fast_forward") {
660
866
  if (!autoSyncEnabled) {
661
867
  throw new RemixError("Local repository is stale and `collab add` sync automation is disabled.", {
662
868
  exitCode: 2,
@@ -887,6 +1093,46 @@ async function collabAdd(params) {
887
1093
  }
888
1094
 
889
1095
  // src/application/collab/collabRecordTurn.ts
1096
+ function assertSupportedRecordingPreflight2(preflight) {
1097
+ if (preflight.status === "not_bound") {
1098
+ throw new RemixError("Repository is not bound to Remix.", {
1099
+ exitCode: 2,
1100
+ hint: preflight.hint
1101
+ });
1102
+ }
1103
+ if (preflight.status === "not_git_repo") {
1104
+ throw new RemixError(preflight.hint || "Not inside a git repository.", {
1105
+ exitCode: 2,
1106
+ hint: preflight.hint
1107
+ });
1108
+ }
1109
+ if (preflight.status === "missing_head") {
1110
+ throw new RemixError("Failed to resolve local HEAD commit.", {
1111
+ exitCode: 1,
1112
+ hint: preflight.hint
1113
+ });
1114
+ }
1115
+ if (preflight.status === "branch_mismatch") {
1116
+ assertPreferredBranchMatch({
1117
+ currentBranch: preflight.currentBranch,
1118
+ preferredBranch: preflight.preferredBranch,
1119
+ allowBranchMismatch: false,
1120
+ operation: "`remix collab record-turn`"
1121
+ });
1122
+ }
1123
+ if (preflight.status === "metadata_conflict") {
1124
+ throw new RemixError("Local repository metadata conflicts with the bound Remix app.", {
1125
+ exitCode: 2,
1126
+ hint: preflight.hint
1127
+ });
1128
+ }
1129
+ if (preflight.status === "reconcile_required") {
1130
+ throw new RemixError("Local repository cannot be fast-forward synced.", {
1131
+ exitCode: 2,
1132
+ hint: preflight.hint
1133
+ });
1134
+ }
1135
+ }
890
1136
  async function collabRecordTurn(params) {
891
1137
  const repoRoot = await findGitRoot(params.cwd);
892
1138
  const binding = await readCollabBinding(repoRoot);
@@ -900,6 +1146,26 @@ async function collabRecordTurn(params) {
900
1146
  const assistantResponse = params.assistantResponse.trim();
901
1147
  if (!prompt) throw new RemixError("Prompt is required.", { exitCode: 2 });
902
1148
  if (!assistantResponse) throw new RemixError("Assistant response is required.", { exitCode: 2 });
1149
+ const preflight = await collabRecordingPreflight({
1150
+ api: params.api,
1151
+ cwd: repoRoot,
1152
+ allowBranchMismatch: params.allowBranchMismatch
1153
+ });
1154
+ assertSupportedRecordingPreflight2(preflight);
1155
+ if (!preflight.worktreeClean) {
1156
+ throw new RemixError("Cannot record a no-diff turn while the worktree has local changes.", {
1157
+ exitCode: 2,
1158
+ hint: "Record the pending code changes as a Remix change step with `remix collab add`, or clean the worktree before retrying `remix collab record-turn`."
1159
+ });
1160
+ }
1161
+ if (preflight.status === "ready_to_fast_forward") {
1162
+ await collabSync({
1163
+ api: params.api,
1164
+ cwd: repoRoot,
1165
+ dryRun: false,
1166
+ allowBranchMismatch: params.allowBranchMismatch
1167
+ });
1168
+ }
903
1169
  const branch = await getCurrentBranch(repoRoot);
904
1170
  assertPreferredBranchMatch({
905
1171
  currentBranch: branch,
@@ -1011,11 +1277,60 @@ async function collabApprove(params) {
1011
1277
  };
1012
1278
  }
1013
1279
 
1280
+ // src/application/collab/collabListMergeRequests.ts
1281
+ var APP_SCOPED_QUEUES = /* @__PURE__ */ new Set(["app_reviewable", "app_outgoing", "app_related_visible"]);
1282
+ async function resolveQueueAppId(params) {
1283
+ if (!APP_SCOPED_QUEUES.has(params.queue)) {
1284
+ return params.appId ?? void 0;
1285
+ }
1286
+ if (params.appId?.trim()) {
1287
+ return params.appId.trim();
1288
+ }
1289
+ if (!params.cwd?.trim()) {
1290
+ throw new RemixError("An app-scoped merge-request queue requires either `appId` or `cwd`.", {
1291
+ exitCode: 2,
1292
+ hint: "Pass `appId` explicitly, or run the request from a Remix-bound checkout with `cwd` set."
1293
+ });
1294
+ }
1295
+ const repoRoot = await findGitRoot(params.cwd);
1296
+ const binding = await readCollabBinding(repoRoot);
1297
+ if (!binding) {
1298
+ throw new RemixError("Repository is not bound to Remix.", {
1299
+ exitCode: 2,
1300
+ hint: "Bind the repository first or pass `appId` explicitly for the app-scoped merge-request queue."
1301
+ });
1302
+ }
1303
+ return binding.currentAppId;
1304
+ }
1305
+ async function collabListMergeRequests(params) {
1306
+ const appId = await resolveQueueAppId({
1307
+ cwd: params.cwd,
1308
+ appId: params.appId,
1309
+ queue: params.queue
1310
+ });
1311
+ const resp = await params.api.listMergeRequests({
1312
+ queue: params.queue,
1313
+ appId,
1314
+ status: params.status,
1315
+ kind: params.kind ?? "merge"
1316
+ });
1317
+ const mergeRequests = unwrapResponseObject(resp, "merge requests");
1318
+ return {
1319
+ queue: params.queue,
1320
+ appId: appId ?? null,
1321
+ mergeRequests
1322
+ };
1323
+ }
1324
+
1014
1325
  // src/application/collab/collabInbox.ts
1015
1326
  async function collabInbox(params) {
1016
- const resp = await params.api.listMergeRequests({ status: "open", kind: "merge" });
1017
- const mergeRequests = unwrapResponseObject(resp, "merge requests");
1018
- return { mergeRequests };
1327
+ const result = await collabListMergeRequests({
1328
+ api: params.api,
1329
+ queue: "reviewable",
1330
+ status: "open",
1331
+ kind: "merge"
1332
+ });
1333
+ return { mergeRequests: result.mergeRequests };
1019
1334
  }
1020
1335
 
1021
1336
  // src/application/collab/collabInit.ts
@@ -1702,8 +2017,8 @@ async function collabStatus(params) {
1702
2017
  }
1703
2018
  const [appResult, incomingResult, outgoingResult, syncResult] = await Promise.allSettled([
1704
2019
  params.api.getApp(binding.currentAppId),
1705
- params.api.listMergeRequests({ targetAppId: binding.currentAppId, status: "open", kind: "merge" }),
1706
- params.api.listMergeRequests({ sourceAppId: binding.currentAppId, status: "open", kind: "merge" }),
2020
+ params.api.listMergeRequests({ queue: "app_reviewable", appId: binding.currentAppId, status: "open", kind: "merge" }),
2021
+ params.api.listMergeRequests({ queue: "app_outgoing", appId: binding.currentAppId, status: "open", kind: "merge" }),
1707
2022
  headCommitHash ? params.api.syncLocalApp(binding.currentAppId, {
1708
2023
  baseCommitHash: headCommitHash,
1709
2024
  repoFingerprint: binding.repoFingerprint ?? void 0,
@@ -1809,7 +2124,7 @@ async function collabStatus(params) {
1809
2124
  } else if (status.reconcile.canApply && status.reconcile.status === "ready_to_reconcile") {
1810
2125
  status.recommendedAction = "reconcile";
1811
2126
  } else if ((status.remote.incomingOpenMergeRequestCount ?? 0) > 0) {
1812
- status.recommendedAction = "review_inbox";
2127
+ status.recommendedAction = "review_queue";
1813
2128
  } else {
1814
2129
  status.recommendedAction = "no_action";
1815
2130
  }
@@ -1905,8 +2220,10 @@ export {
1905
2220
  collabInit,
1906
2221
  collabInvite,
1907
2222
  collabList,
2223
+ collabListMergeRequests,
1908
2224
  collabReconcile,
1909
2225
  collabRecordTurn,
2226
+ collabRecordingPreflight,
1910
2227
  collabReject,
1911
2228
  collabRemix,
1912
2229
  collabRequestMerge,
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApiClient
3
- } from "./chunk-OJMTW22J.js";
3
+ } from "./chunk-R44EOUS4.js";
4
4
  import {
5
5
  createLocalSessionStore,
6
6
  createStoredSessionTokenProvider,
package/dist/repo.d.ts CHANGED
@@ -63,4 +63,4 @@ declare function summarizeUnifiedDiff(diff: string): {
63
63
  deletions: number;
64
64
  };
65
65
 
66
- export { assertRepoSnapshotUnchanged, buildRepoFingerprint, captureRepoSnapshot, cloneGitBundleToDirectory, createBackupBranch, createGitBundle, discardTrackedChanges, ensureCleanWorktree, ensureCommitExists, ensureGitInfoExcludeEntries, fastForwardToCommit, findGitRoot, getAbsoluteGitDir, getCurrentBranch, getDefaultBranch, getGitCommonDir, getGitPath, getHeadCommitHash, getRemoteOriginUrl, getWorkingTreeDiff, getWorkspaceDiff, hardResetToCommit, importGitBundle, listUntrackedFiles, normalizeGitRemote, requireCurrentBranch, summarizeUnifiedDiff, writeTempUnifiedDiffBackup };
66
+ export { type RepoSnapshot, assertRepoSnapshotUnchanged, buildRepoFingerprint, captureRepoSnapshot, cloneGitBundleToDirectory, createBackupBranch, createGitBundle, discardTrackedChanges, ensureCleanWorktree, ensureCommitExists, ensureGitInfoExcludeEntries, fastForwardToCommit, findGitRoot, getAbsoluteGitDir, getCurrentBranch, getDefaultBranch, getGitCommonDir, getGitPath, getHeadCommitHash, getRemoteOriginUrl, getWorkingTreeDiff, getWorkspaceDiff, hardResetToCommit, importGitBundle, listUntrackedFiles, normalizeGitRemote, requireCurrentBranch, summarizeUnifiedDiff, writeTempUnifiedDiffBackup };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remixhq/core",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Remix core library",
5
5
  "homepage": "https://github.com/RemixDotOne/remix-core",
6
6
  "license": "MIT",