@p4code/cli 0.3.26 → 0.3.28
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 +139 -19
- package/dist/client/assets/DiffPanel-C8FwdU8R.js +98 -0
- package/dist/client/assets/{FilePreviewPanel-BSEYlFH_.js → FilePreviewPanel-DdTrZW2J.js} +12 -12
- package/dist/client/assets/PreviewPanel-MIb5H3ir.js +2 -0
- package/dist/client/assets/PullRequestCodeTab-Bq_SI-pj.js +251 -0
- package/dist/client/assets/{fileCommentAnnotations-DktOAoZq.js → fileCommentAnnotations-9363cOl3.js} +2 -2
- package/dist/client/assets/{index-DQk2JhL0.js → index-BQ38fIEf.js} +220 -206
- package/dist/client/assets/{index-B4xwPQ4-.css → index-zVOKVFCn.css} +1 -1
- package/dist/client/assets/previewAssetResource-hBW3v1Su.js +48 -0
- package/dist/client/assets/{renderFileChildren-C8xF9yZB.js → renderFileChildren-CEQtwnJr.js} +2 -2
- package/dist/client/assets/{toggle-group-oAiXdJRV.js → toggle-group-tMSVv__W.js} +2 -2
- package/dist/client/index.html +3 -3
- package/package.json +1 -1
- package/dist/client/assets/DiffPanel-Cp9ZchPD.js +0 -98
- package/dist/client/assets/PreviewPanel-D9gIr3nZ.js +0 -2
- package/dist/client/assets/PullRequestCodeTab-DREOEFKL.js +0 -251
- package/dist/client/assets/previewAssetResource-xr2rxKjm.js +0 -48
package/dist/bin.mjs
CHANGED
|
@@ -239,7 +239,7 @@ const make$92 = () => {
|
|
|
239
239
|
const layer$82 = Layer.sync(NetService, make$92);
|
|
240
240
|
//#endregion
|
|
241
241
|
//#region package.json
|
|
242
|
-
var version = "0.3.
|
|
242
|
+
var version = "0.3.28";
|
|
243
243
|
//#endregion
|
|
244
244
|
//#region src/config.ts
|
|
245
245
|
/**
|
|
@@ -6620,6 +6620,8 @@ Schema$1.Struct({
|
|
|
6620
6620
|
updatedAt: IsoDateTime,
|
|
6621
6621
|
lastError: Schema$1.optional(TrimmedNonEmptyString)
|
|
6622
6622
|
});
|
|
6623
|
+
/** Which half of a Fusion pair a session or turn belongs to. */
|
|
6624
|
+
const FusionRole = Schema$1.Literals(["implementer", "watcher"]);
|
|
6623
6625
|
const ProviderSessionStartInput = Schema$1.Struct({
|
|
6624
6626
|
threadId: ThreadId,
|
|
6625
6627
|
provider: Schema$1.optional(ProviderDriverKind),
|
|
@@ -6631,7 +6633,13 @@ const ProviderSessionStartInput = Schema$1.Struct({
|
|
|
6631
6633
|
sandboxMode: Schema$1.optional(ProviderSandboxMode),
|
|
6632
6634
|
runtimeMode: RuntimeMode,
|
|
6633
6635
|
compressMode: Schema$1.optional(CompressMode),
|
|
6634
|
-
unpromptedSubagents: Schema$1.optional(Schema$1.Boolean)
|
|
6636
|
+
unpromptedSubagents: Schema$1.optional(Schema$1.Boolean),
|
|
6637
|
+
/**
|
|
6638
|
+
* Set when the thread is half of an active Fusion pair at session start, so
|
|
6639
|
+
* providers with a session-level instruction channel carry the role rules
|
|
6640
|
+
* there instead of on every message.
|
|
6641
|
+
*/
|
|
6642
|
+
fusionRole: Schema$1.optional(FusionRole)
|
|
6635
6643
|
});
|
|
6636
6644
|
const ProviderSendTurnInput = Schema$1.Struct({
|
|
6637
6645
|
threadId: ThreadId,
|
|
@@ -6641,7 +6649,8 @@ const ProviderSendTurnInput = Schema$1.Struct({
|
|
|
6641
6649
|
modelSelection: Schema$1.optional(ModelSelection),
|
|
6642
6650
|
interactionMode: Schema$1.optional(ProviderInteractionMode),
|
|
6643
6651
|
compressMode: Schema$1.optional(CompressMode),
|
|
6644
|
-
unpromptedSubagents: Schema$1.optional(Schema$1.Boolean)
|
|
6652
|
+
unpromptedSubagents: Schema$1.optional(Schema$1.Boolean),
|
|
6653
|
+
fusionRole: Schema$1.optional(FusionRole)
|
|
6645
6654
|
});
|
|
6646
6655
|
Schema$1.Struct({
|
|
6647
6656
|
threadId: ThreadId,
|
|
@@ -8499,6 +8508,14 @@ const ServerSettings = Schema$1.Struct({
|
|
|
8499
8508
|
*/
|
|
8500
8509
|
enableUnpromptedSubagents: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true))),
|
|
8501
8510
|
/**
|
|
8511
|
+
* Beta. Whether Fusion role rules travel once through the provider's
|
|
8512
|
+
* session channel (Claude's system prompt, Codex's developer instructions)
|
|
8513
|
+
* with a one-line reference on each message, or the legacy way: the full
|
|
8514
|
+
* block prepended to every applicable message. On keeps thread context
|
|
8515
|
+
* smaller; off is the rollback if a pair misbehaves.
|
|
8516
|
+
*/
|
|
8517
|
+
enableOptimizedFusionPromptDelivery: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true))),
|
|
8518
|
+
/**
|
|
8502
8519
|
* Whether the board offers the scoping agent: the Scope action on a task and
|
|
8503
8520
|
* the panel that drafts a new one by interview.
|
|
8504
8521
|
*
|
|
@@ -8686,6 +8703,7 @@ const ServerSettingsPatch = Schema$1.Struct({
|
|
|
8686
8703
|
enableVerificationBeforeCompletion: Schema$1.optionalKey(Schema$1.Boolean),
|
|
8687
8704
|
enableRootCauseBeforeFix: Schema$1.optionalKey(Schema$1.Boolean),
|
|
8688
8705
|
enableUnpromptedSubagents: Schema$1.optionalKey(Schema$1.Boolean),
|
|
8706
|
+
enableOptimizedFusionPromptDelivery: Schema$1.optionalKey(Schema$1.Boolean),
|
|
8689
8707
|
enableScopingAgent: Schema$1.optionalKey(Schema$1.Boolean),
|
|
8690
8708
|
enablePlanPhase: Schema$1.optionalKey(Schema$1.Boolean),
|
|
8691
8709
|
writeGeneratedSkillsToRepo: Schema$1.optionalKey(Schema$1.Boolean),
|
|
@@ -69122,6 +69140,19 @@ const makeClaudeTextGeneration = Effect.fn("makeClaudeTextGeneration")(function*
|
|
|
69122
69140
|
};
|
|
69123
69141
|
});
|
|
69124
69142
|
//#endregion
|
|
69143
|
+
//#region ../../packages/shared/src/String.ts
|
|
69144
|
+
/**
|
|
69145
|
+
* Drop a leaked tool-call tag from a plan step title. A mis-closed
|
|
69146
|
+
* `<parameter name="subject">` call swallows `</subject> <parameter
|
|
69147
|
+
* name="description">...` into the title; everything from the first closing
|
|
69148
|
+
* or parameter tag onward is noise the banner must not render.
|
|
69149
|
+
*/
|
|
69150
|
+
function cleanPlanStepTitle(title) {
|
|
69151
|
+
const cut = title.search(/<\/[a-z_-]+>\s*(?=<parameter\b)|<parameter\b/i);
|
|
69152
|
+
const cleaned = (cut === -1 ? title : title.slice(0, cut)).trim();
|
|
69153
|
+
return cleaned.length > 0 ? cleaned : title.trim();
|
|
69154
|
+
}
|
|
69155
|
+
//#endregion
|
|
69125
69156
|
//#region ../../packages/shared/src/cliArgs.ts
|
|
69126
69157
|
function tokenizeCliArgs(args) {
|
|
69127
69158
|
const input = args?.trim();
|
|
@@ -69261,6 +69292,40 @@ function formatAskUserQuestionAnswers(answers) {
|
|
|
69261
69292
|
return formatted;
|
|
69262
69293
|
}
|
|
69263
69294
|
//#endregion
|
|
69295
|
+
//#region src/provider/FusionPrompts.ts
|
|
69296
|
+
/**
|
|
69297
|
+
* Role instructions for the two halves of a Fusion pair.
|
|
69298
|
+
*
|
|
69299
|
+
* They travel through the provider's session channel - Claude's system prompt
|
|
69300
|
+
* append, Codex's per-turn developer instructions - rather than as a prefix on
|
|
69301
|
+
* every message. The block is about 650 tokens; a message-level copy sits in
|
|
69302
|
+
* the conversation history for the rest of the thread, is re-read on every
|
|
69303
|
+
* later API call, and is lost at compaction anyway. The session channel is
|
|
69304
|
+
* cached, never accumulates, and survives compaction. Messages then carry
|
|
69305
|
+
* only a one-line reference and the mutable `[fusion-pair]` metadata.
|
|
69306
|
+
*/
|
|
69307
|
+
const FUSION_BUILDER_INSTRUCTIONS = `You are Fusion Builder in an already-created native server pair. Server owns pairing and coordination. Do not inspect or invoke the Fusion skill, create/pair/rename threads, or announce/setup Fusion. Start the user's task directly. Before editing, create and maintain the phase list with your provider's step-tracking tool (Claude Code: TaskCreate for each phase, then TaskUpdate for status, or TodoWrite when that is the tool offered; Codex: update_plan), never the MCP task board tools - one entry per phase in order, exactly one in progress at a time, marked completed at each phase end - so phases render in the task banner. That list holds phase entries only for the whole task; keep step-level or per-file todos out of it. Name each phase in 3-6 words by its outcome, never by a command, file path, or flag, because the banner shows the title verbatim. Prose alone leaves the banner empty. Split it into the fewest substantial phases the task genuinely needs plus a final integration/whole-task phase; most tasks need one to three work phases. Each phase is a complete reviewable slice of behavior. Never split per file, per function, or per trivial step: over-splitting spends review turns instead of finishing the job. Add a phase only when a real review boundary, risky decision, or independent behavior separates the work. Complete exactly one phase per turn, and finish the whole phase in that turn rather than stopping early. Do not run tests, typecheck, lint, or builds per phase; write the tests the change needs, then run verification once in the final phase over the whole task. Exception: a phase whose own correctness is unclear may run the single narrowest check that resolves it. End every phase turn with phase completed, todo status, changed behavior/files, and remaining phases; do not start the next phase in the same turn. Server then wakes the paired Supervisor, which resumes you through ${FUSION_ADVICE_PROMPT_PREFIX}; a user message may also revise or resume the work. Final phase verifies the entire task against the original request and labels it ready for whole-task review. Supervisor is unreachable during your turn. Never spawn/use another Supervisor thread/subagent or attribute Supervisor decisions without ${FUSION_ADVICE_PROMPT_PREFIX}. Within the current phase, continue when straightforward or evidence is clear. For a concrete unresolved tradeoff, correctness risk, or design decision materially needing judgment, stop safely before the risky choice; final response states the exact question and why review is needed. Evaluate/follow Supervisor advice unless conflicting with user request or verified repo state.`;
|
|
69308
|
+
const FUSION_WATCHER_INSTRUCTIONS = `You are Fusion Supervisor (watcher) in an already-created native server pair. Server owns pairing and coordination and wakes you with ${FUSION_REVIEW_PROMPT_PREFIX} or ${FUSION_GATE_PROMPT_PREFIX} prompts at builder turn boundaries. A plain message outside such a wake may arrive after your conversational memory of the pair is gone; its [fusion-pair] metadata block is authoritative: the builder thread exists and is the counterpart thread id. Never report that no builder thread exists. To resume supervision, read builder events with thread_watch_events from lastReviewedImplementerSequence with limit 50, paging forward with the last returned sequence rather than requesting a whole range at once, derive phase from artifacts (git log/status, PR, builder events, including its turn.plan.updated phase list), steer with thread_advise, and answer an open gate with thread_gate_respond. When a review or gate wake prompt specifies an explicit event range, that range wins over this metadata. Never poll or wait for the builder; deliver review or advice, then end the turn.`;
|
|
69309
|
+
/**
|
|
69310
|
+
* The one-line stand-in for the full block on a message whose session already
|
|
69311
|
+
* carries the role instructions.
|
|
69312
|
+
*/
|
|
69313
|
+
const FUSION_BUILDER_REFERENCE_LINE = "[fusion-builder] Fusion Builder rules in your session instructions still apply.";
|
|
69314
|
+
const FUSION_WATCHER_REFERENCE_LINE = "[fusion-watcher] Plain message outside a server wake; Fusion Supervisor rules in your session instructions still apply.";
|
|
69315
|
+
/**
|
|
69316
|
+
* Sent on every turn of a thread whose session still carries role
|
|
69317
|
+
* instructions after its pair was detached. Claude's system prompt is frozen
|
|
69318
|
+
* at session start, so the block cannot be removed; it is countered instead,
|
|
69319
|
+
* the same way a switched-off compress ruleset is.
|
|
69320
|
+
*/
|
|
69321
|
+
const FUSION_DETACHED_REMINDER = "[fusion-detached] The Fusion pair ended. Fusion role rules in your session instructions no longer apply; work as a normal thread.";
|
|
69322
|
+
function fusionRoleInstructionsFor(role) {
|
|
69323
|
+
return role === "implementer" ? FUSION_BUILDER_INSTRUCTIONS : FUSION_WATCHER_INSTRUCTIONS;
|
|
69324
|
+
}
|
|
69325
|
+
function fusionRoleReferenceLineFor(role) {
|
|
69326
|
+
return role === "implementer" ? FUSION_BUILDER_REFERENCE_LINE : FUSION_WATCHER_REFERENCE_LINE;
|
|
69327
|
+
}
|
|
69328
|
+
//#endregion
|
|
69264
69329
|
//#region src/provider/GuardrailPrompts.ts
|
|
69265
69330
|
/** Fresh-evidence gate adapted from superpowers' verification skill. */
|
|
69266
69331
|
const VERIFY_BEFORE_COMPLETION_PROMPT = "NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE. Before claiming complete, fixed, or passing: 1) identify proving command; 2) run it fresh and fully; 3) read full output, exit code, failure count; 4) confirm evidence matches claim; 5) state claim with evidence. Missing or failed proof: report actual status.";
|
|
@@ -69804,7 +69869,7 @@ function extractPlanStepsFromTodoInput(input) {
|
|
|
69804
69869
|
const todos = input.todos;
|
|
69805
69870
|
if (!Array.isArray(todos) || todos.length === 0) return null;
|
|
69806
69871
|
return todos.filter((t) => t !== null && typeof t === "object").map((todo) => ({
|
|
69807
|
-
step: typeof todo.content === "string" && todo.content.trim().length > 0 ? todo.content
|
|
69872
|
+
step: typeof todo.content === "string" && todo.content.trim().length > 0 ? cleanPlanStepTitle(todo.content) : "Task",
|
|
69808
69873
|
status: todo.status === "completed" ? "completed" : todo.status === "in_progress" ? "inProgress" : "pending"
|
|
69809
69874
|
}));
|
|
69810
69875
|
}
|
|
@@ -69834,6 +69899,9 @@ function isClaudeTaskTool(toolName) {
|
|
|
69834
69899
|
function normalizeClaudeTaskStatus(value) {
|
|
69835
69900
|
return value === "completed" ? "completed" : value === "in_progress" ? "inProgress" : "pending";
|
|
69836
69901
|
}
|
|
69902
|
+
function cleanStepSubject(value) {
|
|
69903
|
+
return value === void 0 ? void 0 : cleanPlanStepTitle(value);
|
|
69904
|
+
}
|
|
69837
69905
|
function readString(value) {
|
|
69838
69906
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
69839
69907
|
}
|
|
@@ -69860,7 +69928,7 @@ function applyClaudeTaskToolResult(tasks, tool, result) {
|
|
|
69860
69928
|
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
69861
69929
|
const task = entry;
|
|
69862
69930
|
const id = readString(task.id);
|
|
69863
|
-
const subject = readString(task.subject);
|
|
69931
|
+
const subject = cleanStepSubject(readString(task.subject));
|
|
69864
69932
|
if (!id || !subject) continue;
|
|
69865
69933
|
tasks.set(id, {
|
|
69866
69934
|
id,
|
|
@@ -69874,7 +69942,7 @@ function applyClaudeTaskToolResult(tasks, tool, result) {
|
|
|
69874
69942
|
if (tool.toolName === "TaskCreate") {
|
|
69875
69943
|
const resultTask = readClaudeTaskFromResult(result);
|
|
69876
69944
|
const id = readString(resultTask?.id);
|
|
69877
|
-
const subject = readString(resultTask?.subject) ?? readString(tool.input.subject);
|
|
69945
|
+
const subject = cleanStepSubject(readString(resultTask?.subject) ?? readString(tool.input.subject));
|
|
69878
69946
|
if (!id || !subject) return false;
|
|
69879
69947
|
tasks.set(id, {
|
|
69880
69948
|
id,
|
|
@@ -69888,7 +69956,7 @@ function applyClaudeTaskToolResult(tasks, tool, result) {
|
|
|
69888
69956
|
if (!taskId) return false;
|
|
69889
69957
|
const task = tasks.get(taskId);
|
|
69890
69958
|
if (!task) return false;
|
|
69891
|
-
const subject = readString(tool.input.subject);
|
|
69959
|
+
const subject = cleanStepSubject(readString(tool.input.subject));
|
|
69892
69960
|
if (subject && task.subject !== subject) {
|
|
69893
69961
|
task.subject = subject;
|
|
69894
69962
|
changed = true;
|
|
@@ -71928,7 +71996,8 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
|
|
|
71928
71996
|
...narrateBeforeTools ? [NARRATE_BEFORE_TOOLS_PROMPT] : [],
|
|
71929
71997
|
...guardrailPromptsFor(guardrailSettings),
|
|
71930
71998
|
unpromptedSubagents ? SUBAGENTS_ALLOWED_PROMPT : SUBAGENTS_ON_REQUEST_PROMPT,
|
|
71931
|
-
...compressRuleset !== void 0 ? [compressRuleset] : []
|
|
71999
|
+
...compressRuleset !== void 0 ? [compressRuleset] : [],
|
|
72000
|
+
...input.fusionRole !== void 0 ? [fusionRoleInstructionsFor(input.fusionRole)] : []
|
|
71932
72001
|
].join("\n\n");
|
|
71933
72002
|
const compressionSubagentHook = async (hookInput) => {
|
|
71934
72003
|
if (hookInput.hook_event_name !== "SubagentStart") return {};
|
|
@@ -91582,13 +91651,14 @@ ${P4_CODE_BROWSER_TOOL_INSTRUCTIONS}
|
|
|
91582
91651
|
function toSingleLine(value) {
|
|
91583
91652
|
return value.replaceAll(/\s+/g, " ").trim();
|
|
91584
91653
|
}
|
|
91585
|
-
function buildCodexDeveloperInstructions(interactionMode, runtime, compressMode, guardrailSettings) {
|
|
91654
|
+
function buildCodexDeveloperInstructions(interactionMode, runtime, compressMode, guardrailSettings, fusionRole) {
|
|
91586
91655
|
const base = interactionMode === "plan" ? CODEX_PLAN_MODE_DEVELOPER_INSTRUCTIONS : CODEX_DEFAULT_MODE_DEVELOPER_INSTRUCTIONS;
|
|
91587
91656
|
const compressRuleset = compressRulesetFor(compressMode ?? "off");
|
|
91588
91657
|
return [
|
|
91589
91658
|
base,
|
|
91590
91659
|
...guardrailPromptsFor(guardrailSettings),
|
|
91591
91660
|
...compressRuleset === void 0 ? [] : [`<response_style>${compressRuleset}</response_style>`],
|
|
91661
|
+
...fusionRole === void 0 ? [] : [`<fusion_role>${fusionRoleInstructionsFor(fusionRole)}</fusion_role>`],
|
|
91592
91662
|
`<runtime_info>In case you're asked: you are running in P4Code through the Codex harness, as ${toSingleLine(runtime.model)} with ${toSingleLine(runtime.reasoningEffort)} reasoning effort. No need to mention this otherwise.</runtime_info>`
|
|
91593
91663
|
].join("\n\n");
|
|
91594
91664
|
}
|
|
@@ -91720,7 +91790,7 @@ function buildCodexCollaborationMode(input) {
|
|
|
91720
91790
|
developer_instructions: buildCodexDeveloperInstructions(input.interactionMode, {
|
|
91721
91791
|
model,
|
|
91722
91792
|
reasoningEffort
|
|
91723
|
-
}, input.compressMode, input.guardrailPrompts)
|
|
91793
|
+
}, input.compressMode, input.guardrailPrompts, input.fusionRole)
|
|
91724
91794
|
}
|
|
91725
91795
|
};
|
|
91726
91796
|
}
|
|
@@ -91740,7 +91810,8 @@ function buildTurnStartParams(input) {
|
|
|
91740
91810
|
...input.compressMode ? { compressMode: input.compressMode } : {},
|
|
91741
91811
|
...input.model ? { model: input.model } : {},
|
|
91742
91812
|
...input.effort ? { effort: input.effort } : {},
|
|
91743
|
-
...input.guardrailPrompts ? { guardrailPrompts: input.guardrailPrompts } : {}
|
|
91813
|
+
...input.guardrailPrompts ? { guardrailPrompts: input.guardrailPrompts } : {},
|
|
91814
|
+
...input.fusionRole ? { fusionRole: input.fusionRole } : {}
|
|
91744
91815
|
});
|
|
91745
91816
|
const compressRulesetUndeliverable = input.compressMode !== void 0 && input.compressMode !== "off" && collaborationMode === void 0;
|
|
91746
91817
|
return decodeCodexTurnStartParamsWithCollaborationMode({
|
|
@@ -93486,6 +93557,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
|
|
|
93486
93557
|
...serviceTier ? { serviceTier } : {},
|
|
93487
93558
|
...input.interactionMode !== void 0 ? { interactionMode: input.interactionMode } : {},
|
|
93488
93559
|
...input.compressMode !== void 0 ? { compressMode: input.compressMode } : {},
|
|
93560
|
+
...input.fusionRole !== void 0 ? { fusionRole: input.fusionRole } : {},
|
|
93489
93561
|
...codexAttachments.length > 0 ? { attachments: codexAttachments } : {}
|
|
93490
93562
|
}).pipe(Effect.mapError((cause) => mapCodexRuntimeError(input.threadId, "turn/start", cause)));
|
|
93491
93563
|
});
|
|
@@ -108791,9 +108863,20 @@ const DEFAULT_RUNTIME_MODE = "full-access";
|
|
|
108791
108863
|
const DEFAULT_THREAD_TITLE = "New thread";
|
|
108792
108864
|
const NON_SYSTEM_PROVIDER_STRUCTURED_USER_QUESTIONS = structuredUserQuestionPrompt("your provider's structured user-input question tool");
|
|
108793
108865
|
const FUSION_PROMOTION_INSTRUCTIONS = `Work independently in this normal thread. Fusion is a silent escalation path, not a startup procedure. Do not inspect Fusion tools/skill, mention Fusion status, or announce that Fusion was not invoked. First analyze the task normally. Only if that analysis reveals a concrete unresolved tradeoff, correctness risk, or design decision materially needing a second opinion, stop before implementation, propose Fusion, and ask the user for explicit approval. The user may approve with ordinary affirmative text such as "approved"; /fusion or $fusion also authorizes Fusion directly without a prior proposal. Do not activate, spawn, or promote until one of those authorizations arrives. UI work, complex logic, task size, unfamiliarity, or duration alone never qualifies.`;
|
|
108794
|
-
const FUSION_BUILDER_INSTRUCTIONS = `You are Fusion Builder in an already-created native server pair. Server owns pairing and coordination. Do not inspect or invoke the Fusion skill, create/pair/rename threads, or announce/setup Fusion. Start the user's task directly. Before editing, create and maintain the phase list with your provider's step-tracking tool (Claude Code: TaskCreate for each phase, then TaskUpdate for status, or TodoWrite when that is the tool offered; Codex: update_plan), never the MCP task board tools - one entry per phase in order, exactly one in progress at a time, marked completed at each phase end - so phases render in the task banner. That list holds phase entries only for the whole task; keep step-level or per-file todos out of it. Prose alone leaves the banner empty. Split it into the fewest substantial phases the task genuinely needs plus a final integration/whole-task phase; most tasks need one to three work phases. Each phase is a complete reviewable slice of behavior. Never split per file, per function, or per trivial step: over-splitting spends review turns instead of finishing the job. Add a phase only when a real review boundary, risky decision, or independent behavior separates the work. Complete exactly one phase per turn, and finish the whole phase in that turn rather than stopping early. Do not run tests, typecheck, lint, or builds per phase; write the tests the change needs, then run verification once in the final phase over the whole task. Exception: a phase whose own correctness is unclear may run the single narrowest check that resolves it. End every phase turn with phase completed, todo status, changed behavior/files, and remaining phases; do not start the next phase in the same turn. Server then wakes the paired Supervisor, which resumes you through ${FUSION_ADVICE_PROMPT_PREFIX}; a user message may also revise or resume the work. Final phase verifies the entire task against the original request and labels it ready for whole-task review. Supervisor is unreachable during your turn. Never spawn/use another Supervisor thread/subagent or attribute Supervisor decisions without ${FUSION_ADVICE_PROMPT_PREFIX}. Within the current phase, continue when straightforward or evidence is clear. For a concrete unresolved tradeoff, correctness risk, or design decision materially needing judgment, stop safely before the risky choice; final response states the exact question and why review is needed. Evaluate/follow Supervisor advice unless conflicting with user request or verified repo state.`;
|
|
108795
|
-
const FUSION_WATCHER_INSTRUCTIONS = `You are Fusion Supervisor (watcher) in an already-created native server pair. Server owns pairing and coordination and wakes you with ${FUSION_REVIEW_PROMPT_PREFIX} or ${FUSION_GATE_PROMPT_PREFIX} prompts at builder turn boundaries; this message arrived outside such a wake, so your conversational memory of the pair may be gone. The pair metadata below is authoritative: the builder thread exists and is the counterpart thread id. Never report that no builder thread exists. To resume supervision, read builder events with thread_watch_events from lastReviewedImplementerSequence with limit 50, paging forward with the last returned sequence rather than requesting a whole range at once, derive phase from artifacts (git log/status, PR, builder events, including its turn.plan.updated phase list), steer with thread_advise, and answer an open gate with thread_gate_respond. When a review or gate wake prompt specifies an explicit event range, that range wins over this metadata. Never poll or wait for the builder; deliver review or advice, then end the turn.`;
|
|
108796
108866
|
const isFusionWatcherWakeMessageId = (messageId) => messageId.startsWith("fusion-review:") || messageId.startsWith("fusion-gate:");
|
|
108867
|
+
const findActiveFusionPair = (pairs, threadId) => (pairs ?? []).find((pair) => pair.detachedAt === null && (pair.implementerThreadId === threadId || pair.watcherThreadId === threadId));
|
|
108868
|
+
const fusionRoleForThread = (pairs, threadId) => {
|
|
108869
|
+
const pair = findActiveFusionPair(pairs, threadId);
|
|
108870
|
+
return pair === void 0 ? void 0 : pair.implementerThreadId === threadId ? "implementer" : "watcher";
|
|
108871
|
+
};
|
|
108872
|
+
/**
|
|
108873
|
+
* Providers whose session channel is filled once, at session start, and then
|
|
108874
|
+
* frozen: Claude's system prompt append. Only these need the reactor to
|
|
108875
|
+
* remember what the live session carries. Codex rebuilds its developer
|
|
108876
|
+
* instructions from every turn, and every other provider gets the block on
|
|
108877
|
+
* each message.
|
|
108878
|
+
*/
|
|
108879
|
+
const providerFreezesFusionRoleAtSessionStart = (provider) => provider === "claudeAgent";
|
|
108797
108880
|
const fusionPairContext = (pair, role) => {
|
|
108798
108881
|
const counterpartThreadId = role === "implementer" ? pair.watcherThreadId : pair.implementerThreadId;
|
|
108799
108882
|
return [
|
|
@@ -108911,6 +108994,21 @@ const make$4 = Effect.gen(function* () {
|
|
|
108911
108994
|
* this is how the reactor knows there is something to counter.
|
|
108912
108995
|
*/
|
|
108913
108996
|
const threadSessionRulesetModes = /* @__PURE__ */ new Map();
|
|
108997
|
+
/**
|
|
108998
|
+
* The Fusion role whose instructions the thread's live session was handed
|
|
108999
|
+
* at start, for the same reason as the ruleset above: Claude bakes them into
|
|
109000
|
+
* a frozen system prompt. A session that predates its pair carries none and
|
|
109001
|
+
* keeps getting the full block on each message; a session that outlives its
|
|
109002
|
+
* pair carries stale rules and gets a counter-line instead.
|
|
109003
|
+
*/
|
|
109004
|
+
const threadSessionFusionRoles = /* @__PURE__ */ new Map();
|
|
109005
|
+
/**
|
|
109006
|
+
* The Beta switch between session-channel delivery and the legacy full
|
|
109007
|
+
* block on every message. Read per turn so flipping it affects the next
|
|
109008
|
+
* turn of every thread, running sessions included. A settings read failure
|
|
109009
|
+
* falls back to the default rather than failing the turn.
|
|
109010
|
+
*/
|
|
109011
|
+
const readOptimizedFusionPromptDelivery = serverSettingsService.getSettings.pipe(Effect.map((settings) => settings.enableOptimizedFusionPromptDelivery), Effect.orElseSucceed(() => DEFAULT_SERVER_SETTINGS.enableOptimizedFusionPromptDelivery));
|
|
108914
109012
|
const appendProviderFailureActivity = (input) => Effect.all({
|
|
108915
109013
|
commandId: serverCommandId("provider-failure-activity"),
|
|
108916
109014
|
eventId: serverEventId()
|
|
@@ -109175,7 +109273,8 @@ const make$4 = Effect.gen(function* () {
|
|
|
109175
109273
|
if (!thread) return yield* Effect.die(/* @__PURE__ */ new Error(`Thread '${threadId}' was not found in read model.`));
|
|
109176
109274
|
const desiredRuntimeMode = thread.runtimeMode;
|
|
109177
109275
|
const requestedModelSelection = options?.modelSelection;
|
|
109178
|
-
const
|
|
109276
|
+
const commandReadModel = yield* projectionSnapshotQuery.getCommandReadModel();
|
|
109277
|
+
const watchThreadIds = (commandReadModel.threadPairs ?? []).filter((pair) => pair.detachedAt === null && pair.watcherThreadId === threadId).map((pair) => pair.implementerThreadId);
|
|
109179
109278
|
yield* Effect.forEach(watchThreadIds, (watchedThreadId) => grantActiveMcpWatchThread({
|
|
109180
109279
|
watcherThreadId: threadId,
|
|
109181
109280
|
watchedThreadId
|
|
@@ -109261,8 +109360,12 @@ const make$4 = Effect.gen(function* () {
|
|
|
109261
109360
|
thread,
|
|
109262
109361
|
project
|
|
109263
109362
|
});
|
|
109363
|
+
const optimizedFusionPromptDelivery = yield* readOptimizedFusionPromptDelivery;
|
|
109264
109364
|
const startProviderSession = (input) => {
|
|
109265
109365
|
threadSessionRulesetModes.set(threadId, thread.compressMode);
|
|
109366
|
+
const fusionRole = optimizedFusionPromptDelivery ? fusionRoleForThread(commandReadModel.threadPairs, threadId) : void 0;
|
|
109367
|
+
if (fusionRole === void 0 || !providerFreezesFusionRoleAtSessionStart(preferredProvider)) threadSessionFusionRoles.delete(threadId);
|
|
109368
|
+
else threadSessionFusionRoles.set(threadId, fusionRole);
|
|
109266
109369
|
return providerService.startSession(threadId, {
|
|
109267
109370
|
threadId,
|
|
109268
109371
|
...preferredProvider ? { provider: preferredProvider } : {},
|
|
@@ -109272,7 +109375,8 @@ const make$4 = Effect.gen(function* () {
|
|
|
109272
109375
|
...input?.resumeCursor !== void 0 ? { resumeCursor: input.resumeCursor } : {},
|
|
109273
109376
|
runtimeMode: desiredRuntimeMode,
|
|
109274
109377
|
compressMode: thread.compressMode,
|
|
109275
|
-
unpromptedSubagents: thread.unpromptedSubagents
|
|
109378
|
+
unpromptedSubagents: thread.unpromptedSubagents,
|
|
109379
|
+
...fusionRole !== void 0 ? { fusionRole } : {}
|
|
109276
109380
|
}, watchThreadIds.length > 0 ? {
|
|
109277
109381
|
watchThreadIds,
|
|
109278
109382
|
adviseThreadIds: watchThreadIds
|
|
@@ -109375,10 +109479,23 @@ const make$4 = Effect.gen(function* () {
|
|
|
109375
109479
|
"Attached PDF files are available at these local paths. Read them before answering:",
|
|
109376
109480
|
...documentReferenceLines
|
|
109377
109481
|
].filter((part) => part !== void 0).join("\n\n");
|
|
109378
|
-
const
|
|
109379
|
-
const
|
|
109380
|
-
const
|
|
109482
|
+
const commandReadModel = yield* projectionSnapshotQuery.getCommandReadModel();
|
|
109483
|
+
const activeFusionPair = findActiveFusionPair(commandReadModel.threadPairs, input.threadId);
|
|
109484
|
+
const fusionRole = activeFusionPair === void 0 ? void 0 : activeFusionPair.implementerThreadId === input.threadId ? "implementer" : "watcher";
|
|
109381
109485
|
const activeSession = yield* providerService.listSessions().pipe(Effect.map((sessions) => sessions.find((session) => session.threadId === input.threadId)));
|
|
109486
|
+
const optimizedFusionPromptDelivery = yield* readOptimizedFusionPromptDelivery;
|
|
109487
|
+
const rebuildsFusionRoleEachTurn = activeSession?.provider === "codex";
|
|
109488
|
+
const sessionCarriedFusionRole = threadSessionFusionRoles.get(input.threadId);
|
|
109489
|
+
const sessionFusionRole = !optimizedFusionPromptDelivery ? void 0 : rebuildsFusionRoleEachTurn ? fusionRole : sessionCarriedFusionRole;
|
|
109490
|
+
const fusionInput = expandedInputWithDocuments === void 0 ? void 0 : fusionRole === void 0 || activeFusionPair === void 0 ? [
|
|
109491
|
+
...sessionCarriedFusionRole !== void 0 ? [FUSION_DETACHED_REMINDER] : [],
|
|
109492
|
+
FUSION_PROMOTION_INSTRUCTIONS,
|
|
109493
|
+
expandedInputWithDocuments
|
|
109494
|
+
].join("\n\n") : fusionRole === "watcher" && isFusionWatcherWakeMessageId(input.messageId) ? expandedInputWithDocuments : [
|
|
109495
|
+
sessionFusionRole === fusionRole ? fusionRoleReferenceLineFor(fusionRole) : fusionRoleInstructionsFor(fusionRole),
|
|
109496
|
+
fusionPairContext(activeFusionPair, fusionRole),
|
|
109497
|
+
expandedInputWithDocuments
|
|
109498
|
+
].join("\n\n");
|
|
109382
109499
|
const providerHasStructuredQuestionSystemPrompt = activeSession?.provider === "claudeAgent" || activeSession?.provider === "codex";
|
|
109383
109500
|
const inputWithStructuredQuestionPolicy = fusionInput !== void 0 && !providerHasStructuredQuestionSystemPrompt ? `${NON_SYSTEM_PROVIDER_STRUCTURED_USER_QUESTIONS}\n\n${fusionInput}` : fusionInput;
|
|
109384
109501
|
const sessionModelSwitch = activeSession === void 0 ? "in-session" : activeSession.providerInstanceId === void 0 ? yield* new ProviderAdapterRequestError({
|
|
@@ -109411,7 +109528,8 @@ const make$4 = Effect.gen(function* () {
|
|
|
109411
109528
|
...modelForTurn !== void 0 ? { modelSelection: modelForTurn } : {},
|
|
109412
109529
|
...input.interactionMode !== void 0 ? { interactionMode: input.interactionMode } : {},
|
|
109413
109530
|
compressMode,
|
|
109414
|
-
unpromptedSubagents: thread.unpromptedSubagents
|
|
109531
|
+
unpromptedSubagents: thread.unpromptedSubagents,
|
|
109532
|
+
...optimizedFusionPromptDelivery && fusionRole !== void 0 ? { fusionRole } : {}
|
|
109415
109533
|
};
|
|
109416
109534
|
});
|
|
109417
109535
|
const maybeGenerateAndRenameWorktreeBranchForFirstTurn = Effect.fn("maybeGenerateAndRenameWorktreeBranchForFirstTurn")(function* (input) {
|
|
@@ -109637,6 +109755,7 @@ const make$4 = Effect.gen(function* () {
|
|
|
109637
109755
|
const now = event.payload.createdAt;
|
|
109638
109756
|
if (thread.session && thread.session.status !== "stopped") yield* providerService.stopSession({ threadId: thread.id });
|
|
109639
109757
|
threadSessionRulesetModes.delete(thread.id);
|
|
109758
|
+
threadSessionFusionRoles.delete(thread.id);
|
|
109640
109759
|
yield* setThreadSession({
|
|
109641
109760
|
threadId: thread.id,
|
|
109642
109761
|
session: {
|
|
@@ -109698,6 +109817,7 @@ const make$4 = Effect.gen(function* () {
|
|
|
109698
109817
|
})));
|
|
109699
109818
|
yield* Effect.all([flushQueuedSettle(thread.id), flushQueuedWorkspaceCleanup(thread.id)], { discard: true });
|
|
109700
109819
|
threadSessionRulesetModes.delete(thread.id);
|
|
109820
|
+
threadSessionFusionRoles.delete(thread.id);
|
|
109701
109821
|
threadBackgroundLiveness.clearThreadLiveness(thread.id);
|
|
109702
109822
|
});
|
|
109703
109823
|
const processDomainEvent = Effect.fn("processDomainEvent")(function* (event) {
|
|
@@ -0,0 +1,98 @@
|
|
|
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{$c as i,Al as a,Bl as o,Ca as s,Da as c,Et as l,Fa as ee,Fl as te,Fr as u,Ia as d,La as f,Na as ne,Oa as re,Pa as p,_n as m,b as h,ba as g,el as _,gt as v,h as y,ht as b,kr as ie,lu as x,nl as S,st as C,tl as w,vt as T,wl as E,wr as D,xn as O,yl as ae}from"./previewAssetResource-hBW3v1Su.js";import{a as k,i as oe,n as A,o as j,r as M,s as N,t as se}from"./toggle-group-tMSVv__W.js";import{F as ce,Fr as le,I as ue,J as de,L as fe,Lr as pe,Mr as me,Nr as he,R as P,Y as ge,_ as _e,_r as ve,at as ye,ci as be,cr as xe,ct as Se,dr as Ce,fr as we,h as Te,hr as Ee,it as De,jr as Oe,lr as ke,lt as Ae,oi as je,or as Me,ot as Ne,pr as Pe,rt as Fe,si as Ie,sr as Le,st as Re,ur as ze,yr as Be,zr as Ve}from"./index-BQ38fIEf.js";import{a as He,n as Ue}from"./fileCommentAnnotations-9363cOl3.js";var We=S(`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}C.getState().openFile(e,t);return}r(n?y(t,n):t)}var I=r();function Ke(e,t){let n=(0,I.c)(4),r=Ee(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=D(Qe),te=D(B),d;t[0]===a?d=t[1]:(d=e=>e.getComposerDraft(a)?.reviewComments??qe,t[0]=a,t[1]=d);let f=D(d),[ne,re]=(0,F.useState)(null),[p,m]=(0,F.useState)(null),h;t[2]===n?h=t[3]:(h=new Map(n.map(Ze)),t[2]=n,t[3]=h);let g=h,_;if(t[4]!==p||t[5]!==n||t[6]!==f||t[7]!==r){let e;t[9]!==p||t[10]!==f||t[11]!==r?(e=e=>{let{fileDiff:t,filePath:n,fileKey:i,collapsed:a}=e,o=f.filter(e=>e.sectionId===r&&e.filePath===n&&(e.fenceLanguage??`diff`)===`diff`).reduce((e,n)=>{let r=u(t,n);return r?R(e,r,{id:n.id,kind:`comment`,range:r,rangeLabel:n.rangeLabel,text:n.text}):e},[]),s=p?.fileKey===i?[...o,p.annotation]:o;return{id:i,type:`diff`,fileDiff:t,annotations:s,collapsed:a,version:De(`${a?`1`:`0`}:${s.flatMap(z).join(`:`)}`)}},t[9]=p,t[10]=f,t[11]=r,t[12]=e):e=t[12],_=n.map(e),t[4]=p,t[5]=n,t[6]=f,t[7]=r,t[8]=_}else _=t[8];let v=_,y;t[13]!==a||t[14]!==p?.annotation||t[15]!==te?(y=e=>{re(null),p?.annotation.metadata.entries.some(t=>t.id===e)?m(null):te(a,e)},t[13]=a,t[14]=p?.annotation,t[15]=te,t[16]=y):y=t[16];let b=y,x;t[17]!==ee||t[18]!==a||t[19]!==p||t[20]!==g||t[21]!==r||t[22]!==i?(x=(e,t)=>{let n=p?.annotation.metadata.entries.find(t=>t.id===e),o=p?g.get(p.fileKey):void 0;if(!n||!o)return;let s=ie({id:n.id,sectionId:r,sectionTitle:i,filePath:o.filePath,fileDiff:o.fileDiff,range:n.range,text:t});s&&ee(a,s),re(null),m(null)},t[17]=ee,t[18]=a,t[19]=p,t[20]=g,t[21]=r,t[22]=i,t[23]=x):x=t[23];let S=x,C;t[24]!==g||t[25]!==r||t[26]!==i?(C=(e,t)=>{if(!e)return;let n=t.item;if(n.type!==`diff`)return;let a=g.get(n.id);if(!a)return;let o=Ue(),s=ie({id:o,sectionId:r,sectionTitle:i,filePath:a.filePath,fileDiff:a.fileDiff,range:e,text:``});s&&m({fileKey:n.id,annotation:{side:Je(e),lineNumber:e.end,metadata:{entries:[{id:o,kind:`draft`,range:e,rangeLabel:s.rangeLabel,text:``}]}}})},t[24]=g,t[25]=r,t[26]=i,t[27]=C):C=t[27];let w=C,T=p!==null,E;t[28]===s?E=t[29]:(E=s?{ref:s}:{},t[28]=s,t[29]=E);let O;t[30]===c?O=t[31]:(O=c?{className:c}:{},t[30]=c,t[31]=O);let ae=!T,oe=!T,A;t[32]!==w||t[33]!==o||t[34]!==oe||t[35]!==ae?(A={...o,enableGutterUtility:ae,enableLineSelection:oe,onLineSelectionEnd:w},t[32]=w,t[33]=o,t[34]=oe,t[35]=ae,t[36]=A):A=t[36];let j;t[37]===l?j=t[38]:(j=e=>e.type===`diff`?l(e.fileDiff,e.id,e.collapsed===!0):null,t[37]=l,t[38]=j);let M;t[39]!==b||t[40]!==S?(M=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]=M):M=t[41];let N;return t[42]!==v||t[43]!==ne||t[44]!==A||t[45]!==j||t[46]!==M||t[47]!==E||t[48]!==O?(N=(0,L.jsx)(k,{...E,...O,items:v,selectedLines:ne,onSelectedLinesChange:re,options:A,renderHeaderPrefix:j,renderAnnotation:M}),t[42]=v,t[43]=ne,t[44]=A,t[45]=j,t[46]=M,t[47]=E,t[48]=O,t[49]=N):N=t[49],N}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:E(e,{label:`environment-data:review:diff-preview`,tag:x.reviewGetDiffPreview,staleTimeMs:5e3})}}var et=$e(O);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
|
+
[data-diffs-header],
|
|
3
|
+
[data-diff],
|
|
4
|
+
[data-file],
|
|
5
|
+
[data-error-wrapper],
|
|
6
|
+
[data-virtualizer-buffer] {
|
|
7
|
+
--diffs-header-font-family: var(--font-sans) !important;
|
|
8
|
+
--diffs-font-family: var(--font-mono) !important;
|
|
9
|
+
--diffs-bg: color-mix(in srgb, var(--card) 90%, var(--background)) !important;
|
|
10
|
+
--diffs-light-bg: color-mix(in srgb, var(--card) 90%, var(--background)) !important;
|
|
11
|
+
--diffs-dark-bg: color-mix(in srgb, var(--card) 90%, var(--background)) !important;
|
|
12
|
+
--diffs-token-light-bg: transparent;
|
|
13
|
+
--diffs-token-dark-bg: transparent;
|
|
14
|
+
|
|
15
|
+
--diffs-bg-context-override: color-mix(in srgb, var(--background) 97%, var(--foreground));
|
|
16
|
+
--diffs-bg-hover-override: color-mix(in srgb, var(--background) 94%, var(--foreground));
|
|
17
|
+
--diffs-bg-separator-override: color-mix(in srgb, var(--background) 95%, var(--foreground));
|
|
18
|
+
--diffs-bg-buffer-override: color-mix(in srgb, var(--background) 90%, var(--foreground));
|
|
19
|
+
|
|
20
|
+
--diffs-bg-addition-override: color-mix(in srgb, var(--background) 92%, var(--success));
|
|
21
|
+
--diffs-bg-addition-number-override: color-mix(in srgb, var(--background) 88%, var(--success));
|
|
22
|
+
--diffs-bg-addition-hover-override: color-mix(in srgb, var(--background) 85%, var(--success));
|
|
23
|
+
--diffs-bg-addition-emphasis-override: color-mix(in srgb, var(--background) 80%, var(--success));
|
|
24
|
+
|
|
25
|
+
--diffs-bg-deletion-override: color-mix(in srgb, var(--background) 92%, var(--destructive));
|
|
26
|
+
--diffs-bg-deletion-number-override: color-mix(in srgb, var(--background) 88%, var(--destructive));
|
|
27
|
+
--diffs-bg-deletion-hover-override: color-mix(in srgb, var(--background) 85%, var(--destructive));
|
|
28
|
+
--diffs-bg-deletion-emphasis-override: color-mix(
|
|
29
|
+
in srgb,
|
|
30
|
+
var(--background) 80%,
|
|
31
|
+
var(--destructive)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
background-color: var(--diffs-bg) !important;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[data-file-info] {
|
|
38
|
+
background-color: color-mix(in srgb, var(--card) 94%, var(--foreground)) !important;
|
|
39
|
+
border-block-color: var(--border) !important;
|
|
40
|
+
color: var(--foreground) !important;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
[data-diffs-header] {
|
|
44
|
+
position: sticky !important;
|
|
45
|
+
top: 0;
|
|
46
|
+
z-index: 4;
|
|
47
|
+
background-color: color-mix(in srgb, var(--card) 94%, var(--foreground)) !important;
|
|
48
|
+
border-bottom: 1px solid var(--border) !important;
|
|
49
|
+
align-items: center !important;
|
|
50
|
+
font-family: var(--font-sans) !important;
|
|
51
|
+
font-size: 12px !important;
|
|
52
|
+
line-height: 1 !important;
|
|
53
|
+
min-height: 32px !important;
|
|
54
|
+
padding-block: 6px !important;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
[data-diffs-header] [data-header-content] {
|
|
58
|
+
align-items: center !important;
|
|
59
|
+
line-height: 1 !important;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
[data-diffs-header] [data-metadata] {
|
|
63
|
+
align-items: center !important;
|
|
64
|
+
line-height: 1 !important;
|
|
65
|
+
font-variant-numeric: tabular-nums;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
[data-diffs-header] [data-additions-count],
|
|
69
|
+
[data-diffs-header] [data-deletions-count] {
|
|
70
|
+
font-family: var(--font-mono) !important;
|
|
71
|
+
font-size: 11px !important;
|
|
72
|
+
font-variant-numeric: tabular-nums;
|
|
73
|
+
line-height: 1 !important;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
[data-diffs-header] [data-change-icon],
|
|
77
|
+
[data-diffs-header] [data-rename-icon] {
|
|
78
|
+
display: block;
|
|
79
|
+
flex-shrink: 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
[data-title] {
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
transition:
|
|
85
|
+
color 120ms ease,
|
|
86
|
+
text-decoration-color 120ms ease;
|
|
87
|
+
text-decoration: underline;
|
|
88
|
+
text-decoration-color: transparent;
|
|
89
|
+
text-underline-offset: 2px;
|
|
90
|
+
font-family: var(--font-sans) !important;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
[data-title]:hover {
|
|
94
|
+
color: color-mix(in srgb, var(--foreground) 84%, var(--primary)) !important;
|
|
95
|
+
text-decoration-color: currentColor;
|
|
96
|
+
}
|
|
97
|
+
`;function U({mode:e=`inline`,composerDraftTarget:t,initialGitScope:n,threadRef:r}){let{resolvedTheme:u}=h(),y=le(),[ie]=(0,F.useState)(n),[x,S]=(0,F.useState)(`stacked`),[C,E]=(0,F.useState)(y.wordWrap),[D,O]=(0,F.useState)(y.diffIgnoreWhitespace),[k,_e]=(0,F.useState)(``),[Ee,De]=(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=ae(m.configValueAtom(I?.environmentId??null)),Xe=ve(I?.environmentId??null,z?.availableEditors??[]),Ze=l(I!=null&&R!=null?Oe.status({environmentId:I.environmentId,input:{cwd:R}}):null),B=P(e=>fe(e.byThreadKey,r,ie===`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`&&P.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=Ee.scopeKey===Y?Ee.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:D,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:D}}):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:D}}):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?Oe.listRefs({environmentId:I.environmentId,input:{cwd:X.data.cwd,includeMatchingRemoteRefs:!0,refKind:`local`,...k.trim().length>0?{query:k.trim()}:{},limit:100}}):null),vt=l(W===null&&G===`branch`&&I&&X.data?.cwd?Oe.listRefs({environmentId:I.environmentId,input:{cwd:X.data.cwd,includeMatchingRemoteRefs:!0,refKind:`remote`,...k.trim().length>0?{query:k.trim()}:{},limit:100}}):null),yt=tt(_t.data?.refs.filter(e=>e.name!==Z?.headRef)??[],vt.data?.refs??[]),bt=nt(yt,k),xt=e=>K&&K===e.remote?.name?K:e.local?.name??e.remote?.name??e.id,St=[H,...yt.map(xt)],Ct=[...k.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)(()=>Re(Tt,`diff-panel:${u}`,{compactPartialHunkOffsets:W===null}),[u,Tt,W]),At=(0,F.useMemo)(()=>!Q||Q.kind!==`files`?[]:Q.files.toSorted((e,t)=>Ae(e).localeCompare(Ae(t),void 0,{numeric:!0,sensitivity:`base`})),[Q]),$=(0,F.useMemo)(()=>At.map(e=>{let t=Fe(e);return{fileDiff:e,filePath:Ae(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)(()=>Ne(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=ce({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`&&!a(t)&&console.warn(`Failed to open diff file in editor.`,{operation:`open-diff-file`,environmentId:r.environmentId,threadId:r.threadId,...o(te(t))})})()}})},[R,Pt,Xe,r]),It=(0,F.useCallback)(e=>{De(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)(()=>{De(e=>{let t=e.scopeKey===Y?e.fileKeys:rt;return{scopeKey:Y,fileKeys:oe(jt,t)}})},[Y,jt]),Rt=e=>{P.getState().selectTurn(r,e)},zt=e=>{P.getState().selectGitScope(r,e)},Bt=e=>{P.getState().selectBranchBaseRef(r,e)};return(0,L.jsx)(ge,{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)(s,{children:[(0,L.jsxs)(d,{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)(_,{className:`size-3.5 shrink-0 text-muted-foreground`})]}),(0,L.jsxs)(re,{align:`start`,className:`w-60`,children:[(0,L.jsx)(c,{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)(c,{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)(c,{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)(ne,{children:[(0,L.jsx)(ee,{children:`Turn`}),(0,L.jsx)(p,{className:`w-64`,children:U.map(e=>{let t=e.checkpointTurnCount??V[e.turnId]??`?`;return(0,L.jsxs)(c,{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:Be(e.completedAt,y.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)(be,{className:`size-3.5 shrink-0 opacity-70`}),(0,L.jsxs)(Le,{items:St,filteredItems:Ct,value:K??H,onOpenChange:e=>{e||_e(``)},onValueChange:e=>{e&&Bt(e===H?null:e)},children:[(0,L.jsxs)(Pe,{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)(_,{className:`size-3.5 shrink-0 opacity-70`})]}),(0,L.jsxs)(we,{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)(Ve,{"aria-hidden":`true`,className:`pointer-events-none absolute top-1.5 left-0 size-4 shrink-0 text-muted-foreground/55`}),(0,L.jsx)(ke,{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:k,onChange:e=>_e(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)(xe,{children:`No matching refs.`}),(0,L.jsxs)(Ce,{className:`max-h-64 min-w-0 overflow-x-hidden`,children:[(0,L.jsx)(ze,{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)(ze,{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)(Me,{"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)(w,{"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)(Te,{additions:Nt.additions,deletions:Nt.deletions,className:`mr-1 text-[11px]`,layout:`inline`}),$.length>0&&(0,L.jsxs)(b,{children:[(0,L.jsx)(T,{render:(0,L.jsx)(g,{type:`button`,size:`icon-xs`,variant:`outline`,"aria-label":Mt?`Expand all files`:`Collapse all files`,onClick:Lt}),children:Mt?(0,L.jsx)(je,{className:`size-3`}):(0,L.jsx)(Ie,{className:`size-3`})}),(0,L.jsx)(v,{side:`top`,children:Mt?`Expand all files`:`Collapse all files`})]}),(0,L.jsxs)(A,{className:`shrink-0`,variant:`outline`,size:`xs`,value:[x],onValueChange:e=>{let t=e[0];(t===`stacked`||t===`split`)&&S(t)},children:[(0,L.jsx)(se,{"aria-label":`Stacked diff view`,value:`stacked`,children:(0,L.jsx)(j,{className:`size-3`})}),(0,L.jsx)(se,{"aria-label":`Split diff view`,value:`split`,children:(0,L.jsx)(N,{className:`size-3`})})]}),(0,L.jsxs)(b,{children:[(0,L.jsx)(T,{render:(0,L.jsx)(se,{"aria-label":C?`Disable diff line wrapping`:`Enable diff line wrapping`,variant:`outline`,size:`xs`,pressed:C,onPressedChange:e=>{E(!!e)}}),children:(0,L.jsx)(pe,{className:`size-3`})}),(0,L.jsx)(v,{side:`top`,children:C?`Disable line wrapping`:`Enable line wrapping`})]}),(0,L.jsxs)(b,{children:[(0,L.jsx)(T,{render:(0,L.jsx)(se,{"aria-label":D?`Show whitespace changes`:`Hide whitespace changes`,variant:`outline`,size:`xs`,pressed:D,onPressedChange:e=>{O(!!e)}}),children:(0,L.jsx)(We,{className:`size-3`})}),(0,L.jsx)(v,{side:`top`,children:D?`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=Ae(e);return(0,L.jsxs)(b,{children:[(0,L.jsx)(T,{render:(0,L.jsx)(`button`,{type:`button`,className:f(`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`,ye(e)),"aria-label":n?`Expand ${r}`:`Collapse ${r}`,"aria-expanded":!n,onClick:e=>{e.stopPropagation(),It(t)}}),children:n?(0,L.jsx)(i,{className:`size-4`}):(0,L.jsx)(_,{className:`size-4`})}),(0,L.jsx)(v,{side:`top`,children:n?`Expand diff`:`Collapse diff`})]})},options:{diffStyle:x===`split`?`split`:`unified`,lineDiffType:`none`,overflow:C?`wrap`:`scroll`,theme:Se(u),themeType:u,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:f(`max-h-[72vh] rounded-md border border-border/70 bg-background/70 p-3 font-mono text-[11px] leading-relaxed text-muted-foreground/90`,C?`overflow-auto whitespace-pre-wrap wrap-break-word`:`overflow-auto`),children:Q.text})]})}):Dt?(0,L.jsx)(de,{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{_e as DiffWorkerPoolProvider,U as default};
|
|
98
|
+
//# sourceMappingURL=DiffPanel-C8FwdU8R.js.map
|