@p4code/cli 0.6.16 → 0.6.18
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/bin.mjs +195 -23
- package/dist/client/assets/{DiffPanel-D-49iCgp.js → DiffPanel-Cq5Tpiyo.js} +2 -2
- package/dist/client/assets/{FilePreviewPanel-BoVkA6v5.js → FilePreviewPanel-CzPEQhZw.js} +2 -2
- package/dist/client/assets/{PreviewPanel-BJleJ76o.js → PreviewPanel-sMikTXMp.js} +2 -2
- package/dist/client/assets/{PullRequestCodeTab-DcWaYtU6.js → PullRequestCodeTab-D-0Nrbpq.js} +2 -2
- package/dist/client/assets/{fileCommentAnnotations-CgO_0-Tr.js → fileCommentAnnotations-BRlauqkZ.js} +2 -2
- package/dist/client/assets/{index-sXPBcrsQ.js → index-DYICyvf7.js} +229 -220
- package/dist/client/assets/previewAssetResource-CscIFHNv.js +48 -0
- package/dist/client/assets/{renderFileChildren-rNvuBJzO.js → renderFileChildren-CGBEoF-u.js} +2 -2
- package/dist/client/assets/{toggle-group-BPwLpAJP.js → toggle-group-C8xCVvsa.js} +2 -2
- package/dist/client/index.html +2 -2
- package/package.json +1 -1
- package/dist/client/assets/previewAssetResource-CdRrwvdJ.js +0 -48
package/dist/bin.mjs
CHANGED
|
@@ -268,7 +268,7 @@ const make$124 = () => {
|
|
|
268
268
|
const layer$124 = Layer.sync(NetService, make$124);
|
|
269
269
|
//#endregion
|
|
270
270
|
//#region package.json
|
|
271
|
-
var version$1 = "0.6.
|
|
271
|
+
var version$1 = "0.6.18";
|
|
272
272
|
//#endregion
|
|
273
273
|
//#region src/config.ts
|
|
274
274
|
/**
|
|
@@ -3284,6 +3284,8 @@ const FUSION_GATE_PROMPT_PREFIX = "[fusion-gate]";
|
|
|
3284
3284
|
const FUSION_ACTIVATION_PROMPT_PREFIX = "[fusion-activation]";
|
|
3285
3285
|
/** Server message that returns a Builder to its unfinished phase on Jev's advice. */
|
|
3286
3286
|
const FUSION_JEV_PROMPT_PREFIX = "[fusion-jev]";
|
|
3287
|
+
/** Server message that resumes a Fusion child once after a transient provider failure. */
|
|
3288
|
+
const FUSION_RETRY_PROMPT_PREFIX = "[fusion-retry]";
|
|
3287
3289
|
/**
|
|
3288
3290
|
* Message-id namespaces for server-generated fusion wakes. Wake detection is
|
|
3289
3291
|
* keyed off these rather than message text, which a user or expanded skill
|
|
@@ -5296,7 +5298,7 @@ var OrchestrationSearchThreadsError = class extends Schema$1.TaggedErrorClass()(
|
|
|
5296
5298
|
const ThreadWatchEventsInput = Schema$1.Struct({
|
|
5297
5299
|
threadId: ThreadId.annotate({ description: "The thread to read events from. Any thread on this server, not only this session's own." }),
|
|
5298
5300
|
afterSequence: Schema$1.optional(NonNegativeInt.annotate({ description: "Exclusive sequence cursor. Events with a higher sequence are returned. Omit to read from the beginning." })),
|
|
5299
|
-
limit: Schema$1.optional(NonNegativeInt.
|
|
5301
|
+
limit: Schema$1.optional(NonNegativeInt.annotate({ description: `Maximum events to return (default 50, max 200; larger values are clamped).` }))
|
|
5300
5302
|
});
|
|
5301
5303
|
const ThreadWatchEventsResult = Schema$1.Struct({
|
|
5302
5304
|
threadId: ThreadId,
|
|
@@ -13355,7 +13357,9 @@ const ThreadContextUpdateInput = Schema$1.Struct({
|
|
|
13355
13357
|
});
|
|
13356
13358
|
const ThreadContextUpdateResult = Schema$1.Struct({
|
|
13357
13359
|
pairId: ThreadPairId,
|
|
13358
|
-
updatedAt: IsoDateTime
|
|
13360
|
+
updatedAt: IsoDateTime,
|
|
13361
|
+
/** Explains input the server dropped instead of rejecting the whole update. */
|
|
13362
|
+
notice: Schema$1.optional(Schema$1.String)
|
|
13359
13363
|
});
|
|
13360
13364
|
const RoleContextItems = Schema$1.Struct({
|
|
13361
13365
|
supervisor: SharedContextItems,
|
|
@@ -21561,6 +21565,7 @@ const makeRuntimeSqliteLayer = Effect.fn("makeRuntimeSqliteLayer")(function* (co
|
|
|
21561
21565
|
const applyPragmas = Effect.gen(function* () {
|
|
21562
21566
|
const sql = yield* SqlClient.SqlClient;
|
|
21563
21567
|
yield* sql`PRAGMA journal_mode = WAL;`;
|
|
21568
|
+
yield* sql`PRAGMA synchronous = NORMAL;`;
|
|
21564
21569
|
yield* sql`PRAGMA foreign_keys = ON;`;
|
|
21565
21570
|
});
|
|
21566
21571
|
const setupFile = (dbPath) => Layer.effectDiscard(applyPragmas.pipe(Effect.andThen(runGuardedMigrations({ dbPath })), Effect.andThen(runHistoricalActivityCompaction())));
|
|
@@ -45417,8 +45422,9 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
|
|
|
45417
45422
|
threadId,
|
|
45418
45423
|
...bounds
|
|
45419
45424
|
})).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:listActivities:query", "ProjectionSnapshotQuery.getThreadDetailById:listActivities:decodeRows")), Effect.map((rows) => rows.map(mapThreadActivityRow)));
|
|
45420
|
-
const
|
|
45421
|
-
|
|
45425
|
+
const threadRow = yield* getActiveThreadRowById({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:getThread:query", "ProjectionSnapshotQuery.getThreadDetailById:getThread:decodeRow")));
|
|
45426
|
+
if (Option.isNone(threadRow)) return Option.none();
|
|
45427
|
+
const [messageRows, proposedPlanRows, activities, checkpointRows, turnRows, latestTurnRow, sessionRow, scheduledTaskRows] = yield* Effect.all([
|
|
45422
45428
|
(bounds === void 0 ? listThreadMessageRowsByThread({ threadId }) : listThreadMessageRowsByThreadWindow({
|
|
45423
45429
|
threadId,
|
|
45424
45430
|
...bounds
|
|
@@ -45431,7 +45437,6 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
|
|
|
45431
45437
|
getThreadSessionRowByThread({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:getSession:query", "ProjectionSnapshotQuery.getThreadDetailById:getSession:decodeRow"))),
|
|
45432
45438
|
listThreadScheduledTaskRowsByThread({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:listScheduledTasks:query", "ProjectionSnapshotQuery.getThreadDetailById:listScheduledTasks:decodeRows")))
|
|
45433
45439
|
]);
|
|
45434
|
-
if (Option.isNone(threadRow)) return Option.none();
|
|
45435
45440
|
const thread = {
|
|
45436
45441
|
id: threadRow.value.threadId,
|
|
45437
45442
|
projectId: threadRow.value.projectId,
|
|
@@ -49909,6 +49914,7 @@ const findXcodeProject = (fs, root) => Effect.gen(function* () {
|
|
|
49909
49914
|
});
|
|
49910
49915
|
function createAppleDeviceAdapter(input) {
|
|
49911
49916
|
const sessions = /* @__PURE__ */ new Map();
|
|
49917
|
+
const openings = /* @__PURE__ */ new Map();
|
|
49912
49918
|
const fail = (operation) => (cause) => new DeviceOperationError({
|
|
49913
49919
|
operation,
|
|
49914
49920
|
reason: "request_failed",
|
|
@@ -49921,6 +49927,8 @@ function createAppleDeviceAdapter(input) {
|
|
|
49921
49927
|
const closeSession = (leaseId) => {
|
|
49922
49928
|
const pending = sessions.get(leaseId);
|
|
49923
49929
|
sessions.delete(leaseId);
|
|
49930
|
+
openings.get(leaseId)?.abort();
|
|
49931
|
+
openings.delete(leaseId);
|
|
49924
49932
|
pending?.then(async (owned) => {
|
|
49925
49933
|
try {
|
|
49926
49934
|
await owned.client.call("DeviceInteractionEndSession", { interactionSessionKey: owned.key }, new AbortController().signal);
|
|
@@ -49932,11 +49940,13 @@ function createAppleDeviceAdapter(input) {
|
|
|
49932
49940
|
const workspaceFor = (session) => input.workspacePath !== void 0 || !session.workspaceRoot || session.leaseId !== void 0 && sessions.has(session.leaseId) ? Effect.succeed(input.workspacePath) : findXcodeProject(input.fs, session.workspaceRoot);
|
|
49933
49941
|
const get = (session) => Effect.flatMap(workspaceFor(session), (workspace) => open(session, workspace));
|
|
49934
49942
|
const open = (session, workspace) => Effect.tryPromise({
|
|
49935
|
-
try: async (
|
|
49943
|
+
try: async () => {
|
|
49936
49944
|
if (session.hostId !== "local" || session.platform !== "ios" || !session.leaseId) throw new Error("Apple MCP requires an exact local iOS device lease.");
|
|
49937
49945
|
let pending = sessions.get(session.leaseId);
|
|
49938
49946
|
if (!pending) {
|
|
49939
49947
|
if (sessions.size >= MAX_SESSIONS) throw new Error("Close an existing device session first.");
|
|
49948
|
+
const controller = new AbortController();
|
|
49949
|
+
const signal = controller.signal;
|
|
49940
49950
|
pending = (async () => {
|
|
49941
49951
|
const client = await XcodeMcpClient.start("/usr/bin/xcrun", input.cwd, {
|
|
49942
49952
|
...input.environment,
|
|
@@ -49966,8 +49976,12 @@ function createAppleDeviceAdapter(input) {
|
|
|
49966
49976
|
}
|
|
49967
49977
|
})();
|
|
49968
49978
|
sessions.set(session.leaseId, pending);
|
|
49979
|
+
openings.set(session.leaseId, controller);
|
|
49969
49980
|
const leaseId = session.leaseId;
|
|
49970
|
-
pending.
|
|
49981
|
+
pending.then(() => {
|
|
49982
|
+
if (openings.get(leaseId) === controller) openings.delete(leaseId);
|
|
49983
|
+
}, () => {
|
|
49984
|
+
if (openings.get(leaseId) === controller) openings.delete(leaseId);
|
|
49971
49985
|
if (sessions.get(leaseId) === pending) sessions.delete(leaseId);
|
|
49972
49986
|
});
|
|
49973
49987
|
}
|
|
@@ -61866,6 +61880,38 @@ const prepareSharedCheckout = (input, git) => Effect.gen(function* () {
|
|
|
61866
61880
|
return { branch };
|
|
61867
61881
|
}).pipe(Effect.withSpan("prepareSharedCheckout"));
|
|
61868
61882
|
//#endregion
|
|
61883
|
+
//#region src/orchestration/ShellStreamingThrottle.ts
|
|
61884
|
+
/** Minimum gap between shell refetches caused by one streaming message. */
|
|
61885
|
+
const SHELL_STREAMING_REFRESH_INTERVAL_MS = 1e3;
|
|
61886
|
+
/**
|
|
61887
|
+
* Per-subscription filter for the shell stream. A streaming assistant message
|
|
61888
|
+
* emits a delta roughly every 50 ms and each one only moves the thread's
|
|
61889
|
+
* `updatedAt`, yet every delta would otherwise refetch the thread shell and
|
|
61890
|
+
* push it to the client. The first delta of a message always passes (it can
|
|
61891
|
+
* change `latestTurn`), later deltas pass at most once per interval, and the
|
|
61892
|
+
* final non-streaming message always passes, so the shell still settles on the
|
|
61893
|
+
* current state.
|
|
61894
|
+
*
|
|
61895
|
+
* Returns `(event, nowMs) => keep`. Create one per subscription: the state is
|
|
61896
|
+
* which deltas this subscriber has already seen.
|
|
61897
|
+
*/
|
|
61898
|
+
function makeShellStreamingThrottle(intervalMs = SHELL_STREAMING_REFRESH_INTERVAL_MS) {
|
|
61899
|
+
const lastPassedAtByMessageId = /* @__PURE__ */ new Map();
|
|
61900
|
+
return (event, nowMs) => {
|
|
61901
|
+
if (event.type !== "thread.message-sent") return true;
|
|
61902
|
+
const messageId = event.payload.messageId;
|
|
61903
|
+
if (!event.payload.streaming) {
|
|
61904
|
+
lastPassedAtByMessageId.delete(messageId);
|
|
61905
|
+
return true;
|
|
61906
|
+
}
|
|
61907
|
+
const lastPassedAt = lastPassedAtByMessageId.get(messageId);
|
|
61908
|
+
if (lastPassedAt !== void 0 && nowMs - lastPassedAt < intervalMs) return false;
|
|
61909
|
+
if (lastPassedAtByMessageId.size >= 1e3) lastPassedAtByMessageId.clear();
|
|
61910
|
+
lastPassedAtByMessageId.set(messageId, nowMs);
|
|
61911
|
+
return true;
|
|
61912
|
+
};
|
|
61913
|
+
}
|
|
61914
|
+
//#endregion
|
|
61869
61915
|
//#region src/provider/ProviderInstanceEnvironment.ts
|
|
61870
61916
|
function mergeProviderInstanceEnvironment(environment, baseEnv = process.env) {
|
|
61871
61917
|
if (!environment || environment.length === 0) return baseEnv;
|
|
@@ -92270,6 +92316,11 @@ const makeCodexSubagentModelReporter = (options) => {
|
|
|
92270
92316
|
*/
|
|
92271
92317
|
/** Codex's own name for the token variable of p4code's built-in server. */
|
|
92272
92318
|
const CODEX_P4CODE_BEARER_TOKEN_ENV_VAR = "P4_MCP_BEARER_TOKEN";
|
|
92319
|
+
/**
|
|
92320
|
+
* Codex `mcp_servers.<name>.tool_timeout_sec` for p4code's built-in server, a
|
|
92321
|
+
* TOML float. An hour, because `ask_user_question` blocks until a person answers.
|
|
92322
|
+
*/
|
|
92323
|
+
const CODEX_P4CODE_TOOL_TIMEOUT_SEC = "3600.0";
|
|
92273
92324
|
/** Its own variable, so the Computer Use credential never rides on p4-code's. */
|
|
92274
92325
|
const CODEX_P4_COMPUTER_USE_BEARER_TOKEN_ENV_VAR = "P4_COMPUTER_USE_BEARER_TOKEN";
|
|
92275
92326
|
/** Prefix for the per-server variables the registered servers get. */
|
|
@@ -94405,7 +94456,9 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
|
|
|
94405
94456
|
"-c",
|
|
94406
94457
|
`mcp_servers.${P4CODE_MCP_SERVER_NAME}.url=${mcpSession.endpoint}`,
|
|
94407
94458
|
"-c",
|
|
94408
|
-
`mcp_servers.${P4CODE_MCP_SERVER_NAME}.bearer_token_env_var="${CODEX_P4CODE_BEARER_TOKEN_ENV_VAR}"
|
|
94459
|
+
`mcp_servers.${P4CODE_MCP_SERVER_NAME}.bearer_token_env_var="${CODEX_P4CODE_BEARER_TOKEN_ENV_VAR}"`,
|
|
94460
|
+
"-c",
|
|
94461
|
+
`mcp_servers.${P4CODE_MCP_SERVER_NAME}.tool_timeout_sec=${CODEX_P4CODE_TOOL_TIMEOUT_SEC}`
|
|
94409
94462
|
] : [],
|
|
94410
94463
|
...mcpSession?.computerUse ? [
|
|
94411
94464
|
"-c",
|
|
@@ -132581,7 +132634,10 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker, computerUseBrok
|
|
|
132581
132634
|
output.push(...yield* coalesceShellEvents(pendingEvents));
|
|
132582
132635
|
return output;
|
|
132583
132636
|
});
|
|
132584
|
-
const coalesceShellLiveStream = (stream) =>
|
|
132637
|
+
const coalesceShellLiveStream = (stream) => {
|
|
132638
|
+
const keepStreamingDelta = makeShellStreamingThrottle();
|
|
132639
|
+
return stream.pipe(Stream.filterEffect((input) => input.kind === "event" ? Clock.currentTimeMillis.pipe(Effect.map((nowMs) => keepStreamingDelta(input.event, nowMs))) : Effect.succeed(true)), Stream.groupedWithin(SHELL_COALESCE_MAX_CHUNK, SHELL_COALESCE_WINDOW), Stream.mapEffect(coalesceShellLiveInputs), Stream.flatMap((items) => Stream.fromIterable(items)));
|
|
132640
|
+
};
|
|
132585
132641
|
const dispatchBootstrapTurnStart = (command) => Effect.gen(function* () {
|
|
132586
132642
|
const bootstrap = command.bootstrap;
|
|
132587
132643
|
const { bootstrap: _bootstrap, ...finalTurnStartCommand } = command;
|
|
@@ -136998,7 +137054,9 @@ const ThreadToolkitHandlersLive = ThreadToolkit.toLayer({
|
|
|
136998
137054
|
const { invocation, pair, reject } = yield* requireSharedPair("thread_context_update");
|
|
136999
137055
|
const isBuilder = invocation.threadId === pair.implementerThreadId;
|
|
137000
137056
|
if (isBuilder && (input.requirements !== void 0 || input.decisions !== void 0)) return yield* reject("Supervisor owns requirements and decisions. Propose revisions through thread_ask.");
|
|
137001
|
-
|
|
137057
|
+
const { summary, ...supervisorContext } = input;
|
|
137058
|
+
const ignoresSummary = !isBuilder && summary !== void 0;
|
|
137059
|
+
if (ignoresSummary && input.requirements === void 0 && input.decisions === void 0 && input.blockers.length === 0 && input.evidence.length === 0) return yield* reject("Only Builder may replace its phase summary.");
|
|
137002
137060
|
const crypto = yield* Crypto.Crypto;
|
|
137003
137061
|
const createdAt = DateTime.formatIso(yield* DateTime.now);
|
|
137004
137062
|
yield* dispatchControl({
|
|
@@ -137014,14 +137072,15 @@ const ThreadToolkitHandlersLive = ThreadToolkit.toLayer({
|
|
|
137014
137072
|
summary: "Shared working context updated",
|
|
137015
137073
|
turnId: null,
|
|
137016
137074
|
payload: {
|
|
137017
|
-
...input,
|
|
137075
|
+
...isBuilder ? input : supervisorContext,
|
|
137018
137076
|
pairId: pair.id
|
|
137019
137077
|
}
|
|
137020
137078
|
}
|
|
137021
137079
|
}, invocation.threadId);
|
|
137022
137080
|
return {
|
|
137023
137081
|
pairId: pair.id,
|
|
137024
|
-
updatedAt: createdAt
|
|
137082
|
+
updatedAt: createdAt,
|
|
137083
|
+
...ignoresSummary ? { notice: "summary was ignored because only Builder owns its phase summary; the other fields were saved." } : {}
|
|
137025
137084
|
};
|
|
137026
137085
|
}),
|
|
137027
137086
|
thread_plan_update: (input) => Effect.gen(function* () {
|
|
@@ -139053,7 +139112,7 @@ const WatchToolkitHandlersLive = WatchToolkit.toLayer({
|
|
|
139053
139112
|
const page = yield* (yield* ThreadEventStreamService).read({
|
|
139054
139113
|
threadId: input.threadId,
|
|
139055
139114
|
...input.afterSequence !== void 0 ? { afterSequence: input.afterSequence } : {},
|
|
139056
|
-
limit: input.limit ?? 50
|
|
139115
|
+
limit: Math.min(input.limit ?? 50, 200)
|
|
139057
139116
|
}).pipe(Effect.mapError((cause) => new ThreadWatchFailedError({
|
|
139058
139117
|
threadId: input.threadId,
|
|
139059
139118
|
detail: cause.message
|
|
@@ -145016,7 +145075,8 @@ function citedSequences(summary) {
|
|
|
145016
145075
|
* sequence numbers, the summary is required to cite them, and a dropped line,
|
|
145017
145076
|
* unrenderable transcript field, or dropped ledger row makes coverage
|
|
145018
145077
|
* incomplete. A shortened transcript field or clipped ledger argument stays
|
|
145019
|
-
* visible and its full text stays in the raw event, so neither does.
|
|
145078
|
+
* visible and its full text stays in the raw event, so neither does. A summary
|
|
145079
|
+
* line citing a sequence the transcript lacks is removed, never kept.
|
|
145020
145080
|
*
|
|
145021
145081
|
* @module orchestration/handoff/fusionEvidenceHandoff
|
|
145022
145082
|
*/
|
|
@@ -145170,6 +145230,34 @@ function summaryRejection(input) {
|
|
|
145170
145230
|
if (cited.length === 0) return "summary-uncited";
|
|
145171
145231
|
return cited.every((sequence) => input.includedSequences.has(sequence)) ? null : "summary-citation-invalid";
|
|
145172
145232
|
}
|
|
145233
|
+
/**
|
|
145234
|
+
* The summary with every line citing a sequence absent from the transcript,
|
|
145235
|
+
* and the uncited lines continuing it, removed; or null when nothing was
|
|
145236
|
+
* removed or nothing cited survives.
|
|
145237
|
+
*
|
|
145238
|
+
* A line is the unit of claim: one invented citation condemns the line it is
|
|
145239
|
+
* on, never the lines beside it that cite real evidence. The removal is
|
|
145240
|
+
* disclosed in the text so the supervisor knows the summary was cut.
|
|
145241
|
+
*/
|
|
145242
|
+
function salvageSummary(input) {
|
|
145243
|
+
const lines = input.summary.split("\n");
|
|
145244
|
+
const kept = [];
|
|
145245
|
+
let droppingClaim = false;
|
|
145246
|
+
for (const line of lines) {
|
|
145247
|
+
const cited = citedSequences(line);
|
|
145248
|
+
if (cited.length > 0) droppingClaim = !cited.every((sequence) => input.includedSequences.has(sequence));
|
|
145249
|
+
else if (/^\s*#{1,6}\s/u.test(line)) droppingClaim = false;
|
|
145250
|
+
if (!droppingClaim) kept.push(line);
|
|
145251
|
+
}
|
|
145252
|
+
const dropped = lines.length - kept.length;
|
|
145253
|
+
if (dropped === 0) return null;
|
|
145254
|
+
const text = kept.join("\n").trim();
|
|
145255
|
+
if (summaryRejection({
|
|
145256
|
+
summary: text,
|
|
145257
|
+
includedSequences: input.includedSequences
|
|
145258
|
+
}) !== null) return null;
|
|
145259
|
+
return `${text}\n\n[Server removed ${dropped} summary ${dropped === 1 ? "line" : "lines"} resting on sequences absent from this transcript.]`;
|
|
145260
|
+
}
|
|
145173
145261
|
const buildFusionEvidenceHandoff = Effect.fn("fusionEvidenceHandoff.build")(function* (input) {
|
|
145174
145262
|
const engine = yield* OrchestrationEngineService;
|
|
145175
145263
|
const textGeneration = yield* TextGeneration;
|
|
@@ -145237,6 +145325,19 @@ const buildFusionEvidenceHandoff = Effect.fn("fusionEvidenceHandoff.build")(func
|
|
|
145237
145325
|
produced: Option.none(),
|
|
145238
145326
|
reason
|
|
145239
145327
|
});
|
|
145328
|
+
const salvaged = (result) => {
|
|
145329
|
+
const summary = salvageSummary({
|
|
145330
|
+
summary: result.summary,
|
|
145331
|
+
includedSequences: evidence.includedSequences
|
|
145332
|
+
});
|
|
145333
|
+
return summary === null ? null : {
|
|
145334
|
+
produced: Option.some({
|
|
145335
|
+
...result,
|
|
145336
|
+
summary
|
|
145337
|
+
}),
|
|
145338
|
+
reason: null
|
|
145339
|
+
};
|
|
145340
|
+
};
|
|
145240
145341
|
const attempt = yield* Effect.gen(function* () {
|
|
145241
145342
|
const first = yield* runSummary(handoffSummaryInstructions({ includedSequences: evidence.includedSequences }));
|
|
145242
145343
|
if (Option.isNone(first)) return noSummary("summary-unavailable");
|
|
@@ -145250,6 +145351,8 @@ const buildFusionEvidenceHandoff = Effect.fn("fusionEvidenceHandoff.build")(func
|
|
|
145250
145351
|
produced: first,
|
|
145251
145352
|
reason: null
|
|
145252
145353
|
};
|
|
145354
|
+
const firstSalvage = salvaged(first.value);
|
|
145355
|
+
if (firstSalvage !== null) return firstSalvage;
|
|
145253
145356
|
const repaired = yield* runSummary(handoffSummaryRepairInstructions({
|
|
145254
145357
|
rejection,
|
|
145255
145358
|
summary: first.value.summary,
|
|
@@ -145265,7 +145368,7 @@ const buildFusionEvidenceHandoff = Effect.fn("fusionEvidenceHandoff.build")(func
|
|
|
145265
145368
|
return repairedRejection === null ? {
|
|
145266
145369
|
produced: repaired,
|
|
145267
145370
|
reason: null
|
|
145268
|
-
} : noSummary(repairedRejection);
|
|
145371
|
+
} : salvaged(repaired.value) ?? noSummary(repairedRejection);
|
|
145269
145372
|
}).pipe(Effect.timeoutOption(HANDOFF_TIMEOUT), Effect.map(Option.getOrElse(() => noSummary("summary-unavailable"))));
|
|
145270
145373
|
const produced = attempt.produced;
|
|
145271
145374
|
if (Option.isNone(produced)) return yield* fallback(attempt.reason ?? "summary-unavailable");
|
|
@@ -145356,6 +145459,26 @@ const gateMessageId = (gateId, round) => MessageId.make(`${FUSION_GATE_MESSAGE_I
|
|
|
145356
145459
|
const gateActivityId = (gateId, threadId, suffix) => EventId.make(`fusion-gate:${gateId}:${suffix}:${threadId}`);
|
|
145357
145460
|
const pairFailureCommandId = (pairId, sequence, suffix) => CommandId.make(`server:fusion:${pairId}:provider-failure:${sequence}:${suffix}`);
|
|
145358
145461
|
const pairFailureActivityId = (pairId, sequence, threadId) => EventId.make(`fusion-provider-failure:${pairId}:${sequence}:${threadId}`);
|
|
145462
|
+
const PROVIDER_RETRY_MESSAGE_ID_PREFIX = "fusion-provider-retry:";
|
|
145463
|
+
const providerRetryCommandId = (pairId, sequence) => CommandId.make(`server:fusion:${pairId}:provider-retry:${sequence}`);
|
|
145464
|
+
/** Carries the origin and the failed completion's sequence ahead of the free-form pair id. */
|
|
145465
|
+
const providerRetryMessageId = (origin, sequence, pairId) => MessageId.make(`${PROVIDER_RETRY_MESSAGE_ID_PREFIX}${origin}:${sequence}:${pairId}`);
|
|
145466
|
+
const PROVIDER_RETRY_MESSAGE_ID = /^fusion-provider-retry:(review|other):(\d+):/u;
|
|
145467
|
+
/** The failed completion a review retry resumes, or null for any other message. */
|
|
145468
|
+
const retriedReviewSequence = (messageId) => {
|
|
145469
|
+
const match = messageId === null ? null : PROVIDER_RETRY_MESSAGE_ID.exec(messageId);
|
|
145470
|
+
return match?.[1] === "review" ? Number(match[2]) : null;
|
|
145471
|
+
};
|
|
145472
|
+
const TRANSIENT_PROVIDER_FAILURE = /runtime stream failed|stream disconnected|at capacity|overloaded|server failed|server error|internal error|\b(?:500|502|503|504|529)\b/i;
|
|
145473
|
+
const PERSISTENT_PROVIDER_FAILURE = /usage limit|rate limit|quota|billing|auth|log ?in|credential|unauthori[sz]ed|forbidden|\b(?:401|403)\b|does not exist|not found/i;
|
|
145474
|
+
/**
|
|
145475
|
+
* Whether a failed turn's recorded error is worth one automatic retry: a
|
|
145476
|
+
* dropped stream, a provider at capacity, or a server-side outage. Usage
|
|
145477
|
+
* limits, auth and missing paths never are, because retrying cannot fix them.
|
|
145478
|
+
*/
|
|
145479
|
+
function isTransientProviderFailure(lastError) {
|
|
145480
|
+
return typeof lastError === "string" && TRANSIENT_PROVIDER_FAILURE.test(lastError) && !PERSISTENT_PROVIDER_FAILURE.test(lastError);
|
|
145481
|
+
}
|
|
145359
145482
|
const idlePauseCommandId = (pairId, sequence, threadId) => CommandId.make(`server:fusion:${pairId}:idle-pause:${sequence}:${threadId}`);
|
|
145360
145483
|
const idlePauseActivityId = (pairId, sequence, threadId) => EventId.make(`fusion-idle-pause:${pairId}:${sequence}:${threadId}`);
|
|
145361
145484
|
/**
|
|
@@ -145634,10 +145757,11 @@ const make$3 = Effect.gen(function* () {
|
|
|
145634
145757
|
});
|
|
145635
145758
|
});
|
|
145636
145759
|
/**
|
|
145637
|
-
* A provider-level failure is not a review boundary.
|
|
145638
|
-
* it is still active, record one visible pair-level
|
|
145639
|
-
* idle until a human starts the next turn.
|
|
145640
|
-
* no-op, while ignoring interrupted
|
|
145760
|
+
* A provider-level failure that was not retried is not a review boundary.
|
|
145761
|
+
* Stop the other child if it is still active, record one visible pair-level
|
|
145762
|
+
* reason, and leave both idle until a human starts the next turn.
|
|
145763
|
+
* Deterministic ids make replay a no-op, while ignoring interrupted
|
|
145764
|
+
* completions prevents a reciprocal loop.
|
|
145641
145765
|
*/
|
|
145642
145766
|
const pausePairAfterProviderFailure = Effect.fn("FusionWatcherReactor.pausePairAfterProviderFailure")(function* (input) {
|
|
145643
145767
|
const { readModel } = yield* readPairs;
|
|
@@ -145674,6 +145798,46 @@ const make$3 = Effect.gen(function* () {
|
|
|
145674
145798
|
discard: true
|
|
145675
145799
|
});
|
|
145676
145800
|
});
|
|
145801
|
+
/**
|
|
145802
|
+
* Resumes a child whose turn failed on a transient provider error, once,
|
|
145803
|
+
* instead of pausing the pair and interrupting its healthy peer. True when
|
|
145804
|
+
* the retry went out (now or on an earlier pass); false sends the failure to
|
|
145805
|
+
* the pause. A retry turn that fails again, a turn whose start message is
|
|
145806
|
+
* unknown, a thread someone already started again, and a failure replayed
|
|
145807
|
+
* at boot are never retried.
|
|
145808
|
+
*/
|
|
145809
|
+
const retryTransientProviderFailure = Effect.fn("FusionWatcherReactor.retryTransientProviderFailure")(function* (input) {
|
|
145810
|
+
const { pair, completion, readModel } = input;
|
|
145811
|
+
const threadId = completion.payload.threadId;
|
|
145812
|
+
const retryIds = new Set(["review", "other"].map((origin) => providerRetryMessageId(origin, completion.sequence, pair.id)));
|
|
145813
|
+
const laterStarts = yield* orchestrationEngine.readEvents(completion.sequence, readModel.snapshotSequence - completion.sequence, { eventTypes: ["thread.turn-start-requested"] }).pipe(Stream.takeWhile((event) => event.sequence <= readModel.snapshotSequence), Stream.filter((event) => event.type === "thread.turn-start-requested" && event.payload.threadId === threadId), Stream.runCollect);
|
|
145814
|
+
if (laterStarts.some((event) => event.type === "thread.turn-start-requested" && retryIds.has(event.payload.messageId))) return true;
|
|
145815
|
+
if (input.replayed) return false;
|
|
145816
|
+
const thread = readModel.threads.find((candidate) => candidate.id === threadId && candidate.deletedAt === null);
|
|
145817
|
+
if (laterStarts.length > 0 || thread === void 0 || thread.latestTurn?.state === "running" || !isTransientProviderFailure(thread.session?.lastError) || completion.payload.turnId === null) return false;
|
|
145818
|
+
const started = yield* projectionSnapshotQuery.getTurnStart(threadId, completion.payload.turnId).pipe(Effect.map(Option.getOrNull), Effect.orElseSucceed(() => null));
|
|
145819
|
+
if (started === null || started.messageId === null || started.messageId.startsWith(PROVIDER_RETRY_MESSAGE_ID_PREFIX)) return false;
|
|
145820
|
+
return yield* orchestrationEngine.dispatch({
|
|
145821
|
+
type: "thread.turn.start",
|
|
145822
|
+
commandId: providerRetryCommandId(pair.id, completion.sequence),
|
|
145823
|
+
threadId,
|
|
145824
|
+
message: {
|
|
145825
|
+
messageId: providerRetryMessageId(started.messageId.startsWith("fusion-review:") ? "review" : "other", completion.sequence, pair.id),
|
|
145826
|
+
role: "user",
|
|
145827
|
+
text: `${FUSION_RETRY_PROMPT_PREFIX} Your previous turn stopped on a transient provider error. Continue the same work from where it stopped; no new work or authority is added. If it was already finished, end with the report you would have given.`,
|
|
145828
|
+
attachments: []
|
|
145829
|
+
},
|
|
145830
|
+
runtimeMode: thread.runtimeMode,
|
|
145831
|
+
interactionMode: thread.interactionMode,
|
|
145832
|
+
compressMode: thread.compressMode,
|
|
145833
|
+
unpromptedSubagents: thread.unpromptedSubagents,
|
|
145834
|
+
createdAt: completion.occurredAt
|
|
145835
|
+
}).pipe(Effect.as(true), Effect.catchCause((cause) => Effect.logWarning("provider failure retry was not sent; pausing the pair instead", {
|
|
145836
|
+
pairId: pair.id,
|
|
145837
|
+
sequence: completion.sequence,
|
|
145838
|
+
cause
|
|
145839
|
+
}).pipe(Effect.as(false))));
|
|
145840
|
+
});
|
|
145677
145841
|
const wakeWasRequested = Effect.fn("FusionWatcherReactor.wakeWasRequested")(function* (afterSequence, throughSequence, messageId) {
|
|
145678
145842
|
return (yield* orchestrationEngine.readEvents(afterSequence, throughSequence - afterSequence, { eventTypes: ["thread.turn-start-requested"] }).pipe(Stream.takeWhile((event) => event.sequence <= throughSequence), Stream.filter((event) => event.type === "thread.turn-start-requested" && event.payload.messageId === messageId), Stream.take(1), Stream.runCollect)).length > 0;
|
|
145679
145843
|
});
|
|
@@ -146008,7 +146172,7 @@ const make$3 = Effect.gen(function* () {
|
|
|
146008
146172
|
resolvedAt: event.payload.createdAt
|
|
146009
146173
|
});
|
|
146010
146174
|
});
|
|
146011
|
-
const isFusionProtocolText = (text) => text.startsWith("[fusion-review]") || text.startsWith("[fusion-gate]") || text.startsWith("[fusion-activation]") || text.startsWith("[fusion-jev]") || text.startsWith("[fusion-advice]");
|
|
146175
|
+
const isFusionProtocolText = (text) => text.startsWith("[fusion-review]") || text.startsWith("[fusion-gate]") || text.startsWith("[fusion-activation]") || text.startsWith("[fusion-jev]") || text.startsWith("[fusion-retry]") || text.startsWith("[fusion-advice]");
|
|
146012
146176
|
const processMessageSent = Effect.fn("FusionWatcherReactor.processMessageSent")(function* (event) {
|
|
146013
146177
|
if (event.sequence <= liveEventsAfterSequence) return;
|
|
146014
146178
|
if (event.payload.role !== "user") return;
|
|
@@ -147081,17 +147245,19 @@ Set outcome to summarized, fallback, or failed from the review that just ended.
|
|
|
147081
147245
|
if (Option.isNone(turn)) return;
|
|
147082
147246
|
const started = turn.value;
|
|
147083
147247
|
if (started.threadId !== pair.watcherThreadId) return;
|
|
147248
|
+
const retriedSequence = retriedReviewSequence(started.messageId);
|
|
147249
|
+
const retriedTurnId = retriedSequence === null ? null : yield* orchestrationEngine.readEvents(retriedSequence - 1, 1).pipe(Stream.runHead, Effect.map(Option.flatMap((event) => event.type === "thread.turn-completed" && event.payload.threadId === pair.watcherThreadId ? Option.fromNullishOr(event.payload.turnId) : Option.none())), Effect.map(Option.getOrNull), Effect.orElseSucceed(() => null));
|
|
147084
147250
|
const readAt = Date.parse(latest.readAt);
|
|
147085
147251
|
if (latest.turnId === null) {
|
|
147086
147252
|
if (input.replayed) return;
|
|
147087
147253
|
if (started.startedAt !== null && readAt < Date.parse(started.startedAt)) return;
|
|
147088
147254
|
if (readAt > Date.parse(completion.occurredAt)) return;
|
|
147089
|
-
} else if (latest.turnId !== completion.payload.turnId) return;
|
|
147255
|
+
} else if (latest.turnId !== completion.payload.turnId && (retriedTurnId === null || latest.turnId !== retriedTurnId)) return;
|
|
147090
147256
|
const wakeAt = (prefix) => projectionSnapshotQuery.getLatestThreadMessageWithIdPrefix(pair.watcherThreadId, prefix).pipe(Effect.map(Option.flatMap((wake) => {
|
|
147091
147257
|
const sentAt = Date.parse(wake.createdAt);
|
|
147092
147258
|
return Number.isNaN(sentAt) || sentAt > readAt ? Option.none() : Option.some(sentAt);
|
|
147093
147259
|
})), Effect.orElseSucceed(() => Option.none()));
|
|
147094
|
-
if (!(started.messageId === null ? yield* Effect.map(Effect.all([wakeAt("fusion-review:"), wakeAt("fusion-gate:")]), ([review, gate]) => Option.isSome(review) && (Option.isNone(gate) || gate.value < review.value)) : started.messageId.startsWith("fusion-review:"))) return;
|
|
147260
|
+
if (!(started.messageId === null ? yield* Effect.map(Effect.all([wakeAt("fusion-review:"), wakeAt("fusion-gate:")]), ([review, gate]) => Option.isSome(review) && (Option.isNone(gate) || gate.value < review.value)) : started.messageId.startsWith("fusion-review:") || retriedSequence !== null)) return;
|
|
147095
147261
|
if (latest.hasReport) {
|
|
147096
147262
|
if (input.watcher !== void 0) yield* dispatchEvidenceReportRepair(pair, input.watcher, completion.occurredAt, {
|
|
147097
147263
|
watchedThreadId: latest.watchedThreadId,
|
|
@@ -147107,6 +147273,12 @@ Set outcome to summarized, fallback, or failed from the review that just ended.
|
|
|
147107
147273
|
const activePairs = (readModel.threadPairs ?? []).filter((pair) => pair.detachedAt === null);
|
|
147108
147274
|
const failedPair = activePairs.find((pair) => pair.implementerThreadId === event.payload.threadId || pair.watcherThreadId === event.payload.threadId);
|
|
147109
147275
|
if (event.payload.state === "failed" && failedPair !== void 0) {
|
|
147276
|
+
if (yield* retryTransientProviderFailure({
|
|
147277
|
+
pair: failedPair,
|
|
147278
|
+
completion: event,
|
|
147279
|
+
readModel,
|
|
147280
|
+
replayed: event.sequence <= liveEventsAfterSequence
|
|
147281
|
+
})) return;
|
|
147110
147282
|
yield* pausePairAfterProviderFailure({
|
|
147111
147283
|
pair: failedPair,
|
|
147112
147284
|
failedThreadId: event.payload.threadId,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-QTnfLwEv.js";import{n as t,r as n,t as r}from"./compiler-runtime-CLAvuQ-D.js";import{$a as i,$u as a,Ba as o,Cl as s,Cn as c,Dt as l,Eu as ee,Ga as te,Kl as u,Kr as ne,La as d,Qa as f,Qr as re,Sl as p,Vr as m,Wa as h,Xa as ie,Za as g,_t as _,b as v,bu as ae,ct as y,eo as b,gt as x,h as S,hu as C,lu as w,vn as oe,wl as T,xl as E,yt as D}from"./previewAssetResource-
|
|
1
|
+
import{r as e}from"./rolldown-runtime-QTnfLwEv.js";import{n as t,r as n,t as r}from"./compiler-runtime-CLAvuQ-D.js";import{$a as i,$u as a,Ba as o,Cl as s,Cn as c,Dt as l,Eu as ee,Ga as te,Kl as u,Kr as ne,La as d,Qa as f,Qr as re,Sl as p,Vr as m,Wa as h,Xa as ie,Za as g,_t as _,b as v,bu as ae,ct as y,eo as b,gt as x,h as S,hu as C,lu as w,vn as oe,wl as T,xl as E,yt as D}from"./previewAssetResource-CscIFHNv.js";import{a as O,c as se,i as k,n as A,o as j,r as M,s as ce,t as le}from"./toggle-group-C8xCVvsa.js";import{A as ue,Fr as de,J as fe,Lr as pe,M as N,Mr as me,Nr as he,Rr as ge,Y as _e,_ as ve,ar as ye,cr as be,ct as xe,dr as Se,dt as Ce,ft as P,h as we,ir as Te,j as Ee,jr as De,k as Oe,lr as ke,lt as Ae,nr as je,oi as Me,or as Ne,ot as Pe,pr as Fe,rr as Ie,si as Le,sr as Re,st as ze,ut as Be,yr as Ve}from"./index-DYICyvf7.js";import{a as He,n as Ue}from"./fileCommentAnnotations-BRlauqkZ.js";var We=T(`pilcrow`,[[`path`,{d:`M13 4v16`,key:`8vvj80`}],[`path`,{d:`M17 4v16`,key:`7dpous`}],[`path`,{d:`M19 4H9.5a4.5 4.5 0 0 0 0 9H13`,key:`sh4n9v`}]]),F=e(n(),1);function Ge({threadRef:e,filePath:t,activeCwd:n,openInEditor:r,openFileSurface:i}){if(e){if(i){i(t);return}y.getState().openFile(e,t);return}r(n?S(t,n):t)}var I=r();function Ke(e,t){let n=(0,I.c)(4),r=Se(e,t),i;return n[0]!==r.data||n[1]!==r.error||n[2]!==r.isPending?(i={data:r.data,error:r.error,isPending:r.isPending},n[0]=r.data,n[1]=r.error,n[2]=r.isPending,n[3]=i):i=n[3],i}var L=t(),qe=[];function Je(e){return(e.endSide??e.side)===`deletions`?`deletions`:`additions`}function R(e,t,n){let r=Je(t),i=e.findIndex(e=>e.side===r&&e.lineNumber===t.end);return i<0?[...e,{side:r,lineNumber:t.end,metadata:{entries:[n]}}]:e.map((e,t)=>t===i?{...e,metadata:{entries:[...e.metadata.entries,n]}}:e)}function Ye(e){let t=(0,I.c)(50),{files:n,sectionId:r,sectionTitle:i,composerDraftTarget:a,options:o,viewerRef:s,className:c,renderHeaderPrefix:l}=e,ee=m(Qe),te=m(B),u;t[0]===a?u=t[1]:(u=e=>e.getComposerDraft(a)?.reviewComments??qe,t[0]=a,t[1]=u);let d=m(u),[f,p]=(0,F.useState)(null),[h,ie]=(0,F.useState)(null),g;t[2]===n?g=t[3]:(g=new Map(n.map(Ze)),t[2]=n,t[3]=g);let _=g,v;if(t[4]!==h||t[5]!==n||t[6]!==d||t[7]!==r){let e;t[9]!==h||t[10]!==d||t[11]!==r?(e=e=>{let{fileDiff:t,filePath:n,fileKey:i,collapsed:a}=e,o=d.filter(e=>e.sectionId===r&&e.filePath===n&&(e.fenceLanguage??`diff`)===`diff`).reduce((e,n)=>{let r=re(t,n);return r?R(e,r,{id:n.id,kind:`comment`,range:r,rangeLabel:n.rangeLabel,text:n.text}):e},[]),s=h?.fileKey===i?[...o,h.annotation]:o;return{id:i,type:`diff`,fileDiff:t,annotations:s,collapsed:a,version:ze(`${a?`1`:`0`}:${s.flatMap(z).join(`:`)}`)}},t[9]=h,t[10]=d,t[11]=r,t[12]=e):e=t[12],v=n.map(e),t[4]=h,t[5]=n,t[6]=d,t[7]=r,t[8]=v}else v=t[8];let ae=v,y;t[13]!==a||t[14]!==h?.annotation||t[15]!==te?(y=e=>{p(null),h?.annotation.metadata.entries.some(t=>t.id===e)?ie(null):te(a,e)},t[13]=a,t[14]=h?.annotation,t[15]=te,t[16]=y):y=t[16];let b=y,x;t[17]!==ee||t[18]!==a||t[19]!==h||t[20]!==_||t[21]!==r||t[22]!==i?(x=(e,t)=>{let n=h?.annotation.metadata.entries.find(t=>t.id===e),o=h?_.get(h.fileKey):void 0;if(!n||!o)return;let s=ne({id:n.id,sectionId:r,sectionTitle:i,filePath:o.filePath,fileDiff:o.fileDiff,range:n.range,text:t});s&&ee(a,s),p(null),ie(null)},t[17]=ee,t[18]=a,t[19]=h,t[20]=_,t[21]=r,t[22]=i,t[23]=x):x=t[23];let S=x,C;t[24]!==_||t[25]!==r||t[26]!==i?(C=(e,t)=>{if(!e)return;let n=t.item;if(n.type!==`diff`)return;let a=_.get(n.id);if(!a)return;let o=Ue(),s=ne({id:o,sectionId:r,sectionTitle:i,filePath:a.filePath,fileDiff:a.fileDiff,range:e,text:``});s&&ie({fileKey:n.id,annotation:{side:Je(e),lineNumber:e.end,metadata:{entries:[{id:o,kind:`draft`,range:e,rangeLabel:s.rangeLabel,text:``}]}}})},t[24]=_,t[25]=r,t[26]=i,t[27]=C):C=t[27];let w=C,oe=h!==null,T;t[28]===s?T=t[29]:(T=s?{ref:s}:{},t[28]=s,t[29]=T);let E;t[30]===c?E=t[31]:(E=c?{className:c}:{},t[30]=c,t[31]=E);let D=!oe,se=!oe,k;t[32]!==w||t[33]!==o||t[34]!==se||t[35]!==D?(k={...o,enableGutterUtility:D,enableLineSelection:se,onLineSelectionEnd:w},t[32]=w,t[33]=o,t[34]=se,t[35]=D,t[36]=k):k=t[36];let A;t[37]===l?A=t[38]:(A=e=>e.type===`diff`?l(e.fileDiff,e.id,e.collapsed===!0):null,t[37]=l,t[38]=A);let j;t[39]!==b||t[40]!==S?(j=e=>(0,L.jsx)(`div`,{className:`py-1`,children:e.metadata.entries.map(e=>(0,L.jsx)(He,{kind:e.kind,rangeLabel:e.rangeLabel,text:e.text,onCancel:()=>b(e.id),onComment:t=>S(e.id,t),onDelete:()=>b(e.id)},e.id))}),t[39]=b,t[40]=S,t[41]=j):j=t[41];let M;return t[42]!==ae||t[43]!==f||t[44]!==k||t[45]!==A||t[46]!==j||t[47]!==T||t[48]!==E?(M=(0,L.jsx)(O,{...T,...E,items:ae,selectedLines:f,onSelectedLinesChange:p,options:k,renderHeaderPrefix:A,renderAnnotation:j}),t[42]=ae,t[43]=f,t[44]=k,t[45]=A,t[46]=j,t[47]=T,t[48]=E,t[49]=M):M=t[49],M}function z(e){return e.metadata.entries.map(Xe)}function Xe(e){return`${e.id}:${e.rangeLabel}:${e.text}`}function Ze(e){return[e.fileKey,e]}function B(e){return e.removeReviewComment}function Qe(e){return e.addReviewComment}function $e(e){return{diffPreview:w(e,{label:`environment-data:review:diff-preview`,tag:a.reviewGetDiffPreview,staleTimeMs:5e3})}}var et=$e(c);function V(e){return e.remoteName&&e.name.startsWith(`${e.remoteName}/`)?e.name.slice(e.remoteName.length+1):e.name}function tt(e,t){let n=new Set(t),r=e.map(e=>{let r=t.filter(t=>n.has(t)&&V(t)===e.name),i=r.find(e=>e.remoteName===`origin`)??r[0]??null;return i&&n.delete(i),{id:`local:${e.name}`,label:e.name,local:e,remote:i}}),i=t.filter(e=>n.has(e)).map(e=>({id:`remote:${e.name}`,label:e.name,local:null,remote:e}));return[...r,...i]}function nt(e,t){let n=t.trim().toLocaleLowerCase();return n.length===0?e:e.filter(e=>e.label.toLocaleLowerCase().includes(n)||e.local?.name.toLocaleLowerCase().includes(n)===!0||e.remote?.name.toLocaleLowerCase().includes(n)===!0)}var H=`__automatic_base_ref__`,rt=new Set,it=`
|
|
2
2
|
[data-diffs-header],
|
|
3
3
|
[data-diff],
|
|
4
4
|
[data-file],
|
|
@@ -95,4 +95,4 @@ import{r as e}from"./rolldown-runtime-QTnfLwEv.js";import{n as t,r as n,t as r}f
|
|
|
95
95
|
text-decoration-color: currentColor;
|
|
96
96
|
}
|
|
97
97
|
`;function U({mode:e=`inline`,composerDraftTarget:t,initialGitScope:n,threadRef:r}){let{resolvedTheme:a}=v(),c=de(),[ne]=(0,F.useState)(n),[re,m]=(0,F.useState)(`stacked`),[y,S]=(0,F.useState)(c.wordWrap),[w,T]=(0,F.useState)(c.diffIgnoreWhitespace),[O,ve]=(0,F.useState)(``),[Se,ze]=(0,F.useState)(()=>({scopeKey:null,fileKeys:rt})),He=(0,F.useRef)(null),Ue=r.threadId,I=he(r),qe=I?.projectId??null,Je=me(I&&qe?{environmentId:I.environmentId,projectId:qe}:null),R=I?.worktreePath??Je?.workspaceRoot,z=u(oe.configValueAtom(I?.environmentId??null)),Xe=Fe(I?.environmentId??null,z?.availableEditors??[]),Ze=l(I!=null&&R!=null?De.status({environmentId:I.environmentId,input:{cwd:R}}):null),B=N(e=>Ee(e.byThreadKey,r,ne===`unstaged`)),Qe=Ze.data?.isRepo??!0,{turnDiffSummaries:$e,inferredCheckpointTurnCountByTurnId:V}=ue(I),U=(0,F.useMemo)(()=>[...$e].toSorted((e,t)=>{let n=e.checkpointTurnCount??V[e.turnId]??0,r=t.checkpointTurnCount??V[t.turnId]??0;return n===r?t.completedAt.localeCompare(e.completedAt):r-n}),[V,$e]);(0,F.useEffect)(()=>{B.kind===`turn`&&N.getState().reconcileTurnSelection(r,U.map(e=>e.turnId))},[B,U,r]);let W=B.kind===`turn`?B.turnId:null,G=B.kind===`unstaged`?`unstaged`:`branch`,K=B.kind===`branch`?B.baseRef:null,at=B.kind===`turn`?B.filePath:null,ot=B.kind===`turn`?B.revealRequestId:0,q=W===null?void 0:U.find(e=>e.turnId===W)??U[0],J=q&&(q.checkpointTurnCount??V[q.turnId]),st=U[0],ct=W===null?G===`unstaged`?`Working tree`:`Branch changes`:q?.turnId===st?.turnId?`Latest turn`:`Turn ${J??`?`}`,lt=q?`turn:${q.turnId}`:G,Y=`${r.environmentId}:${r.threadId}:${lt}`,ut=Se.scopeKey===Y?Se.fileKeys:rt,dt=q?`Turn ${J??`?`}`:G===`unstaged`?`Working tree`:`Branch changes`,ft=(0,F.useMemo)(()=>typeof J==`number`?{fromTurnCount:Math.max(0,J-1),toTurnCount:J}:null,[J]),pt=Ke({environmentId:I?.environmentId??null,threadId:Ue,fromTurnCount:ft?.fromTurnCount??null,toTurnCount:ft?.toTurnCount??null,ignoreWhitespace:w,cacheScope:q?`turn:${q.turnId}`:null},{enabled:Qe&&q!==void 0}),mt=l(W===null&&I&&R?et.diffPreview({environmentId:I.environmentId,input:{cwd:R,...K?{baseRef:K}:{},ignoreWhitespace:w}}):null),ht=W===null&&mt.error?.includes(`configured workspace root`)===!0&&z?.cwd!==void 0&&z.cwd!==R,gt=l(ht&&I&&z?et.diffPreview({environmentId:I.environmentId,input:{cwd:z.cwd,...K?{baseRef:K}:{},ignoreWhitespace:w}}):null),X=ht?gt:mt,Z=X.data?.sources.find(e=>e.kind===(G===`unstaged`?`working-tree`:`branch-range`)),_t=l(W===null&&G===`branch`&&I&&X.data?.cwd?De.listRefs({environmentId:I.environmentId,input:{cwd:X.data.cwd,includeMatchingRemoteRefs:!0,refKind:`local`,...O.trim().length>0?{query:O.trim()}:{},limit:100}}):null),vt=l(W===null&&G===`branch`&&I&&X.data?.cwd?De.listRefs({environmentId:I.environmentId,input:{cwd:X.data.cwd,includeMatchingRemoteRefs:!0,refKind:`remote`,...O.trim().length>0?{query:O.trim()}:{},limit:100}}):null),yt=tt(_t.data?.refs.filter(e=>e.name!==Z?.headRef)??[],vt.data?.refs??[]),bt=nt(yt,O),xt=e=>K&&K===e.remote?.name?K:e.local?.name??e.remote?.name??e.id,St=[H,...yt.map(xt)],Ct=[...O.trim().length===0?[H]:[],...bt.map(xt)],wt=Z?.diff,Tt=q?pt.data?.diff:wt,Et=!q&&Z?.truncated===!0,Dt=q?pt.isPending:X.isPending,Ot=q?pt.error:X.error,kt=typeof Tt==`string`&&Tt.trim().length===0,Q=(0,F.useMemo)(()=>Be(Tt,`diff-panel:${a}`,{compactPartialHunkOffsets:W===null}),[a,Tt,W]),At=(0,F.useMemo)(()=>!Q||Q.kind!==`files`?[]:Q.files.toSorted((e,t)=>P(e).localeCompare(P(t),void 0,{numeric:!0,sensitivity:`base`})),[Q]),$=(0,F.useMemo)(()=>At.map(e=>{let t=Pe(e);return{fileDiff:e,filePath:P(e),fileKey:t,collapsed:ut.has(t)}}),[ut,At]),jt=(0,F.useMemo)(()=>$.map(e=>e.fileKey),[$]),Mt=M(jt,ut),Nt=(0,F.useMemo)(()=>Ae(At),[At]);(0,F.useEffect)(()=>{if(!at)return;let e=$.find(e=>e.filePath===at);e&&He.current?.scrollTo({type:`item`,id:e.fileKey,align:`start`})},[$,at,ot]);let Pt=Oe({threadRef:r,workspaceRoot:R??null}),Ft=(0,F.useCallback)(e=>{Ge({threadRef:r,filePath:e,activeCwd:R,openFileSurface:Pt,openInEditor:e=>{(async()=>{let t=await Xe(e);t._tag===`Failure`&&!C(t)&&console.warn(`Failed to open diff file in editor.`,{operation:`open-diff-file`,environmentId:r.environmentId,threadId:r.threadId,...ee(ae(t))})})()}})},[R,Pt,Xe,r]),It=(0,F.useCallback)(e=>{ze(t=>{let n=new Set(t.scopeKey===Y?t.fileKeys:[]);return n.has(e)?n.delete(e):n.add(e),{scopeKey:Y,fileKeys:n}})},[Y]),Lt=(0,F.useCallback)(()=>{ze(e=>{let t=e.scopeKey===Y?e.fileKeys:rt;return{scopeKey:Y,fileKeys:k(jt,t)}})},[Y,jt]),Rt=e=>{N.getState().selectTurn(r,e)},zt=e=>{N.getState().selectGitScope(r,e)},Bt=e=>{N.getState().selectBranchBaseRef(r,e)};return(0,L.jsx)(_e,{mode:e,header:(0,L.jsxs)(L.Fragment,{children:[(0,L.jsxs)(`div`,{className:`flex min-w-0 flex-1 items-center gap-3 [-webkit-app-region:no-drag]`,children:[(0,L.jsxs)(o,{children:[(0,L.jsxs)(i,{className:`inline-flex h-6 max-w-full items-center gap-1 rounded-md bg-muted/70 px-2 text-xs font-medium text-foreground outline-none transition-colors hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring`,"aria-label":`Diff scope: ${ct}`,children:[(0,L.jsx)(`span`,{className:`truncate`,children:ct}),(0,L.jsx)(p,{className:`size-3.5 shrink-0 text-muted-foreground`})]}),(0,L.jsxs)(te,{align:`start`,className:`w-60`,children:[(0,L.jsx)(h,{className:W===null&&G===`unstaged`?`bg-foreground/[0.08]`:void 0,onClick:()=>zt(`unstaged`),children:(0,L.jsx)(`span`,{children:`Working tree`})}),(0,L.jsx)(h,{className:W===null&&G===`branch`?`bg-foreground/[0.08]`:void 0,onClick:()=>zt(`branch`),children:(0,L.jsx)(`span`,{children:`Branch changes`})}),(0,L.jsx)(h,{className:W!==null&&q?.turnId===st?.turnId?`bg-foreground/[0.08]`:void 0,onClick:()=>{st&&Rt(st.turnId)},children:(0,L.jsx)(`span`,{children:`Latest turn`})}),(0,L.jsxs)(ie,{children:[(0,L.jsx)(f,{children:`Turn`}),(0,L.jsx)(g,{className:`w-64`,children:U.map(e=>{let t=e.checkpointTurnCount??V[e.turnId]??`?`;return(0,L.jsxs)(h,{className:e.turnId===q?.turnId?`bg-foreground/[0.08]`:void 0,onClick:()=>Rt(e.turnId),children:[(0,L.jsxs)(`span`,{children:[`Turn `,t]}),(0,L.jsx)(`span`,{className:`ml-auto text-xs tabular-nums text-muted-foreground`,children:Ve(e.completedAt,c.timestampFormat)})]},e.turnId)})})]})]})]}),W===null&&G===`branch`&&Z?.baseRef&&(0,L.jsxs)(`div`,{className:`flex min-w-0 max-w-full items-center gap-2 overflow-hidden text-xs text-muted-foreground`,title:`${Z.headRef??`HEAD`} → ${Z.baseRef}`,"aria-label":`Comparing ${Z.headRef??`HEAD`} against ${Z.baseRef}`,children:[(0,L.jsx)(`span`,{className:`min-w-0 max-w-48 truncate`,children:Z.headRef??`HEAD`}),(0,L.jsx)(Le,{className:`size-3.5 shrink-0 opacity-70`}),(0,L.jsxs)(je,{items:St,filteredItems:Ct,value:K??H,onOpenChange:e=>{e||ve(``)},onValueChange:e=>{e&&Bt(e===H?null:e)},children:[(0,L.jsxs)(be,{className:`inline-flex min-w-0 max-w-48 items-center gap-1 overflow-hidden rounded-md px-1.5 py-1 outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring`,"aria-label":`Change comparison target. Currently ${Z.baseRef}`,children:[(0,L.jsx)(`span`,{className:`min-w-0 truncate`,children:Z.baseRef}),(0,L.jsx)(p,{className:`size-3.5 shrink-0 opacity-70`})]}),(0,L.jsxs)(Re,{align:`start`,className:`w-72 min-w-0 max-w-[calc(100vw-1rem)] overflow-hidden [&>[data-slot=combobox-popup]]:min-w-0 [&>[data-slot=combobox-popup]]:overflow-hidden`,children:[(0,L.jsx)(`div`,{className:`min-w-0 shrink-0 px-3 pt-2.5`,children:(0,L.jsxs)(`div`,{className:`relative -translate-y-px border-b border-border/70 pb-1.5 transition-colors focus-within:border-ring`,children:[(0,L.jsx)(ge,{"aria-hidden":`true`,className:`pointer-events-none absolute top-1.5 left-0 size-4 shrink-0 text-muted-foreground/55`}),(0,L.jsx)(Te,{className:`[&_input]:h-6.5 [&_input]:ps-5 [&_input]:font-sans [&_input]:leading-6.5`,inputClassName:`rounded-none bg-transparent text-sm`,placeholder:`Search refs...`,showTrigger:!1,size:`sm`,unstyled:!0,value:O,onChange:e=>ve(e.target.value)})]})}),(0,L.jsxs)(`div`,{className:`grid shrink-0 grid-cols-[1rem_minmax(0,1fr)] items-center gap-2 border-b border-border/70 ps-3 pe-6.5 pt-2 pb-1.5 font-medium text-[10px] text-muted-foreground uppercase tracking-wide`,children:[(0,L.jsx)(`span`,{"aria-hidden":`true`}),(0,L.jsxs)(`div`,{className:`grid min-w-0 grid-cols-[minmax(0,1fr)_2rem] items-center`,children:[(0,L.jsx)(`span`,{children:`Branch`}),(0,L.jsx)(`span`,{className:`text-right`,children:`Remote`})]})]}),(0,L.jsx)(Ie,{children:`No matching refs.`}),(0,L.jsxs)(Ne,{className:`max-h-64 min-w-0 overflow-x-hidden`,children:[(0,L.jsx)(ye,{className:`h-8 w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)] py-0`,contentClassName:`w-full min-w-0 overflow-hidden`,value:H,children:(0,L.jsx)(`span`,{className:`block min-w-0 truncate`,children:`Automatic`})}),yt.map(e=>{let t=xt(e),n=e.local!==null&&e.remote!==null,r=e.remote?.name===t;return(0,L.jsx)(ye,{className:`h-8 w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)] py-0`,contentClassName:`w-full min-w-0 overflow-hidden`,value:t,children:(0,L.jsxs)(`div`,{className:`grid w-full min-w-0 grid-cols-[minmax(0,1fr)_2rem] items-center overflow-hidden`,children:[(0,L.jsx)(`span`,{className:`block min-w-0 truncate pe-2`,children:e.label}),n?(0,L.jsx)(`div`,{className:`flex justify-end`,onClick:e=>e.stopPropagation(),onPointerDown:e=>e.stopPropagation(),children:(0,L.jsx)(ke,{"aria-label":`Use remote version of ${e.label}`,checked:r,className:`[--thumb-size:--spacing(3)]`,onCheckedChange:t=>{let n=t?e.remote?.name:e.local?.name;n&&Bt(n)}})}):e.remote?(0,L.jsx)(`span`,{className:`flex justify-end text-muted-foreground`,title:`Remote only`,children:(0,L.jsx)(s,{"aria-hidden":`true`,className:`size-3`})}):null]})},e.id)})]})]})]})]})]}),(0,L.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1 [-webkit-app-region:no-drag]`,children:[$.length>0&&(0,L.jsx)(we,{additions:Nt.additions,deletions:Nt.deletions,className:`mr-1 text-[11px]`,layout:`inline`}),$.length>0&&(0,L.jsxs)(x,{children:[(0,L.jsx)(D,{render:(0,L.jsx)(d,{type:`button`,size:`icon-xs`,variant:`outline`,"aria-label":Mt?`Expand all files`:`Collapse all files`,onClick:Lt}),children:Mt?(0,L.jsx)(Me,{className:`size-3`}):(0,L.jsx)(se,{className:`size-3`})}),(0,L.jsx)(_,{side:`top`,children:Mt?`Expand all files`:`Collapse all files`})]}),(0,L.jsxs)(A,{className:`shrink-0`,variant:`outline`,size:`xs`,value:[re],onValueChange:e=>{let t=e[0];(t===`stacked`||t===`split`)&&m(t)},children:[(0,L.jsx)(le,{"aria-label":`Stacked diff view`,value:`stacked`,children:(0,L.jsx)(j,{className:`size-3`})}),(0,L.jsx)(le,{"aria-label":`Split diff view`,value:`split`,children:(0,L.jsx)(ce,{className:`size-3`})})]}),(0,L.jsxs)(x,{children:[(0,L.jsx)(D,{render:(0,L.jsx)(le,{"aria-label":y?`Disable diff line wrapping`:`Enable diff line wrapping`,variant:`outline`,size:`xs`,pressed:y,onPressedChange:e=>{S(!!e)}}),children:(0,L.jsx)(pe,{className:`size-3`})}),(0,L.jsx)(_,{side:`top`,children:y?`Disable line wrapping`:`Enable line wrapping`})]}),(0,L.jsxs)(x,{children:[(0,L.jsx)(D,{render:(0,L.jsx)(le,{"aria-label":w?`Show whitespace changes`:`Hide whitespace changes`,variant:`outline`,size:`xs`,pressed:w,onPressedChange:e=>{T(!!e)}}),children:(0,L.jsx)(We,{className:`size-3`})}),(0,L.jsx)(_,{side:`top`,children:w?`Show whitespace changes`:`Hide whitespace changes`})]})]})]}),children:I?Qe?W!==null&&U.length===0?(0,L.jsx)(`div`,{className:`flex flex-1 items-center justify-center px-5 text-center text-xs text-muted-foreground/70`,children:`No completed turns yet.`}):(0,L.jsx)(L.Fragment,{children:(0,L.jsxs)(`div`,{className:`diff-panel-viewport flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden`,children:[Et&&(0,L.jsx)(`p`,{className:`shrink-0 border-b border-border/70 bg-muted/40 px-3 py-1.5 text-[11px] text-muted-foreground`,children:`This diff was truncated because it exceeded the preview limit. The changes shown are incomplete.`}),Ot&&!Q&&(0,L.jsx)(`div`,{className:`px-3`,children:(0,L.jsx)(`p`,{className:`mb-2 text-[11px] text-red-500/80`,children:Ot})}),Q?Q.kind===`files`?(0,L.jsx)(`div`,{className:`min-h-0 flex-1`,onClickCapture:e=>{let t=(e.nativeEvent.composedPath?.()??[]).find(e=>e instanceof HTMLElement&&e.hasAttribute(`data-title`))?.textContent?.trim();t&&Ft(t)},children:(0,L.jsx)(Ye,{viewerRef:He,className:`diff-render-surface h-full min-h-0 overflow-auto`,files:$,sectionId:lt,sectionTitle:dt,composerDraftTarget:t,renderHeaderPrefix:(e,t,n)=>{let r=P(e);return(0,L.jsxs)(x,{children:[(0,L.jsx)(D,{render:(0,L.jsx)(`button`,{type:`button`,className:b(`inline-flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-sm border-0 bg-transparent p-0 transition-colors hover:bg-foreground/10 focus-visible:outline-hidden`,xe(e)),"aria-label":n?`Expand ${r}`:`Collapse ${r}`,"aria-expanded":!n,onClick:e=>{e.stopPropagation(),It(t)}}),children:n?(0,L.jsx)(E,{className:`size-4`}):(0,L.jsx)(p,{className:`size-4`})}),(0,L.jsx)(_,{side:`top`,children:n?`Expand diff`:`Collapse diff`})]})},options:{diffStyle:re===`split`?`split`:`unified`,lineDiffType:`none`,overflow:y?`wrap`:`scroll`,theme:Ce(a),themeType:a,unsafeCSS:it,stickyHeaders:!0,itemMetrics:{diffHeaderHeight:33},layout:{paddingTop:0,paddingBottom:8,gap:8}}},Y??lt)}):(0,L.jsx)(`div`,{className:`min-h-0 flex-1 overflow-auto p-2`,children:(0,L.jsxs)(`div`,{className:`space-y-2`,children:[(0,L.jsx)(`p`,{className:`text-[11px] text-muted-foreground/75`,children:Q.reason}),(0,L.jsx)(`pre`,{className:b(`max-h-[72vh] rounded-md border border-border/70 bg-background/70 p-3 font-mono text-[11px] leading-relaxed text-muted-foreground/90`,y?`overflow-auto whitespace-pre-wrap wrap-break-word`:`overflow-auto`),children:Q.text})]})}):Dt?(0,L.jsx)(fe,{label:q?`Loading checkpoint diff...`:G===`unstaged`?`Loading working tree diff...`:`Loading branch diff...`}):(0,L.jsx)(`div`,{className:`flex h-full items-center justify-center px-3 py-2 text-xs text-muted-foreground/70`,children:(0,L.jsx)(`p`,{children:kt?`No net changes in this selection.`:`No patch available for this selection.`})})]})}):(0,L.jsx)(`div`,{className:`flex flex-1 items-center justify-center px-5 text-center text-xs text-muted-foreground/70`,children:`Turn diffs are unavailable because this project is not a git repository.`}):(0,L.jsx)(`div`,{className:`flex flex-1 items-center justify-center px-5 text-center text-xs text-muted-foreground/70`,children:`Select a thread to inspect turn diffs.`})})}export{ve as DiffWorkerPoolProvider,U as default};
|
|
98
|
-
//# sourceMappingURL=DiffPanel-
|
|
98
|
+
//# sourceMappingURL=DiffPanel-Cq5Tpiyo.js.map
|