@mduan/paseo-cli 0.11.0-fork.1 → 0.11.0-fork.3
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/node_modules/@getpaseo/client/package.json +3 -3
- package/node_modules/@getpaseo/highlight/package.json +1 -1
- package/node_modules/@getpaseo/plugin/package.json +3 -3
- package/node_modules/@getpaseo/protocol/dist/agent-types.d.ts +3 -0
- package/node_modules/@getpaseo/protocol/dist/generated/validation/ws-outbound.aot.js +337 -1
- package/node_modules/@getpaseo/protocol/dist/messages.js +4 -0
- package/node_modules/@getpaseo/protocol/package.json +1 -1
- package/node_modules/@getpaseo/relay/package.json +1 -1
- package/node_modules/@getpaseo/server/dist/server/builtin-plugins/package.json +1 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-manager.d.ts +2 -2
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-manager.js +5 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-projections.js +4 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-sdk-types.d.ts +8 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-storage.d.ts +2 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-storage.js +2 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/cost.d.ts +17 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/cost.js +25 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/subtitle-format.d.ts +8 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/subtitle-format.js +22 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/appended-lines-reader.d.ts +20 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/appended-lines-reader.js +59 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/agent.js +147 -4
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/live-source.d.ts +6 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/live-source.js +33 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/presentation.d.ts +4 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/presentation.js +6 -8
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/replay-source.d.ts +13 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/replay-source.js +44 -22
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/transcript-cost.d.ts +18 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/transcript-cost.js +50 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/pricing.d.ts +15 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/pricing.js +32 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.d.ts +4 -8
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.js +11 -51
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.d.ts +7 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.js +119 -17
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/snapshot.d.ts +14 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/snapshot.js +91 -4
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/store.d.ts +3 -3
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/store.js +24 -18
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-930503b4f858c84de293b25a88bddcd5.js → desktop-attachment-bridge-6eaa3854bb0e0bf2260c50ed5acac196.js} +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6eaa3854bb0e0bf2260c50ed5acac196.js.br +4 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6eaa3854bb0e0bf2260c50ed5acac196.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-46b63a296048f752e9cace2869e65020.js → desktop-attachment-store-f093e6af17b9293a6d18bd73214b3172.js} +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-46b63a296048f752e9cace2869e65020.js.br → desktop-attachment-store-f093e6af17b9293a6d18bd73214b3172.js.br} +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-f093e6af17b9293a6d18bd73214b3172.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{index-9489c4e1587c4252f0bd3b6e4b1abab3.js → index-ac557a7bf2f9db15fc71b6d2cbb3fcf7.js} +748 -747
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-ac557a7bf2f9db15fc71b6d2cbb3fcf7.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-ac557a7bf2f9db15fc71b6d2cbb3fcf7.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-4443393854050b1919467b89f1cbafc4.js → indexeddb-attachment-store-c1b8c035b248805cc62bb0f7b8e50acc.js} +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-4443393854050b1919467b89f1cbafc4.js.br → indexeddb-attachment-store-c1b8c035b248805cc62bb0f7b8e50acc.js.br} +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c1b8c035b248805cc62bb0f7b8e50acc.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-d5f9e56b2ce163fcb45fa34b52e2c3d1.js → native-file-attachment-store-c3b75054cb85e7c8b21aedadaf7d54f3.js} +3 -3
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-c3b75054cb85e7c8b21aedadaf7d54f3.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-c3b75054cb85e7c8b21aedadaf7d54f3.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.gz +0 -0
- package/node_modules/@getpaseo/server/package.json +6 -6
- package/package.json +7 -7
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-930503b4f858c84de293b25a88bddcd5.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-930503b4f858c84de293b25a88bddcd5.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-46b63a296048f752e9cace2869e65020.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-9489c4e1587c4252f0bd3b6e4b1abab3.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-9489c4e1587c4252f0bd3b6e4b1abab3.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-4443393854050b1919467b89f1cbafc4.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-d5f9e56b2ce163fcb45fa34b52e2c3d1.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-d5f9e56b2ce163fcb45fa34b52e2c3d1.js.gz +0 -0
package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.js
CHANGED
|
@@ -11,8 +11,10 @@ import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
|
|
|
11
11
|
import { composeSystemPromptParts } from "../system-prompt.js";
|
|
12
12
|
import { curateAgentActivity } from "../activity-curator.js";
|
|
13
13
|
import { CodexAsyncQuestions, codexAsyncQuestionToTimeline } from "./codex/async-questions.js";
|
|
14
|
-
import {
|
|
14
|
+
import { getSharedCodexPriceList } from "./codex/pricing.js";
|
|
15
15
|
import { CodexRolloutCost } from "./codex/rollout-cost.js";
|
|
16
|
+
import { rollupProviderSubagentCosts } from "../provider-subagents/cost.js";
|
|
17
|
+
import { formatSubagentCosts, formatSubagentTokens, } from "../provider-subagents/subtitle-format.js";
|
|
16
18
|
import { mapCodexToolCallEnvelope, mapCodexToolCallFromThreadItem, normalizeCommandExecutionCommand, splitCodexMcpToolResultImages, } from "./codex/tool-call-mapper.js";
|
|
17
19
|
import { checkProviderLaunchAvailable, createProviderEnv, createProviderEnvSpec, resolveProviderLaunch, } from "../provider-launch-config.js";
|
|
18
20
|
import { findExecutable, probeExecutable, } from "../../../executable-resolution/executable-resolution.js";
|
|
@@ -723,12 +725,6 @@ function filterCodexThreadsByCwd(threads, cwd) {
|
|
|
723
725
|
const belongsToWorkspace = createPathEquivalenceMatcher(cwd);
|
|
724
726
|
return threads.filter((thread) => typeof thread.cwd === "string" && belongsToWorkspace(thread.cwd));
|
|
725
727
|
}
|
|
726
|
-
let sharedCodexPriceList;
|
|
727
|
-
// One price list per daemon, so every Codex session and custom Codex provider shares one fetch.
|
|
728
|
-
function getSharedCodexPriceList(logger) {
|
|
729
|
-
sharedCodexPriceList ?? (sharedCodexPriceList = new CodexPriceList({ logger }));
|
|
730
|
-
return sharedCodexPriceList;
|
|
731
|
-
}
|
|
732
728
|
var CodexCostStatus;
|
|
733
729
|
(function (CodexCostStatus) {
|
|
734
730
|
/** No priced request yet, an unpriced model, or no rollout file. */
|
|
@@ -750,16 +746,34 @@ function isSameCostEstimate(left, right) {
|
|
|
750
746
|
}
|
|
751
747
|
return left.status === right.status;
|
|
752
748
|
}
|
|
753
|
-
//
|
|
749
|
+
// All cost fields are always written, undefined included, so the agent manager's usage merge on
|
|
754
750
|
// turn completion cannot keep a stale value from the previous state.
|
|
755
|
-
function withCostEstimate(usage, estimate) {
|
|
751
|
+
function withCostEstimate(usage, estimate, subagentCostUsd) {
|
|
756
752
|
switch (estimate.status) {
|
|
757
753
|
case CodexCostStatus.Estimated:
|
|
758
|
-
return {
|
|
754
|
+
return {
|
|
755
|
+
...usage,
|
|
756
|
+
...(subagentCostUsd > 0 ? { subagentCostUsd } : { subagentCostUsd: undefined }),
|
|
757
|
+
totalCostUsd: estimate.costUsd + subagentCostUsd,
|
|
758
|
+
totalCostUnavailable: false,
|
|
759
|
+
totalCostEstimated: true,
|
|
760
|
+
};
|
|
759
761
|
case CodexCostStatus.Unavailable:
|
|
760
|
-
return {
|
|
762
|
+
return {
|
|
763
|
+
...usage,
|
|
764
|
+
subagentCostUsd: undefined,
|
|
765
|
+
totalCostUsd: undefined,
|
|
766
|
+
totalCostUnavailable: true,
|
|
767
|
+
totalCostEstimated: undefined,
|
|
768
|
+
};
|
|
761
769
|
case CodexCostStatus.Pending:
|
|
762
|
-
return {
|
|
770
|
+
return {
|
|
771
|
+
...usage,
|
|
772
|
+
subagentCostUsd: undefined,
|
|
773
|
+
totalCostUsd: undefined,
|
|
774
|
+
totalCostUnavailable: undefined,
|
|
775
|
+
totalCostEstimated: undefined,
|
|
776
|
+
};
|
|
763
777
|
}
|
|
764
778
|
}
|
|
765
779
|
export function toAgentUsage(tokenUsage) {
|
|
@@ -2598,6 +2612,7 @@ export class CodexAppServerAgentSession {
|
|
|
2598
2612
|
this.emittedProviderSubagentUserMessageKeys = new Set();
|
|
2599
2613
|
this.subAgentCallsByCallId = new Map();
|
|
2600
2614
|
this.subAgentCallIdByChildThreadId = new Map();
|
|
2615
|
+
this.subAgentUsageByThreadId = new Map();
|
|
2601
2616
|
this.pendingSubAgentNotificationsByThreadId = new Map();
|
|
2602
2617
|
this.warnedUnknownNotificationMethods = new Set();
|
|
2603
2618
|
this.warnedInvalidNotificationPayloads = new Set();
|
|
@@ -3000,6 +3015,7 @@ export class CodexAppServerAgentSession {
|
|
|
3000
3015
|
const { timeline, subAgentRoutes } = history;
|
|
3001
3016
|
this.subAgentCallsByCallId.clear();
|
|
3002
3017
|
this.subAgentCallIdByChildThreadId.clear();
|
|
3018
|
+
this.subAgentUsageByThreadId.clear();
|
|
3003
3019
|
this.pendingSubAgentNotificationsByThreadId.clear();
|
|
3004
3020
|
this.persistedProviderSubagentEvents = [];
|
|
3005
3021
|
this.loadingPersistedHistory = true;
|
|
@@ -3041,6 +3057,9 @@ export class CodexAppServerAgentSession {
|
|
|
3041
3057
|
parentSubagentId: next.parentSubagentId,
|
|
3042
3058
|
});
|
|
3043
3059
|
try {
|
|
3060
|
+
const usage = {};
|
|
3061
|
+
this.subAgentUsageByThreadId.set(next.route.childThreadId, usage);
|
|
3062
|
+
await this.refreshSubAgentCost(next.route.childThreadId, usage, client);
|
|
3044
3063
|
const childHistory = await loadCodexThreadHistoryTimeline({
|
|
3045
3064
|
threadId: next.route.childThreadId,
|
|
3046
3065
|
cwd: this.config.cwd ?? null,
|
|
@@ -4271,6 +4290,9 @@ export class CodexAppServerAgentSession {
|
|
|
4271
4290
|
}
|
|
4272
4291
|
dispatchSubAgentNotification(parsed, callId) {
|
|
4273
4292
|
switch (parsed.kind) {
|
|
4293
|
+
case "token_usage_updated":
|
|
4294
|
+
this.handleSubAgentTokenUsage(parsed);
|
|
4295
|
+
return;
|
|
4274
4296
|
case "thread_started":
|
|
4275
4297
|
this.emitSubAgentActivityUpdate(callId, "running", { reopen: true });
|
|
4276
4298
|
return;
|
|
@@ -4937,7 +4959,10 @@ export class CodexAppServerAgentSession {
|
|
|
4937
4959
|
}
|
|
4938
4960
|
handleTokenUsageUpdatedNotification(parsed) {
|
|
4939
4961
|
const usage = toAgentUsage(parsed.tokenUsage);
|
|
4940
|
-
|
|
4962
|
+
const subagentCostUsd = this.subagentCostRollup().totalCostUsd;
|
|
4963
|
+
this.latestUsage = usage
|
|
4964
|
+
? withCostEstimate(usage, this.costEstimate, subagentCostUsd)
|
|
4965
|
+
: undefined;
|
|
4941
4966
|
if (this.latestUsage) {
|
|
4942
4967
|
this.notifySubscribers({
|
|
4943
4968
|
type: "usage_updated",
|
|
@@ -4947,6 +4972,83 @@ export class CodexAppServerAgentSession {
|
|
|
4947
4972
|
}
|
|
4948
4973
|
void this.refreshRolloutCost();
|
|
4949
4974
|
}
|
|
4975
|
+
handleSubAgentTokenUsage(parsed) {
|
|
4976
|
+
const threadId = parsed.threadId;
|
|
4977
|
+
if (!threadId)
|
|
4978
|
+
return;
|
|
4979
|
+
let usage = this.subAgentUsageByThreadId.get(threadId);
|
|
4980
|
+
if (!usage) {
|
|
4981
|
+
usage = {};
|
|
4982
|
+
this.subAgentUsageByThreadId.set(threadId, usage);
|
|
4983
|
+
}
|
|
4984
|
+
// The last request's context, which is what the Claude subagent rows report as tokens too.
|
|
4985
|
+
usage.tokens = toAgentUsage(parsed.tokenUsage)?.contextWindowUsedTokens;
|
|
4986
|
+
this.emitSubAgentSubtitle(threadId, usage);
|
|
4987
|
+
void this.refreshSubAgentCost(threadId, usage);
|
|
4988
|
+
}
|
|
4989
|
+
async refreshSubAgentCost(threadId, usage, client = this.client) {
|
|
4990
|
+
const priceList = this.deps.codexPriceList;
|
|
4991
|
+
if (!priceList)
|
|
4992
|
+
return;
|
|
4993
|
+
try {
|
|
4994
|
+
usage.rolloutCost ?? (usage.rolloutCost = this.openRolloutCost(threadId, client));
|
|
4995
|
+
const rolloutCost = await usage.rolloutCost;
|
|
4996
|
+
const prices = await priceList.get();
|
|
4997
|
+
if (!rolloutCost || !prices)
|
|
4998
|
+
return;
|
|
4999
|
+
usage.costUsd = await rolloutCost.read({ prices, serviceTier: this.serviceTier });
|
|
5000
|
+
usage.model = rolloutCost.model;
|
|
5001
|
+
if (this.subAgentUsageByThreadId.get(threadId) !== usage)
|
|
5002
|
+
return;
|
|
5003
|
+
this.refreshCostPresentation();
|
|
5004
|
+
}
|
|
5005
|
+
catch (error) {
|
|
5006
|
+
usage.rolloutCost = undefined;
|
|
5007
|
+
this.logger.warn({ error, threadId }, "Failed to read a Codex subagent rollout for its cost");
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
emitSubAgentSubtitle(threadId, usage, subagentCostUsd = 0) {
|
|
5011
|
+
// A provider subtitle replaces the row's agent type, so it leads with it.
|
|
5012
|
+
const callId = this.subAgentCallIdByChildThreadId.get(threadId);
|
|
5013
|
+
const detail = callId ? this.subAgentCallsByCallId.get(callId)?.toolCall.detail : undefined;
|
|
5014
|
+
const subtitle = [
|
|
5015
|
+
detail?.type === "sub_agent" ? (detail.subAgentType ?? "Codex subagent") : undefined,
|
|
5016
|
+
usage.model,
|
|
5017
|
+
formatSubagentTokens(usage.tokens),
|
|
5018
|
+
...formatSubagentCosts({ ownCostUsd: usage.costUsd, subagentCostUsd }),
|
|
5019
|
+
]
|
|
5020
|
+
.filter((part) => part !== undefined)
|
|
5021
|
+
.join(" · ");
|
|
5022
|
+
if (!subtitle || subtitle === usage.subtitle)
|
|
5023
|
+
return;
|
|
5024
|
+
usage.subtitle = subtitle;
|
|
5025
|
+
this.emitEvent({
|
|
5026
|
+
type: "provider_subagent",
|
|
5027
|
+
provider: CODEX_PROVIDER,
|
|
5028
|
+
event: { type: "upsert", id: threadId, subtitle },
|
|
5029
|
+
});
|
|
5030
|
+
}
|
|
5031
|
+
subagentCostRollup() {
|
|
5032
|
+
return rollupProviderSubagentCosts([...this.subAgentCallIdByChildThreadId].map(([threadId, callId]) => ({
|
|
5033
|
+
id: threadId,
|
|
5034
|
+
parentSubagentId: this.subAgentCallsByCallId.get(callId)?.parentSubagentId ?? null,
|
|
5035
|
+
ownCostUsd: this.subAgentUsageByThreadId.get(threadId)?.costUsd ?? 0,
|
|
5036
|
+
})));
|
|
5037
|
+
}
|
|
5038
|
+
refreshCostPresentation() {
|
|
5039
|
+
const costs = this.subagentCostRollup();
|
|
5040
|
+
for (const [threadId, usage] of this.subAgentUsageByThreadId) {
|
|
5041
|
+
this.emitSubAgentSubtitle(threadId, usage, costs.byId.get(threadId)?.subagentCostUsd);
|
|
5042
|
+
}
|
|
5043
|
+
if (!this.latestUsage)
|
|
5044
|
+
return;
|
|
5045
|
+
this.latestUsage = withCostEstimate(this.latestUsage, this.costEstimate, costs.totalCostUsd);
|
|
5046
|
+
this.notifySubscribers({
|
|
5047
|
+
type: "usage_updated",
|
|
5048
|
+
provider: CODEX_PROVIDER,
|
|
5049
|
+
usage: this.latestUsage,
|
|
5050
|
+
});
|
|
5051
|
+
}
|
|
4950
5052
|
async refreshRolloutCost() {
|
|
4951
5053
|
const threadId = this.currentThreadId;
|
|
4952
5054
|
const priceList = this.deps.codexPriceList;
|
|
@@ -4979,17 +5081,17 @@ export class CodexAppServerAgentSession {
|
|
|
4979
5081
|
this.costEstimate = estimate;
|
|
4980
5082
|
if (!this.latestUsage)
|
|
4981
5083
|
return;
|
|
4982
|
-
this.latestUsage = withCostEstimate(this.latestUsage, estimate);
|
|
5084
|
+
this.latestUsage = withCostEstimate(this.latestUsage, estimate, this.subagentCostRollup().totalCostUsd);
|
|
4983
5085
|
this.notifySubscribers({
|
|
4984
5086
|
type: "usage_updated",
|
|
4985
5087
|
provider: CODEX_PROVIDER,
|
|
4986
5088
|
usage: this.latestUsage,
|
|
4987
5089
|
});
|
|
4988
5090
|
}
|
|
4989
|
-
async openRolloutCost(threadId) {
|
|
4990
|
-
if (!
|
|
5091
|
+
async openRolloutCost(threadId, client = this.client) {
|
|
5092
|
+
if (!client)
|
|
4991
5093
|
return undefined;
|
|
4992
|
-
const response = toObjectRecord(await
|
|
5094
|
+
const response = toObjectRecord(await client.request("thread/read", { threadId, includeTurns: false }));
|
|
4993
5095
|
// Thread.path is marked unstable in the app-server schema; without it there is no estimate.
|
|
4994
5096
|
const rolloutPath = toObjectRecord(response?.thread)?.path;
|
|
4995
5097
|
return typeof rolloutPath === "string" ? new CodexRolloutCost(rolloutPath) : undefined;
|
|
@@ -3,12 +3,26 @@ export interface WorkingTreeSnapshot {
|
|
|
3
3
|
repoRoot: string;
|
|
4
4
|
tree: string;
|
|
5
5
|
}
|
|
6
|
+
export type TurnStartSnapshot = WorkingTreeSnapshot & {
|
|
7
|
+
head?: string;
|
|
8
|
+
headLogPath: string;
|
|
9
|
+
headLogSize: number;
|
|
10
|
+
};
|
|
6
11
|
/**
|
|
7
12
|
* Writes the whole working tree (tracked changes plus untracked, non-ignored files up to 1 MiB)
|
|
8
13
|
* as a git tree object. Staging goes through a copy of the index, so the user's index, HEAD and
|
|
9
14
|
* branches are untouched; only git objects are written.
|
|
10
15
|
*/
|
|
11
16
|
export declare function snapshotWorkingTree(cwd: string): Promise<WorkingTreeSnapshot | null>;
|
|
17
|
+
/** A working tree snapshot plus where HEAD and its reflog stood, to separate out branch moves. */
|
|
18
|
+
export declare function snapshotTurnStart(cwd: string): Promise<TurnStartSnapshot | null>;
|
|
19
|
+
/**
|
|
20
|
+
* The tree to diff a turn from. When the turn moved HEAD to another commit, the start snapshot's
|
|
21
|
+
* uncommitted changes are replayed onto where HEAD landed, so the diff holds the agent's edits and
|
|
22
|
+
* commits and none of the content the move brought in. Undefined when that can't be worked out
|
|
23
|
+
* (no reflog, unborn branch, replay conflict); the turn then gets no diff.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveTurnFromTree(start: TurnStartSnapshot): Promise<string | undefined>;
|
|
12
26
|
export declare function diffTreeStats(params: {
|
|
13
27
|
repoRoot: string;
|
|
14
28
|
fromTree: string;
|
|
@@ -15,10 +15,14 @@ async function git(args, options) {
|
|
|
15
15
|
}
|
|
16
16
|
async function resolveRepo(cwd) {
|
|
17
17
|
try {
|
|
18
|
-
const [repoRoot, indexPath] = (await git(["rev-parse", "--show-toplevel", "--git-path", "index"], { cwd }))
|
|
18
|
+
const [repoRoot, indexPath, headLogPath] = (await git(["rev-parse", "--show-toplevel", "--git-path", "index", "--git-path", "logs/HEAD"], { cwd }))
|
|
19
19
|
.trim()
|
|
20
20
|
.split("\n");
|
|
21
|
-
return {
|
|
21
|
+
return {
|
|
22
|
+
repoRoot,
|
|
23
|
+
indexPath: path.resolve(cwd, indexPath),
|
|
24
|
+
headLogPath: path.resolve(cwd, headLogPath),
|
|
25
|
+
};
|
|
22
26
|
}
|
|
23
27
|
catch {
|
|
24
28
|
// Not a git repository (or git is missing): turn diffs are git-only.
|
|
@@ -43,6 +47,19 @@ export async function snapshotWorkingTree(cwd) {
|
|
|
43
47
|
const repo = await resolveRepo(cwd);
|
|
44
48
|
if (!repo)
|
|
45
49
|
return null;
|
|
50
|
+
return { repoRoot: repo.repoRoot, tree: await writeWorkingTree(repo) };
|
|
51
|
+
}
|
|
52
|
+
/** A working tree snapshot plus where HEAD and its reflog stood, to separate out branch moves. */
|
|
53
|
+
export async function snapshotTurnStart(cwd) {
|
|
54
|
+
const repo = await resolveRepo(cwd);
|
|
55
|
+
if (!repo)
|
|
56
|
+
return null;
|
|
57
|
+
const headLogSize = await fs.stat(repo.headLogPath).then((stat) => stat.size, () => 0);
|
|
58
|
+
const head = await readHead(repo.repoRoot);
|
|
59
|
+
const tree = await writeWorkingTree(repo);
|
|
60
|
+
return { repoRoot: repo.repoRoot, tree, head, headLogPath: repo.headLogPath, headLogSize };
|
|
61
|
+
}
|
|
62
|
+
async function writeWorkingTree(repo) {
|
|
46
63
|
const tempIndex = path.join(os.tmpdir(), `paseo-turn-index-${randomUUID()}`);
|
|
47
64
|
try {
|
|
48
65
|
const stat = await fs.stat(repo.indexPath).catch(() => null);
|
|
@@ -61,13 +78,83 @@ export async function snapshotWorkingTree(cwd) {
|
|
|
61
78
|
input: untracked.map((file) => `${file}\0`).join(""),
|
|
62
79
|
});
|
|
63
80
|
}
|
|
64
|
-
|
|
65
|
-
return { repoRoot: repo.repoRoot, tree };
|
|
81
|
+
return (await git(["write-tree"], { cwd: repo.repoRoot, env })).trim();
|
|
66
82
|
}
|
|
67
83
|
finally {
|
|
68
84
|
await fs.rm(tempIndex, { force: true });
|
|
69
85
|
}
|
|
70
86
|
}
|
|
87
|
+
async function readHead(repoRoot) {
|
|
88
|
+
try {
|
|
89
|
+
return (await git(["rev-parse", "--verify", "-q", "HEAD"], { cwd: repoRoot })).trim();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function readFileFrom(filePath, offset) {
|
|
96
|
+
const handle = await fs.open(filePath, "r").catch(() => null);
|
|
97
|
+
if (!handle)
|
|
98
|
+
return undefined;
|
|
99
|
+
try {
|
|
100
|
+
const { size } = await handle.stat();
|
|
101
|
+
if (size < offset)
|
|
102
|
+
return undefined;
|
|
103
|
+
const buffer = Buffer.alloc(size - offset);
|
|
104
|
+
await handle.read(buffer, 0, buffer.length, offset);
|
|
105
|
+
return buffer.toString("utf8");
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
await handle.close();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const OWN_COMMIT_MESSAGE = /^commit( \((initial|amend)\))?: /;
|
|
112
|
+
/**
|
|
113
|
+
* The commit HEAD landed on after the turn's last branch move (checkout, reset, pull, merge,
|
|
114
|
+
* rebase, cherry-pick), read from the reflog lines the turn appended. Undefined when HEAD only
|
|
115
|
+
* moved by the agent's own commits; null when the reflog can't tell.
|
|
116
|
+
*/
|
|
117
|
+
async function findLastBranchMove(start) {
|
|
118
|
+
const appended = await readFileFrom(start.headLogPath, start.headLogSize);
|
|
119
|
+
if (appended === undefined)
|
|
120
|
+
return null;
|
|
121
|
+
let landing;
|
|
122
|
+
for (const line of appended.split("\n")) {
|
|
123
|
+
// <old> <new> <identity> <time> <tz>\t<message>
|
|
124
|
+
const [header, message = ""] = line.split("\t", 2);
|
|
125
|
+
const [oldHead, newHead] = header.split(" ");
|
|
126
|
+
if (!newHead || oldHead === newHead || OWN_COMMIT_MESSAGE.test(message))
|
|
127
|
+
continue;
|
|
128
|
+
landing = newHead;
|
|
129
|
+
}
|
|
130
|
+
return landing;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The tree to diff a turn from. When the turn moved HEAD to another commit, the start snapshot's
|
|
134
|
+
* uncommitted changes are replayed onto where HEAD landed, so the diff holds the agent's edits and
|
|
135
|
+
* commits and none of the content the move brought in. Undefined when that can't be worked out
|
|
136
|
+
* (no reflog, unborn branch, replay conflict); the turn then gets no diff.
|
|
137
|
+
*/
|
|
138
|
+
export async function resolveTurnFromTree(start) {
|
|
139
|
+
const head = await readHead(start.repoRoot);
|
|
140
|
+
if (head === start.head)
|
|
141
|
+
return start.tree;
|
|
142
|
+
if (!head || !start.head)
|
|
143
|
+
return undefined;
|
|
144
|
+
const landing = await findLastBranchMove(start);
|
|
145
|
+
if (landing === null)
|
|
146
|
+
return undefined;
|
|
147
|
+
if (landing === undefined || landing === start.head)
|
|
148
|
+
return start.tree;
|
|
149
|
+
try {
|
|
150
|
+
const output = await git(["merge-tree", "--write-tree", `--merge-base=${start.head}`, landing, start.tree], { cwd: start.repoRoot });
|
|
151
|
+
return output.split("\n")[0];
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Exit code 1: the start's uncommitted changes conflict with where HEAD landed.
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
71
158
|
export async function diffTreeStats(params) {
|
|
72
159
|
if (params.fromTree === params.toTree)
|
|
73
160
|
return [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Logger } from "pino";
|
|
2
2
|
import { type AgentTurnDiffTarget, type TurnDiffSummary } from "../../messages.js";
|
|
3
|
-
import { type
|
|
3
|
+
import { type TurnStartSnapshot } from "./snapshot.js";
|
|
4
4
|
export interface TurnDiffRange {
|
|
5
5
|
repoRoot: string;
|
|
6
6
|
fromTree: string;
|
|
@@ -8,7 +8,7 @@ export interface TurnDiffRange {
|
|
|
8
8
|
}
|
|
9
9
|
export interface RecordTurnInput {
|
|
10
10
|
agentId: string;
|
|
11
|
-
start:
|
|
11
|
+
start: TurnStartSnapshot;
|
|
12
12
|
turnId: string;
|
|
13
13
|
userMessageIds: string[];
|
|
14
14
|
}
|
|
@@ -21,7 +21,7 @@ export declare class TurnDiffStore {
|
|
|
21
21
|
private readonly logger;
|
|
22
22
|
private readonly queues;
|
|
23
23
|
constructor(dir: string, logger: Logger);
|
|
24
|
-
captureStart(cwd: string): Promise<
|
|
24
|
+
captureStart(cwd: string): Promise<TurnStartSnapshot | null>;
|
|
25
25
|
recordTurn(input: RecordTurnInput): Promise<void>;
|
|
26
26
|
list(agentId: string): Promise<TurnDiffSummary[]>;
|
|
27
27
|
resolveRange(agentId: string, target: AgentTurnDiffTarget): Promise<TurnDiffRange | null>;
|
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
import { withTimeout } from "../../../utils/promise-timeout.js";
|
|
5
5
|
import { writeJsonFileAtomic } from "../../atomic-file.js";
|
|
6
6
|
import { TurnDiffFileStatSchema, } from "../../messages.js";
|
|
7
|
-
import { diffTreeStats, snapshotWorkingTree, syncTreeRefs, } from "./snapshot.js";
|
|
7
|
+
import { diffTreeStats, resolveTurnFromTree, snapshotTurnStart, snapshotWorkingTree, syncTreeRefs, } from "./snapshot.js";
|
|
8
8
|
// The prompt waits for the start snapshot; past this, the turn goes without a diff.
|
|
9
9
|
const START_SNAPSHOT_TIMEOUT_MS = 2000;
|
|
10
10
|
const MAX_STORED_TURNS = 200;
|
|
@@ -17,15 +17,18 @@ const StoredTurnSchema = TreeRangeSchema.extend({
|
|
|
17
17
|
});
|
|
18
18
|
const TurnDiffRecordSchema = z.object({
|
|
19
19
|
repoRoot: z.string(),
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
lastTurn: TreeRangeSchema,
|
|
20
|
+
// Most recent finished turn, kept even when it changed nothing. Absent when the turn moved HEAD
|
|
21
|
+
// in a way its diff couldn't be separated from.
|
|
22
|
+
lastTurn: TreeRangeSchema.optional(),
|
|
24
23
|
// Turns that changed files, oldest first.
|
|
25
24
|
turns: z.array(StoredTurnSchema),
|
|
26
25
|
});
|
|
27
26
|
function referencedTrees(record) {
|
|
28
|
-
const trees = new Set(
|
|
27
|
+
const trees = new Set();
|
|
28
|
+
if (record.lastTurn) {
|
|
29
|
+
trees.add(record.lastTurn.fromTree);
|
|
30
|
+
trees.add(record.lastTurn.toTree);
|
|
31
|
+
}
|
|
29
32
|
for (const turn of record.turns) {
|
|
30
33
|
trees.add(turn.fromTree);
|
|
31
34
|
trees.add(turn.toTree);
|
|
@@ -53,7 +56,7 @@ export class TurnDiffStore {
|
|
|
53
56
|
async captureStart(cwd) {
|
|
54
57
|
try {
|
|
55
58
|
return await withTimeout({
|
|
56
|
-
promise:
|
|
59
|
+
promise: snapshotTurnStart(cwd),
|
|
57
60
|
timeoutMs: START_SNAPSHOT_TIMEOUT_MS,
|
|
58
61
|
label: "Turn start snapshot",
|
|
59
62
|
});
|
|
@@ -77,9 +80,11 @@ export class TurnDiffStore {
|
|
|
77
80
|
const { repoRoot } = record;
|
|
78
81
|
switch (target.kind) {
|
|
79
82
|
case "last_turn":
|
|
80
|
-
return { repoRoot, ...record.lastTurn };
|
|
83
|
+
return record.lastTurn ? { repoRoot, ...record.lastTurn } : null;
|
|
84
|
+
// COMPAT(turnDiffSession): added in v0.11.0-beta.3, remove after 2027-01-04. Older clients
|
|
85
|
+
// can still ask for the removed Chat Session diff; it is always unavailable.
|
|
81
86
|
case "session":
|
|
82
|
-
return
|
|
87
|
+
return null;
|
|
83
88
|
case "turn": {
|
|
84
89
|
const turn = record.turns.find((candidate) => candidate.turnId === target.turnId);
|
|
85
90
|
return turn ? { repoRoot, fromTree: turn.fromTree, toTree: turn.toTree } : null;
|
|
@@ -99,26 +104,27 @@ export class TurnDiffStore {
|
|
|
99
104
|
const end = await snapshotWorkingTree(start.repoRoot);
|
|
100
105
|
if (!end)
|
|
101
106
|
return;
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
const fromTree = await resolveTurnFromTree(start);
|
|
108
|
+
if (!fromTree) {
|
|
109
|
+
this.logger.info({ agentId, turnId }, "Turn moved HEAD in a way its diff can't separate");
|
|
110
|
+
}
|
|
111
|
+
const files = fromTree
|
|
112
|
+
? await diffTreeStats({ repoRoot: start.repoRoot, fromTree, toTree: end.tree })
|
|
113
|
+
: [];
|
|
107
114
|
const previous = await this.read(agentId);
|
|
108
115
|
const isSameRepo = previous?.repoRoot === start.repoRoot;
|
|
109
116
|
const record = {
|
|
110
117
|
repoRoot: start.repoRoot,
|
|
111
|
-
|
|
112
|
-
lastTurn: { fromTree: start.tree, toTree: end.tree },
|
|
118
|
+
lastTurn: fromTree ? { fromTree, toTree: end.tree } : undefined,
|
|
113
119
|
turns: isSameRepo ? previous.turns : [],
|
|
114
120
|
};
|
|
115
|
-
if (files.length > 0) {
|
|
121
|
+
if (fromTree && files.length > 0) {
|
|
116
122
|
const completedAt = new Date().toISOString();
|
|
117
123
|
const turn = {
|
|
118
124
|
turnId,
|
|
119
125
|
userMessageIds,
|
|
120
126
|
completedAt,
|
|
121
|
-
fromTree
|
|
127
|
+
fromTree,
|
|
122
128
|
toTree: end.tree,
|
|
123
129
|
files,
|
|
124
130
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},
|
|
1
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},5138,[4429,4430]);
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},
|
|
1
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},5137,[4247]);
|