@remixhq/core 0.1.33 → 0.1.35
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 +1 -1
- package/dist/collab.d.ts +2 -2
- package/dist/collab.js +425 -57
- package/dist/{contracts-WCYiMqwB.d.ts → contracts-BqC3Lj7W.d.ts} +2 -2
- package/dist/history.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CoreConfig } from './config.js';
|
|
2
2
|
import { T as TokenProvider } from './tokenProvider-B9so5Pm3.js';
|
|
3
|
-
import { T as TurnUsage } from './contracts-
|
|
3
|
+
import { T as TurnUsage } from './contracts-BqC3Lj7W.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
type HistoryImportProvider = "claude_code" | "cursor";
|
package/dist/collab.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as CollabApiClient, a as TurnUsagePayload, b as CollabFinalizeTurnResult, c as CollabRecordingPreflight, d as CollabApproveMode, e as CollabApprovalStrategy, f as CollabApproveResult, M as MergeRequestQueue, g as MergeRequest, I as InvitationScopeType, h as CollabMember, A as AppProfileInput, J as JsonObject, i as AppDeltaResponse, j as CollabStatus, k as MergeRequestReview } from './contracts-
|
|
2
|
-
export { l as AppHeadResponse, m as AppMember, n as AppMemberRole, o as AppReconcileResponse, p as CollabFinalizeTurnAutoSync, q as CollabFinalizeTurnMode, r as CollabPendingFinalizeState, s as CollabPendingFinalizeSummary, t as CollabRecordingPreflightStatus, u as CollabRepoStateKind, v as CollabStatusBlockedReason, w as CollabStatusRecommendedAction, x as CollabTurn, y as MembershipScopeType, z as MergeRequestStatus, B as ModelCall, O as OrganizationMember, D as OrganizationMemberRole, P as ProjectMember, E as ProjectMemberRole, R as ReconcilePreflightResponse, S as ServerToolUsage, F as SyncLocalResponse, G as SyncUpstreamResponse, T as TurnUsage, H as TurnUsageCaptureSource, K as TurnUsageConfidence, L as TurnUsagePreviousPatch } from './contracts-
|
|
1
|
+
import { C as CollabApiClient, a as TurnUsagePayload, b as CollabFinalizeTurnResult, c as CollabRecordingPreflight, d as CollabApproveMode, e as CollabApprovalStrategy, f as CollabApproveResult, M as MergeRequestQueue, g as MergeRequest, I as InvitationScopeType, h as CollabMember, A as AppProfileInput, J as JsonObject, i as AppDeltaResponse, j as CollabStatus, k as MergeRequestReview } from './contracts-BqC3Lj7W.js';
|
|
2
|
+
export { l as AppHeadResponse, m as AppMember, n as AppMemberRole, o as AppReconcileResponse, p as CollabFinalizeTurnAutoSync, q as CollabFinalizeTurnMode, r as CollabPendingFinalizeState, s as CollabPendingFinalizeSummary, t as CollabRecordingPreflightStatus, u as CollabRepoStateKind, v as CollabStatusBlockedReason, w as CollabStatusRecommendedAction, x as CollabTurn, y as MembershipScopeType, z as MergeRequestStatus, B as ModelCall, O as OrganizationMember, D as OrganizationMemberRole, P as ProjectMember, E as ProjectMemberRole, R as ReconcilePreflightResponse, S as ServerToolUsage, F as SyncLocalResponse, G as SyncUpstreamResponse, T as TurnUsage, H as TurnUsageCaptureSource, K as TurnUsageConfidence, L as TurnUsagePreviousPatch } from './contracts-BqC3Lj7W.js';
|
|
3
3
|
import { B as BranchBindingMode } from './binding-WiIRI2fl.js';
|
|
4
4
|
|
|
5
5
|
declare function collabFinalizeTurn(params: {
|
package/dist/collab.js
CHANGED
|
@@ -509,6 +509,13 @@ import path3 from "path";
|
|
|
509
509
|
function getBaselinePath(params) {
|
|
510
510
|
return path3.join(getBaselinesRoot(), `${buildLaneStateKey(params)}.json`);
|
|
511
511
|
}
|
|
512
|
+
function normalizeNullableString(value) {
|
|
513
|
+
const normalized = String(value ?? "").trim();
|
|
514
|
+
return normalized || null;
|
|
515
|
+
}
|
|
516
|
+
function isSameBaselineIdentity(left, right) {
|
|
517
|
+
return left.repoRoot === right.repoRoot && (left.repoFingerprint ?? null) === (right.repoFingerprint ?? null) && (left.laneId ?? null) === (right.laneId ?? null) && left.currentAppId === right.currentAppId && (left.branchName ?? null) === (right.branchName ?? null);
|
|
518
|
+
}
|
|
512
519
|
async function readLocalBaseline(params) {
|
|
513
520
|
try {
|
|
514
521
|
const raw = await fs2.readFile(getBaselinePath(params), "utf8");
|
|
@@ -558,6 +565,105 @@ async function writeLocalBaseline(baseline) {
|
|
|
558
565
|
await writeJsonAtomic(getBaselinePath(baseline), normalized);
|
|
559
566
|
return normalized;
|
|
560
567
|
}
|
|
568
|
+
async function readAllLocalBaselines() {
|
|
569
|
+
let entries;
|
|
570
|
+
try {
|
|
571
|
+
entries = await fs2.readdir(getBaselinesRoot());
|
|
572
|
+
} catch (error) {
|
|
573
|
+
if (error?.code === "ENOENT") return [];
|
|
574
|
+
throw error;
|
|
575
|
+
}
|
|
576
|
+
const baselines = [];
|
|
577
|
+
for (const entry of entries) {
|
|
578
|
+
if (!entry.endsWith(".json")) continue;
|
|
579
|
+
try {
|
|
580
|
+
const raw = await fs2.readFile(path3.join(getBaselinesRoot(), entry), "utf8");
|
|
581
|
+
const parsed = JSON.parse(raw);
|
|
582
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
583
|
+
if (![1, 2].includes(Number(parsed.schemaVersion)) || typeof parsed.key !== "string" || typeof parsed.repoRoot !== "string") {
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
baselines.push({
|
|
587
|
+
schemaVersion: Number(parsed.schemaVersion) === 2 ? 2 : 1,
|
|
588
|
+
key: parsed.key,
|
|
589
|
+
repoRoot: parsed.repoRoot,
|
|
590
|
+
repoFingerprint: parsed.repoFingerprint ?? null,
|
|
591
|
+
laneId: parsed.laneId ?? null,
|
|
592
|
+
currentAppId: String(parsed.currentAppId ?? ""),
|
|
593
|
+
branchName: parsed.branchName ?? null,
|
|
594
|
+
lastSnapshotId: parsed.lastSnapshotId ?? null,
|
|
595
|
+
lastSnapshotHash: parsed.lastSnapshotHash ?? null,
|
|
596
|
+
lastServerRevisionId: parsed.lastServerRevisionId ?? null,
|
|
597
|
+
lastServerTreeHash: parsed.lastServerTreeHash ?? null,
|
|
598
|
+
lastServerHeadHash: parsed.lastServerHeadHash ?? null,
|
|
599
|
+
lastSeenLocalCommitHash: parsed.lastSeenLocalCommitHash ?? null,
|
|
600
|
+
updatedAt: String(parsed.updatedAt ?? "")
|
|
601
|
+
});
|
|
602
|
+
} catch {
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return baselines;
|
|
607
|
+
}
|
|
608
|
+
async function migrateLocalBaselineForLaneChange(params) {
|
|
609
|
+
if ((params.fromLaneId ?? null) === (params.toLaneId ?? null)) {
|
|
610
|
+
return { status: "same_lane" };
|
|
611
|
+
}
|
|
612
|
+
const target = await readLocalBaseline({
|
|
613
|
+
repoRoot: params.repoRoot,
|
|
614
|
+
repoFingerprint: params.repoFingerprint,
|
|
615
|
+
laneId: params.toLaneId
|
|
616
|
+
});
|
|
617
|
+
if (target) {
|
|
618
|
+
return { status: "target_exists" };
|
|
619
|
+
}
|
|
620
|
+
const source = await readLocalBaseline({
|
|
621
|
+
repoRoot: params.repoRoot,
|
|
622
|
+
repoFingerprint: params.repoFingerprint,
|
|
623
|
+
laneId: params.fromLaneId
|
|
624
|
+
});
|
|
625
|
+
if (!source) {
|
|
626
|
+
return { status: "source_missing" };
|
|
627
|
+
}
|
|
628
|
+
const expectedSource = {
|
|
629
|
+
repoRoot: params.repoRoot,
|
|
630
|
+
repoFingerprint: params.repoFingerprint,
|
|
631
|
+
laneId: params.fromLaneId,
|
|
632
|
+
currentAppId: params.currentAppId,
|
|
633
|
+
branchName: params.branchName
|
|
634
|
+
};
|
|
635
|
+
const actualSource = {
|
|
636
|
+
repoRoot: source.repoRoot,
|
|
637
|
+
repoFingerprint: source.repoFingerprint,
|
|
638
|
+
laneId: source.laneId,
|
|
639
|
+
currentAppId: source.currentAppId,
|
|
640
|
+
branchName: source.branchName
|
|
641
|
+
};
|
|
642
|
+
if (!isSameBaselineIdentity(actualSource, expectedSource)) {
|
|
643
|
+
return { status: "source_missing" };
|
|
644
|
+
}
|
|
645
|
+
const baseline = await writeLocalBaseline({
|
|
646
|
+
...source,
|
|
647
|
+
laneId: params.toLaneId
|
|
648
|
+
});
|
|
649
|
+
return { status: "migrated", baseline };
|
|
650
|
+
}
|
|
651
|
+
async function findCompatibleLocalBaseline(params) {
|
|
652
|
+
const targetKey = buildLaneStateKey(params);
|
|
653
|
+
const branchName = normalizeNullableString(params.branchName);
|
|
654
|
+
const candidates = (await readAllLocalBaselines()).filter((baseline) => {
|
|
655
|
+
if (baseline.key === targetKey) return false;
|
|
656
|
+
if (baseline.repoRoot !== params.repoRoot) return false;
|
|
657
|
+
if ((baseline.repoFingerprint ?? null) !== (params.repoFingerprint ?? null)) return false;
|
|
658
|
+
if (baseline.currentAppId !== params.currentAppId) return false;
|
|
659
|
+
return true;
|
|
660
|
+
});
|
|
661
|
+
const branchMatches = candidates.filter((baseline) => normalizeNullableString(baseline.branchName) === branchName);
|
|
662
|
+
const compatible = branchMatches.length > 0 ? branchMatches : candidates.filter((baseline) => normalizeNullableString(baseline.branchName) === null);
|
|
663
|
+
if (compatible.length === 0) return { status: "none", candidateCount: 0 };
|
|
664
|
+
if (compatible.length > 1) return { status: "ambiguous", candidateCount: compatible.length };
|
|
665
|
+
return { status: "found", baseline: compatible[0] };
|
|
666
|
+
}
|
|
561
667
|
async function clearLocalBaseline(params) {
|
|
562
668
|
try {
|
|
563
669
|
await fs2.unlink(getBaselinePath(params));
|
|
@@ -1500,6 +1606,7 @@ function resolveLaneLookupProjectId(params) {
|
|
|
1500
1606
|
return params.explicitRootProjectId ?? (params.requireRemoteLane ? void 0 : localProjectId ?? params.fallbackProjectId ?? void 0);
|
|
1501
1607
|
}
|
|
1502
1608
|
async function persistResolvedLane(repoRoot, binding) {
|
|
1609
|
+
const previousBinding = await readCollabBinding(repoRoot);
|
|
1503
1610
|
await writeCollabBinding(repoRoot, {
|
|
1504
1611
|
projectId: binding.projectId,
|
|
1505
1612
|
currentAppId: binding.currentAppId,
|
|
@@ -1512,6 +1619,16 @@ async function persistResolvedLane(repoRoot, binding) {
|
|
|
1512
1619
|
branchName: binding.branchName,
|
|
1513
1620
|
bindingMode: binding.bindingMode
|
|
1514
1621
|
});
|
|
1622
|
+
if (previousBinding && (previousBinding.laneId ?? null) !== (binding.laneId ?? null)) {
|
|
1623
|
+
await migrateLocalBaselineForLaneChange({
|
|
1624
|
+
repoRoot,
|
|
1625
|
+
repoFingerprint: binding.repoFingerprint,
|
|
1626
|
+
currentAppId: binding.currentAppId,
|
|
1627
|
+
branchName: binding.branchName,
|
|
1628
|
+
fromLaneId: previousBinding.laneId,
|
|
1629
|
+
toLaneId: binding.laneId
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1515
1632
|
return readCollabBinding(repoRoot);
|
|
1516
1633
|
}
|
|
1517
1634
|
function buildAmbiguousResolution(params) {
|
|
@@ -1911,11 +2028,36 @@ async function collabDetectRepoState(params) {
|
|
|
1911
2028
|
return detected;
|
|
1912
2029
|
}
|
|
1913
2030
|
try {
|
|
1914
|
-
|
|
2031
|
+
let baseline = await readLocalBaseline({
|
|
1915
2032
|
repoFingerprint: binding.repoFingerprint,
|
|
1916
2033
|
laneId: binding.laneId,
|
|
1917
2034
|
repoRoot
|
|
1918
2035
|
});
|
|
2036
|
+
let ambiguousBaselineCandidateCount = null;
|
|
2037
|
+
if (!baseline) {
|
|
2038
|
+
const compatibleBaseline = await findCompatibleLocalBaseline({
|
|
2039
|
+
repoRoot,
|
|
2040
|
+
repoFingerprint: binding.repoFingerprint,
|
|
2041
|
+
laneId: binding.laneId,
|
|
2042
|
+
currentAppId: binding.currentAppId,
|
|
2043
|
+
branchName: binding.branchName
|
|
2044
|
+
});
|
|
2045
|
+
if (compatibleBaseline.status === "found") {
|
|
2046
|
+
baseline = await writeLocalBaseline({
|
|
2047
|
+
...compatibleBaseline.baseline,
|
|
2048
|
+
repoRoot,
|
|
2049
|
+
repoFingerprint: binding.repoFingerprint,
|
|
2050
|
+
laneId: binding.laneId,
|
|
2051
|
+
currentAppId: binding.currentAppId,
|
|
2052
|
+
branchName: binding.branchName
|
|
2053
|
+
});
|
|
2054
|
+
detected.warnings.push(
|
|
2055
|
+
`Recovered local Remix baseline after lane id changed from ${compatibleBaseline.baseline.laneId ?? "null"} to ${binding.laneId ?? "null"} for app ${binding.currentAppId} on branch ${binding.branchName ?? "(unknown)"}.`
|
|
2056
|
+
);
|
|
2057
|
+
} else if (compatibleBaseline.status === "ambiguous") {
|
|
2058
|
+
ambiguousBaselineCandidateCount = compatibleBaseline.candidateCount;
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
1919
2061
|
const hasFullBaseline = Boolean(baseline?.lastSnapshotHash && baseline?.lastServerHeadHash);
|
|
1920
2062
|
const metadataIdentityPromise = hasFullBaseline ? getAppDeltaCached(params.api, binding.currentAppId, {
|
|
1921
2063
|
baseHeadHash: baseline.lastServerHeadHash,
|
|
@@ -1988,7 +2130,7 @@ async function collabDetectRepoState(params) {
|
|
|
1988
2130
|
}
|
|
1989
2131
|
}
|
|
1990
2132
|
detected.repoState = "external_local_base_changed";
|
|
1991
|
-
detected.hint = "No local Remix revision baseline exists for this lane yet. Run `remix collab init` or sync this lane to seed the baseline.";
|
|
2133
|
+
detected.hint = ambiguousBaselineCandidateCount !== null ? `No local Remix revision baseline exists for this lane, and multiple compatible local baselines were found (${ambiguousBaselineCandidateCount}). Run \`remix collab status\` or sync this lane to seed an unambiguous baseline.` : "No local Remix revision baseline exists for this lane yet. Run `remix collab init` or sync this lane to seed the baseline.";
|
|
1992
2134
|
return detected;
|
|
1993
2135
|
}
|
|
1994
2136
|
const localHeadMovedSinceBaseline = Boolean(baseline.lastSeenLocalCommitHash) && localCommitHash !== baseline.lastSeenLocalCommitHash;
|
|
@@ -3098,11 +3240,174 @@ async function drainPendingFinalizeQueue(params) {
|
|
|
3098
3240
|
|
|
3099
3241
|
// src/application/collab/collabFinalizeTurn.ts
|
|
3100
3242
|
var FINALIZE_AWAIT_INIT_POST_TIMEOUT_MS = 6e4;
|
|
3243
|
+
var FINALIZE_UNALIGNED_DRAIN_TIMEOUT_MS = 1e4;
|
|
3101
3244
|
function collectWarnings(value) {
|
|
3102
3245
|
if (!Array.isArray(value)) return [];
|
|
3103
3246
|
return value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
3104
3247
|
}
|
|
3248
|
+
function throwBlockingDetectedStatus(detected) {
|
|
3249
|
+
if (detected.status === "not_bound") {
|
|
3250
|
+
throw new RemixError("Repository is not bound to Remix.", {
|
|
3251
|
+
code: "not_bound",
|
|
3252
|
+
exitCode: 2,
|
|
3253
|
+
hint: detected.hint
|
|
3254
|
+
});
|
|
3255
|
+
}
|
|
3256
|
+
if (detected.status === "branch_binding_missing") {
|
|
3257
|
+
throw new RemixError(detected.hint || "Current branch is not ready for Remix recording.", {
|
|
3258
|
+
code: detected.status,
|
|
3259
|
+
exitCode: 2,
|
|
3260
|
+
hint: detected.hint
|
|
3261
|
+
});
|
|
3262
|
+
}
|
|
3263
|
+
if (detected.status === "family_ambiguous") {
|
|
3264
|
+
throw new RemixError(detected.hint || "Current branch is not ready for Remix recording.", {
|
|
3265
|
+
code: detected.status,
|
|
3266
|
+
exitCode: 2,
|
|
3267
|
+
hint: detected.hint
|
|
3268
|
+
});
|
|
3269
|
+
}
|
|
3270
|
+
if (detected.status === "metadata_conflict" || detected.status === "branch_mismatch") {
|
|
3271
|
+
throw new RemixError("Repository must be realigned before finalizing the turn.", {
|
|
3272
|
+
code: detected.status,
|
|
3273
|
+
exitCode: 2,
|
|
3274
|
+
hint: detected.hint
|
|
3275
|
+
});
|
|
3276
|
+
}
|
|
3277
|
+
if (detected.status === "remote_error") {
|
|
3278
|
+
const message = detected.hint || "Failed to determine the current repo state.";
|
|
3279
|
+
throw new RemixError(message, {
|
|
3280
|
+
code: detected.status,
|
|
3281
|
+
exitCode: 1,
|
|
3282
|
+
hint: detected.hint
|
|
3283
|
+
});
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
function withTimeout(work, timeoutMs, message) {
|
|
3287
|
+
let timer;
|
|
3288
|
+
const timeout = new Promise((_, reject) => {
|
|
3289
|
+
timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
3290
|
+
timer.unref?.();
|
|
3291
|
+
});
|
|
3292
|
+
return Promise.race([work, timeout]).finally(() => {
|
|
3293
|
+
if (timer) clearTimeout(timer);
|
|
3294
|
+
});
|
|
3295
|
+
}
|
|
3296
|
+
async function drainPendingFinalizeBeforeUnalignedFallback(params) {
|
|
3297
|
+
const summary = await summarizePendingFinalizeJobs({
|
|
3298
|
+
repoRoot: params.repoRoot,
|
|
3299
|
+
repoFingerprint: params.repoFingerprint,
|
|
3300
|
+
currentAppId: params.currentAppId,
|
|
3301
|
+
laneId: params.laneId
|
|
3302
|
+
});
|
|
3303
|
+
if (summary.activeJobCount <= 0) {
|
|
3304
|
+
return { attempted: false, warnings: [] };
|
|
3305
|
+
}
|
|
3306
|
+
const warnings = [];
|
|
3307
|
+
try {
|
|
3308
|
+
await withTimeout(
|
|
3309
|
+
drainPendingFinalizeQueue({ api: params.api }),
|
|
3310
|
+
FINALIZE_UNALIGNED_DRAIN_TIMEOUT_MS,
|
|
3311
|
+
`Timed out waiting ${Math.round(
|
|
3312
|
+
FINALIZE_UNALIGNED_DRAIN_TIMEOUT_MS / 1e3
|
|
3313
|
+
)}s for pending Remix turn recording to advance the local baseline.`
|
|
3314
|
+
);
|
|
3315
|
+
} catch (error) {
|
|
3316
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3317
|
+
warnings.push(`Pending Remix turn recording could not be drained before this turn was captured: ${message}`);
|
|
3318
|
+
} finally {
|
|
3319
|
+
invalidateAppHeadCache(params.currentAppId);
|
|
3320
|
+
invalidateAppDeltaCacheForApp(params.currentAppId);
|
|
3321
|
+
}
|
|
3322
|
+
return { attempted: true, warnings };
|
|
3323
|
+
}
|
|
3105
3324
|
var FINALIZE_QUEUED_WARNING = "Queued only: the local Remix turn was captured, but no remote change step or collab turn exists yet. Drain or await finalize before merge-related flows.";
|
|
3325
|
+
var CONVERSATION_ONLY_WARNING = "Recorded conversation only: this turn was not materialized into a change step.";
|
|
3326
|
+
function buildConversationOnlyWorkspaceMetadata(params) {
|
|
3327
|
+
const metadata = {
|
|
3328
|
+
branch: params.branchName,
|
|
3329
|
+
repoRoot: params.repoRoot,
|
|
3330
|
+
remoteUrl: params.remoteUrl,
|
|
3331
|
+
defaultBranch: params.defaultBranch,
|
|
3332
|
+
recordingMode: "conversation_only",
|
|
3333
|
+
materializationStatus: params.materializationStatus,
|
|
3334
|
+
alignmentRequired: params.alignmentRequired,
|
|
3335
|
+
baselineSnapshotId: params.baselineSnapshotId,
|
|
3336
|
+
baselineServerRevisionId: params.baselineServerRevisionId,
|
|
3337
|
+
baselineServerHeadHash: params.baselineServerHeadHash,
|
|
3338
|
+
currentServerRevisionId: params.currentServerRevisionId,
|
|
3339
|
+
currentServerHeadHash: params.currentServerHeadHash,
|
|
3340
|
+
currentServerHeadCommitId: params.currentServerHeadCommitId,
|
|
3341
|
+
localCommitHash: params.localCommitHash,
|
|
3342
|
+
repoStateAtCapture: params.repoState,
|
|
3343
|
+
actor: params.actor ?? null
|
|
3344
|
+
};
|
|
3345
|
+
if (params.turnUsage) {
|
|
3346
|
+
metadata.turnUsage = params.turnUsage;
|
|
3347
|
+
}
|
|
3348
|
+
if (typeof params.promptedAt === "string" && params.promptedAt.trim()) {
|
|
3349
|
+
metadata.promptedAt = params.promptedAt.trim();
|
|
3350
|
+
}
|
|
3351
|
+
return metadata;
|
|
3352
|
+
}
|
|
3353
|
+
async function recordConversationOnlyTurn(params) {
|
|
3354
|
+
const idempotencyKey = params.explicitIdempotencyKey?.trim() || buildDeterministicIdempotencyKey({
|
|
3355
|
+
kind: "collab_finalize_turn_conversation_only_v1",
|
|
3356
|
+
appId: params.binding.currentAppId,
|
|
3357
|
+
laneId: params.binding.laneId,
|
|
3358
|
+
materializationStatus: params.materializationStatus,
|
|
3359
|
+
alignmentRequired: params.alignmentRequired,
|
|
3360
|
+
baselineSnapshotId: params.baselineSnapshotId ?? null,
|
|
3361
|
+
baselineServerRevisionId: params.baselineServerRevisionId ?? null,
|
|
3362
|
+
baselineServerHeadHash: params.baselineServerHeadHash ?? null,
|
|
3363
|
+
currentServerRevisionId: params.currentServerRevisionId ?? null,
|
|
3364
|
+
currentServerHeadHash: params.currentServerHeadHash ?? null,
|
|
3365
|
+
currentServerHeadCommitId: params.currentServerHeadCommitId ?? null,
|
|
3366
|
+
localCommitHash: params.localCommitHash ?? null,
|
|
3367
|
+
repoState: params.repoState,
|
|
3368
|
+
prompt: params.prompt,
|
|
3369
|
+
assistantResponse: params.assistantResponse
|
|
3370
|
+
});
|
|
3371
|
+
const collabTurnResp = await params.api.createCollabTurn(params.binding.currentAppId, {
|
|
3372
|
+
threadId: params.binding.threadId ?? void 0,
|
|
3373
|
+
collabLaneId: params.binding.laneId ?? void 0,
|
|
3374
|
+
prompt: params.prompt,
|
|
3375
|
+
assistantResponse: params.assistantResponse,
|
|
3376
|
+
actor: params.actor,
|
|
3377
|
+
workspaceMetadata: buildConversationOnlyWorkspaceMetadata({
|
|
3378
|
+
repoRoot: params.repoRoot,
|
|
3379
|
+
branchName: params.binding.branchName,
|
|
3380
|
+
remoteUrl: params.binding.remoteUrl,
|
|
3381
|
+
defaultBranch: params.binding.defaultBranch,
|
|
3382
|
+
baselineSnapshotId: params.baselineSnapshotId ?? null,
|
|
3383
|
+
baselineServerRevisionId: params.baselineServerRevisionId ?? null,
|
|
3384
|
+
baselineServerHeadHash: params.baselineServerHeadHash ?? null,
|
|
3385
|
+
currentServerRevisionId: params.currentServerRevisionId ?? null,
|
|
3386
|
+
currentServerHeadHash: params.currentServerHeadHash ?? null,
|
|
3387
|
+
currentServerHeadCommitId: params.currentServerHeadCommitId ?? null,
|
|
3388
|
+
localCommitHash: params.localCommitHash ?? null,
|
|
3389
|
+
repoState: params.repoState,
|
|
3390
|
+
materializationStatus: params.materializationStatus,
|
|
3391
|
+
alignmentRequired: params.alignmentRequired,
|
|
3392
|
+
actor: params.actor ?? null,
|
|
3393
|
+
turnUsage: params.turnUsage ?? null,
|
|
3394
|
+
promptedAt: params.promptedAt
|
|
3395
|
+
}),
|
|
3396
|
+
idempotencyKey
|
|
3397
|
+
});
|
|
3398
|
+
const collabTurn = unwrapResponseObject(collabTurnResp, "collab turn");
|
|
3399
|
+
return {
|
|
3400
|
+
mode: "conversation_only",
|
|
3401
|
+
idempotencyKey,
|
|
3402
|
+
queued: false,
|
|
3403
|
+
jobId: null,
|
|
3404
|
+
repoState: params.repoState,
|
|
3405
|
+
changeStep: null,
|
|
3406
|
+
collabTurn,
|
|
3407
|
+
autoSync: null,
|
|
3408
|
+
warnings: [CONVERSATION_ONLY_WARNING, ...collectWarnings(params.warnings ?? [])]
|
|
3409
|
+
};
|
|
3410
|
+
}
|
|
3106
3411
|
async function collabFinalizeTurn(params) {
|
|
3107
3412
|
const repoRoot = await findGitRoot(params.cwd);
|
|
3108
3413
|
const binding = await ensureActiveLaneBinding({
|
|
@@ -3171,6 +3476,24 @@ async function collabFinalizeTurn(params) {
|
|
|
3171
3476
|
` : "") + "Run `remix collab init` again to retry \u2014 the post-init drainer cleared the local binding so this is safe."
|
|
3172
3477
|
});
|
|
3173
3478
|
}
|
|
3479
|
+
try {
|
|
3480
|
+
return await recordConversationOnlyTurn({
|
|
3481
|
+
api: params.api,
|
|
3482
|
+
binding,
|
|
3483
|
+
repoRoot,
|
|
3484
|
+
prompt,
|
|
3485
|
+
assistantResponse,
|
|
3486
|
+
explicitIdempotencyKey: params.idempotencyKey,
|
|
3487
|
+
actor: params.actor,
|
|
3488
|
+
turnUsage: params.turnUsage,
|
|
3489
|
+
promptedAt: params.promptedAt,
|
|
3490
|
+
repoState: "init_post_pending",
|
|
3491
|
+
materializationStatus: "skipped_init_post_pending",
|
|
3492
|
+
alignmentRequired: "init_post",
|
|
3493
|
+
warnings: [`Init post job ${pendingInitPost.id} is still pending; recorded conversation only.`]
|
|
3494
|
+
});
|
|
3495
|
+
} catch {
|
|
3496
|
+
}
|
|
3174
3497
|
throw new RemixError("Timed out waiting for the initial Remix import to finish provisioning.", {
|
|
3175
3498
|
exitCode: 2,
|
|
3176
3499
|
hint: `Init post job ${pendingInitPost.id} did not complete within ${Math.round(
|
|
@@ -3179,67 +3502,95 @@ async function collabFinalizeTurn(params) {
|
|
|
3179
3502
|
});
|
|
3180
3503
|
}
|
|
3181
3504
|
}
|
|
3182
|
-
|
|
3505
|
+
let detected = await collabDetectRepoState({
|
|
3183
3506
|
api: params.api,
|
|
3184
3507
|
cwd: repoRoot,
|
|
3185
3508
|
allowBranchMismatch: params.allowBranchMismatch
|
|
3186
3509
|
});
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
code: detected.status,
|
|
3197
|
-
exitCode: 2,
|
|
3198
|
-
hint: detected.hint
|
|
3199
|
-
});
|
|
3200
|
-
}
|
|
3201
|
-
if (detected.status === "family_ambiguous") {
|
|
3202
|
-
throw new RemixError(detected.hint || "Current branch is not ready for Remix recording.", {
|
|
3203
|
-
code: detected.status,
|
|
3204
|
-
exitCode: 2,
|
|
3205
|
-
hint: detected.hint
|
|
3206
|
-
});
|
|
3207
|
-
}
|
|
3208
|
-
if (detected.status === "metadata_conflict" || detected.status === "branch_mismatch") {
|
|
3209
|
-
throw new RemixError("Repository must be realigned before finalizing the turn.", {
|
|
3210
|
-
code: detected.status,
|
|
3211
|
-
exitCode: 2,
|
|
3212
|
-
hint: detected.hint
|
|
3213
|
-
});
|
|
3214
|
-
}
|
|
3215
|
-
if (detected.status === "missing_head" || detected.status === "remote_error") {
|
|
3216
|
-
const message = detected.hint || "Failed to determine the current repo state.";
|
|
3217
|
-
throw new RemixError(message, {
|
|
3218
|
-
code: detected.status,
|
|
3219
|
-
exitCode: 1,
|
|
3220
|
-
hint: detected.hint
|
|
3510
|
+
throwBlockingDetectedStatus(detected);
|
|
3511
|
+
let pendingFinalizeDrainWarnings = [];
|
|
3512
|
+
if (detected.repoState === "server_only_changed" || detected.repoState === "both_changed") {
|
|
3513
|
+
const recovery = await drainPendingFinalizeBeforeUnalignedFallback({
|
|
3514
|
+
api: params.api,
|
|
3515
|
+
repoRoot,
|
|
3516
|
+
repoFingerprint: binding.repoFingerprint,
|
|
3517
|
+
currentAppId: binding.currentAppId,
|
|
3518
|
+
laneId: binding.laneId
|
|
3221
3519
|
});
|
|
3520
|
+
if (recovery.attempted) {
|
|
3521
|
+
pendingFinalizeDrainWarnings = recovery.warnings;
|
|
3522
|
+
detected = await collabDetectRepoState({
|
|
3523
|
+
api: params.api,
|
|
3524
|
+
cwd: repoRoot,
|
|
3525
|
+
allowBranchMismatch: params.allowBranchMismatch
|
|
3526
|
+
});
|
|
3527
|
+
throwBlockingDetectedStatus(detected);
|
|
3528
|
+
}
|
|
3222
3529
|
}
|
|
3223
|
-
if (detected.
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3530
|
+
if (detected.status === "missing_head") {
|
|
3531
|
+
return recordConversationOnlyTurn({
|
|
3532
|
+
api: params.api,
|
|
3533
|
+
binding,
|
|
3534
|
+
repoRoot,
|
|
3535
|
+
prompt,
|
|
3536
|
+
assistantResponse,
|
|
3537
|
+
explicitIdempotencyKey: params.idempotencyKey,
|
|
3538
|
+
actor: params.actor,
|
|
3539
|
+
turnUsage: params.turnUsage,
|
|
3540
|
+
promptedAt: params.promptedAt,
|
|
3541
|
+
repoState: "missing_head",
|
|
3542
|
+
materializationStatus: "skipped_missing_head",
|
|
3543
|
+
alignmentRequired: "head",
|
|
3544
|
+
localCommitHash: null,
|
|
3545
|
+
warnings: [...pendingFinalizeDrainWarnings, ...detected.warnings]
|
|
3228
3546
|
});
|
|
3229
3547
|
}
|
|
3230
|
-
if (detected.repoState === "both_changed") {
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3548
|
+
if (detected.repoState === "server_only_changed" || detected.repoState === "both_changed") {
|
|
3549
|
+
return recordConversationOnlyTurn({
|
|
3550
|
+
api: params.api,
|
|
3551
|
+
binding,
|
|
3552
|
+
repoRoot,
|
|
3553
|
+
prompt,
|
|
3554
|
+
assistantResponse,
|
|
3555
|
+
explicitIdempotencyKey: params.idempotencyKey,
|
|
3556
|
+
actor: params.actor,
|
|
3557
|
+
turnUsage: params.turnUsage,
|
|
3558
|
+
promptedAt: params.promptedAt,
|
|
3559
|
+
repoState: detected.repoState,
|
|
3560
|
+
materializationStatus: "skipped_unaligned",
|
|
3561
|
+
alignmentRequired: detected.repoState === "both_changed" ? "reconcile" : "sync",
|
|
3562
|
+
baselineSnapshotId: detected.baseline.lastSnapshotId,
|
|
3563
|
+
baselineServerRevisionId: detected.baseline.lastServerRevisionId,
|
|
3564
|
+
baselineServerHeadHash: detected.baseline.lastServerHeadHash,
|
|
3565
|
+
currentServerRevisionId: detected.currentServerRevisionId,
|
|
3566
|
+
currentServerHeadHash: detected.currentServerHeadHash,
|
|
3567
|
+
currentServerHeadCommitId: detected.currentServerHeadCommitId,
|
|
3568
|
+
localCommitHash: detected.localCommitHash,
|
|
3569
|
+
warnings: [...pendingFinalizeDrainWarnings, ...detected.warnings]
|
|
3236
3570
|
});
|
|
3237
3571
|
}
|
|
3238
3572
|
if (detected.repoState === "external_local_base_changed") {
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3573
|
+
return recordConversationOnlyTurn({
|
|
3574
|
+
api: params.api,
|
|
3575
|
+
binding,
|
|
3576
|
+
repoRoot,
|
|
3577
|
+
prompt,
|
|
3578
|
+
assistantResponse,
|
|
3579
|
+
explicitIdempotencyKey: params.idempotencyKey,
|
|
3580
|
+
actor: params.actor,
|
|
3581
|
+
turnUsage: params.turnUsage,
|
|
3582
|
+
promptedAt: params.promptedAt,
|
|
3583
|
+
repoState: "external_local_base_changed",
|
|
3584
|
+
materializationStatus: "skipped_baseline_missing",
|
|
3585
|
+
alignmentRequired: "baseline",
|
|
3586
|
+
baselineSnapshotId: detected.baseline.lastSnapshotId,
|
|
3587
|
+
baselineServerRevisionId: detected.baseline.lastServerRevisionId,
|
|
3588
|
+
baselineServerHeadHash: detected.baseline.lastServerHeadHash,
|
|
3589
|
+
currentServerRevisionId: detected.currentServerRevisionId,
|
|
3590
|
+
currentServerHeadHash: detected.currentServerHeadHash,
|
|
3591
|
+
currentServerHeadCommitId: detected.currentServerHeadCommitId,
|
|
3592
|
+
localCommitHash: detected.localCommitHash,
|
|
3593
|
+
warnings: [...pendingFinalizeDrainWarnings, ...detected.warnings]
|
|
3243
3594
|
});
|
|
3244
3595
|
}
|
|
3245
3596
|
const baseline = await readLocalBaseline({
|
|
@@ -3248,10 +3599,27 @@ async function collabFinalizeTurn(params) {
|
|
|
3248
3599
|
repoRoot
|
|
3249
3600
|
});
|
|
3250
3601
|
if (!baseline) {
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3602
|
+
return recordConversationOnlyTurn({
|
|
3603
|
+
api: params.api,
|
|
3604
|
+
binding,
|
|
3605
|
+
repoRoot,
|
|
3606
|
+
prompt,
|
|
3607
|
+
assistantResponse,
|
|
3608
|
+
explicitIdempotencyKey: params.idempotencyKey,
|
|
3609
|
+
actor: params.actor,
|
|
3610
|
+
turnUsage: params.turnUsage,
|
|
3611
|
+
promptedAt: params.promptedAt,
|
|
3612
|
+
repoState: "baseline_missing",
|
|
3613
|
+
materializationStatus: "skipped_baseline_missing",
|
|
3614
|
+
alignmentRequired: "baseline",
|
|
3615
|
+
baselineSnapshotId: detected.baseline.lastSnapshotId,
|
|
3616
|
+
baselineServerRevisionId: detected.baseline.lastServerRevisionId,
|
|
3617
|
+
baselineServerHeadHash: detected.baseline.lastServerHeadHash,
|
|
3618
|
+
currentServerRevisionId: detected.currentServerRevisionId,
|
|
3619
|
+
currentServerHeadHash: detected.currentServerHeadHash,
|
|
3620
|
+
currentServerHeadCommitId: detected.currentServerHeadCommitId,
|
|
3621
|
+
localCommitHash: detected.localCommitHash,
|
|
3622
|
+
warnings: [...pendingFinalizeDrainWarnings, ...detected.warnings]
|
|
3255
3623
|
});
|
|
3256
3624
|
}
|
|
3257
3625
|
const snapshot = await captureLocalSnapshot({
|
|
@@ -3309,7 +3677,7 @@ async function collabFinalizeTurn(params) {
|
|
|
3309
3677
|
changeStep: null,
|
|
3310
3678
|
collabTurn: null,
|
|
3311
3679
|
autoSync: null,
|
|
3312
|
-
warnings: [FINALIZE_QUEUED_WARNING, ...collectWarnings(detected.warnings)]
|
|
3680
|
+
warnings: [FINALIZE_QUEUED_WARNING, ...collectWarnings([...pendingFinalizeDrainWarnings, ...detected.warnings])]
|
|
3313
3681
|
};
|
|
3314
3682
|
}
|
|
3315
3683
|
|
|
@@ -135,7 +135,7 @@ type MergeRequestReview = {
|
|
|
135
135
|
type CollabApproveMode = "remote-only" | "sync-target-repo";
|
|
136
136
|
type CollabApprovalStrategy = "ai_patch_apply" | "git_merge_auto_resolve" | "git_merge_manual_resolution";
|
|
137
137
|
type CollabStatusBlockedReason = "not_git_repo" | "not_bound" | "branch_binding_missing" | "family_ambiguous" | "missing_head" | "detached_head" | "branch_mismatch" | "dirty_worktree" | "baseline_missing" | "metadata_conflict" | "remote_error";
|
|
138
|
-
type CollabRepoStateKind = "idle" | "local_only_changed" | "server_only_changed" | "both_changed" | "external_local_base_changed" | "metadata_conflict" | "binding_problem";
|
|
138
|
+
type CollabRepoStateKind = "idle" | "local_only_changed" | "server_only_changed" | "both_changed" | "external_local_base_changed" | "baseline_missing" | "missing_head" | "init_post_pending" | "metadata_conflict" | "binding_problem";
|
|
139
139
|
type CollabPendingFinalizeState = "idle" | "queued" | "processing" | "retry_scheduled" | "awaiting_usage" | "failed";
|
|
140
140
|
type CollabPendingFinalizeSummary = {
|
|
141
141
|
state: CollabPendingFinalizeState;
|
|
@@ -382,7 +382,7 @@ type CollabTurn = {
|
|
|
382
382
|
prompt: string | null;
|
|
383
383
|
assistantResponse: string | null;
|
|
384
384
|
};
|
|
385
|
-
type CollabFinalizeTurnMode = "changed_turn" | "no_diff_turn";
|
|
385
|
+
type CollabFinalizeTurnMode = "changed_turn" | "no_diff_turn" | "conversation_only";
|
|
386
386
|
type CollabFinalizeTurnAutoSync = {
|
|
387
387
|
requested: boolean;
|
|
388
388
|
eligible: boolean;
|
package/dist/history.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export { S as SessionStore, a as StoredSession, W as WithRefreshLock, c as creat
|
|
|
4
4
|
export { createDefaultRefreshLock, createLocalSessionStore, createSupabaseAuthHelpers, defaultSessionFilePath, isInvalidGrantError, isNetworkError } from './auth.js';
|
|
5
5
|
export { AgentMemoryItem, AgentMemoryKind, AgentMemorySearchItem, AgentMemorySearchResponse, AgentMemorySummary, AgentMemoryTimelineResponse, ApiClient, AppContext, AppContextAccessPath, AppPreviewExpectedKind, AppPreviewProcessStatus, AppPreviewQuery, AppPreviewResponse, AppReconcileResponse, AppSandboxCommandRun, Bundle, BundlePlatform, BundleStatus, ChangeStepDiffResponse, DetectProjectRuntimeTargetsPayload, ImportProjectRuntimeEnvPayload, InitiateBundleRequest, InvitationRecord, MergeRequest, MergeRequestReview, MergeRequestStatus, ProjectRuntimeEnvMetadata, ProjectRuntimeEnvScope, ProjectRuntimeTargetMetadata, ProjectRuntimeTargetScope, ProjectTrigger, ProjectTriggerPayload, ProjectTriggerScope, ProjectTriggerStep, ProjectTriggerStepPayload, ReconcilePreflightResponse, ResolveProjectRuntimeEnvForLocalPullResponse, RunAppRuntimeTargetPayload, RunAppSandboxCommandPayload, RunAppTriggerEventPayload, RunAppTriggerPayload, RuntimeCommandKind, RuntimeTargetKind, SetProjectRuntimeEnvPayload, SetProjectRuntimeTargetPayload, SyncLocalResponse, SyncUpstreamResponse, TriggerEventMetadata, TriggerEventSource, TriggerIntegrationStatus, TriggerMode, TriggerRun, TriggerStepRun, TriggerStepType, UpdateProjectTriggerPayload, createApiClient } from './api.js';
|
|
6
6
|
import 'zod';
|
|
7
|
-
import './contracts-
|
|
7
|
+
import './contracts-BqC3Lj7W.js';
|