lody 0.50.1 → 0.51.0
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/index.js +1844 -417
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import require$$3$5, { randomUUID,
|
|
2
|
+
import require$$3$5, { randomUUID, createHash as createHash$1, randomBytes } from "crypto";
|
|
3
3
|
import require$$0$5, { inspect as inspect$1, types as types$6 } from "util";
|
|
4
4
|
import require$$2$6 from "url";
|
|
5
5
|
import * as path$2 from "path";
|
|
@@ -56,6 +56,7 @@ import fsPromises, { stat, open } from "node:fs/promises";
|
|
|
56
56
|
import { fileURLToPath } from "node:url";
|
|
57
57
|
import require$$2$7 from "assert";
|
|
58
58
|
import { performance as performance$1 } from "perf_hooks";
|
|
59
|
+
import { createRequire as createRequire$1 } from "node:module";
|
|
59
60
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
60
61
|
import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
|
|
61
62
|
let program;
|
|
@@ -36821,7 +36822,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
|
|
|
36821
36822
|
return client;
|
|
36822
36823
|
}
|
|
36823
36824
|
const name = "lody";
|
|
36824
|
-
const version$4 = "0.
|
|
36825
|
+
const version$4 = "0.51.0";
|
|
36825
36826
|
const description$1 = "Lody Agent CLI tool for managing remote command execution";
|
|
36826
36827
|
const type$2 = "module";
|
|
36827
36828
|
const main$3 = "dist/index.js";
|
|
@@ -36865,7 +36866,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
|
|
|
36865
36866
|
};
|
|
36866
36867
|
const optionalDependencies = {
|
|
36867
36868
|
"acp-extension-claude": "0.31.1",
|
|
36868
|
-
"acp-extension-codex": "0.
|
|
36869
|
+
"acp-extension-codex": "0.14.3"
|
|
36869
36870
|
};
|
|
36870
36871
|
const devDependencies = {
|
|
36871
36872
|
"@agentclientprotocol/sdk": "catalog:",
|
|
@@ -59959,9 +59960,6 @@ ${fromBody}`;
|
|
|
59959
59960
|
function ora(options) {
|
|
59960
59961
|
return new Ora(options);
|
|
59961
59962
|
}
|
|
59962
|
-
const NEVER = Object.freeze({
|
|
59963
|
-
status: "aborted"
|
|
59964
|
-
});
|
|
59965
59963
|
function $constructor(name2, initializer2, params) {
|
|
59966
59964
|
function init2(inst, def) {
|
|
59967
59965
|
if (!inst._zod) {
|
|
@@ -66974,6 +66972,33 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
66974
66972
|
email: string$2(),
|
|
66975
66973
|
name: string$2().nullable().optional()
|
|
66976
66974
|
}).passthrough();
|
|
66975
|
+
function isRecord$6(value) {
|
|
66976
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66977
|
+
}
|
|
66978
|
+
function asRecord(value) {
|
|
66979
|
+
return isRecord$6(value) ? value : null;
|
|
66980
|
+
}
|
|
66981
|
+
function readSessionUserFromResponse(response) {
|
|
66982
|
+
if (!isRecord$6(response)) {
|
|
66983
|
+
return null;
|
|
66984
|
+
}
|
|
66985
|
+
if ("data" in response) {
|
|
66986
|
+
const nested = readSessionUserFromResponse(response.data);
|
|
66987
|
+
if (nested) {
|
|
66988
|
+
return nested;
|
|
66989
|
+
}
|
|
66990
|
+
}
|
|
66991
|
+
const user = asRecord(response.user);
|
|
66992
|
+
const parsed = SessionUserSchema.safeParse(user);
|
|
66993
|
+
if (!parsed.success) {
|
|
66994
|
+
return null;
|
|
66995
|
+
}
|
|
66996
|
+
return {
|
|
66997
|
+
id: parsed.data.id,
|
|
66998
|
+
email: parsed.data.email,
|
|
66999
|
+
name: parsed.data.name
|
|
67000
|
+
};
|
|
67001
|
+
}
|
|
66977
67002
|
const ValidateCliTokenResponseSchema = object$1({
|
|
66978
67003
|
valid: boolean(),
|
|
66979
67004
|
userId: string$2().optional(),
|
|
@@ -67278,6 +67303,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
67278
67303
|
user: existingAuth.user
|
|
67279
67304
|
};
|
|
67280
67305
|
}
|
|
67306
|
+
async getSessionUserFromSessionToken(sessionToken) {
|
|
67307
|
+
const trimmedToken = sessionToken.trim();
|
|
67308
|
+
if (!trimmedToken) {
|
|
67309
|
+
return null;
|
|
67310
|
+
}
|
|
67311
|
+
try {
|
|
67312
|
+
const response = await fetch(`${this.siteUrl}/api/auth/get-session`, {
|
|
67313
|
+
method: "GET",
|
|
67314
|
+
headers: {
|
|
67315
|
+
Authorization: `Bearer ${trimmedToken}`
|
|
67316
|
+
}
|
|
67317
|
+
});
|
|
67318
|
+
if (!response.ok) {
|
|
67319
|
+
this.logger.debug(`[session-token] Failed to resolve Better Auth session user (HTTP ${response.status})`);
|
|
67320
|
+
return null;
|
|
67321
|
+
}
|
|
67322
|
+
return readSessionUserFromResponse(await response.json().catch(() => null));
|
|
67323
|
+
} catch (error2) {
|
|
67324
|
+
this.logger.debug(`[session-token] Failed to resolve Better Auth session user: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
67325
|
+
return null;
|
|
67326
|
+
}
|
|
67327
|
+
}
|
|
67281
67328
|
async validateToken(token2) {
|
|
67282
67329
|
const validation2 = await validateExistingToken(token2, this.siteUrl);
|
|
67283
67330
|
if (!validation2.valid) {
|
|
@@ -77817,8 +77864,11 @@ Task description:
|
|
|
77817
77864
|
type: "idle"
|
|
77818
77865
|
};
|
|
77819
77866
|
},
|
|
77820
|
-
running() {
|
|
77821
|
-
return {
|
|
77867
|
+
running(activity) {
|
|
77868
|
+
return activity ? {
|
|
77869
|
+
type: "running",
|
|
77870
|
+
activity
|
|
77871
|
+
} : {
|
|
77822
77872
|
type: "running"
|
|
77823
77873
|
};
|
|
77824
77874
|
},
|
|
@@ -78612,6 +78662,27 @@ Task description:
|
|
|
78612
78662
|
localProjectId: LocalProjectIdSchema,
|
|
78613
78663
|
branchName: string$2()
|
|
78614
78664
|
}).strict();
|
|
78665
|
+
const LocalProjectHistoryProviderSchema = _enum$1([
|
|
78666
|
+
"codex",
|
|
78667
|
+
"claude"
|
|
78668
|
+
]);
|
|
78669
|
+
const LocalProjectSyncHistoryRequestSchema = object$1({
|
|
78670
|
+
type: literal("local-project/sync-history"),
|
|
78671
|
+
machineId: MachineIdSchema,
|
|
78672
|
+
workspaceId: WorkspaceIdSchema,
|
|
78673
|
+
localProjectId: LocalProjectIdSchema,
|
|
78674
|
+
provider: LocalProjectHistoryProviderSchema,
|
|
78675
|
+
requestedByUserId: string$2().trim().min(1).optional()
|
|
78676
|
+
}).strict();
|
|
78677
|
+
const LocalProjectImportHistoryRequestSchema = object$1({
|
|
78678
|
+
type: literal("local-project/import-history"),
|
|
78679
|
+
machineId: MachineIdSchema,
|
|
78680
|
+
workspaceId: WorkspaceIdSchema,
|
|
78681
|
+
localProjectId: LocalProjectIdSchema,
|
|
78682
|
+
provider: LocalProjectHistoryProviderSchema,
|
|
78683
|
+
acpSessionIds: array$3(ACPSessionIdSchema),
|
|
78684
|
+
requestedByUserId: string$2().trim().min(1).optional()
|
|
78685
|
+
}).strict();
|
|
78615
78686
|
const WorktreeListFilesRequestSchema = object$1({
|
|
78616
78687
|
type: literal("worktree/list-files"),
|
|
78617
78688
|
machineId: MachineIdSchema,
|
|
@@ -78635,6 +78706,8 @@ Task description:
|
|
|
78635
78706
|
LocalProjectListFilesRequestSchema,
|
|
78636
78707
|
LocalProjectReadFileRequestSchema,
|
|
78637
78708
|
LocalProjectCheckoutBranchRequestSchema,
|
|
78709
|
+
LocalProjectSyncHistoryRequestSchema,
|
|
78710
|
+
LocalProjectImportHistoryRequestSchema,
|
|
78638
78711
|
WorktreeListFilesRequestSchema,
|
|
78639
78712
|
WorktreeReadFileRequestSchema
|
|
78640
78713
|
]);
|
|
@@ -78676,12 +78749,45 @@ Task description:
|
|
|
78676
78749
|
error: string$2()
|
|
78677
78750
|
}).strict()
|
|
78678
78751
|
]);
|
|
78752
|
+
const LocalProjectHistorySyncSummarySchema = object$1({
|
|
78753
|
+
listed: number$3().int().nonnegative(),
|
|
78754
|
+
imported: number$3().int().nonnegative(),
|
|
78755
|
+
refreshed: number$3().int().nonnegative(),
|
|
78756
|
+
skipped: number$3().int().nonnegative(),
|
|
78757
|
+
conflicted: number$3().int().nonnegative(),
|
|
78758
|
+
failed: number$3().int().nonnegative(),
|
|
78759
|
+
failures: array$3(object$1({
|
|
78760
|
+
acpSessionId: string$2(),
|
|
78761
|
+
message: string$2()
|
|
78762
|
+
}).strict())
|
|
78763
|
+
}).strict();
|
|
78764
|
+
const LocalProjectHistoryCatalogItemSchema = object$1({
|
|
78765
|
+
acpSessionId: string$2(),
|
|
78766
|
+
title: string$2(),
|
|
78767
|
+
updatedAt: string$2().optional(),
|
|
78768
|
+
importedSessionId: string$2().optional(),
|
|
78769
|
+
status: _enum$1([
|
|
78770
|
+
"available",
|
|
78771
|
+
"imported",
|
|
78772
|
+
"sync_conflict"
|
|
78773
|
+
]).optional()
|
|
78774
|
+
}).strict();
|
|
78775
|
+
const LocalProjectHistoryCatalogResultSchema = object$1({
|
|
78776
|
+
listed: number$3().int().nonnegative(),
|
|
78777
|
+
lastListedAt: number$3().int().nonnegative(),
|
|
78778
|
+
sessions: array$3(LocalProjectHistoryCatalogItemSchema)
|
|
78779
|
+
}).strict();
|
|
78780
|
+
const LocalProjectHistoryImportResultSchema = object$1({
|
|
78781
|
+
summary: LocalProjectHistorySyncSummarySchema,
|
|
78782
|
+
catalog: LocalProjectHistoryCatalogResultSchema
|
|
78783
|
+
}).strict();
|
|
78679
78784
|
const LocalProjectControlErrorCodeSchema = _enum$1([
|
|
78680
78785
|
"invalid_request",
|
|
78681
78786
|
"machine_mismatch",
|
|
78682
78787
|
"workspace_required",
|
|
78683
78788
|
"workspace_not_found",
|
|
78684
78789
|
"daemon_unavailable",
|
|
78790
|
+
"access_denied",
|
|
78685
78791
|
"local_project_not_found",
|
|
78686
78792
|
"path_invalid",
|
|
78687
78793
|
"execution_failed",
|
|
@@ -78697,6 +78803,8 @@ Task description:
|
|
|
78697
78803
|
"local-project/list-files",
|
|
78698
78804
|
"local-project/read-file",
|
|
78699
78805
|
"local-project/checkout-branch",
|
|
78806
|
+
"local-project/sync-history",
|
|
78807
|
+
"local-project/import-history",
|
|
78700
78808
|
"worktree/list-files",
|
|
78701
78809
|
"worktree/read-file"
|
|
78702
78810
|
]),
|
|
@@ -78760,6 +78868,16 @@ Task description:
|
|
|
78760
78868
|
type: literal("local-project/checkout-branch"),
|
|
78761
78869
|
result: LocalProjectCheckoutBranchResultSchema
|
|
78762
78870
|
}).strict(),
|
|
78871
|
+
object$1({
|
|
78872
|
+
ok: literal(true),
|
|
78873
|
+
type: literal("local-project/sync-history"),
|
|
78874
|
+
result: LocalProjectHistoryCatalogResultSchema
|
|
78875
|
+
}).strict(),
|
|
78876
|
+
object$1({
|
|
78877
|
+
ok: literal(true),
|
|
78878
|
+
type: literal("local-project/import-history"),
|
|
78879
|
+
result: LocalProjectHistoryImportResultSchema
|
|
78880
|
+
}).strict(),
|
|
78763
78881
|
object$1({
|
|
78764
78882
|
ok: literal(true),
|
|
78765
78883
|
type: literal("worktree/list-files"),
|
|
@@ -79031,7 +79149,8 @@ Task description:
|
|
|
79031
79149
|
"active",
|
|
79032
79150
|
"paused",
|
|
79033
79151
|
"budgetLimited",
|
|
79034
|
-
"complete"
|
|
79152
|
+
"complete",
|
|
79153
|
+
"cleared"
|
|
79035
79154
|
]),
|
|
79036
79155
|
tokenBudget: number$3().nullable().optional(),
|
|
79037
79156
|
tokensUsed: number$3(),
|
|
@@ -79077,7 +79196,7 @@ Task description:
|
|
|
79077
79196
|
"claude",
|
|
79078
79197
|
"codex"
|
|
79079
79198
|
]);
|
|
79080
|
-
function isRecord$
|
|
79199
|
+
function isRecord$5(value) {
|
|
79081
79200
|
return typeof value === "object" && value !== null;
|
|
79082
79201
|
}
|
|
79083
79202
|
function getTrimmedString(value) {
|
|
@@ -79094,7 +79213,7 @@ Task description:
|
|
|
79094
79213
|
return value === "builtin" || value === "registry";
|
|
79095
79214
|
}
|
|
79096
79215
|
function normalizeLegacyProjectRef(value) {
|
|
79097
|
-
if (!isRecord$
|
|
79216
|
+
if (!isRecord$5(value)) {
|
|
79098
79217
|
return value;
|
|
79099
79218
|
}
|
|
79100
79219
|
const kind = value.kind;
|
|
@@ -79110,13 +79229,13 @@ Task description:
|
|
|
79110
79229
|
normalized.branch = existingBranch;
|
|
79111
79230
|
} else {
|
|
79112
79231
|
const legacyBranchFromString = getTrimmedString(legacyProject);
|
|
79113
|
-
const legacyBranchFromObject = isRecord$
|
|
79232
|
+
const legacyBranchFromObject = isRecord$5(legacyProject) ? getTrimmedString(legacyProject.branch) ?? getTrimmedString(legacyProject.project) : void 0;
|
|
79114
79233
|
const resolvedBranch = legacyBranchFromString ?? legacyBranchFromObject;
|
|
79115
79234
|
if (resolvedBranch) {
|
|
79116
79235
|
normalized.branch = resolvedBranch;
|
|
79117
79236
|
}
|
|
79118
79237
|
}
|
|
79119
|
-
if (isRecord$
|
|
79238
|
+
if (isRecord$5(legacyProject)) {
|
|
79120
79239
|
if (kind === "github" && !getTrimmedString(normalized.repoFullName)) {
|
|
79121
79240
|
const repoFullName = getTrimmedString(legacyProject.repoFullName);
|
|
79122
79241
|
if (repoFullName) {
|
|
@@ -79153,7 +79272,7 @@ Task description:
|
|
|
79153
79272
|
};
|
|
79154
79273
|
normalized.project = normalizeLegacyProjectRef(normalized.project);
|
|
79155
79274
|
const currentProject = normalized.project;
|
|
79156
|
-
const projectRecord = isRecord$
|
|
79275
|
+
const projectRecord = isRecord$5(currentProject) ? currentProject : void 0;
|
|
79157
79276
|
const explicitBranch = getTrimmedString(normalized.branch) ?? getTrimmedString(currentProject) ?? (projectRecord ? getTrimmedString(projectRecord.branch) ?? getTrimmedString(projectRecord.project) : void 0);
|
|
79158
79277
|
const repoFullName = (projectRecord ? getTrimmedString(projectRecord.repoFullName) : void 0) ?? getTrimmedString(normalized.repoFullName) ?? getTrimmedString(normalized.githubRepo);
|
|
79159
79278
|
const localProjectId = (projectRecord ? getTrimmedString(projectRecord.localProjectId) : void 0) ?? getTrimmedString(normalized.localProjectId);
|
|
@@ -79196,7 +79315,7 @@ Task description:
|
|
|
79196
79315
|
return normalized;
|
|
79197
79316
|
}
|
|
79198
79317
|
function normalizeLegacyAcpSessionConfig(value) {
|
|
79199
|
-
if (!isRecord$
|
|
79318
|
+
if (!isRecord$5(value)) {
|
|
79200
79319
|
return value;
|
|
79201
79320
|
}
|
|
79202
79321
|
const normalized = {
|
|
@@ -79231,13 +79350,13 @@ Task description:
|
|
|
79231
79350
|
return normalized;
|
|
79232
79351
|
}
|
|
79233
79352
|
function normalizeLegacySessionMessage(parsed) {
|
|
79234
|
-
if (!isRecord$
|
|
79353
|
+
if (!isRecord$5(parsed)) {
|
|
79235
79354
|
return parsed;
|
|
79236
79355
|
}
|
|
79237
79356
|
const messageType = parsed.type;
|
|
79238
79357
|
if (messageType === "session/create" || messageType === "session/chat") {
|
|
79239
79358
|
const normalized = normalizeLegacySessionProject(parsed);
|
|
79240
|
-
if (!isRecord$
|
|
79359
|
+
if (!isRecord$5(normalized)) {
|
|
79241
79360
|
return normalized;
|
|
79242
79361
|
}
|
|
79243
79362
|
normalized.acpSessionConfig = normalizeLegacyAcpSessionConfig(normalized.acpSessionConfig);
|
|
@@ -79301,6 +79420,21 @@ Task description:
|
|
|
79301
79420
|
}
|
|
79302
79421
|
}
|
|
79303
79422
|
const REGISTRY_ACP_AGENTS = [
|
|
79423
|
+
{
|
|
79424
|
+
id: "agoragentic-acp",
|
|
79425
|
+
name: "Agoragentic",
|
|
79426
|
+
version: "1.3.0",
|
|
79427
|
+
description: "Agent marketplace with 174+ AI capabilities. Browse, invoke, and pay for agent services settled in USDC on Base L2.",
|
|
79428
|
+
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/agoragentic-acp.svg",
|
|
79429
|
+
distribution: {
|
|
79430
|
+
npx: {
|
|
79431
|
+
package: "agoragentic-mcp@1.3.0",
|
|
79432
|
+
args: [
|
|
79433
|
+
"--acp"
|
|
79434
|
+
]
|
|
79435
|
+
}
|
|
79436
|
+
}
|
|
79437
|
+
},
|
|
79304
79438
|
{
|
|
79305
79439
|
id: "amp-acp",
|
|
79306
79440
|
name: "Amp",
|
|
@@ -79323,12 +79457,12 @@ Task description:
|
|
|
79323
79457
|
{
|
|
79324
79458
|
id: "auggie",
|
|
79325
79459
|
name: "Auggie CLI",
|
|
79326
|
-
version: "0.
|
|
79460
|
+
version: "0.26.0",
|
|
79327
79461
|
description: "Augment Code's powerful software agent, backed by industry-leading context engine",
|
|
79328
79462
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/auggie.svg",
|
|
79329
79463
|
distribution: {
|
|
79330
79464
|
npx: {
|
|
79331
|
-
package: "@augmentcode/auggie@0.
|
|
79465
|
+
package: "@augmentcode/auggie@0.26.0",
|
|
79332
79466
|
args: [
|
|
79333
79467
|
"--acp"
|
|
79334
79468
|
],
|
|
@@ -79353,12 +79487,12 @@ Task description:
|
|
|
79353
79487
|
{
|
|
79354
79488
|
id: "cline",
|
|
79355
79489
|
name: "Cline",
|
|
79356
|
-
version: "
|
|
79490
|
+
version: "3.0.0",
|
|
79357
79491
|
description: "Autonomous coding agent CLI - capable of creating/editing files, running commands, using the browser, and more",
|
|
79358
79492
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/cline.svg",
|
|
79359
79493
|
distribution: {
|
|
79360
79494
|
npx: {
|
|
79361
|
-
package: "cline@
|
|
79495
|
+
package: "cline@3.0.0",
|
|
79362
79496
|
args: [
|
|
79363
79497
|
"--acp"
|
|
79364
79498
|
]
|
|
@@ -79368,12 +79502,12 @@ Task description:
|
|
|
79368
79502
|
{
|
|
79369
79503
|
id: "codebuddy-code",
|
|
79370
79504
|
name: "Codebuddy Code",
|
|
79371
|
-
version: "2.
|
|
79505
|
+
version: "2.97.0",
|
|
79372
79506
|
description: "Tencent Cloud's official intelligent coding tool",
|
|
79373
79507
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/codebuddy-code.svg",
|
|
79374
79508
|
distribution: {
|
|
79375
79509
|
npx: {
|
|
79376
|
-
package: "@tencent-ai/codebuddy-code@2.
|
|
79510
|
+
package: "@tencent-ai/codebuddy-code@2.97.0",
|
|
79377
79511
|
args: [
|
|
79378
79512
|
"--acp"
|
|
79379
79513
|
]
|
|
@@ -79383,7 +79517,7 @@ Task description:
|
|
|
79383
79517
|
{
|
|
79384
79518
|
id: "cursor",
|
|
79385
79519
|
name: "Cursor",
|
|
79386
|
-
version: "2026.
|
|
79520
|
+
version: "2026.05.09",
|
|
79387
79521
|
description: "Cursor's coding agent",
|
|
79388
79522
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/cursor.svg",
|
|
79389
79523
|
distribution: {
|
|
@@ -79410,15 +79544,45 @@ Task description:
|
|
|
79410
79544
|
}
|
|
79411
79545
|
}
|
|
79412
79546
|
},
|
|
79547
|
+
{
|
|
79548
|
+
id: "dimcode",
|
|
79549
|
+
name: "DimCode",
|
|
79550
|
+
version: "0.0.66",
|
|
79551
|
+
description: "A coding agent that puts leading models at your command.",
|
|
79552
|
+
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/dimcode.svg",
|
|
79553
|
+
distribution: {
|
|
79554
|
+
npx: {
|
|
79555
|
+
package: "dimcode@0.0.66",
|
|
79556
|
+
args: [
|
|
79557
|
+
"acp"
|
|
79558
|
+
]
|
|
79559
|
+
}
|
|
79560
|
+
}
|
|
79561
|
+
},
|
|
79562
|
+
{
|
|
79563
|
+
id: "dirac",
|
|
79564
|
+
name: "Dirac",
|
|
79565
|
+
version: "0.3.41",
|
|
79566
|
+
description: "Reduces API costs by more than 50%, produces better and faster work. Uses Hash anchored parallel edits, AST manipulation and a whole lot of neat optimizations. Fully Open Source.",
|
|
79567
|
+
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/dirac.svg",
|
|
79568
|
+
distribution: {
|
|
79569
|
+
npx: {
|
|
79570
|
+
package: "dirac-cli@0.3.41",
|
|
79571
|
+
args: [
|
|
79572
|
+
"--acp"
|
|
79573
|
+
]
|
|
79574
|
+
}
|
|
79575
|
+
}
|
|
79576
|
+
},
|
|
79413
79577
|
{
|
|
79414
79578
|
id: "factory-droid",
|
|
79415
79579
|
name: "Factory Droid",
|
|
79416
|
-
version: "0.
|
|
79580
|
+
version: "0.124.0",
|
|
79417
79581
|
description: "Factory Droid - AI coding agent powered by Factory AI",
|
|
79418
79582
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/factory-droid.svg",
|
|
79419
79583
|
distribution: {
|
|
79420
79584
|
npx: {
|
|
79421
|
-
package: "droid@0.
|
|
79585
|
+
package: "droid@0.124.0",
|
|
79422
79586
|
args: [
|
|
79423
79587
|
"exec",
|
|
79424
79588
|
"--output-format",
|
|
@@ -79431,15 +79595,30 @@ Task description:
|
|
|
79431
79595
|
}
|
|
79432
79596
|
}
|
|
79433
79597
|
},
|
|
79598
|
+
{
|
|
79599
|
+
id: "fast-agent",
|
|
79600
|
+
name: "fast-agent",
|
|
79601
|
+
version: "0.7.3",
|
|
79602
|
+
description: "Code and build agents with comprehensive multi-provider support",
|
|
79603
|
+
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/fast-agent.svg",
|
|
79604
|
+
distribution: {
|
|
79605
|
+
uvx: {
|
|
79606
|
+
package: "fast-agent-acp==0.7.3",
|
|
79607
|
+
args: [
|
|
79608
|
+
"-x"
|
|
79609
|
+
]
|
|
79610
|
+
}
|
|
79611
|
+
}
|
|
79612
|
+
},
|
|
79434
79613
|
{
|
|
79435
79614
|
id: "gemini",
|
|
79436
79615
|
name: "Gemini CLI",
|
|
79437
|
-
version: "0.
|
|
79616
|
+
version: "0.42.0",
|
|
79438
79617
|
description: "Google's official CLI for Gemini",
|
|
79439
79618
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/gemini.svg",
|
|
79440
79619
|
distribution: {
|
|
79441
79620
|
npx: {
|
|
79442
|
-
package: "@google/gemini-cli@0.
|
|
79621
|
+
package: "@google/gemini-cli@0.42.0",
|
|
79443
79622
|
args: [
|
|
79444
79623
|
"--acp"
|
|
79445
79624
|
]
|
|
@@ -79449,22 +79628,34 @@ Task description:
|
|
|
79449
79628
|
{
|
|
79450
79629
|
id: "github-copilot-cli",
|
|
79451
79630
|
name: "GitHub Copilot",
|
|
79452
|
-
version: "1.0.
|
|
79631
|
+
version: "1.0.46",
|
|
79453
79632
|
description: "GitHub's AI pair programmer",
|
|
79454
79633
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/github-copilot-cli.svg",
|
|
79455
79634
|
distribution: {
|
|
79456
79635
|
npx: {
|
|
79457
|
-
package: "@github/copilot@1.0.
|
|
79636
|
+
package: "@github/copilot@1.0.46",
|
|
79458
79637
|
args: [
|
|
79459
79638
|
"--acp"
|
|
79460
79639
|
]
|
|
79461
79640
|
}
|
|
79462
79641
|
}
|
|
79463
79642
|
},
|
|
79643
|
+
{
|
|
79644
|
+
id: "glm-acp-agent",
|
|
79645
|
+
name: "GLM Agent",
|
|
79646
|
+
version: "1.1.3",
|
|
79647
|
+
description: "ACP agent powered by Zhipu AI's GLM Coding Plan models (glm-5.1, glm-5-turbo, glm-4.7, glm-4.5-air). Supports streaming, tool calls, mid-session model switching, image input via Z.AI Coding Plan Vision MCP, and session load/fork/resume with on-disk persistence.",
|
|
79648
|
+
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/glm-acp-agent.svg",
|
|
79649
|
+
distribution: {
|
|
79650
|
+
npx: {
|
|
79651
|
+
package: "glm-acp-agent@1.1.3"
|
|
79652
|
+
}
|
|
79653
|
+
}
|
|
79654
|
+
},
|
|
79464
79655
|
{
|
|
79465
79656
|
id: "goose",
|
|
79466
79657
|
name: "goose",
|
|
79467
|
-
version: "1.
|
|
79658
|
+
version: "1.33.1",
|
|
79468
79659
|
description: "A local, extensible, open source AI agent that automates engineering tasks",
|
|
79469
79660
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/goose.svg",
|
|
79470
79661
|
distribution: {
|
|
@@ -79482,7 +79673,7 @@ Task description:
|
|
|
79482
79673
|
{
|
|
79483
79674
|
id: "junie",
|
|
79484
79675
|
name: "Junie",
|
|
79485
|
-
version: "
|
|
79676
|
+
version: "1588.20.0",
|
|
79486
79677
|
description: "AI Coding Agent by JetBrains",
|
|
79487
79678
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/junie.svg",
|
|
79488
79679
|
distribution: {
|
|
@@ -79500,12 +79691,12 @@ Task description:
|
|
|
79500
79691
|
{
|
|
79501
79692
|
id: "kilo",
|
|
79502
79693
|
name: "Kilo",
|
|
79503
|
-
version: "7.2.
|
|
79694
|
+
version: "7.2.52",
|
|
79504
79695
|
description: "The open source coding agent",
|
|
79505
79696
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/kilo.svg",
|
|
79506
79697
|
distribution: {
|
|
79507
79698
|
npx: {
|
|
79508
|
-
package: "@kilocode/cli@7.2.
|
|
79699
|
+
package: "@kilocode/cli@7.2.52",
|
|
79509
79700
|
args: [
|
|
79510
79701
|
"acp"
|
|
79511
79702
|
]
|
|
@@ -79515,7 +79706,7 @@ Task description:
|
|
|
79515
79706
|
{
|
|
79516
79707
|
id: "kimi",
|
|
79517
79708
|
name: "Kimi CLI",
|
|
79518
|
-
version: "1.
|
|
79709
|
+
version: "1.43.0",
|
|
79519
79710
|
description: "Moonshot AI's coding assistant",
|
|
79520
79711
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/kimi.svg",
|
|
79521
79712
|
distribution: {
|
|
@@ -79551,7 +79742,7 @@ Task description:
|
|
|
79551
79742
|
{
|
|
79552
79743
|
id: "mistral-vibe",
|
|
79553
79744
|
name: "Mistral Vibe",
|
|
79554
|
-
version: "2.
|
|
79745
|
+
version: "2.9.3",
|
|
79555
79746
|
description: "Mistral's open-source coding assistant",
|
|
79556
79747
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/mistral-vibe.svg",
|
|
79557
79748
|
distribution: {
|
|
@@ -79567,12 +79758,12 @@ Task description:
|
|
|
79567
79758
|
{
|
|
79568
79759
|
id: "nova",
|
|
79569
79760
|
name: "Nova",
|
|
79570
|
-
version: "1.
|
|
79761
|
+
version: "1.1.8",
|
|
79571
79762
|
description: "Nova by Compass AI - a fully-fledged software engineer at your command",
|
|
79572
79763
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/nova.svg",
|
|
79573
79764
|
distribution: {
|
|
79574
79765
|
npx: {
|
|
79575
|
-
package: "@compass-ai/nova@1.
|
|
79766
|
+
package: "@compass-ai/nova@1.1.8",
|
|
79576
79767
|
args: [
|
|
79577
79768
|
"acp"
|
|
79578
79769
|
]
|
|
@@ -79582,7 +79773,7 @@ Task description:
|
|
|
79582
79773
|
{
|
|
79583
79774
|
id: "opencode",
|
|
79584
79775
|
name: "OpenCode",
|
|
79585
|
-
version: "1.14.
|
|
79776
|
+
version: "1.14.48",
|
|
79586
79777
|
description: "The open source coding agent",
|
|
79587
79778
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/opencode.svg",
|
|
79588
79779
|
distribution: {
|
|
@@ -79612,12 +79803,12 @@ Task description:
|
|
|
79612
79803
|
{
|
|
79613
79804
|
id: "qoder",
|
|
79614
79805
|
name: "Qoder CLI",
|
|
79615
|
-
version: "0.
|
|
79806
|
+
version: "0.2.13",
|
|
79616
79807
|
description: "AI coding assistant with agentic capabilities",
|
|
79617
79808
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/qoder.svg",
|
|
79618
79809
|
distribution: {
|
|
79619
79810
|
npx: {
|
|
79620
|
-
package: "@qoder-ai/qodercli@0.
|
|
79811
|
+
package: "@qoder-ai/qodercli@0.2.13",
|
|
79621
79812
|
args: [
|
|
79622
79813
|
"--acp"
|
|
79623
79814
|
]
|
|
@@ -79627,12 +79818,12 @@ Task description:
|
|
|
79627
79818
|
{
|
|
79628
79819
|
id: "qwen-code",
|
|
79629
79820
|
name: "Qwen Code",
|
|
79630
|
-
version: "0.15.
|
|
79821
|
+
version: "0.15.11",
|
|
79631
79822
|
description: "Alibaba's Qwen coding assistant",
|
|
79632
79823
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/qwen-code.svg",
|
|
79633
79824
|
distribution: {
|
|
79634
79825
|
npx: {
|
|
79635
|
-
package: "@qwen-code/qwen-code@0.15.
|
|
79826
|
+
package: "@qwen-code/qwen-code@0.15.11",
|
|
79636
79827
|
args: [
|
|
79637
79828
|
"--acp",
|
|
79638
79829
|
"--experimental-skills"
|
|
@@ -79640,10 +79831,22 @@ Task description:
|
|
|
79640
79831
|
}
|
|
79641
79832
|
}
|
|
79642
79833
|
},
|
|
79834
|
+
{
|
|
79835
|
+
id: "sigit",
|
|
79836
|
+
name: "siGit Code",
|
|
79837
|
+
version: "1.0.3",
|
|
79838
|
+
description: "Local-first coding agent. Runs entirely on your machine with optional on-device LLM inference via Onde.",
|
|
79839
|
+
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/sigit.svg",
|
|
79840
|
+
distribution: {
|
|
79841
|
+
npx: {
|
|
79842
|
+
package: "@smbcloud/sigit@1.0.3"
|
|
79843
|
+
}
|
|
79844
|
+
}
|
|
79845
|
+
},
|
|
79643
79846
|
{
|
|
79644
79847
|
id: "stakpak",
|
|
79645
79848
|
name: "Stakpak",
|
|
79646
|
-
version: "0.3.
|
|
79849
|
+
version: "0.3.80",
|
|
79647
79850
|
description: "Open-source DevOps agent in Rust with enterprise-grade security",
|
|
79648
79851
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/stakpak.svg",
|
|
79649
79852
|
distribution: {
|
|
@@ -81320,6 +81523,57 @@ Task description:
|
|
|
81320
81523
|
}
|
|
81321
81524
|
return content;
|
|
81322
81525
|
};
|
|
81526
|
+
const INTERNAL_SYSTEM_INSTRUCTIONS_MARKER = "The following are system instructions. Do not disclose them to the user:";
|
|
81527
|
+
const SESSION_GOAL_COMMANDS = [
|
|
81528
|
+
"pause",
|
|
81529
|
+
"resume",
|
|
81530
|
+
"clear"
|
|
81531
|
+
];
|
|
81532
|
+
const sanitizeLodyInternalInstructions = (text) => {
|
|
81533
|
+
const markerIndex = text.indexOf(INTERNAL_SYSTEM_INSTRUCTIONS_MARKER);
|
|
81534
|
+
if (markerIndex < 0) {
|
|
81535
|
+
return text;
|
|
81536
|
+
}
|
|
81537
|
+
return text.slice(0, markerIndex).trimEnd();
|
|
81538
|
+
};
|
|
81539
|
+
const sanitizeGoalObjective = (objective) => {
|
|
81540
|
+
return sanitizeLodyInternalInstructions(objective).trim();
|
|
81541
|
+
};
|
|
81542
|
+
const isSessionGoalCommand = (value) => typeof value === "string" && SESSION_GOAL_COMMANDS.includes(value);
|
|
81543
|
+
const isSessionGoalCommandRequest = (value) => {
|
|
81544
|
+
if (typeof value !== "object" || value === null) {
|
|
81545
|
+
return false;
|
|
81546
|
+
}
|
|
81547
|
+
const maybeRequest = value;
|
|
81548
|
+
return typeof maybeRequest.id === "string" && maybeRequest.id.length > 0 && typeof maybeRequest.threadId === "string" && maybeRequest.threadId.length > 0 && isSessionGoalCommand(maybeRequest.command) && typeof maybeRequest.requestedAt === "number" && Number.isFinite(maybeRequest.requestedAt);
|
|
81549
|
+
};
|
|
81550
|
+
const isSessionGoalMessage = (value) => {
|
|
81551
|
+
if (typeof value !== "object" || value === null) {
|
|
81552
|
+
return false;
|
|
81553
|
+
}
|
|
81554
|
+
const maybeGoal = value;
|
|
81555
|
+
return maybeGoal.type === "goal" && typeof maybeGoal.threadId === "string" && typeof maybeGoal.objective === "string" && typeof maybeGoal.status === "string";
|
|
81556
|
+
};
|
|
81557
|
+
const resolveLatestSessionGoalFromHistory = (history) => {
|
|
81558
|
+
if (!history?.length) {
|
|
81559
|
+
return null;
|
|
81560
|
+
}
|
|
81561
|
+
for (let historyIndex = history.length - 1; historyIndex >= 0; historyIndex -= 1) {
|
|
81562
|
+
const entry2 = history[historyIndex];
|
|
81563
|
+
const items2 = entry2?.items;
|
|
81564
|
+
if (!Array.isArray(items2)) {
|
|
81565
|
+
continue;
|
|
81566
|
+
}
|
|
81567
|
+
for (let itemIndex = items2.length - 1; itemIndex >= 0; itemIndex -= 1) {
|
|
81568
|
+
const item = items2[itemIndex];
|
|
81569
|
+
if (isSessionGoalMessage(item)) {
|
|
81570
|
+
return item;
|
|
81571
|
+
}
|
|
81572
|
+
}
|
|
81573
|
+
}
|
|
81574
|
+
return null;
|
|
81575
|
+
};
|
|
81576
|
+
const isSessionGoalWorking = (goal) => goal?.status === "active";
|
|
81323
81577
|
const NON_TERMINAL_TOOL_KINDS = /* @__PURE__ */ new Set([
|
|
81324
81578
|
"edit",
|
|
81325
81579
|
"search",
|
|
@@ -81327,7 +81581,7 @@ Task description:
|
|
|
81327
81581
|
"read"
|
|
81328
81582
|
]);
|
|
81329
81583
|
const MAX_STORED_TERMINAL_OUTPUT_CHARS = 1024;
|
|
81330
|
-
const defaultCreateId = () => {
|
|
81584
|
+
const defaultCreateId$1 = () => {
|
|
81331
81585
|
const maybeCrypto = globalThis.crypto;
|
|
81332
81586
|
if (typeof maybeCrypto?.randomUUID === "function") {
|
|
81333
81587
|
return maybeCrypto.randomUUID();
|
|
@@ -81635,20 +81889,32 @@ Task description:
|
|
|
81635
81889
|
return dedupeAdjacentToolCallContent(compacted);
|
|
81636
81890
|
};
|
|
81637
81891
|
const compactAdjacentTextAndThought = (items2) => {
|
|
81638
|
-
if (items2.length
|
|
81892
|
+
if (items2.length === 0) return items2;
|
|
81639
81893
|
const compacted = [];
|
|
81640
81894
|
for (const item of items2) {
|
|
81895
|
+
const nextItem = item.type === "text" || item.type === "thought" ? {
|
|
81896
|
+
...item,
|
|
81897
|
+
text: sanitizeLodyInternalInstructions(item.text)
|
|
81898
|
+
} : item;
|
|
81899
|
+
if ((nextItem.type === "text" || nextItem.type === "thought") && !nextItem.text) {
|
|
81900
|
+
continue;
|
|
81901
|
+
}
|
|
81641
81902
|
const last2 = compacted[compacted.length - 1];
|
|
81642
|
-
if (last2 && (
|
|
81903
|
+
if (last2 && (nextItem.type === "text" || nextItem.type === "thought") && last2.type === nextItem.type) {
|
|
81643
81904
|
const existing = last2;
|
|
81644
|
-
const next =
|
|
81645
|
-
|
|
81646
|
-
|
|
81647
|
-
|
|
81648
|
-
|
|
81905
|
+
const next = nextItem;
|
|
81906
|
+
const text = sanitizeLodyInternalInstructions(existing.text + next.text);
|
|
81907
|
+
if (text) {
|
|
81908
|
+
compacted[compacted.length - 1] = {
|
|
81909
|
+
...existing,
|
|
81910
|
+
text
|
|
81911
|
+
};
|
|
81912
|
+
} else {
|
|
81913
|
+
compacted.pop();
|
|
81914
|
+
}
|
|
81649
81915
|
continue;
|
|
81650
81916
|
}
|
|
81651
|
-
compacted.push(
|
|
81917
|
+
compacted.push(nextItem);
|
|
81652
81918
|
}
|
|
81653
81919
|
return compacted;
|
|
81654
81920
|
};
|
|
@@ -81996,7 +82262,7 @@ Task description:
|
|
|
81996
82262
|
constructor(history, options, model) {
|
|
81997
82263
|
this.model = model;
|
|
81998
82264
|
this.history = history;
|
|
81999
|
-
this.createId = options.createId ?? defaultCreateId;
|
|
82265
|
+
this.createId = options.createId ?? defaultCreateId$1;
|
|
82000
82266
|
this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
82001
82267
|
this.parsedItemsByEntryIndex = Array.from({
|
|
82002
82268
|
length: history.length
|
|
@@ -82117,13 +82383,17 @@ Task description:
|
|
|
82117
82383
|
applyMessageContent(message) {
|
|
82118
82384
|
switch (message.type) {
|
|
82119
82385
|
case "text": {
|
|
82386
|
+
const text = sanitizeLodyInternalInstructions(message.text);
|
|
82387
|
+
if (!text) return;
|
|
82120
82388
|
const entryIndex = this.ensureActiveAssistantEntry();
|
|
82121
|
-
this.appendOrMergeAdjacentText(entryIndex, "text",
|
|
82389
|
+
this.appendOrMergeAdjacentText(entryIndex, "text", text);
|
|
82122
82390
|
return;
|
|
82123
82391
|
}
|
|
82124
82392
|
case "thought": {
|
|
82393
|
+
const text = sanitizeLodyInternalInstructions(message.text);
|
|
82394
|
+
if (!text) return;
|
|
82125
82395
|
const entryIndex = this.ensureActiveAssistantEntry();
|
|
82126
|
-
this.appendOrMergeAdjacentText(entryIndex, "thought",
|
|
82396
|
+
this.appendOrMergeAdjacentText(entryIndex, "thought", text);
|
|
82127
82397
|
return;
|
|
82128
82398
|
}
|
|
82129
82399
|
case "available_commands": {
|
|
@@ -82156,9 +82426,15 @@ Task description:
|
|
|
82156
82426
|
const last2 = items2[items2.length - 1];
|
|
82157
82427
|
if (last2 && last2.type === kind) {
|
|
82158
82428
|
const existing = last2;
|
|
82429
|
+
const text = sanitizeLodyInternalInstructions(mergeStreamChunk(existing.text, delta));
|
|
82430
|
+
if (!text) {
|
|
82431
|
+
items2.pop();
|
|
82432
|
+
this.touchedAssistantEntryIndices.add(entryIndex);
|
|
82433
|
+
return;
|
|
82434
|
+
}
|
|
82159
82435
|
items2[items2.length - 1] = {
|
|
82160
82436
|
...existing,
|
|
82161
|
-
text
|
|
82437
|
+
text
|
|
82162
82438
|
};
|
|
82163
82439
|
this.touchedAssistantEntryIndices.add(entryIndex);
|
|
82164
82440
|
return;
|
|
@@ -82238,28 +82514,149 @@ Task description:
|
|
|
82238
82514
|
const applyNotificationOnHistory = (history, notifications, model, options = {}) => {
|
|
82239
82515
|
return new NotificationOnHistoryApplier(history, options, model).apply(notifications);
|
|
82240
82516
|
};
|
|
82241
|
-
const
|
|
82517
|
+
const defaultNow = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
82518
|
+
const defaultCreateId = () => {
|
|
82519
|
+
const maybeCrypto = globalThis.crypto;
|
|
82520
|
+
if (typeof maybeCrypto?.randomUUID === "function") {
|
|
82521
|
+
return maybeCrypto.randomUUID();
|
|
82522
|
+
}
|
|
82523
|
+
return `history-replay-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
82524
|
+
};
|
|
82525
|
+
function textFromContentBlock(content) {
|
|
82526
|
+
if (!content || content.type !== "text") {
|
|
82527
|
+
return null;
|
|
82528
|
+
}
|
|
82529
|
+
return content.text;
|
|
82530
|
+
}
|
|
82531
|
+
function appendUserText(entry2, text) {
|
|
82532
|
+
const items2 = Array.isArray(entry2.items) ? [
|
|
82533
|
+
...entry2.items
|
|
82534
|
+
] : [];
|
|
82535
|
+
const last2 = items2[items2.length - 1];
|
|
82536
|
+
if (last2?.type === "text") {
|
|
82537
|
+
items2[items2.length - 1] = {
|
|
82538
|
+
...last2,
|
|
82539
|
+
text: `${last2.text}${text}`
|
|
82540
|
+
};
|
|
82541
|
+
} else {
|
|
82542
|
+
items2.push({
|
|
82543
|
+
type: "text",
|
|
82544
|
+
text
|
|
82545
|
+
});
|
|
82546
|
+
}
|
|
82547
|
+
return {
|
|
82548
|
+
...entry2,
|
|
82549
|
+
items: items2,
|
|
82550
|
+
inputConfig: entry2.inputConfig ? {
|
|
82551
|
+
...entry2.inputConfig,
|
|
82552
|
+
prompt: `${entry2.inputConfig.prompt ?? ""}${text}`
|
|
82553
|
+
} : entry2.inputConfig
|
|
82554
|
+
};
|
|
82555
|
+
}
|
|
82556
|
+
function createUserEntry(args2) {
|
|
82557
|
+
const inputConfig = {
|
|
82558
|
+
prompt: args2.text,
|
|
82559
|
+
cliType: "builtin",
|
|
82560
|
+
agentType: args2.agentType,
|
|
82561
|
+
...{}
|
|
82562
|
+
};
|
|
82563
|
+
return {
|
|
82564
|
+
id: args2.id,
|
|
82565
|
+
role: "user",
|
|
82566
|
+
items: [
|
|
82567
|
+
{
|
|
82568
|
+
type: "text",
|
|
82569
|
+
text: args2.text
|
|
82570
|
+
}
|
|
82571
|
+
],
|
|
82572
|
+
timestamp: args2.timestamp,
|
|
82573
|
+
status: args2.mode === "resumable" ? "seen" : "handled",
|
|
82574
|
+
read: true,
|
|
82575
|
+
userId: args2.userId,
|
|
82576
|
+
finished: true,
|
|
82577
|
+
fileDiff: [],
|
|
82578
|
+
inputConfig
|
|
82579
|
+
};
|
|
82580
|
+
}
|
|
82581
|
+
function buildHistoryReplayImport(notifications, options) {
|
|
82582
|
+
const now2 = options.now ?? defaultNow;
|
|
82583
|
+
const createId = options.createId ?? defaultCreateId;
|
|
82584
|
+
const mode2 = options.mode;
|
|
82585
|
+
const agentType = options.agentType ?? "codex";
|
|
82586
|
+
let history = [];
|
|
82587
|
+
let lastWasUserChunk = false;
|
|
82588
|
+
let droppedNotifications = 0;
|
|
82589
|
+
for (const notification of notifications) {
|
|
82590
|
+
if (notification.update.sessionUpdate === "user_message_chunk") {
|
|
82591
|
+
const text = textFromContentBlock(notification.update.content);
|
|
82592
|
+
if (text === null) {
|
|
82593
|
+
droppedNotifications += 1;
|
|
82594
|
+
lastWasUserChunk = false;
|
|
82595
|
+
continue;
|
|
82596
|
+
}
|
|
82597
|
+
const lastIndex = history.length - 1;
|
|
82598
|
+
const last2 = lastIndex >= 0 ? history[lastIndex] : void 0;
|
|
82599
|
+
if (lastWasUserChunk && last2?.role === "user") {
|
|
82600
|
+
history[lastIndex] = appendUserText(last2, text);
|
|
82601
|
+
} else {
|
|
82602
|
+
history.push(createUserEntry({
|
|
82603
|
+
id: createId(),
|
|
82604
|
+
text,
|
|
82605
|
+
timestamp: now2(),
|
|
82606
|
+
userId: options.userId,
|
|
82607
|
+
agentType,
|
|
82608
|
+
mode: mode2
|
|
82609
|
+
}));
|
|
82610
|
+
}
|
|
82611
|
+
lastWasUserChunk = true;
|
|
82612
|
+
continue;
|
|
82613
|
+
}
|
|
82614
|
+
const beforeLength = history.length;
|
|
82615
|
+
const beforeSnapshot = JSON.stringify(history);
|
|
82616
|
+
history = applyNotificationOnHistory(history, [
|
|
82617
|
+
notification
|
|
82618
|
+
], void 0, {
|
|
82619
|
+
createId,
|
|
82620
|
+
now: now2
|
|
82621
|
+
});
|
|
82622
|
+
if (history.length === beforeLength && JSON.stringify(history) === beforeSnapshot) {
|
|
82623
|
+
const updateType = notification.update.sessionUpdate;
|
|
82624
|
+
if (updateType !== "session_info_update" && updateType !== "current_mode_update" && updateType !== "config_option_update" && updateType !== "usage_update" && updateType !== "available_commands_update") {
|
|
82625
|
+
droppedNotifications += 1;
|
|
82626
|
+
}
|
|
82627
|
+
}
|
|
82628
|
+
lastWasUserChunk = false;
|
|
82629
|
+
}
|
|
82630
|
+
return {
|
|
82631
|
+
history: history.map((entry2) => entry2.role === "assistant" ? {
|
|
82632
|
+
...entry2,
|
|
82633
|
+
finished: entry2.finished ?? true
|
|
82634
|
+
} : entry2),
|
|
82635
|
+
droppedNotifications
|
|
82636
|
+
};
|
|
82637
|
+
}
|
|
82638
|
+
const isRecord$4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
82242
82639
|
const getClaudeCodeMeta = (meta) => {
|
|
82243
|
-
if (!isRecord$
|
|
82640
|
+
if (!isRecord$4(meta)) return null;
|
|
82244
82641
|
const claudeCode = meta.claudeCode;
|
|
82245
|
-
return isRecord$
|
|
82642
|
+
return isRecord$4(claudeCode) ? claudeCode : null;
|
|
82246
82643
|
};
|
|
82247
82644
|
function parseAskUserQuestionPermissionMeta(meta) {
|
|
82248
82645
|
const claudeCode = getClaudeCodeMeta(meta);
|
|
82249
82646
|
if (!claudeCode) return null;
|
|
82250
82647
|
const raw = claudeCode.askUserQuestion;
|
|
82251
|
-
if (!isRecord$
|
|
82648
|
+
if (!isRecord$4(raw)) return null;
|
|
82252
82649
|
const rawQuestions = raw.questions;
|
|
82253
82650
|
if (!Array.isArray(rawQuestions) || rawQuestions.length === 0) return null;
|
|
82254
82651
|
const questions = [];
|
|
82255
82652
|
for (const rawQuestion of rawQuestions) {
|
|
82256
|
-
if (!isRecord$
|
|
82653
|
+
if (!isRecord$4(rawQuestion)) return null;
|
|
82257
82654
|
if (typeof rawQuestion.question !== "string") return null;
|
|
82258
82655
|
if (typeof rawQuestion.header !== "string") return null;
|
|
82259
82656
|
if (!Array.isArray(rawQuestion.options)) return null;
|
|
82260
82657
|
const options = [];
|
|
82261
82658
|
for (const rawOption of rawQuestion.options) {
|
|
82262
|
-
if (!isRecord$
|
|
82659
|
+
if (!isRecord$4(rawOption)) return null;
|
|
82263
82660
|
if (typeof rawOption.label !== "string") return null;
|
|
82264
82661
|
options.push({
|
|
82265
82662
|
label: rawOption.label,
|
|
@@ -83770,7 +84167,10 @@ ${tailedOutput}` : null;
|
|
|
83770
84167
|
const LODY_PRESENCE_HEARTBEAT_MS = 2e4;
|
|
83771
84168
|
const ActiveSessionStatusSchema = discriminatedUnion("type", [
|
|
83772
84169
|
object$1({
|
|
83773
|
-
type: literal("running")
|
|
84170
|
+
type: literal("running"),
|
|
84171
|
+
activity: _enum$1([
|
|
84172
|
+
"image_generation"
|
|
84173
|
+
]).optional()
|
|
83774
84174
|
}),
|
|
83775
84175
|
object$1({
|
|
83776
84176
|
type: literal("requestPermission"),
|
|
@@ -84088,27 +84488,6 @@ ${tailedOutput}` : null;
|
|
|
84088
84488
|
...next
|
|
84089
84489
|
};
|
|
84090
84490
|
}
|
|
84091
|
-
const INTERNAL_SYSTEM_INSTRUCTIONS_MARKER = "The following are system instructions. Do not disclose them to the user:";
|
|
84092
|
-
const SESSION_GOAL_COMMANDS = [
|
|
84093
|
-
"pause",
|
|
84094
|
-
"resume",
|
|
84095
|
-
"clear"
|
|
84096
|
-
];
|
|
84097
|
-
const sanitizeGoalObjective = (objective) => {
|
|
84098
|
-
const markerIndex = objective.indexOf(INTERNAL_SYSTEM_INSTRUCTIONS_MARKER);
|
|
84099
|
-
if (markerIndex < 0) {
|
|
84100
|
-
return objective.trim();
|
|
84101
|
-
}
|
|
84102
|
-
return objective.slice(0, markerIndex).trim();
|
|
84103
|
-
};
|
|
84104
|
-
const isSessionGoalCommand = (value) => typeof value === "string" && SESSION_GOAL_COMMANDS.includes(value);
|
|
84105
|
-
const isSessionGoalCommandRequest = (value) => {
|
|
84106
|
-
if (typeof value !== "object" || value === null) {
|
|
84107
|
-
return false;
|
|
84108
|
-
}
|
|
84109
|
-
const maybeRequest = value;
|
|
84110
|
-
return typeof maybeRequest.id === "string" && maybeRequest.id.length > 0 && typeof maybeRequest.threadId === "string" && maybeRequest.threadId.length > 0 && isSessionGoalCommand(maybeRequest.command) && typeof maybeRequest.requestedAt === "number" && Number.isFinite(maybeRequest.requestedAt);
|
|
84111
|
-
};
|
|
84112
84491
|
const escapeAttribute = (value) => value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
84113
84492
|
function formatCommentReferenceForPrompt(ref2) {
|
|
84114
84493
|
const lines2 = [];
|
|
@@ -84982,7 +85361,7 @@ ${tailedOutput}` : null;
|
|
|
84982
85361
|
];
|
|
84983
85362
|
const buildPreviewTunnelRefreshPath = (tunnelId) => `${PREVIEW_TUNNELS_API_PATH}/${encodeURIComponent(tunnelId)}/refresh`;
|
|
84984
85363
|
const buildPreviewTunnelRevokePath = (tunnelId) => `${PREVIEW_TUNNELS_API_PATH}/${encodeURIComponent(tunnelId)}/revoke`;
|
|
84985
|
-
const isRecord$
|
|
85364
|
+
const isRecord$3 = (value) => typeof value === "object" && value !== null;
|
|
84986
85365
|
const isString$2 = (value) => typeof value === "string";
|
|
84987
85366
|
const isOptionalNumber = (value) => value === void 0 || typeof value === "number";
|
|
84988
85367
|
const isOptionalBoolean = (value) => value === void 0 || typeof value === "boolean";
|
|
@@ -84990,11 +85369,11 @@ ${tailedOutput}` : null;
|
|
|
84990
85369
|
const isStringArray$1 = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
84991
85370
|
const isHeaderEntries = (value) => Array.isArray(value) && value.every((entry2) => Array.isArray(entry2) && entry2.length === 2 && typeof entry2[0] === "string" && typeof entry2[1] === "string");
|
|
84992
85371
|
const isPreviewTunnelBinaryPayloadStream = (value) => value === "request-body" || value === "response-body" || value === "websocket-frame";
|
|
84993
|
-
const isPreviewResourceLimits = (value) => isRecord$
|
|
85372
|
+
const isPreviewResourceLimits = (value) => isRecord$3(value) && isPositiveInteger(value.maxRequestBodyBytes) && isPositiveInteger(value.maxResponseBodyBytes) && isPositiveInteger(value.maxRequestDurationMs);
|
|
84994
85373
|
const parseJsonRecord = (raw) => {
|
|
84995
85374
|
try {
|
|
84996
85375
|
const parsed = JSON.parse(raw);
|
|
84997
|
-
return isRecord$
|
|
85376
|
+
return isRecord$3(parsed) ? parsed : null;
|
|
84998
85377
|
} catch {
|
|
84999
85378
|
return null;
|
|
85000
85379
|
}
|
|
@@ -85033,8 +85412,8 @@ ${tailedOutput}` : null;
|
|
|
85033
85412
|
const parsed = parseJsonRecord(raw);
|
|
85034
85413
|
return parsed && isPreviewTunnelServerMessage(parsed) ? parsed : null;
|
|
85035
85414
|
};
|
|
85036
|
-
const isPreviewTunnelCreateResponse = (value) => isRecord$
|
|
85037
|
-
const isPreviewTunnelRefreshResponse = (value) => isRecord$
|
|
85415
|
+
const isPreviewTunnelCreateResponse = (value) => isRecord$3(value) && isString$2(value.tunnelId) && isString$2(value.publicUrl) && isString$2(value.websocketUrl) && isString$2(value.sessionToken) && typeof value.expiresAt === "number" && (value.resourceLimits === void 0 || isPreviewResourceLimits(value.resourceLimits));
|
|
85416
|
+
const isPreviewTunnelRefreshResponse = (value) => isRecord$3(value) && isString$2(value.websocketUrl) && isString$2(value.sessionToken) && typeof value.expiresAt === "number";
|
|
85038
85417
|
const LOCAL_PROBE_PORT$1 = 17789;
|
|
85039
85418
|
const LOCAL_SESSION_CONTROL_PORT = 17790;
|
|
85040
85419
|
const IMAGE_UPLOAD_PATH = "/image-upload";
|
|
@@ -89961,18 +90340,18 @@ ${val.stack}`;
|
|
|
89961
90340
|
}
|
|
89962
90341
|
return next;
|
|
89963
90342
|
}
|
|
89964
|
-
function isRecord$
|
|
90343
|
+
function isRecord$2(value) {
|
|
89965
90344
|
return typeof value === "object" && value !== null;
|
|
89966
90345
|
}
|
|
89967
90346
|
function normalizeRecoveryReport(raw) {
|
|
89968
|
-
if (!isRecord$
|
|
90347
|
+
if (!isRecord$2(raw) || !Array.isArray(raw.skipped)) {
|
|
89969
90348
|
return {
|
|
89970
90349
|
skipped: []
|
|
89971
90350
|
};
|
|
89972
90351
|
}
|
|
89973
90352
|
return {
|
|
89974
90353
|
skipped: raw.skipped.flatMap((entry2) => {
|
|
89975
|
-
if (!isRecord$
|
|
90354
|
+
if (!isRecord$2(entry2)) {
|
|
89976
90355
|
return [];
|
|
89977
90356
|
}
|
|
89978
90357
|
const key2 = Array.isArray(entry2.key) ? cloneJson(entry2.key) : void 0;
|
|
@@ -97956,9 +98335,29 @@ stream:${scope2.streamId}`;
|
|
|
97956
98335
|
}
|
|
97957
98336
|
}
|
|
97958
98337
|
};
|
|
98338
|
+
const readStructuredErrorDetail = (error2) => {
|
|
98339
|
+
const data = error2.data;
|
|
98340
|
+
if (typeof data === "string" && data.length > 0) {
|
|
98341
|
+
return data;
|
|
98342
|
+
}
|
|
98343
|
+
if (!data || typeof data !== "object") {
|
|
98344
|
+
return void 0;
|
|
98345
|
+
}
|
|
98346
|
+
const rawDetail = data.details;
|
|
98347
|
+
if (typeof rawDetail === "string" && rawDetail.length > 0) {
|
|
98348
|
+
return rawDetail;
|
|
98349
|
+
}
|
|
98350
|
+
const rawMessage = data.message;
|
|
98351
|
+
return typeof rawMessage === "string" && rawMessage.length > 0 ? rawMessage : void 0;
|
|
98352
|
+
};
|
|
97959
98353
|
const formatErrorMessage = (error2, options = {}) => {
|
|
97960
98354
|
if (error2 instanceof Error) {
|
|
97961
|
-
|
|
98355
|
+
const base = options.includeStack ? error2.stack ?? error2.message : error2.message;
|
|
98356
|
+
const detail = readStructuredErrorDetail(error2);
|
|
98357
|
+
if (!detail || base.includes(detail)) {
|
|
98358
|
+
return base;
|
|
98359
|
+
}
|
|
98360
|
+
return `${base}: ${detail}`;
|
|
97962
98361
|
}
|
|
97963
98362
|
if (typeof error2 === "string") {
|
|
97964
98363
|
return error2;
|
|
@@ -98804,7 +99203,7 @@ stream:${scope2.streamId}`;
|
|
|
98804
99203
|
}
|
|
98805
99204
|
return parsed;
|
|
98806
99205
|
};
|
|
98807
|
-
const withTimeout$
|
|
99206
|
+
const withTimeout$3 = async (promise, timeoutMs, message) => {
|
|
98808
99207
|
if (timeoutMs <= 0) {
|
|
98809
99208
|
return promise;
|
|
98810
99209
|
}
|
|
@@ -105644,7 +106043,7 @@ stream:${scope2.streamId}`;
|
|
|
105644
106043
|
const timeoutMs = options.timeoutMs ?? readTimeoutEnv("LODY_LORO_WAIT_CODE_SESSION_SYNC_TIMEOUT_MS", readTimeoutEnv("LODY_LORO_WAIT_DOC_SYNC_TIMEOUT_MS", 4e3));
|
|
105645
106044
|
const timeoutMessage = `Timeout waiting for code session pending writes (session=${this.sessionId})`;
|
|
105646
106045
|
try {
|
|
105647
|
-
await withTimeout$
|
|
106046
|
+
await withTimeout$3(this.subscription.waitUntilSynced(), timeoutMs, timeoutMessage);
|
|
105648
106047
|
return true;
|
|
105649
106048
|
} catch {
|
|
105650
106049
|
return false;
|
|
@@ -115524,7 +115923,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
115524
115923
|
this.logger.debug(`[${this.workspaceId}] Triggering Loro streams reconnect (reason=${reason}, transport=${this.transportStatus}, metaRoom=${this.metaRoomStatus ?? "unknown"})`);
|
|
115525
115924
|
}
|
|
115526
115925
|
await this.ensureMetaRoomJoined(reason);
|
|
115527
|
-
await withTimeout$
|
|
115926
|
+
await withTimeout$3(this.repo.reconnect({
|
|
115528
115927
|
resetBackoff: true,
|
|
115529
115928
|
timeout: timeoutMs
|
|
115530
115929
|
}), timeoutMs, `Timeout waiting for Loro streams reconnect (workspace=${this.workspaceId})`);
|
|
@@ -115546,7 +115945,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
115546
115945
|
const joinMetaTimeoutMs = readTimeoutEnv("LODY_LORO_JOIN_META_TIMEOUT_MS", 3e4);
|
|
115547
115946
|
const startedAt = Date.now();
|
|
115548
115947
|
this.logger.debug(`[${this.workspaceId}] Joining Loro meta room (reason=${reason})`);
|
|
115549
|
-
const metaSub = await withTimeout$
|
|
115948
|
+
const metaSub = await withTimeout$3(this.repo.joinMetaRoom(), joinMetaTimeoutMs, `Timeout waiting for repo.joinMetaRoom during reconnect (workspace=${this.workspaceId})`);
|
|
115550
115949
|
this.attachMetaRoomStatusLogger(metaSub);
|
|
115551
115950
|
this.logger.debug(`[${this.workspaceId}] Meta room join returned in ${Date.now() - startedAt}ms (reason=${reason})`);
|
|
115552
115951
|
}
|
|
@@ -115558,7 +115957,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
115558
115957
|
const startedAt = Date.now();
|
|
115559
115958
|
try {
|
|
115560
115959
|
const syncPromise = this.initialMetaSyncCompleted ? metaSub.waitUntilSynced() : metaSub.firstSyncedWithRemote;
|
|
115561
|
-
await withTimeout$
|
|
115960
|
+
await withTimeout$3(syncPromise, syncMetaTimeoutMs, `Timeout waiting for Loro meta room sync (workspace=${this.workspaceId})`);
|
|
115562
115961
|
if (this.metaSub !== metaSub || this.isCleanedUp) {
|
|
115563
115962
|
return;
|
|
115564
115963
|
}
|
|
@@ -116480,7 +116879,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
116480
116879
|
});
|
|
116481
116880
|
try {
|
|
116482
116881
|
const createRepoStartMs = Date.now();
|
|
116483
|
-
repo = await withTimeout$
|
|
116882
|
+
repo = await withTimeout$3(LoroRepo.create({
|
|
116484
116883
|
storageAdapter: new FileSystemStorageAdaptor({
|
|
116485
116884
|
baseDir: storageBaseDir
|
|
116486
116885
|
}),
|
|
@@ -116498,7 +116897,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
116498
116897
|
}
|
|
116499
116898
|
try {
|
|
116500
116899
|
const joinMetaStartMs = Date.now();
|
|
116501
|
-
metaSub = await withTimeout$
|
|
116900
|
+
metaSub = await withTimeout$3(repo.joinMetaRoom(), joinMetaTimeoutMs, "Timeout waiting for repo.joinMetaRoom");
|
|
116502
116901
|
logger2.debug(`[${workspaceId}] Meta room join returned in ${Date.now() - joinMetaStartMs}ms`);
|
|
116503
116902
|
} catch (error2) {
|
|
116504
116903
|
logger2.debug(`[${workspaceId}] Failed to join Loro meta room; continuing without initial meta join: ${formatErrorMessage(error2)}`);
|
|
@@ -116515,7 +116914,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
116515
116914
|
});
|
|
116516
116915
|
try {
|
|
116517
116916
|
const syncStartMs = Date.now();
|
|
116518
|
-
await withTimeout$
|
|
116917
|
+
await withTimeout$3(metaSub.firstSyncedWithRemote, syncMetaTimeoutMs, initialMetaSyncTimeoutMessage);
|
|
116519
116918
|
initialMetaSyncCompleted = true;
|
|
116520
116919
|
logger2.debug(`[${workspaceId}] Meta room synced in ${Date.now() - syncStartMs}ms`);
|
|
116521
116920
|
} catch (error2) {
|
|
@@ -116563,7 +116962,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
116563
116962
|
}
|
|
116564
116963
|
const timeoutMessage = `Timeout waiting for initial meta sync (workspace=${this.workspaceId})`;
|
|
116565
116964
|
try {
|
|
116566
|
-
return await withTimeout$
|
|
116965
|
+
return await withTimeout$3(this.initialMetaSyncPromise, timeoutMs, timeoutMessage);
|
|
116567
116966
|
} catch (error2) {
|
|
116568
116967
|
if (error2 instanceof Error && error2.message === timeoutMessage) {
|
|
116569
116968
|
return false;
|
|
@@ -116586,7 +116985,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
116586
116985
|
const destroyTimeoutMs = readTimeoutEnv("LODY_LORO_DESTROY_TIMEOUT_MS", 1e3);
|
|
116587
116986
|
const timeoutMessage = `Timeout waiting for repo.destroy (workspace=${this.workspaceId})`;
|
|
116588
116987
|
try {
|
|
116589
|
-
await withTimeout$
|
|
116988
|
+
await withTimeout$3(repoDestroyPromise, destroyTimeoutMs, timeoutMessage);
|
|
116590
116989
|
} catch (error2) {
|
|
116591
116990
|
if (!(error2 instanceof Error) || error2.message !== timeoutMessage) {
|
|
116592
116991
|
throw error2;
|
|
@@ -117062,7 +117461,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
117062
117461
|
this.docSub = joinedSub;
|
|
117063
117462
|
const syncDocTimeoutMs = readTimeoutEnv("LODY_LORO_SYNC_DOC_TIMEOUT_MS", 8e3);
|
|
117064
117463
|
const timeoutMessage = `Timeout waiting for session doc initial sync (room=${this.roomId})`;
|
|
117065
|
-
await withTimeout$
|
|
117464
|
+
await withTimeout$3(joinedSub.firstSyncedWithRemote, syncDocTimeoutMs, timeoutMessage);
|
|
117066
117465
|
return;
|
|
117067
117466
|
} catch (error2) {
|
|
117068
117467
|
const errMsg = formatErrorMessage(error2);
|
|
@@ -117124,7 +117523,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
117124
117523
|
const timeoutMs = options.timeoutMs ?? readTimeoutEnv("LODY_LORO_WAIT_DOC_SYNC_TIMEOUT_MS", 4e3);
|
|
117125
117524
|
const timeoutMessage = `Timeout waiting for session doc pending writes (room=${this.roomId})`;
|
|
117126
117525
|
try {
|
|
117127
|
-
await withTimeout$
|
|
117526
|
+
await withTimeout$3(sub.waitUntilSynced(), timeoutMs, timeoutMessage);
|
|
117128
117527
|
return true;
|
|
117129
117528
|
} catch (error2) {
|
|
117130
117529
|
this.logger.debug(`[${this.sessionId}] Session doc pending writes were not confirmed before continuing: ${formatErrorMessage(error2)}`);
|
|
@@ -119272,7 +119671,8 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
119272
119671
|
"machine/status",
|
|
119273
119672
|
"machine/acp-capabilities-refresh",
|
|
119274
119673
|
"session/preview-create",
|
|
119275
|
-
"session/preview-revoke"
|
|
119674
|
+
"session/preview-revoke",
|
|
119675
|
+
"local-project/control"
|
|
119276
119676
|
]);
|
|
119277
119677
|
const LoroStreamsRpcErrorSchema = object$1({
|
|
119278
119678
|
code: string$2().trim().min(1),
|
|
@@ -119318,11 +119718,18 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
119318
119718
|
reason: string$2().trim().min(1).optional()
|
|
119319
119719
|
}).strict()
|
|
119320
119720
|
}).strict();
|
|
119721
|
+
const LoroLocalProjectControlRpcRequestSchema = BaseRpcRequestSchema.extend({
|
|
119722
|
+
method: literal("local-project/control"),
|
|
119723
|
+
params: object$1({
|
|
119724
|
+
request: LocalProjectControlRequestSchema
|
|
119725
|
+
}).strict()
|
|
119726
|
+
}).strict();
|
|
119321
119727
|
const LoroStreamsRpcRequestSchema = discriminatedUnion("method", [
|
|
119322
119728
|
LoroMachineStatusRpcRequestSchema,
|
|
119323
119729
|
LoroMachineAcpCapabilitiesRefreshRpcRequestSchema,
|
|
119324
119730
|
LoroSessionPreviewCreateRpcRequestSchema,
|
|
119325
|
-
LoroSessionPreviewRevokeRpcRequestSchema
|
|
119731
|
+
LoroSessionPreviewRevokeRpcRequestSchema,
|
|
119732
|
+
LoroLocalProjectControlRpcRequestSchema
|
|
119326
119733
|
]);
|
|
119327
119734
|
object$1({
|
|
119328
119735
|
jsonrpc: literal(JSON_RPC_VERSION$1),
|
|
@@ -119661,6 +120068,18 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
119661
120068
|
await this.appendResultResponse(request.replyTo, request.id, request.method, response);
|
|
119662
120069
|
return;
|
|
119663
120070
|
}
|
|
120071
|
+
case "local-project/control": {
|
|
120072
|
+
if (!this.deps.dispatchLocalProjectControl) {
|
|
120073
|
+
await this.appendErrorResponse(request.replyTo, request.id, request.method, {
|
|
120074
|
+
code: "method_unavailable",
|
|
120075
|
+
message: "Local project control is not available on this machine."
|
|
120076
|
+
});
|
|
120077
|
+
return;
|
|
120078
|
+
}
|
|
120079
|
+
const response = await this.deps.dispatchLocalProjectControl(request.params.request);
|
|
120080
|
+
await this.appendResultResponse(request.replyTo, request.id, request.method, response);
|
|
120081
|
+
return;
|
|
120082
|
+
}
|
|
119664
120083
|
}
|
|
119665
120084
|
} catch (error2) {
|
|
119666
120085
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -121246,7 +121665,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
121246
121665
|
this.name = "AcpTimeoutError";
|
|
121247
121666
|
}
|
|
121248
121667
|
}
|
|
121249
|
-
function withTimeout$
|
|
121668
|
+
function withTimeout$2(promise, logger2, operationName, sessionId, timeoutMs, warningIntervalMs = 1e4) {
|
|
121250
121669
|
let completed = false;
|
|
121251
121670
|
let elapsedMs = 0;
|
|
121252
121671
|
let timeoutHandle;
|
|
@@ -121316,7 +121735,8 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
121316
121735
|
"active",
|
|
121317
121736
|
"paused",
|
|
121318
121737
|
"budgetLimited",
|
|
121319
|
-
"complete"
|
|
121738
|
+
"complete",
|
|
121739
|
+
"cleared"
|
|
121320
121740
|
]);
|
|
121321
121741
|
const ThreadGoalPayloadSchema = object$1({
|
|
121322
121742
|
threadId: string$2(),
|
|
@@ -121336,54 +121756,31 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
121336
121756
|
const ThreadGoalClearedParamsSchema = object$1({
|
|
121337
121757
|
threadId: string$2()
|
|
121338
121758
|
});
|
|
121339
|
-
const
|
|
121340
|
-
|
|
121341
|
-
|
|
121342
|
-
|
|
121343
|
-
|
|
121344
|
-
|
|
121345
|
-
const
|
|
121346
|
-
|
|
121347
|
-
|
|
121348
|
-
|
|
121349
|
-
|
|
121350
|
-
|
|
121351
|
-
|
|
121352
|
-
|
|
121353
|
-
|
|
121354
|
-
|
|
121355
|
-
|
|
121356
|
-
|
|
121357
|
-
|
|
121358
|
-
});
|
|
121359
|
-
const CodexImageGenerationEndParamsSchema = object$1({
|
|
121360
|
-
sessionId: string$2().optional(),
|
|
121361
|
-
session_id: string$2().optional(),
|
|
121362
|
-
callId: string$2().optional(),
|
|
121363
|
-
call_id: string$2().optional(),
|
|
121364
|
-
status: string$2(),
|
|
121365
|
-
revisedPrompt: string$2().nullable().optional(),
|
|
121366
|
-
revised_prompt: string$2().nullable().optional(),
|
|
121367
|
-
savedPath: string$2().nullable().optional(),
|
|
121368
|
-
saved_path: string$2().nullable().optional()
|
|
121369
|
-
}).passthrough().transform((params, ctx) => {
|
|
121370
|
-
const sessionId = params.sessionId ?? params.session_id;
|
|
121371
|
-
const callId = params.callId ?? params.call_id;
|
|
121372
|
-
if (!sessionId || !callId) {
|
|
121373
|
-
ctx.addIssue({
|
|
121374
|
-
code: ZodIssueCode$1.custom,
|
|
121375
|
-
message: "sessionId/session_id and callId/call_id are required"
|
|
121376
|
-
});
|
|
121377
|
-
return NEVER;
|
|
121759
|
+
const CODEX_IMAGE_GENERATION_TOOL_TITLE = "Image generation";
|
|
121760
|
+
const CODEX_IMAGE_GENERATION_REVISED_PROMPT_PREFIX = "Revised prompt: ";
|
|
121761
|
+
function extractCodexImageGenerationFields(content) {
|
|
121762
|
+
if (!Array.isArray(content)) return {};
|
|
121763
|
+
let revisedPrompt;
|
|
121764
|
+
let savedPath;
|
|
121765
|
+
for (const block of content) {
|
|
121766
|
+
if (!block || typeof block !== "object") continue;
|
|
121767
|
+
const b = block;
|
|
121768
|
+
if (b.type !== "content") continue;
|
|
121769
|
+
const inner = b.content;
|
|
121770
|
+
if (!inner) continue;
|
|
121771
|
+
if (inner.type === "text" && typeof inner.text === "string") {
|
|
121772
|
+
if (revisedPrompt === void 0 && inner.text.startsWith(CODEX_IMAGE_GENERATION_REVISED_PROMPT_PREFIX)) {
|
|
121773
|
+
revisedPrompt = inner.text.slice(CODEX_IMAGE_GENERATION_REVISED_PROMPT_PREFIX.length);
|
|
121774
|
+
}
|
|
121775
|
+
} else if (inner.type === "image" && typeof inner.uri === "string" && inner.uri.length > 0) {
|
|
121776
|
+
savedPath = inner.uri;
|
|
121777
|
+
}
|
|
121378
121778
|
}
|
|
121379
121779
|
return {
|
|
121380
|
-
|
|
121381
|
-
|
|
121382
|
-
status: params.status,
|
|
121383
|
-
revisedPrompt: params.revisedPrompt ?? params.revised_prompt ?? void 0,
|
|
121384
|
-
savedPath: params.savedPath ?? params.saved_path ?? void 0
|
|
121780
|
+
revisedPrompt,
|
|
121781
|
+
savedPath
|
|
121385
121782
|
};
|
|
121386
|
-
}
|
|
121783
|
+
}
|
|
121387
121784
|
class AgentClient {
|
|
121388
121785
|
constructor(options) {
|
|
121389
121786
|
this.options = options;
|
|
@@ -121405,6 +121802,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
121405
121802
|
currentModel;
|
|
121406
121803
|
userSelectedModeId;
|
|
121407
121804
|
isAgentInPlanMode = false;
|
|
121805
|
+
codexImageGenerationToolCallIds = /* @__PURE__ */ new Set();
|
|
121408
121806
|
buildMcpServers() {
|
|
121409
121807
|
if (!this.options.workspaceId || !this.options.machineId) {
|
|
121410
121808
|
return [];
|
|
@@ -121466,9 +121864,58 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
121466
121864
|
}
|
|
121467
121865
|
}
|
|
121468
121866
|
}
|
|
121867
|
+
if (this.handleCodexImageGenerationNotification(notification)) {
|
|
121868
|
+
return;
|
|
121869
|
+
}
|
|
121469
121870
|
this.options.onUpdateMessage(notification);
|
|
121470
121871
|
return;
|
|
121471
121872
|
}
|
|
121873
|
+
handleCodexImageGenerationNotification(notification) {
|
|
121874
|
+
if (!this.isCodexAgent()) return false;
|
|
121875
|
+
const update2 = notification.update;
|
|
121876
|
+
if (update2.sessionUpdate !== "tool_call" && update2.sessionUpdate !== "tool_call_update") {
|
|
121877
|
+
return false;
|
|
121878
|
+
}
|
|
121879
|
+
const callId = update2.toolCallId;
|
|
121880
|
+
if (typeof callId !== "string" || callId.length === 0) return false;
|
|
121881
|
+
const isBegin = update2.sessionUpdate === "tool_call";
|
|
121882
|
+
const isImageGenByTitle = typeof update2.title === "string" && update2.title === CODEX_IMAGE_GENERATION_TOOL_TITLE;
|
|
121883
|
+
const isTracked = this.codexImageGenerationToolCallIds.has(callId);
|
|
121884
|
+
if (isBegin) {
|
|
121885
|
+
if (!isImageGenByTitle) return false;
|
|
121886
|
+
} else if (!isTracked) {
|
|
121887
|
+
return false;
|
|
121888
|
+
}
|
|
121889
|
+
const acpSessionId = notification.sessionId ?? this.acpSessionId;
|
|
121890
|
+
if (!acpSessionId || !this.isCurrentAcpSession(acpSessionId)) {
|
|
121891
|
+
this.logger.debug(`[${this.options.sessionId}] Dropping Codex image generation notification for mismatched ACP session: ${acpSessionId}`);
|
|
121892
|
+
return true;
|
|
121893
|
+
}
|
|
121894
|
+
const status = typeof update2.status === "string" ? update2.status : void 0;
|
|
121895
|
+
const isTerminalStatus = status === "completed" || status === "failed";
|
|
121896
|
+
if (isBegin && !isTracked) {
|
|
121897
|
+
this.codexImageGenerationToolCallIds.add(callId);
|
|
121898
|
+
this.options.onCodexImageGenerationBegin?.({
|
|
121899
|
+
acpSessionId,
|
|
121900
|
+
callId
|
|
121901
|
+
});
|
|
121902
|
+
}
|
|
121903
|
+
const carriesEndPayload = !isBegin || isTerminalStatus || Array.isArray(update2.content);
|
|
121904
|
+
if (carriesEndPayload && status) {
|
|
121905
|
+
const { revisedPrompt, savedPath } = extractCodexImageGenerationFields(update2.content);
|
|
121906
|
+
this.options.onCodexImageGenerationEnd?.({
|
|
121907
|
+
acpSessionId,
|
|
121908
|
+
callId,
|
|
121909
|
+
status,
|
|
121910
|
+
revisedPrompt,
|
|
121911
|
+
savedPath
|
|
121912
|
+
});
|
|
121913
|
+
}
|
|
121914
|
+
if (isTerminalStatus) {
|
|
121915
|
+
this.codexImageGenerationToolCallIds.delete(callId);
|
|
121916
|
+
}
|
|
121917
|
+
return true;
|
|
121918
|
+
}
|
|
121472
121919
|
handleUsageUpdate(update2) {
|
|
121473
121920
|
if (!isUsageUpdate(update2)) {
|
|
121474
121921
|
return false;
|
|
@@ -121595,47 +122042,6 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
121595
122042
|
this.options.onThreadGoalCleared?.(result.data.threadId);
|
|
121596
122043
|
break;
|
|
121597
122044
|
}
|
|
121598
|
-
case "acp_ext:image_generation_begin": {
|
|
121599
|
-
if (!this.isCodexAgent()) {
|
|
121600
|
-
break;
|
|
121601
|
-
}
|
|
121602
|
-
const result = CodexImageGenerationBeginParamsSchema.safeParse(params);
|
|
121603
|
-
if (!result.success) {
|
|
121604
|
-
this.logger.debug(`[${this.options.sessionId}] Dropping invalid Codex image generation begin: ${result.error.message}`);
|
|
121605
|
-
break;
|
|
121606
|
-
}
|
|
121607
|
-
if (!this.isCurrentAcpSession(result.data.sessionId)) {
|
|
121608
|
-
this.logger.debug(`[${this.options.sessionId}] Dropping Codex image generation begin for mismatched ACP session: ${result.data.sessionId}`);
|
|
121609
|
-
break;
|
|
121610
|
-
}
|
|
121611
|
-
this.options.onCodexImageGenerationBegin?.({
|
|
121612
|
-
acpSessionId: result.data.sessionId,
|
|
121613
|
-
callId: result.data.callId
|
|
121614
|
-
});
|
|
121615
|
-
break;
|
|
121616
|
-
}
|
|
121617
|
-
case "acp_ext:image_generation_end": {
|
|
121618
|
-
if (!this.isCodexAgent()) {
|
|
121619
|
-
break;
|
|
121620
|
-
}
|
|
121621
|
-
const result = CodexImageGenerationEndParamsSchema.safeParse(params);
|
|
121622
|
-
if (!result.success) {
|
|
121623
|
-
this.logger.debug(`[${this.options.sessionId}] Dropping invalid Codex image generation end: ${result.error.message}`);
|
|
121624
|
-
break;
|
|
121625
|
-
}
|
|
121626
|
-
if (!this.isCurrentAcpSession(result.data.sessionId)) {
|
|
121627
|
-
this.logger.debug(`[${this.options.sessionId}] Dropping Codex image generation end for mismatched ACP session: ${result.data.sessionId}`);
|
|
121628
|
-
break;
|
|
121629
|
-
}
|
|
121630
|
-
this.options.onCodexImageGenerationEnd?.({
|
|
121631
|
-
acpSessionId: result.data.sessionId,
|
|
121632
|
-
callId: result.data.callId,
|
|
121633
|
-
status: result.data.status,
|
|
121634
|
-
revisedPrompt: result.data.revisedPrompt,
|
|
121635
|
-
savedPath: result.data.savedPath
|
|
121636
|
-
});
|
|
121637
|
-
break;
|
|
121638
|
-
}
|
|
121639
122045
|
}
|
|
121640
122046
|
}
|
|
121641
122047
|
isCodexAgent() {
|
|
@@ -121653,7 +122059,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
121653
122059
|
type: "initialize_start"
|
|
121654
122060
|
});
|
|
121655
122061
|
const ACP_INIT_TIMEOUT_MS = Math.max(0, timeoutOptions.initTimeoutMs ?? 12e4);
|
|
121656
|
-
const initResponse = await withTimeout$
|
|
122062
|
+
const initResponse = await withTimeout$2(withAbort(connection.initialize({
|
|
121657
122063
|
protocolVersion: PROTOCOL_VERSION,
|
|
121658
122064
|
clientCapabilities: {
|
|
121659
122065
|
terminal: this.terminalEnabled,
|
|
@@ -121761,7 +122167,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
121761
122167
|
} else {
|
|
121762
122168
|
this.logger.debug(`[${this.options.sessionId}] Calling connection.newSession (cwd=${workdir})`);
|
|
121763
122169
|
const ACP_NEW_SESSION_TIMEOUT_MS = Math.max(0, timeoutOptions.newSessionTimeoutMs ?? 12e4);
|
|
121764
|
-
sessionResponse = await withTimeout$
|
|
122170
|
+
sessionResponse = await withTimeout$2(withAbort(connection.newSession({
|
|
121765
122171
|
cwd: workdir,
|
|
121766
122172
|
mcpServers
|
|
121767
122173
|
}), startupAbort), this.logger, "connection.newSession", this.options.sessionId, ACP_NEW_SESSION_TIMEOUT_MS);
|
|
@@ -121874,7 +122280,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
121874
122280
|
return false;
|
|
121875
122281
|
}
|
|
121876
122282
|
this.logger.debug(`[${this.options.sessionId}] Closing ACP session (acpSessionId=${sessionId} timeoutMs=${timeoutMs})`);
|
|
121877
|
-
await withTimeout$
|
|
122283
|
+
await withTimeout$2(closeSession2.call(this.connection, {
|
|
121878
122284
|
sessionId
|
|
121879
122285
|
}), this.logger, "connection.closeSession", this.options.sessionId, timeoutMs, Math.min(timeoutMs, 1e3));
|
|
121880
122286
|
this.logger.debug(`[${this.options.sessionId}] ACP session close finished (acpSessionId=${sessionId})`);
|
|
@@ -122012,11 +122418,13 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122012
122418
|
},
|
|
122013
122419
|
codex: {
|
|
122014
122420
|
packageName: "acp-extension-codex",
|
|
122015
|
-
version: "0.
|
|
122421
|
+
version: "0.14.3",
|
|
122016
122422
|
binName: "acp-extension-codex",
|
|
122017
122423
|
args: [
|
|
122018
122424
|
"-c",
|
|
122019
|
-
"shell_environment_policy.ignore_default_excludes=true"
|
|
122425
|
+
"shell_environment_policy.ignore_default_excludes=true",
|
|
122426
|
+
"-c",
|
|
122427
|
+
"features.goals=true"
|
|
122020
122428
|
]
|
|
122021
122429
|
}
|
|
122022
122430
|
};
|
|
@@ -122030,12 +122438,50 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122030
122438
|
"claude",
|
|
122031
122439
|
"codex"
|
|
122032
122440
|
]);
|
|
122441
|
+
const moduleRequire = createRequire$1(import.meta.url);
|
|
122442
|
+
function isRecord$1(value) {
|
|
122443
|
+
return typeof value === "object" && value !== null;
|
|
122444
|
+
}
|
|
122445
|
+
function resolveInstalledPackageBin(setting) {
|
|
122446
|
+
try {
|
|
122447
|
+
const packageJsonPath = moduleRequire.resolve(`${setting.packageName}/package.json`);
|
|
122448
|
+
const packageJson = JSON.parse(readFileSync$1(packageJsonPath, "utf8"));
|
|
122449
|
+
if (!isRecord$1(packageJson) || packageJson.version !== setting.version) {
|
|
122450
|
+
return void 0;
|
|
122451
|
+
}
|
|
122452
|
+
const bin2 = packageJson.bin;
|
|
122453
|
+
const namedBin = isRecord$1(bin2) ? bin2[setting.binName] : void 0;
|
|
122454
|
+
const relativeBin = typeof bin2 === "string" ? bin2 : typeof namedBin === "string" ? namedBin : void 0;
|
|
122455
|
+
if (!relativeBin) {
|
|
122456
|
+
return void 0;
|
|
122457
|
+
}
|
|
122458
|
+
const binPath = resolve$2(dirname$1(packageJsonPath), relativeBin);
|
|
122459
|
+
return existsSync(binPath) ? binPath : void 0;
|
|
122460
|
+
} catch {
|
|
122461
|
+
return void 0;
|
|
122462
|
+
}
|
|
122463
|
+
}
|
|
122033
122464
|
function resolveBuiltinACPSetting(agentType) {
|
|
122034
122465
|
if (!builtinTypeSet.has(agentType)) {
|
|
122035
122466
|
throw new Error(`Unsupported builtin ACP type: ${agentType}`);
|
|
122036
122467
|
}
|
|
122037
122468
|
const builtinType = agentType;
|
|
122038
122469
|
const setting = BuiltinACPSetting[builtinType];
|
|
122470
|
+
if (builtinType === "claude") {
|
|
122471
|
+
const localClaudeAcpPath = resolveInstalledPackageBin(setting);
|
|
122472
|
+
if (localClaudeAcpPath) {
|
|
122473
|
+
return {
|
|
122474
|
+
status: {
|
|
122475
|
+
agent: `local ${setting.packageName}@${setting.version}`,
|
|
122476
|
+
command: localClaudeAcpPath
|
|
122477
|
+
},
|
|
122478
|
+
exec: {
|
|
122479
|
+
command: localClaudeAcpPath,
|
|
122480
|
+
args: setting.args ?? []
|
|
122481
|
+
}
|
|
122482
|
+
};
|
|
122483
|
+
}
|
|
122484
|
+
}
|
|
122039
122485
|
const agent = `${setting.packageName}@${setting.version}`;
|
|
122040
122486
|
const packageSpec = `${setting.packageName}@${setting.version}`;
|
|
122041
122487
|
const args2 = [
|
|
@@ -122072,11 +122518,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122072
122518
|
}
|
|
122073
122519
|
return `${agent.id}@${agent.version}`;
|
|
122074
122520
|
}
|
|
122075
|
-
function
|
|
122076
|
-
const agent = registryAgentsById[agentType];
|
|
122077
|
-
if (!agent) {
|
|
122078
|
-
throw new Error(`Unknown registry ACP type: ${agentType}`);
|
|
122079
|
-
}
|
|
122521
|
+
function resolveRegistryAgentACPSetting(agent) {
|
|
122080
122522
|
if (agent.distribution.local?.command) {
|
|
122081
122523
|
const isNpx = agent.distribution.local.command === "npx";
|
|
122082
122524
|
const args2 = [
|
|
@@ -122116,7 +122558,31 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122116
122558
|
}
|
|
122117
122559
|
};
|
|
122118
122560
|
}
|
|
122119
|
-
|
|
122561
|
+
if (agent.distribution.uvx?.package) {
|
|
122562
|
+
const args2 = [
|
|
122563
|
+
agent.distribution.uvx.package,
|
|
122564
|
+
...agent.distribution.uvx.args ?? []
|
|
122565
|
+
];
|
|
122566
|
+
return {
|
|
122567
|
+
status: {
|
|
122568
|
+
agent: `${agent.name}@${agent.version}`,
|
|
122569
|
+
command: "uvx"
|
|
122570
|
+
},
|
|
122571
|
+
exec: {
|
|
122572
|
+
command: "uvx",
|
|
122573
|
+
args: args2,
|
|
122574
|
+
env: agent.distribution.uvx.env
|
|
122575
|
+
}
|
|
122576
|
+
};
|
|
122577
|
+
}
|
|
122578
|
+
throw new Error(`Registry ACP ${agent.id} has no supported launcher`);
|
|
122579
|
+
}
|
|
122580
|
+
function resolveRegistryACPSetting(agentType) {
|
|
122581
|
+
const agent = registryAgentsById[agentType];
|
|
122582
|
+
if (!agent) {
|
|
122583
|
+
throw new Error(`Unknown registry ACP type: ${agentType}`);
|
|
122584
|
+
}
|
|
122585
|
+
return resolveRegistryAgentACPSetting(agent);
|
|
122120
122586
|
}
|
|
122121
122587
|
function resolveACPSetting(input2) {
|
|
122122
122588
|
if (input2.cliType === "builtin") {
|
|
@@ -122327,7 +122793,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122327
122793
|
sessionResponse
|
|
122328
122794
|
};
|
|
122329
122795
|
};
|
|
122330
|
-
function waitForChildProcessExit(child, timeoutMs) {
|
|
122796
|
+
function waitForChildProcessExit$1(child, timeoutMs) {
|
|
122331
122797
|
if (child.exitCode !== null) {
|
|
122332
122798
|
return Promise.resolve(true);
|
|
122333
122799
|
}
|
|
@@ -122348,32 +122814,32 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122348
122814
|
child.once("exit", onExit2);
|
|
122349
122815
|
});
|
|
122350
122816
|
}
|
|
122351
|
-
function signalChildProcess(child, signal) {
|
|
122817
|
+
function signalChildProcess$1(child, signal) {
|
|
122352
122818
|
if (process.platform !== "win32" && typeof child.pid === "number" && child.pid > 0) {
|
|
122353
122819
|
process.kill(-child.pid, signal);
|
|
122354
122820
|
return;
|
|
122355
122821
|
}
|
|
122356
122822
|
child.kill(signal);
|
|
122357
122823
|
}
|
|
122358
|
-
async function terminateChildProcess(child, logger2, sessionLabel, exitTimeoutMs) {
|
|
122824
|
+
async function terminateChildProcess$1(child, logger2, sessionLabel, exitTimeoutMs) {
|
|
122359
122825
|
if (child.exitCode !== null) {
|
|
122360
122826
|
return;
|
|
122361
122827
|
}
|
|
122362
122828
|
try {
|
|
122363
|
-
signalChildProcess(child, "SIGTERM");
|
|
122829
|
+
signalChildProcess$1(child, "SIGTERM");
|
|
122364
122830
|
} catch {
|
|
122365
122831
|
return;
|
|
122366
122832
|
}
|
|
122367
|
-
if (await waitForChildProcessExit(child, exitTimeoutMs)) {
|
|
122833
|
+
if (await waitForChildProcessExit$1(child, exitTimeoutMs)) {
|
|
122368
122834
|
return;
|
|
122369
122835
|
}
|
|
122370
122836
|
logger2.debug(`[${sessionLabel}] ACP agent process did not exit within ${exitTimeoutMs}ms of SIGTERM; escalating to SIGKILL`);
|
|
122371
122837
|
try {
|
|
122372
|
-
signalChildProcess(child, "SIGKILL");
|
|
122838
|
+
signalChildProcess$1(child, "SIGKILL");
|
|
122373
122839
|
} catch {
|
|
122374
122840
|
return;
|
|
122375
122841
|
}
|
|
122376
|
-
await waitForChildProcessExit(child, exitTimeoutMs);
|
|
122842
|
+
await waitForChildProcessExit$1(child, exitTimeoutMs);
|
|
122377
122843
|
}
|
|
122378
122844
|
const spawnAcpProcess = (options) => {
|
|
122379
122845
|
const setting = resolveACPSetting({
|
|
@@ -122520,7 +122986,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122520
122986
|
sessionResponse: started.sessionResponse
|
|
122521
122987
|
};
|
|
122522
122988
|
} catch (error2) {
|
|
122523
|
-
await terminateChildProcess(agentProcess, options.logger, "acp-startup", 3e3);
|
|
122989
|
+
await terminateChildProcess$1(agentProcess, options.logger, "acp-startup", 3e3);
|
|
122524
122990
|
throw error2;
|
|
122525
122991
|
} finally {
|
|
122526
122992
|
startupMonitor.dispose();
|
|
@@ -122536,7 +123002,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122536
123002
|
options.logger.debug(`[${options.sessionLabel}] ACP session close failed during local agent shutdown: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
122537
123003
|
}
|
|
122538
123004
|
}
|
|
122539
|
-
await terminateChildProcess(options.agentProcess, options.logger, options.sessionLabel, exitTimeoutMs);
|
|
123005
|
+
await terminateChildProcess$1(options.agentProcess, options.logger, options.sessionLabel, exitTimeoutMs);
|
|
122540
123006
|
}
|
|
122541
123007
|
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
122542
123008
|
const getStringField = (obj, key2) => {
|
|
@@ -124668,6 +125134,8 @@ path=/${options.repoFullName}.git
|
|
|
124668
125134
|
codexImageGenerationTurnIds: /* @__PURE__ */ new Map(),
|
|
124669
125135
|
codexImageGenerationUploads: /* @__PURE__ */ new Map(),
|
|
124670
125136
|
codexImageGenerationUploadedCallIds: /* @__PURE__ */ new Set(),
|
|
125137
|
+
codexImageGenerationActiveCallIds: /* @__PURE__ */ new Set(),
|
|
125138
|
+
codexImageGenerationActivityStatusChain: Promise.resolve(),
|
|
124671
125139
|
permissionWaitMs: 0,
|
|
124672
125140
|
autoApprovePermissions: false,
|
|
124673
125141
|
pendingUnread: false,
|
|
@@ -124767,6 +125235,7 @@ path=/${options.repoFullName}.git
|
|
|
124767
125235
|
state2.contextWindowUsageTimer = null;
|
|
124768
125236
|
}
|
|
124769
125237
|
state2.contextWindowUsageBuffer = null;
|
|
125238
|
+
state2.codexImageGenerationActiveCallIds.clear();
|
|
124770
125239
|
state2.permissionWaitMs = 0;
|
|
124771
125240
|
state2.pendingUnread = false;
|
|
124772
125241
|
}
|
|
@@ -125543,6 +126012,154 @@ $mem | ConvertTo-Json -Compress
|
|
|
125543
126012
|
return null;
|
|
125544
126013
|
}
|
|
125545
126014
|
}
|
|
126015
|
+
function getImportedAcpSourceAcpSessionId(meta) {
|
|
126016
|
+
const externalHistory = meta.externalHistory;
|
|
126017
|
+
const provider2 = externalHistory?.provider;
|
|
126018
|
+
if (!externalHistory || provider2 !== "codex" && provider2 !== "claude") {
|
|
126019
|
+
return void 0;
|
|
126020
|
+
}
|
|
126021
|
+
return externalHistory.sourceAcpSessionId;
|
|
126022
|
+
}
|
|
126023
|
+
function isImportedAcpReplayUserTurn(entry2, meta) {
|
|
126024
|
+
const provider2 = meta.externalHistory?.provider;
|
|
126025
|
+
const sourceAcpSessionId = getImportedAcpSourceAcpSessionId(meta);
|
|
126026
|
+
return !!provider2 && !!sourceAcpSessionId && entry2.id.startsWith(`${provider2}:${sourceAcpSessionId}:turn:`);
|
|
126027
|
+
}
|
|
126028
|
+
function resolveResumableAcpSessionId(meta) {
|
|
126029
|
+
const acpSessionId = meta?.acpSessionId;
|
|
126030
|
+
if (!meta || !acpSessionId) {
|
|
126031
|
+
return void 0;
|
|
126032
|
+
}
|
|
126033
|
+
if (!meta.externalHistory) {
|
|
126034
|
+
return acpSessionId;
|
|
126035
|
+
}
|
|
126036
|
+
const sourceAcpSessionId = meta.externalHistory.sourceAcpSessionId;
|
|
126037
|
+
if (!sourceAcpSessionId) {
|
|
126038
|
+
return void 0;
|
|
126039
|
+
}
|
|
126040
|
+
return acpSessionId === sourceAcpSessionId ? void 0 : acpSessionId;
|
|
126041
|
+
}
|
|
126042
|
+
function resolveDispatchAcpSessionId(meta) {
|
|
126043
|
+
const liveSessionId = resolveResumableAcpSessionId(meta);
|
|
126044
|
+
if (liveSessionId || !meta?.externalHistory || meta.externalHistory.status === "sync_conflict") {
|
|
126045
|
+
return liveSessionId;
|
|
126046
|
+
}
|
|
126047
|
+
return meta.externalHistory.sourceAcpSessionId;
|
|
126048
|
+
}
|
|
126049
|
+
function resolveSessionDispatchAction(snapshot, machineId) {
|
|
126050
|
+
const { meta, history, hasActiveTurn, hasBlockingPendingCreate, hasReusableSession } = snapshot;
|
|
126051
|
+
if (!meta || meta.machineId !== machineId) {
|
|
126052
|
+
return {
|
|
126053
|
+
type: "noop",
|
|
126054
|
+
reason: "not-owned"
|
|
126055
|
+
};
|
|
126056
|
+
}
|
|
126057
|
+
if (meta.isArchived) {
|
|
126058
|
+
return {
|
|
126059
|
+
type: "noop",
|
|
126060
|
+
reason: "archived"
|
|
126061
|
+
};
|
|
126062
|
+
}
|
|
126063
|
+
if (hasBlockingPendingCreate) {
|
|
126064
|
+
return {
|
|
126065
|
+
type: "noop",
|
|
126066
|
+
reason: "pending-create"
|
|
126067
|
+
};
|
|
126068
|
+
}
|
|
126069
|
+
const statusType = meta.status?.type;
|
|
126070
|
+
if (statusType === "running" || statusType === "requestPermission" || statusType === "initializing") {
|
|
126071
|
+
if (hasActiveTurn) {
|
|
126072
|
+
return {
|
|
126073
|
+
type: "noop",
|
|
126074
|
+
reason: "active-session"
|
|
126075
|
+
};
|
|
126076
|
+
}
|
|
126077
|
+
return {
|
|
126078
|
+
type: "reset-stale-status",
|
|
126079
|
+
statusType
|
|
126080
|
+
};
|
|
126081
|
+
}
|
|
126082
|
+
const turn = findNextDispatchableUserTurn(history, meta);
|
|
126083
|
+
if (!turn) {
|
|
126084
|
+
return {
|
|
126085
|
+
type: "no-dispatchable-turn"
|
|
126086
|
+
};
|
|
126087
|
+
}
|
|
126088
|
+
const mode2 = hasReusableSession || resolveDispatchAcpSessionId(meta) ? "continue" : "create";
|
|
126089
|
+
return {
|
|
126090
|
+
type: "dispatch",
|
|
126091
|
+
mode: mode2,
|
|
126092
|
+
turn
|
|
126093
|
+
};
|
|
126094
|
+
}
|
|
126095
|
+
function resolveSessionCancelAction(meta, lastSeenCancelTurn, machineId) {
|
|
126096
|
+
if (!meta || meta.machineId !== machineId) {
|
|
126097
|
+
return {
|
|
126098
|
+
type: "noop",
|
|
126099
|
+
reason: "not-owned"
|
|
126100
|
+
};
|
|
126101
|
+
}
|
|
126102
|
+
if (meta.isArchived) {
|
|
126103
|
+
return {
|
|
126104
|
+
type: "noop",
|
|
126105
|
+
reason: "archived"
|
|
126106
|
+
};
|
|
126107
|
+
}
|
|
126108
|
+
const lastCanceledTurn = meta.lastCanceledTurn;
|
|
126109
|
+
if (typeof lastCanceledTurn !== "string" || !lastCanceledTurn) {
|
|
126110
|
+
return {
|
|
126111
|
+
type: "noop",
|
|
126112
|
+
reason: "no-cancel-turn"
|
|
126113
|
+
};
|
|
126114
|
+
}
|
|
126115
|
+
if (lastCanceledTurn === lastSeenCancelTurn) {
|
|
126116
|
+
return {
|
|
126117
|
+
type: "noop",
|
|
126118
|
+
reason: "already-seen"
|
|
126119
|
+
};
|
|
126120
|
+
}
|
|
126121
|
+
return {
|
|
126122
|
+
type: "cancel",
|
|
126123
|
+
turnId: lastCanceledTurn
|
|
126124
|
+
};
|
|
126125
|
+
}
|
|
126126
|
+
function findNextDispatchableUserTurn(history, meta) {
|
|
126127
|
+
for (const entry2 of history) {
|
|
126128
|
+
if (entry2.role !== "user") {
|
|
126129
|
+
continue;
|
|
126130
|
+
}
|
|
126131
|
+
if (isImportedAcpReplayUserTurn(entry2, meta)) {
|
|
126132
|
+
continue;
|
|
126133
|
+
}
|
|
126134
|
+
if (typeof entry2.status === "string") {
|
|
126135
|
+
if (entry2.status === "pending" || entry2.status === "seen" || entry2.status === "processing") {
|
|
126136
|
+
return entry2;
|
|
126137
|
+
}
|
|
126138
|
+
continue;
|
|
126139
|
+
}
|
|
126140
|
+
if (entry2.read === false) {
|
|
126141
|
+
return entry2;
|
|
126142
|
+
}
|
|
126143
|
+
if (entry2.id === meta.processingUserMsgId) {
|
|
126144
|
+
return entry2;
|
|
126145
|
+
}
|
|
126146
|
+
if (entry2.id === meta.latestUserMsgId && entry2.id !== meta.lastHandledUserMsgId) {
|
|
126147
|
+
return entry2;
|
|
126148
|
+
}
|
|
126149
|
+
}
|
|
126150
|
+
return null;
|
|
126151
|
+
}
|
|
126152
|
+
function resolveDispatchTurnInput(entry2) {
|
|
126153
|
+
const historyBlocks = historyItemsToInputBlocks(entry2.items);
|
|
126154
|
+
const configuredBlocks = normalizeSessionInputBlocks(entry2.inputConfig?.inputBlocks, "");
|
|
126155
|
+
const fallbackBlocks = normalizeSessionInputBlocks(void 0, entry2.inputConfig?.prompt ?? "");
|
|
126156
|
+
const inputBlocks = configuredBlocks.length > 0 ? configuredBlocks : historyBlocks.length > 0 ? historyBlocks : fallbackBlocks;
|
|
126157
|
+
const prompt2 = entry2.inputConfig?.prompt ?? extractPromptPreviewFromInputBlocks(inputBlocks.length > 0 ? inputBlocks : historyBlocks);
|
|
126158
|
+
return {
|
|
126159
|
+
inputBlocks,
|
|
126160
|
+
prompt: prompt2
|
|
126161
|
+
};
|
|
126162
|
+
}
|
|
125546
126163
|
class SessionTurnCancelled extends TaggedError("SessionTurnCancelled") {
|
|
125547
126164
|
}
|
|
125548
126165
|
class SessionTurnHalted extends TaggedError("SessionTurnHalted") {
|
|
@@ -125618,17 +126235,15 @@ $mem | ConvertTo-Json -Compress
|
|
|
125618
126235
|
const { sessionId, threadId: threadId2, command: command2 } = request;
|
|
125619
126236
|
this.deps.logger.debug(`[${sessionId}] Goal command requested (command=${command2} threadId=${threadId2})`);
|
|
125620
126237
|
const existingSession = this.deps.sessionManager.getSession(sessionId);
|
|
125621
|
-
|
|
125622
|
-
const candidateSession = existingSession ?? (pendingSession ? await pendingSession : null);
|
|
125623
|
-
if (candidateSession?.agentClient && candidateSession.acpSessionId) {
|
|
126238
|
+
if (existingSession?.agentClient && existingSession.acpSessionId) {
|
|
125624
126239
|
try {
|
|
125625
|
-
await
|
|
126240
|
+
await existingSession.agentClient.controlThreadGoal(existingSession.acpSessionId, command2, threadId2);
|
|
125626
126241
|
this.deps.logger.debug(`[${sessionId}] Goal command sent through ACP extension method (command=${command2})`);
|
|
125627
126242
|
return {
|
|
125628
126243
|
status: "handled"
|
|
125629
126244
|
};
|
|
125630
126245
|
} catch (error2) {
|
|
125631
|
-
this.deps.logger.debug(`[${sessionId}] ACP extension goal command unavailable; falling back to
|
|
126246
|
+
this.deps.logger.debug(`[${sessionId}] ACP extension goal command unavailable; falling back to local state update: ${formatErrorMessage(error2)}`);
|
|
125632
126247
|
}
|
|
125633
126248
|
}
|
|
125634
126249
|
if (this.getExecutionSnapshot(sessionId).hasActiveTurn) {
|
|
@@ -125638,26 +126253,8 @@ $mem | ConvertTo-Json -Compress
|
|
|
125638
126253
|
};
|
|
125639
126254
|
}
|
|
125640
126255
|
try {
|
|
125641
|
-
|
|
125642
|
-
|
|
125643
|
-
return {
|
|
125644
|
-
status: "failed",
|
|
125645
|
-
error: "Agent session is not ready"
|
|
125646
|
-
};
|
|
125647
|
-
}
|
|
125648
|
-
this.deps.beginACPReplaySuppression(sessionId);
|
|
125649
|
-
try {
|
|
125650
|
-
await session.agentClient.prompt(session.acpSessionId, [
|
|
125651
|
-
{
|
|
125652
|
-
type: "text",
|
|
125653
|
-
text: `/goal ${command2}`
|
|
125654
|
-
}
|
|
125655
|
-
]);
|
|
125656
|
-
} finally {
|
|
125657
|
-
this.deps.endACPReplaySuppression(sessionId);
|
|
125658
|
-
}
|
|
125659
|
-
this.deps.touchSession(sessionId);
|
|
125660
|
-
this.deps.logger.debug(`[${sessionId}] Goal command sent through hidden slash command (command=${command2})`);
|
|
126256
|
+
await this.persistLocalGoalCommandFallback(request);
|
|
126257
|
+
this.deps.logger.debug(`[${sessionId}] Goal command applied through local state fallback (command=${command2})`);
|
|
125661
126258
|
return {
|
|
125662
126259
|
status: "handled"
|
|
125663
126260
|
};
|
|
@@ -125670,58 +126267,50 @@ $mem | ConvertTo-Json -Compress
|
|
|
125670
126267
|
};
|
|
125671
126268
|
}
|
|
125672
126269
|
}
|
|
125673
|
-
async
|
|
125674
|
-
const existing = this.deps.sessionManager.getSession(request.sessionId);
|
|
125675
|
-
if (existing) {
|
|
125676
|
-
return existing;
|
|
125677
|
-
}
|
|
125678
|
-
const pending2 = this.deps.sessionManager.getPendingSession(request.sessionId);
|
|
125679
|
-
if (pending2) {
|
|
125680
|
-
return await pending2;
|
|
125681
|
-
}
|
|
125682
|
-
const sessionDoc = await this.deps.workspaceDocument.getOrCreateSessionDoc(request.sessionId);
|
|
126270
|
+
async resolveThreadGoalForLocalFallback(sessionDoc, threadId2) {
|
|
125683
126271
|
const meta = await sessionDoc.getMetaState();
|
|
125684
|
-
|
|
125685
|
-
|
|
126272
|
+
const metaGoal = meta?.latestGoal;
|
|
126273
|
+
if (metaGoal?.threadId === threadId2) {
|
|
126274
|
+
return metaGoal;
|
|
125686
126275
|
}
|
|
125687
|
-
|
|
125688
|
-
|
|
126276
|
+
const historyGoal = resolveLatestSessionGoalFromHistory(await sessionDoc.getHistory());
|
|
126277
|
+
if (historyGoal?.threadId === threadId2) {
|
|
126278
|
+
return historyGoal;
|
|
126279
|
+
}
|
|
126280
|
+
return null;
|
|
126281
|
+
}
|
|
126282
|
+
async resolveLatestGoalForCompletionNotification(sessionId, sessionDoc) {
|
|
126283
|
+
let metaGoal = null;
|
|
126284
|
+
try {
|
|
126285
|
+
metaGoal = (await sessionDoc.getMetaState())?.latestGoal ?? null;
|
|
126286
|
+
} catch (error2) {
|
|
126287
|
+
this.deps.logger.debug(`[${sessionId}] Failed to read latest goal meta before completion notification: ${formatErrorMessage(error2)}`);
|
|
125689
126288
|
}
|
|
125690
|
-
|
|
125691
|
-
|
|
126289
|
+
try {
|
|
126290
|
+
return resolveLatestSessionGoalFromHistory(await sessionDoc.getHistory()) ?? metaGoal;
|
|
126291
|
+
} catch (error2) {
|
|
126292
|
+
this.deps.logger.debug(`[${sessionId}] Failed to read latest goal history before completion notification: ${formatErrorMessage(error2)}`);
|
|
126293
|
+
return metaGoal;
|
|
125692
126294
|
}
|
|
125693
|
-
|
|
125694
|
-
|
|
125695
|
-
const
|
|
125696
|
-
|
|
125697
|
-
|
|
126295
|
+
}
|
|
126296
|
+
async persistLocalGoalCommandFallback(request) {
|
|
126297
|
+
const sessionDoc = await this.deps.workspaceDocument.getOrCreateSessionDoc(request.sessionId);
|
|
126298
|
+
const existingGoal = await this.resolveThreadGoalForLocalFallback(sessionDoc, request.threadId);
|
|
126299
|
+
if (!existingGoal) {
|
|
126300
|
+
if (request.command === "clear") {
|
|
126301
|
+
return;
|
|
126302
|
+
}
|
|
126303
|
+
throw new Error(`Goal thread not found: ${request.threadId}`);
|
|
125698
126304
|
}
|
|
125699
|
-
const
|
|
125700
|
-
|
|
125701
|
-
|
|
125702
|
-
|
|
125703
|
-
|
|
125704
|
-
sessionId: request.sessionId,
|
|
125705
|
-
workspaceId: this.deps.workspaceId,
|
|
125706
|
-
agentCliType: meta.cliType,
|
|
125707
|
-
agentType: meta.agentType,
|
|
125708
|
-
userId: request.userId,
|
|
125709
|
-
machineId: this.deps.machineId,
|
|
125710
|
-
assumeDocExisting: true,
|
|
125711
|
-
env: agentConfigEnvResolution.env ?? void 0,
|
|
125712
|
-
githubRepo: resolveProjectGitHubRepo(project),
|
|
125713
|
-
branch: project?.branch?.trim() || void 0,
|
|
125714
|
-
restoreBranchName: meta.branchName?.trim() || void 0,
|
|
125715
|
-
project,
|
|
125716
|
-
resume: true,
|
|
125717
|
-
workdir,
|
|
125718
|
-
parentSessionId: meta.parentSessionId,
|
|
125719
|
-
userName: request.userName,
|
|
125720
|
-
userEmail: request.userEmail
|
|
126305
|
+
const nextStatus = request.command === "pause" ? "paused" : request.command === "resume" ? "active" : "cleared";
|
|
126306
|
+
const updatedGoal = {
|
|
126307
|
+
...existingGoal,
|
|
126308
|
+
status: nextStatus,
|
|
126309
|
+
updatedAt: getServerNow()
|
|
125721
126310
|
};
|
|
125722
|
-
|
|
125723
|
-
|
|
125724
|
-
|
|
126311
|
+
await upsertThreadGoalInHistory(sessionDoc, updatedGoal);
|
|
126312
|
+
await this.deps.workspaceDocument.repo.upsertDocMeta(sessionDoc.roomId, {
|
|
126313
|
+
latestGoal: updatedGoal
|
|
125725
126314
|
});
|
|
125726
126315
|
}
|
|
125727
126316
|
formatGiB(bytes) {
|
|
@@ -126058,7 +126647,8 @@ $mem | ConvertTo-Json -Compress
|
|
|
126058
126647
|
const rawDataMessage = dataObj?.message;
|
|
126059
126648
|
const dataDetails = typeof rawDetails === "string" && rawDetails.length > 0 ? rawDetails : void 0;
|
|
126060
126649
|
const dataMessage = typeof rawDataMessage === "string" && rawDataMessage.length > 0 ? rawDataMessage : void 0;
|
|
126061
|
-
const
|
|
126650
|
+
const dataString = typeof acpError.data === "string" && acpError.data.length > 0 ? acpError.data : void 0;
|
|
126651
|
+
const userMessage = dataDetails || dataMessage || dataString || acpError.message;
|
|
126062
126652
|
this.deps.logger.warn(`[${sessionId}] ACP error occurred (code=${acpError.code} reason=${failureReason}): ${userMessage}`);
|
|
126063
126653
|
await this.deps.recordChatFailure(sessionDoc, failureReason, userMessage);
|
|
126064
126654
|
if (this.shouldTerminateOnACPError(acpError.code, failureReason)) {
|
|
@@ -126162,6 +126752,11 @@ $mem | ConvertTo-Json -Compress
|
|
|
126162
126752
|
this.deps.logger.debug(`[${sessionId}] Failed to persist session lastMessageAt: ${formatErrorMessage(error2)}`);
|
|
126163
126753
|
}
|
|
126164
126754
|
this.deps.touchSession(sessionId);
|
|
126755
|
+
const latestGoal = await this.resolveLatestGoalForCompletionNotification(sessionId, sessionDoc);
|
|
126756
|
+
if (isSessionGoalWorking(latestGoal)) {
|
|
126757
|
+
this.deps.logger.debug(`[${sessionId}] Skipping session completion notification because a thread goal is still active`);
|
|
126758
|
+
return;
|
|
126759
|
+
}
|
|
126165
126760
|
await this.deps.turnFinalization.notifySessionCompleted(sessionId, userId);
|
|
126166
126761
|
}
|
|
126167
126762
|
async runVisibleSessionTurn(options, body) {
|
|
@@ -126557,7 +127152,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
126557
127152
|
const agentConfigEnv = agentConfigEnvResolution.env ?? void 0;
|
|
126558
127153
|
self2.deps.logger.debug(`[${sessionId}] Resume env resolved (agentConfigId=${meta?.agentConfigId ?? "none"} reason=${agentConfigEnvResolution.reason} keys=${agentConfigEnv ? Object.keys(agentConfigEnv).length : 0})`);
|
|
126559
127154
|
const requestedResumeSessionId = acpSessionConfig.resume;
|
|
126560
|
-
const storedResumeSessionId = meta
|
|
127155
|
+
const storedResumeSessionId = resolveResumableAcpSessionId(meta);
|
|
126561
127156
|
const resumeSessionId = requestedResumeSessionId ?? storedResumeSessionId;
|
|
126562
127157
|
const resumeSource = requestedResumeSessionId ? "request" : storedResumeSessionId ? "meta" : "none";
|
|
126563
127158
|
self2.deps.logger.debug(`[${sessionId}] Session not found in memory; restoring (project=${project?.kind === "github" ? project.repoFullName : project?.kind === "local" ? `local:${project.localProjectId}` : "none"} resume=${resumeSessionId ? "yes" : "no"} resumeSource=${resumeSource} resumeSessionId=${resumeSessionId ?? "none"})`);
|
|
@@ -127274,117 +127869,6 @@ $mem | ConvertTo-Json -Compress
|
|
|
127274
127869
|
};
|
|
127275
127870
|
}
|
|
127276
127871
|
}
|
|
127277
|
-
function resolveSessionDispatchAction(snapshot, machineId) {
|
|
127278
|
-
const { meta, history, hasActiveTurn, hasBlockingPendingCreate, hasReusableSession } = snapshot;
|
|
127279
|
-
if (!meta || meta.machineId !== machineId) {
|
|
127280
|
-
return {
|
|
127281
|
-
type: "noop",
|
|
127282
|
-
reason: "not-owned"
|
|
127283
|
-
};
|
|
127284
|
-
}
|
|
127285
|
-
if (meta.isArchived) {
|
|
127286
|
-
return {
|
|
127287
|
-
type: "noop",
|
|
127288
|
-
reason: "archived"
|
|
127289
|
-
};
|
|
127290
|
-
}
|
|
127291
|
-
if (hasBlockingPendingCreate) {
|
|
127292
|
-
return {
|
|
127293
|
-
type: "noop",
|
|
127294
|
-
reason: "pending-create"
|
|
127295
|
-
};
|
|
127296
|
-
}
|
|
127297
|
-
const statusType = meta.status?.type;
|
|
127298
|
-
if (statusType === "running" || statusType === "requestPermission" || statusType === "initializing") {
|
|
127299
|
-
if (hasActiveTurn) {
|
|
127300
|
-
return {
|
|
127301
|
-
type: "noop",
|
|
127302
|
-
reason: "active-session"
|
|
127303
|
-
};
|
|
127304
|
-
}
|
|
127305
|
-
return {
|
|
127306
|
-
type: "reset-stale-status",
|
|
127307
|
-
statusType
|
|
127308
|
-
};
|
|
127309
|
-
}
|
|
127310
|
-
const turn = findNextDispatchableUserTurn(history, meta);
|
|
127311
|
-
if (!turn) {
|
|
127312
|
-
return {
|
|
127313
|
-
type: "no-dispatchable-turn"
|
|
127314
|
-
};
|
|
127315
|
-
}
|
|
127316
|
-
const mode2 = hasReusableSession || meta.acpSessionId ? "continue" : "create";
|
|
127317
|
-
return {
|
|
127318
|
-
type: "dispatch",
|
|
127319
|
-
mode: mode2,
|
|
127320
|
-
turn
|
|
127321
|
-
};
|
|
127322
|
-
}
|
|
127323
|
-
function resolveSessionCancelAction(meta, lastSeenCancelTurn, machineId) {
|
|
127324
|
-
if (!meta || meta.machineId !== machineId) {
|
|
127325
|
-
return {
|
|
127326
|
-
type: "noop",
|
|
127327
|
-
reason: "not-owned"
|
|
127328
|
-
};
|
|
127329
|
-
}
|
|
127330
|
-
if (meta.isArchived) {
|
|
127331
|
-
return {
|
|
127332
|
-
type: "noop",
|
|
127333
|
-
reason: "archived"
|
|
127334
|
-
};
|
|
127335
|
-
}
|
|
127336
|
-
const lastCanceledTurn = meta.lastCanceledTurn;
|
|
127337
|
-
if (typeof lastCanceledTurn !== "string" || !lastCanceledTurn) {
|
|
127338
|
-
return {
|
|
127339
|
-
type: "noop",
|
|
127340
|
-
reason: "no-cancel-turn"
|
|
127341
|
-
};
|
|
127342
|
-
}
|
|
127343
|
-
if (lastCanceledTurn === lastSeenCancelTurn) {
|
|
127344
|
-
return {
|
|
127345
|
-
type: "noop",
|
|
127346
|
-
reason: "already-seen"
|
|
127347
|
-
};
|
|
127348
|
-
}
|
|
127349
|
-
return {
|
|
127350
|
-
type: "cancel",
|
|
127351
|
-
turnId: lastCanceledTurn
|
|
127352
|
-
};
|
|
127353
|
-
}
|
|
127354
|
-
function findNextDispatchableUserTurn(history, meta) {
|
|
127355
|
-
for (const entry2 of history) {
|
|
127356
|
-
if (entry2.role !== "user") {
|
|
127357
|
-
continue;
|
|
127358
|
-
}
|
|
127359
|
-
if (typeof entry2.status === "string") {
|
|
127360
|
-
if (entry2.status === "pending" || entry2.status === "seen" || entry2.status === "processing") {
|
|
127361
|
-
return entry2;
|
|
127362
|
-
}
|
|
127363
|
-
continue;
|
|
127364
|
-
}
|
|
127365
|
-
if (entry2.read === false) {
|
|
127366
|
-
return entry2;
|
|
127367
|
-
}
|
|
127368
|
-
if (entry2.id === meta.processingUserMsgId) {
|
|
127369
|
-
return entry2;
|
|
127370
|
-
}
|
|
127371
|
-
if (entry2.id === meta.latestUserMsgId && entry2.id !== meta.lastHandledUserMsgId) {
|
|
127372
|
-
return entry2;
|
|
127373
|
-
}
|
|
127374
|
-
}
|
|
127375
|
-
return null;
|
|
127376
|
-
}
|
|
127377
|
-
function resolveDispatchTurnInput(entry2) {
|
|
127378
|
-
const historyBlocks = historyItemsToInputBlocks(entry2.items);
|
|
127379
|
-
const configuredBlocks = normalizeSessionInputBlocks(entry2.inputConfig?.inputBlocks, "");
|
|
127380
|
-
const fallbackBlocks = normalizeSessionInputBlocks(void 0, entry2.inputConfig?.prompt ?? "");
|
|
127381
|
-
const inputBlocks = configuredBlocks.length > 0 ? configuredBlocks : historyBlocks.length > 0 ? historyBlocks : fallbackBlocks;
|
|
127382
|
-
const prompt2 = entry2.inputConfig?.prompt ?? extractPromptPreviewFromInputBlocks(inputBlocks.length > 0 ? inputBlocks : historyBlocks);
|
|
127383
|
-
return {
|
|
127384
|
-
inputBlocks,
|
|
127385
|
-
prompt: prompt2
|
|
127386
|
-
};
|
|
127387
|
-
}
|
|
127388
127872
|
const isConfigOptionValueRecord = (value) => {
|
|
127389
127873
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
127390
127874
|
return false;
|
|
@@ -127723,14 +128207,10 @@ $mem | ConvertTo-Json -Compress
|
|
|
127723
128207
|
if (request.id === this.goalCommandSeenId.get(sessionId)) {
|
|
127724
128208
|
return;
|
|
127725
128209
|
}
|
|
127726
|
-
const user = await this.userResolver.resolve(meta.userId);
|
|
127727
128210
|
const result = await this.deps.executionService.controlSessionGoal({
|
|
127728
128211
|
sessionId,
|
|
127729
128212
|
threadId: request.threadId,
|
|
127730
|
-
command: request.command
|
|
127731
|
-
userId: meta.userId,
|
|
127732
|
-
userName: user.name,
|
|
127733
|
-
userEmail: user.email
|
|
128213
|
+
command: request.command
|
|
127734
128214
|
});
|
|
127735
128215
|
if (result.status === "deferred") {
|
|
127736
128216
|
this.deps.logger.debug(`[${sessionId}] Deferring hidden goal command ${request.command} until active turn completes`);
|
|
@@ -127741,7 +128221,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
127741
128221
|
lastGoalCommand: void 0
|
|
127742
128222
|
});
|
|
127743
128223
|
if (result.status === "failed") {
|
|
127744
|
-
this.deps.logger.debug(`[${sessionId}]
|
|
128224
|
+
this.deps.logger.debug(`[${sessionId}] Goal command ${request.command} failed: ${result.error}`);
|
|
127745
128225
|
}
|
|
127746
128226
|
}
|
|
127747
128227
|
async buildChatRequestFromHistoryEntry(meta, entry2) {
|
|
@@ -127763,7 +128243,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
127763
128243
|
modelId: entry2.inputConfig?.modelId,
|
|
127764
128244
|
configOptionValues: entry2.inputConfig?.configOptionValues,
|
|
127765
128245
|
issuePRMentions: entry2.inputConfig?.issuePRMentions,
|
|
127766
|
-
resume: entry2.inputConfig?.resume ?? meta
|
|
128246
|
+
resume: entry2.inputConfig?.resume ?? resolveDispatchAcpSessionId(meta)
|
|
127767
128247
|
},
|
|
127768
128248
|
userTurnId: entry2.id,
|
|
127769
128249
|
userId: entry2.userId ?? meta.userId,
|
|
@@ -127825,7 +128305,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
127825
128305
|
modelId: queuedItem.acpSessionConfig?.modelId,
|
|
127826
128306
|
configOptionValues: isConfigOptionValueRecord(queuedItem.acpSessionConfig?.configOptionValues) ? queuedItem.acpSessionConfig.configOptionValues : void 0,
|
|
127827
128307
|
issuePRMentions: queuedItem.acpSessionConfig?.issuePRMentions,
|
|
127828
|
-
resume: meta
|
|
128308
|
+
resume: resolveResumableAcpSessionId(meta)
|
|
127829
128309
|
});
|
|
127830
128310
|
const pendingEntry = buildPendingUserHistoryEntry({
|
|
127831
128311
|
userId: queuedItem.userId ?? meta.userId,
|
|
@@ -128861,7 +129341,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
128861
129341
|
}
|
|
128862
129342
|
})();
|
|
128863
129343
|
try {
|
|
128864
|
-
await withTimeout(readyPromise, TUNNEL_READY_TIMEOUT_MS, "Timed out waiting for preview tunnel control connection to become ready");
|
|
129344
|
+
await withTimeout$1(readyPromise, TUNNEL_READY_TIMEOUT_MS, "Timed out waiting for preview tunnel control connection to become ready");
|
|
128865
129345
|
} catch (error2) {
|
|
128866
129346
|
await close2("Preview tunnel failed to become ready");
|
|
128867
129347
|
throw error2;
|
|
@@ -129684,7 +130164,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
129684
130164
|
function asError(error2) {
|
|
129685
130165
|
return error2 instanceof Error ? error2 : new Error(formatError(error2));
|
|
129686
130166
|
}
|
|
129687
|
-
async function withTimeout(promise, timeoutMs, message) {
|
|
130167
|
+
async function withTimeout$1(promise, timeoutMs, message) {
|
|
129688
130168
|
let timeoutHandle;
|
|
129689
130169
|
const timeoutPromise = new Promise((_2, reject) => {
|
|
129690
130170
|
timeoutHandle = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
@@ -130546,6 +131026,794 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
130546
131026
|
return Math.round(this.deps.now?.() ?? getServerNow());
|
|
130547
131027
|
}
|
|
130548
131028
|
}
|
|
131029
|
+
const ACP_OPERATION_TIMEOUT_MS = 12e4;
|
|
131030
|
+
const ACP_PROCESS_EXIT_TIMEOUT_MS = 3e3;
|
|
131031
|
+
function waitForChildProcessExit(child, timeoutMs) {
|
|
131032
|
+
if (child.exitCode !== null) {
|
|
131033
|
+
return Promise.resolve(true);
|
|
131034
|
+
}
|
|
131035
|
+
return new Promise((resolve2) => {
|
|
131036
|
+
const timeout2 = setTimeout(() => {
|
|
131037
|
+
child.off("exit", onExit2);
|
|
131038
|
+
resolve2(child.exitCode !== null);
|
|
131039
|
+
}, timeoutMs);
|
|
131040
|
+
const onExit2 = () => {
|
|
131041
|
+
clearTimeout(timeout2);
|
|
131042
|
+
resolve2(true);
|
|
131043
|
+
};
|
|
131044
|
+
child.once("exit", onExit2);
|
|
131045
|
+
});
|
|
131046
|
+
}
|
|
131047
|
+
function signalChildProcess(child, signal) {
|
|
131048
|
+
if (process.platform !== "win32" && typeof child.pid === "number" && child.pid > 0) {
|
|
131049
|
+
process.kill(-child.pid, signal);
|
|
131050
|
+
return;
|
|
131051
|
+
}
|
|
131052
|
+
child.kill(signal);
|
|
131053
|
+
}
|
|
131054
|
+
async function terminateChildProcess(child) {
|
|
131055
|
+
if (child.exitCode !== null) {
|
|
131056
|
+
return;
|
|
131057
|
+
}
|
|
131058
|
+
try {
|
|
131059
|
+
signalChildProcess(child, "SIGTERM");
|
|
131060
|
+
} catch {
|
|
131061
|
+
return;
|
|
131062
|
+
}
|
|
131063
|
+
if (await waitForChildProcessExit(child, ACP_PROCESS_EXIT_TIMEOUT_MS)) {
|
|
131064
|
+
return;
|
|
131065
|
+
}
|
|
131066
|
+
try {
|
|
131067
|
+
signalChildProcess(child, "SIGKILL");
|
|
131068
|
+
} catch {
|
|
131069
|
+
return;
|
|
131070
|
+
}
|
|
131071
|
+
await waitForChildProcessExit(child, ACP_PROCESS_EXIT_TIMEOUT_MS);
|
|
131072
|
+
}
|
|
131073
|
+
async function withTimeout(promise, label2) {
|
|
131074
|
+
let timeout2 = null;
|
|
131075
|
+
try {
|
|
131076
|
+
return await Promise.race([
|
|
131077
|
+
promise,
|
|
131078
|
+
new Promise((_resolve, reject) => {
|
|
131079
|
+
timeout2 = setTimeout(() => reject(new Error(`${label2} timed out after ${ACP_OPERATION_TIMEOUT_MS}ms`)), ACP_OPERATION_TIMEOUT_MS);
|
|
131080
|
+
})
|
|
131081
|
+
]);
|
|
131082
|
+
} finally {
|
|
131083
|
+
if (timeout2) {
|
|
131084
|
+
clearTimeout(timeout2);
|
|
131085
|
+
}
|
|
131086
|
+
}
|
|
131087
|
+
}
|
|
131088
|
+
class AcpReplayCollectorClient {
|
|
131089
|
+
notifications = [];
|
|
131090
|
+
async requestPermission() {
|
|
131091
|
+
return {
|
|
131092
|
+
outcome: {
|
|
131093
|
+
outcome: "cancelled"
|
|
131094
|
+
}
|
|
131095
|
+
};
|
|
131096
|
+
}
|
|
131097
|
+
async sessionUpdate(params) {
|
|
131098
|
+
this.notifications.push(parseSessionNotification(params));
|
|
131099
|
+
}
|
|
131100
|
+
}
|
|
131101
|
+
function getProviderLabel$1(provider2) {
|
|
131102
|
+
return provider2 === "claude" ? "Claude" : "Codex";
|
|
131103
|
+
}
|
|
131104
|
+
async function createHistoryAcpConnection(args2) {
|
|
131105
|
+
const setting = resolveACPSetting({
|
|
131106
|
+
cliType: "builtin",
|
|
131107
|
+
agentType: args2.provider
|
|
131108
|
+
});
|
|
131109
|
+
const env2 = setting.exec.env ? {
|
|
131110
|
+
...process.env,
|
|
131111
|
+
...setting.exec.env
|
|
131112
|
+
} : process.env;
|
|
131113
|
+
const agentProcess = spawnAcpProcess({
|
|
131114
|
+
cliType: "builtin",
|
|
131115
|
+
agentType: args2.provider,
|
|
131116
|
+
workdir: args2.workdir,
|
|
131117
|
+
env: env2
|
|
131118
|
+
});
|
|
131119
|
+
agentProcess.stderr?.setEncoding("utf8");
|
|
131120
|
+
agentProcess.stderr?.on("data", (chunk) => {
|
|
131121
|
+
if (!chunk) return;
|
|
131122
|
+
args2.logger.debug(`[${args2.provider}-history-sync] ACP stderr: ${chunk.slice(0, 1200)}`);
|
|
131123
|
+
});
|
|
131124
|
+
if (!agentProcess.stdout || !agentProcess.stdin) {
|
|
131125
|
+
await terminateChildProcess(agentProcess);
|
|
131126
|
+
throw new Error(`${getProviderLabel$1(args2.provider)} ACP process did not expose stdio streams`);
|
|
131127
|
+
}
|
|
131128
|
+
const output = createStdoutReadableStream(agentProcess.stdout);
|
|
131129
|
+
const input2 = createStdinWritableStream(agentProcess.stdin);
|
|
131130
|
+
const stream2 = ndJsonStream(input2, output);
|
|
131131
|
+
const collector = new AcpReplayCollectorClient();
|
|
131132
|
+
const connection = new ClientSideConnection(() => collector, stream2);
|
|
131133
|
+
try {
|
|
131134
|
+
const initResponse = await withTimeout(connection.initialize({
|
|
131135
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
131136
|
+
clientCapabilities: {
|
|
131137
|
+
terminal: false,
|
|
131138
|
+
fs: {
|
|
131139
|
+
readTextFile: false,
|
|
131140
|
+
writeTextFile: false
|
|
131141
|
+
}
|
|
131142
|
+
}
|
|
131143
|
+
}), `${getProviderLabel$1(args2.provider)} ACP initialize`);
|
|
131144
|
+
return {
|
|
131145
|
+
agentProcess,
|
|
131146
|
+
connection,
|
|
131147
|
+
collector,
|
|
131148
|
+
initResponse
|
|
131149
|
+
};
|
|
131150
|
+
} catch (error2) {
|
|
131151
|
+
await terminateChildProcess(agentProcess);
|
|
131152
|
+
throw error2;
|
|
131153
|
+
}
|
|
131154
|
+
}
|
|
131155
|
+
async function resolveCatalogQueryPaths(rootPath) {
|
|
131156
|
+
const resolved = path__default.resolve(rootPath);
|
|
131157
|
+
let real = null;
|
|
131158
|
+
try {
|
|
131159
|
+
real = await fs$5.realpath(resolved);
|
|
131160
|
+
} catch {
|
|
131161
|
+
real = null;
|
|
131162
|
+
}
|
|
131163
|
+
const paths = [
|
|
131164
|
+
resolved
|
|
131165
|
+
];
|
|
131166
|
+
if (real && real !== resolved) {
|
|
131167
|
+
paths.push(real);
|
|
131168
|
+
}
|
|
131169
|
+
return paths;
|
|
131170
|
+
}
|
|
131171
|
+
async function listPaginatedHistorySessions(cwd, listPage) {
|
|
131172
|
+
const sessions = [];
|
|
131173
|
+
let cursor;
|
|
131174
|
+
do {
|
|
131175
|
+
const response = await listPage({
|
|
131176
|
+
cwd,
|
|
131177
|
+
cursor
|
|
131178
|
+
});
|
|
131179
|
+
sessions.push(...response.sessions);
|
|
131180
|
+
cursor = response.nextCursor;
|
|
131181
|
+
} while (cursor);
|
|
131182
|
+
return sessions;
|
|
131183
|
+
}
|
|
131184
|
+
async function listHistorySessionsForLocalProject(args2) {
|
|
131185
|
+
const queryPaths = await resolveCatalogQueryPaths(args2.rootPath);
|
|
131186
|
+
const bySessionId = /* @__PURE__ */ new Map();
|
|
131187
|
+
for (const cwd of queryPaths) {
|
|
131188
|
+
const { agentProcess, connection, initResponse } = await createHistoryAcpConnection({
|
|
131189
|
+
provider: args2.provider,
|
|
131190
|
+
workdir: cwd,
|
|
131191
|
+
logger: args2.logger
|
|
131192
|
+
});
|
|
131193
|
+
try {
|
|
131194
|
+
if (!initResponse.agentCapabilities?.sessionCapabilities?.list) {
|
|
131195
|
+
throw new Error(`${getProviderLabel$1(args2.provider)} ACP agent does not advertise sessionCapabilities.list`);
|
|
131196
|
+
}
|
|
131197
|
+
const sessions = await listPaginatedHistorySessions(cwd, async ({ cursor }) => withTimeout(connection.listSessions({
|
|
131198
|
+
cwd,
|
|
131199
|
+
cursor
|
|
131200
|
+
}), `${getProviderLabel$1(args2.provider)} ACP listSessions (${cwd})`));
|
|
131201
|
+
for (const session of sessions) {
|
|
131202
|
+
bySessionId.set(session.sessionId, session);
|
|
131203
|
+
}
|
|
131204
|
+
} finally {
|
|
131205
|
+
await terminateChildProcess(agentProcess);
|
|
131206
|
+
}
|
|
131207
|
+
}
|
|
131208
|
+
return {
|
|
131209
|
+
sessions: [
|
|
131210
|
+
...bySessionId.values()
|
|
131211
|
+
],
|
|
131212
|
+
queryPaths
|
|
131213
|
+
};
|
|
131214
|
+
}
|
|
131215
|
+
async function loadHistorySessionReplay(args2) {
|
|
131216
|
+
const cwd = path__default.resolve(args2.rootPath);
|
|
131217
|
+
const { agentProcess, connection, collector, initResponse } = await createHistoryAcpConnection({
|
|
131218
|
+
provider: args2.provider,
|
|
131219
|
+
workdir: cwd,
|
|
131220
|
+
logger: args2.logger
|
|
131221
|
+
});
|
|
131222
|
+
try {
|
|
131223
|
+
if (!initResponse.agentCapabilities?.loadSession) {
|
|
131224
|
+
throw new Error(`${getProviderLabel$1(args2.provider)} ACP agent does not advertise loadSession`);
|
|
131225
|
+
}
|
|
131226
|
+
await withTimeout(connection.loadSession({
|
|
131227
|
+
sessionId: args2.acpSessionId,
|
|
131228
|
+
cwd,
|
|
131229
|
+
mcpServers: []
|
|
131230
|
+
}), `${getProviderLabel$1(args2.provider)} ACP loadSession (${args2.acpSessionId})`);
|
|
131231
|
+
return collector.notifications;
|
|
131232
|
+
} catch (error2) {
|
|
131233
|
+
throw new Error(`Failed to load ${getProviderLabel$1(args2.provider)} session ${args2.acpSessionId}: ${formatErrorMessage(error2)}`, {
|
|
131234
|
+
cause: error2
|
|
131235
|
+
});
|
|
131236
|
+
} finally {
|
|
131237
|
+
await terminateChildProcess(agentProcess);
|
|
131238
|
+
}
|
|
131239
|
+
}
|
|
131240
|
+
const syncLeases = /* @__PURE__ */ new Set();
|
|
131241
|
+
const machineCatalogWriteChains = /* @__PURE__ */ new Map();
|
|
131242
|
+
async function withMachineCatalogWriteLock(machineRoomId, fn) {
|
|
131243
|
+
const prev = machineCatalogWriteChains.get(machineRoomId);
|
|
131244
|
+
const current2 = (async () => {
|
|
131245
|
+
if (prev) {
|
|
131246
|
+
await prev.catch(() => {
|
|
131247
|
+
});
|
|
131248
|
+
}
|
|
131249
|
+
return fn();
|
|
131250
|
+
})();
|
|
131251
|
+
machineCatalogWriteChains.set(machineRoomId, current2);
|
|
131252
|
+
try {
|
|
131253
|
+
return await current2;
|
|
131254
|
+
} finally {
|
|
131255
|
+
if (machineCatalogWriteChains.get(machineRoomId) === current2) {
|
|
131256
|
+
machineCatalogWriteChains.delete(machineRoomId);
|
|
131257
|
+
}
|
|
131258
|
+
}
|
|
131259
|
+
}
|
|
131260
|
+
function emptySummary() {
|
|
131261
|
+
return {
|
|
131262
|
+
listed: 0,
|
|
131263
|
+
imported: 0,
|
|
131264
|
+
refreshed: 0,
|
|
131265
|
+
skipped: 0,
|
|
131266
|
+
conflicted: 0,
|
|
131267
|
+
failed: 0,
|
|
131268
|
+
failures: []
|
|
131269
|
+
};
|
|
131270
|
+
}
|
|
131271
|
+
function stableJson(value) {
|
|
131272
|
+
if (value === null || typeof value !== "object") {
|
|
131273
|
+
return JSON.stringify(value);
|
|
131274
|
+
}
|
|
131275
|
+
if (Array.isArray(value)) {
|
|
131276
|
+
return `[${value.map((item) => stableJson(item)).join(",")}]`;
|
|
131277
|
+
}
|
|
131278
|
+
const record2 = value;
|
|
131279
|
+
const entries = Object.keys(record2).filter((key2) => record2[key2] !== void 0).sort().map((key2) => `${JSON.stringify(key2)}:${stableJson(record2[key2])}`);
|
|
131280
|
+
return `{${entries.join(",")}}`;
|
|
131281
|
+
}
|
|
131282
|
+
function hashText(value) {
|
|
131283
|
+
return createHash$1("sha256").update(value).digest("hex");
|
|
131284
|
+
}
|
|
131285
|
+
function normalizeHistoryEntryForHash(entry2) {
|
|
131286
|
+
return {
|
|
131287
|
+
role: entry2.role,
|
|
131288
|
+
items: entry2.items ?? [],
|
|
131289
|
+
plan: entry2.plan ?? []
|
|
131290
|
+
};
|
|
131291
|
+
}
|
|
131292
|
+
function hashHistoryEntry(entry2) {
|
|
131293
|
+
return hashText(stableJson(normalizeHistoryEntryForHash(entry2)));
|
|
131294
|
+
}
|
|
131295
|
+
function materializeReplay(args2) {
|
|
131296
|
+
let tempId = 0;
|
|
131297
|
+
const nowIso = new Date(getServerNow()).toISOString();
|
|
131298
|
+
const replay = buildHistoryReplayImport(args2.replayNotifications, {
|
|
131299
|
+
agentType: args2.provider,
|
|
131300
|
+
userId: args2.userId,
|
|
131301
|
+
now: () => nowIso,
|
|
131302
|
+
createId: () => `${args2.provider}:${args2.acpSessionId}:tmp:${tempId++}`,
|
|
131303
|
+
mode: "imported_snapshot"
|
|
131304
|
+
});
|
|
131305
|
+
const turnHashes = replay.history.map(hashHistoryEntry);
|
|
131306
|
+
const history = replay.history.map((entry2, index2) => ({
|
|
131307
|
+
...entry2,
|
|
131308
|
+
id: `${args2.provider}:${args2.acpSessionId}:turn:${index2}:${turnHashes[index2].slice(0, 16)}`
|
|
131309
|
+
}));
|
|
131310
|
+
return {
|
|
131311
|
+
history,
|
|
131312
|
+
turnHashes,
|
|
131313
|
+
replayDigest: hashText(turnHashes.join("\n"))
|
|
131314
|
+
};
|
|
131315
|
+
}
|
|
131316
|
+
function isPrefix(prefix, value) {
|
|
131317
|
+
if (prefix.length > value.length) {
|
|
131318
|
+
return false;
|
|
131319
|
+
}
|
|
131320
|
+
for (let index2 = 0; index2 < prefix.length; index2 += 1) {
|
|
131321
|
+
if (prefix[index2] !== value[index2]) {
|
|
131322
|
+
return false;
|
|
131323
|
+
}
|
|
131324
|
+
}
|
|
131325
|
+
return true;
|
|
131326
|
+
}
|
|
131327
|
+
function decideHistoryRefresh(args2) {
|
|
131328
|
+
if (args2.replayDigest === args2.externalHistory.replayDigest) {
|
|
131329
|
+
return {
|
|
131330
|
+
status: "skipped",
|
|
131331
|
+
reason: "digest_match"
|
|
131332
|
+
};
|
|
131333
|
+
}
|
|
131334
|
+
if (!isPrefix(args2.externalHistory.importedTurnHashes, args2.turnHashes)) {
|
|
131335
|
+
return {
|
|
131336
|
+
status: "conflicted",
|
|
131337
|
+
reason: "prefix_mismatch"
|
|
131338
|
+
};
|
|
131339
|
+
}
|
|
131340
|
+
if (args2.currentHistoryLength !== void 0 && args2.currentHistoryLength !== args2.externalHistory.importedTurnCount) {
|
|
131341
|
+
return {
|
|
131342
|
+
status: "conflicted",
|
|
131343
|
+
reason: "local_history_has_untracked_suffix"
|
|
131344
|
+
};
|
|
131345
|
+
}
|
|
131346
|
+
const appendFromIndex = args2.externalHistory.importedTurnCount;
|
|
131347
|
+
return args2.turnHashes.length > appendFromIndex ? {
|
|
131348
|
+
status: "refreshed",
|
|
131349
|
+
reason: "prefix_append",
|
|
131350
|
+
appendFromIndex
|
|
131351
|
+
} : {
|
|
131352
|
+
status: "skipped",
|
|
131353
|
+
reason: "empty_suffix",
|
|
131354
|
+
appendFromIndex
|
|
131355
|
+
};
|
|
131356
|
+
}
|
|
131357
|
+
async function listWorkspaceSessionMetas(manager) {
|
|
131358
|
+
const scanner = manager.repo.getMeta();
|
|
131359
|
+
if (!scanner) {
|
|
131360
|
+
return [];
|
|
131361
|
+
}
|
|
131362
|
+
const roomIds = /* @__PURE__ */ new Set();
|
|
131363
|
+
for (const row of await scanner.scan({
|
|
131364
|
+
prefix: [
|
|
131365
|
+
"m"
|
|
131366
|
+
]
|
|
131367
|
+
})) {
|
|
131368
|
+
const key2 = row.key;
|
|
131369
|
+
if (!Array.isArray(key2) || key2.length < 2) {
|
|
131370
|
+
continue;
|
|
131371
|
+
}
|
|
131372
|
+
const roomId = key2[1];
|
|
131373
|
+
if (typeof roomId === "string" && isSessionDocRoomId(roomId)) {
|
|
131374
|
+
roomIds.add(roomId);
|
|
131375
|
+
}
|
|
131376
|
+
}
|
|
131377
|
+
const metas = await Promise.all([
|
|
131378
|
+
...roomIds
|
|
131379
|
+
].map(async (roomId) => {
|
|
131380
|
+
const record2 = await manager.repo.getDocMeta(roomId);
|
|
131381
|
+
if (!record2?.meta || isLoroRepoDocDeleted(record2)) {
|
|
131382
|
+
return null;
|
|
131383
|
+
}
|
|
131384
|
+
const sessionId = roomId.slice("session-".length);
|
|
131385
|
+
return {
|
|
131386
|
+
sessionId,
|
|
131387
|
+
meta: record2.meta
|
|
131388
|
+
};
|
|
131389
|
+
}));
|
|
131390
|
+
return metas.filter((meta) => meta !== null);
|
|
131391
|
+
}
|
|
131392
|
+
function buildExistingHistorySessionIndex(metas, machineId, provider2) {
|
|
131393
|
+
const index2 = /* @__PURE__ */ new Map();
|
|
131394
|
+
for (const entry2 of metas) {
|
|
131395
|
+
if (entry2.meta.machineId !== machineId) continue;
|
|
131396
|
+
if (entry2.meta.cliType !== "builtin") continue;
|
|
131397
|
+
if (entry2.meta.agentType !== provider2) continue;
|
|
131398
|
+
const acpSessionIds = /* @__PURE__ */ new Set();
|
|
131399
|
+
if (entry2.meta.externalHistory?.provider === provider2) {
|
|
131400
|
+
const sourceAcpSessionId = entry2.meta.externalHistory.sourceAcpSessionId;
|
|
131401
|
+
if (sourceAcpSessionId) {
|
|
131402
|
+
acpSessionIds.add(sourceAcpSessionId);
|
|
131403
|
+
}
|
|
131404
|
+
if (entry2.meta.acpSessionId && entry2.meta.acpSessionId !== sourceAcpSessionId) {
|
|
131405
|
+
acpSessionIds.add(entry2.meta.acpSessionId);
|
|
131406
|
+
}
|
|
131407
|
+
} else if (entry2.meta.acpSessionId) {
|
|
131408
|
+
acpSessionIds.add(entry2.meta.acpSessionId);
|
|
131409
|
+
}
|
|
131410
|
+
for (const acpSessionId of acpSessionIds) {
|
|
131411
|
+
index2.set(acpSessionId, entry2);
|
|
131412
|
+
}
|
|
131413
|
+
}
|
|
131414
|
+
return index2;
|
|
131415
|
+
}
|
|
131416
|
+
function getProviderLabel(provider2) {
|
|
131417
|
+
return provider2 === "claude" ? "Claude" : "Codex";
|
|
131418
|
+
}
|
|
131419
|
+
function resolveSessionTitle(info, provider2) {
|
|
131420
|
+
const title2 = info.title?.trim();
|
|
131421
|
+
return title2 || `${getProviderLabel(provider2)} session`;
|
|
131422
|
+
}
|
|
131423
|
+
function parseUpdatedAtMs(updatedAt) {
|
|
131424
|
+
if (!updatedAt) return 0;
|
|
131425
|
+
const parsed = Date.parse(updatedAt);
|
|
131426
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
131427
|
+
}
|
|
131428
|
+
function compareCatalogItems(left2, right2) {
|
|
131429
|
+
const leftUpdatedAt = parseUpdatedAtMs(left2.updatedAt);
|
|
131430
|
+
const rightUpdatedAt = parseUpdatedAtMs(right2.updatedAt);
|
|
131431
|
+
if (leftUpdatedAt !== rightUpdatedAt) {
|
|
131432
|
+
return rightUpdatedAt - leftUpdatedAt;
|
|
131433
|
+
}
|
|
131434
|
+
return left2.title.localeCompare(right2.title);
|
|
131435
|
+
}
|
|
131436
|
+
function getHistoryCatalogStatus(existing) {
|
|
131437
|
+
if (!existing) return "available";
|
|
131438
|
+
return existing.meta.externalHistory?.status === "sync_conflict" ? "sync_conflict" : "imported";
|
|
131439
|
+
}
|
|
131440
|
+
function buildCatalogItem(provider2, info, existing) {
|
|
131441
|
+
const acpSessionId = info.sessionId;
|
|
131442
|
+
return {
|
|
131443
|
+
acpSessionId,
|
|
131444
|
+
title: resolveSessionTitle(info, provider2),
|
|
131445
|
+
updatedAt: info.updatedAt ?? void 0,
|
|
131446
|
+
importedSessionId: existing?.sessionId,
|
|
131447
|
+
status: getHistoryCatalogStatus(existing)
|
|
131448
|
+
};
|
|
131449
|
+
}
|
|
131450
|
+
function shouldSkipBySourceUpdatedAt(info, externalHistory) {
|
|
131451
|
+
if (externalHistory.status === "metadata_only") {
|
|
131452
|
+
return false;
|
|
131453
|
+
}
|
|
131454
|
+
if (!info.updatedAt || !externalHistory.sourceUpdatedAt) {
|
|
131455
|
+
return false;
|
|
131456
|
+
}
|
|
131457
|
+
const next = Date.parse(info.updatedAt);
|
|
131458
|
+
const current2 = Date.parse(externalHistory.sourceUpdatedAt);
|
|
131459
|
+
return Number.isFinite(next) && Number.isFinite(current2) && next <= current2;
|
|
131460
|
+
}
|
|
131461
|
+
function resolveSourceUpdatedAtMs(info, fallback2) {
|
|
131462
|
+
if (!info.updatedAt) {
|
|
131463
|
+
return fallback2;
|
|
131464
|
+
}
|
|
131465
|
+
const parsed = Date.parse(info.updatedAt);
|
|
131466
|
+
return Number.isFinite(parsed) ? parsed : fallback2;
|
|
131467
|
+
}
|
|
131468
|
+
function buildExternalHistoryMeta(args2) {
|
|
131469
|
+
return {
|
|
131470
|
+
provider: args2.provider,
|
|
131471
|
+
source: args2.provider === "claude" ? "local-claude-home" : "local-codex-home",
|
|
131472
|
+
sourceAcpSessionId: args2.sourceAcpSessionId,
|
|
131473
|
+
sourceUpdatedAt: args2.sourceUpdatedAt ?? void 0,
|
|
131474
|
+
replayDigest: args2.materialized.replayDigest,
|
|
131475
|
+
importedTurnCount: args2.materialized.turnHashes.length,
|
|
131476
|
+
importedTurnHashes: args2.materialized.turnHashes,
|
|
131477
|
+
lastSyncAt: getServerNow(),
|
|
131478
|
+
status: args2.status ?? "synced",
|
|
131479
|
+
conflictReason: args2.conflictReason
|
|
131480
|
+
};
|
|
131481
|
+
}
|
|
131482
|
+
function buildMetadataOnlyExternalHistoryMeta(args2) {
|
|
131483
|
+
return {
|
|
131484
|
+
provider: args2.provider,
|
|
131485
|
+
source: args2.provider === "claude" ? "local-claude-home" : "local-codex-home",
|
|
131486
|
+
sourceAcpSessionId: args2.sourceAcpSessionId,
|
|
131487
|
+
sourceUpdatedAt: args2.sourceUpdatedAt ?? void 0,
|
|
131488
|
+
importedTurnCount: 0,
|
|
131489
|
+
importedTurnHashes: [],
|
|
131490
|
+
lastSyncAt: getServerNow(),
|
|
131491
|
+
status: "metadata_only"
|
|
131492
|
+
};
|
|
131493
|
+
}
|
|
131494
|
+
class LocalProjectHistorySyncService {
|
|
131495
|
+
constructor(manager, logger2, context2, provider2 = "codex") {
|
|
131496
|
+
this.manager = manager;
|
|
131497
|
+
this.logger = logger2;
|
|
131498
|
+
this.context = context2;
|
|
131499
|
+
this.provider = provider2;
|
|
131500
|
+
}
|
|
131501
|
+
provider;
|
|
131502
|
+
async syncLocalProject(args2) {
|
|
131503
|
+
const leaseKey = `${this.provider}:${this.context.workspaceId}:${this.context.machineId}:${args2.localProjectId}`;
|
|
131504
|
+
if (syncLeases.has(leaseKey)) {
|
|
131505
|
+
throw new Error(`${getProviderLabel(this.provider)} history sync is already running for this local project`);
|
|
131506
|
+
}
|
|
131507
|
+
syncLeases.add(leaseKey);
|
|
131508
|
+
try {
|
|
131509
|
+
return await this.syncLocalProjectInner(args2);
|
|
131510
|
+
} finally {
|
|
131511
|
+
syncLeases.delete(leaseKey);
|
|
131512
|
+
}
|
|
131513
|
+
}
|
|
131514
|
+
async syncLocalProjectInner(args2) {
|
|
131515
|
+
const snapshot = await this.listCatalogSnapshot(args2.rootPath);
|
|
131516
|
+
return await this.writeCatalogResult({
|
|
131517
|
+
localProjectId: args2.localProjectId,
|
|
131518
|
+
sessions: snapshot.sessions,
|
|
131519
|
+
existingByAcpSessionId: snapshot.existingByAcpSessionId
|
|
131520
|
+
});
|
|
131521
|
+
}
|
|
131522
|
+
async importLocalProjectSessions(args2) {
|
|
131523
|
+
const leaseKey = `${this.provider}:${this.context.workspaceId}:${this.context.machineId}:${args2.localProjectId}`;
|
|
131524
|
+
if (syncLeases.has(leaseKey)) {
|
|
131525
|
+
throw new Error(`${getProviderLabel(this.provider)} history sync is already running for this local project`);
|
|
131526
|
+
}
|
|
131527
|
+
syncLeases.add(leaseKey);
|
|
131528
|
+
try {
|
|
131529
|
+
return await this.importLocalProjectSessionsInner(args2);
|
|
131530
|
+
} finally {
|
|
131531
|
+
syncLeases.delete(leaseKey);
|
|
131532
|
+
}
|
|
131533
|
+
}
|
|
131534
|
+
async importLocalProjectSessionsInner(args2) {
|
|
131535
|
+
const summary2 = emptySummary();
|
|
131536
|
+
const selectedIds = [
|
|
131537
|
+
...new Set(args2.acpSessionIds)
|
|
131538
|
+
];
|
|
131539
|
+
summary2.listed = selectedIds.length;
|
|
131540
|
+
const snapshot = await this.listCatalogSnapshot(args2.rootPath);
|
|
131541
|
+
const infoByAcpSessionId = new Map(snapshot.sessions.map((info) => [
|
|
131542
|
+
info.sessionId,
|
|
131543
|
+
info
|
|
131544
|
+
]));
|
|
131545
|
+
const project = {
|
|
131546
|
+
kind: "local",
|
|
131547
|
+
localProjectId: args2.localProjectId
|
|
131548
|
+
};
|
|
131549
|
+
for (const selectedId of selectedIds) {
|
|
131550
|
+
const acpSessionId = selectedId;
|
|
131551
|
+
const info = infoByAcpSessionId.get(selectedId);
|
|
131552
|
+
try {
|
|
131553
|
+
if (!info) {
|
|
131554
|
+
throw new Error(`${getProviderLabel(this.provider)} session was not found in the local project catalog`);
|
|
131555
|
+
}
|
|
131556
|
+
const existing = snapshot.existingByAcpSessionId.get(selectedId);
|
|
131557
|
+
if (!existing) {
|
|
131558
|
+
const importedSession = await this.importNewSession({
|
|
131559
|
+
info,
|
|
131560
|
+
acpSessionId,
|
|
131561
|
+
project
|
|
131562
|
+
});
|
|
131563
|
+
snapshot.existingByAcpSessionId.set(selectedId, importedSession);
|
|
131564
|
+
summary2.imported += 1;
|
|
131565
|
+
continue;
|
|
131566
|
+
}
|
|
131567
|
+
const status = await this.refreshExistingSession({
|
|
131568
|
+
existing,
|
|
131569
|
+
info,
|
|
131570
|
+
acpSessionId,
|
|
131571
|
+
rootPath: args2.rootPath
|
|
131572
|
+
});
|
|
131573
|
+
summary2[status] += 1;
|
|
131574
|
+
} catch (error2) {
|
|
131575
|
+
summary2.failed += 1;
|
|
131576
|
+
summary2.failures.push({
|
|
131577
|
+
acpSessionId,
|
|
131578
|
+
message: formatErrorMessage(error2)
|
|
131579
|
+
});
|
|
131580
|
+
this.logger.debug(`[${this.provider}-history-sync] Failed to import ${getProviderLabel(this.provider)} session ${acpSessionId}: ${formatErrorMessage(error2)}`);
|
|
131581
|
+
}
|
|
131582
|
+
}
|
|
131583
|
+
const catalog = await this.writeCatalogResult({
|
|
131584
|
+
localProjectId: args2.localProjectId,
|
|
131585
|
+
sessions: snapshot.sessions,
|
|
131586
|
+
existingByAcpSessionId: snapshot.existingByAcpSessionId
|
|
131587
|
+
});
|
|
131588
|
+
return {
|
|
131589
|
+
summary: summary2,
|
|
131590
|
+
catalog
|
|
131591
|
+
};
|
|
131592
|
+
}
|
|
131593
|
+
async listCatalogSnapshot(rootPath) {
|
|
131594
|
+
const catalog = await listHistorySessionsForLocalProject({
|
|
131595
|
+
provider: this.provider,
|
|
131596
|
+
rootPath,
|
|
131597
|
+
logger: this.logger
|
|
131598
|
+
});
|
|
131599
|
+
const sessionMetas = await listWorkspaceSessionMetas(this.manager);
|
|
131600
|
+
const existingByAcpSessionId = buildExistingHistorySessionIndex(sessionMetas, this.context.machineId, this.provider);
|
|
131601
|
+
return {
|
|
131602
|
+
sessions: catalog.sessions,
|
|
131603
|
+
existingByAcpSessionId
|
|
131604
|
+
};
|
|
131605
|
+
}
|
|
131606
|
+
async writeCatalogResult(args2) {
|
|
131607
|
+
const lastListedAt = Math.round(getServerNow());
|
|
131608
|
+
const sessions = args2.sessions.map((info) => buildCatalogItem(this.provider, info, args2.existingByAcpSessionId.get(info.sessionId))).sort(compareCatalogItems);
|
|
131609
|
+
const catalog = {
|
|
131610
|
+
listed: sessions.length,
|
|
131611
|
+
lastListedAt,
|
|
131612
|
+
sessions
|
|
131613
|
+
};
|
|
131614
|
+
const machineRoomId = getMachineRoomId(this.context.machineId);
|
|
131615
|
+
await withMachineCatalogWriteLock(machineRoomId, async () => {
|
|
131616
|
+
const current2 = await this.manager.repo.getDocMeta(machineRoomId);
|
|
131617
|
+
const rawExisting = current2?.meta?.localProjects;
|
|
131618
|
+
const existing = rawExisting && typeof rawExisting === "object" ? rawExisting : {};
|
|
131619
|
+
const previous = existing[args2.localProjectId];
|
|
131620
|
+
if (!previous) {
|
|
131621
|
+
return;
|
|
131622
|
+
}
|
|
131623
|
+
await this.manager.repo.upsertDocMeta(machineRoomId, {
|
|
131624
|
+
localProjects: {
|
|
131625
|
+
...existing,
|
|
131626
|
+
[args2.localProjectId]: {
|
|
131627
|
+
...previous,
|
|
131628
|
+
history: {
|
|
131629
|
+
...previous.history ?? {},
|
|
131630
|
+
[this.provider]: {
|
|
131631
|
+
lastListedAt,
|
|
131632
|
+
sessions: Object.fromEntries(sessions.map((item) => [
|
|
131633
|
+
item.acpSessionId,
|
|
131634
|
+
item
|
|
131635
|
+
]))
|
|
131636
|
+
}
|
|
131637
|
+
}
|
|
131638
|
+
}
|
|
131639
|
+
}
|
|
131640
|
+
});
|
|
131641
|
+
});
|
|
131642
|
+
return catalog;
|
|
131643
|
+
}
|
|
131644
|
+
async importNewSession(args2) {
|
|
131645
|
+
const sessionId = v4();
|
|
131646
|
+
const roomId = getSessionRoomId(sessionId);
|
|
131647
|
+
const nowMs = getServerNow();
|
|
131648
|
+
const lastMessageAt = resolveSourceUpdatedAtMs(args2.info, nowMs);
|
|
131649
|
+
const meta = {
|
|
131650
|
+
id: sessionId,
|
|
131651
|
+
machineId: this.context.machineId,
|
|
131652
|
+
createdAt: new Date(nowMs).toISOString(),
|
|
131653
|
+
userId: this.context.userId,
|
|
131654
|
+
status: SessionStatusFactory.idle(),
|
|
131655
|
+
isArchived: false,
|
|
131656
|
+
origin: this.provider,
|
|
131657
|
+
cliType: "builtin",
|
|
131658
|
+
agentType: this.provider,
|
|
131659
|
+
project: args2.project,
|
|
131660
|
+
title: resolveSessionTitle(args2.info, this.provider),
|
|
131661
|
+
lastMessageAt,
|
|
131662
|
+
externalHistory: buildMetadataOnlyExternalHistoryMeta({
|
|
131663
|
+
provider: this.provider,
|
|
131664
|
+
sourceAcpSessionId: args2.acpSessionId,
|
|
131665
|
+
sourceUpdatedAt: args2.info.updatedAt
|
|
131666
|
+
})
|
|
131667
|
+
};
|
|
131668
|
+
await this.manager.repo.upsertDocMeta(roomId, meta);
|
|
131669
|
+
return {
|
|
131670
|
+
sessionId,
|
|
131671
|
+
meta
|
|
131672
|
+
};
|
|
131673
|
+
}
|
|
131674
|
+
async refreshExistingSession(args2) {
|
|
131675
|
+
const externalHistory = args2.existing.meta.externalHistory;
|
|
131676
|
+
if (externalHistory?.provider !== this.provider) {
|
|
131677
|
+
return "skipped";
|
|
131678
|
+
}
|
|
131679
|
+
if (shouldSkipBySourceUpdatedAt(args2.info, externalHistory)) {
|
|
131680
|
+
return "skipped";
|
|
131681
|
+
}
|
|
131682
|
+
const replayNotifications = await loadHistorySessionReplay({
|
|
131683
|
+
provider: this.provider,
|
|
131684
|
+
rootPath: args2.rootPath,
|
|
131685
|
+
acpSessionId: args2.acpSessionId,
|
|
131686
|
+
logger: this.logger
|
|
131687
|
+
});
|
|
131688
|
+
const materialized = materializeReplay({
|
|
131689
|
+
provider: this.provider,
|
|
131690
|
+
acpSessionId: args2.acpSessionId,
|
|
131691
|
+
replayNotifications,
|
|
131692
|
+
userId: this.context.userId
|
|
131693
|
+
});
|
|
131694
|
+
const replayDecision = decideHistoryRefresh({
|
|
131695
|
+
externalHistory,
|
|
131696
|
+
replayDigest: materialized.replayDigest,
|
|
131697
|
+
turnHashes: materialized.turnHashes
|
|
131698
|
+
});
|
|
131699
|
+
if (replayDecision.reason === "digest_match") {
|
|
131700
|
+
await this.manager.repo.upsertDocMeta(getSessionRoomId(args2.existing.sessionId), {
|
|
131701
|
+
origin: this.provider,
|
|
131702
|
+
externalHistory: buildExternalHistoryMeta({
|
|
131703
|
+
provider: this.provider,
|
|
131704
|
+
sourceAcpSessionId: args2.acpSessionId,
|
|
131705
|
+
sourceUpdatedAt: args2.info.updatedAt,
|
|
131706
|
+
materialized
|
|
131707
|
+
})
|
|
131708
|
+
});
|
|
131709
|
+
return "skipped";
|
|
131710
|
+
}
|
|
131711
|
+
if (replayDecision.status === "conflicted") {
|
|
131712
|
+
await this.markConflict(args2.existing.sessionId, args2.info, materialized, replayDecision.reason);
|
|
131713
|
+
return "conflicted";
|
|
131714
|
+
}
|
|
131715
|
+
const sessionDoc = await this.manager.getOrCreateSessionDoc(args2.existing.sessionId);
|
|
131716
|
+
const currentHistory = await sessionDoc.getHistory();
|
|
131717
|
+
const appendDecision = decideHistoryRefresh({
|
|
131718
|
+
externalHistory,
|
|
131719
|
+
replayDigest: materialized.replayDigest,
|
|
131720
|
+
turnHashes: materialized.turnHashes,
|
|
131721
|
+
currentHistoryLength: currentHistory.length
|
|
131722
|
+
});
|
|
131723
|
+
if (appendDecision.status === "conflicted") {
|
|
131724
|
+
await this.markConflict(args2.existing.sessionId, args2.info, materialized, appendDecision.reason);
|
|
131725
|
+
const synced2 = await sessionDoc.waitUntilSynced();
|
|
131726
|
+
if (!synced2) {
|
|
131727
|
+
this.logger.debug(`[${this.provider}-history-sync] Conflict marker for ${args2.existing.sessionId} did not confirm sync before unload; clients may see the previous state until next sync.`);
|
|
131728
|
+
}
|
|
131729
|
+
await this.manager.cleanSessionDoc(args2.existing.sessionId, {
|
|
131730
|
+
preserveStatus: true
|
|
131731
|
+
});
|
|
131732
|
+
return "conflicted";
|
|
131733
|
+
}
|
|
131734
|
+
const suffix = materialized.history.slice(appendDecision.appendFromIndex);
|
|
131735
|
+
await sessionDoc.updateHistory((history) => [
|
|
131736
|
+
...history,
|
|
131737
|
+
...suffix
|
|
131738
|
+
]);
|
|
131739
|
+
await this.manager.repo.upsertDocMeta(getSessionRoomId(args2.existing.sessionId), {
|
|
131740
|
+
origin: this.provider,
|
|
131741
|
+
lastMessageAt: resolveSourceUpdatedAtMs(args2.info, getServerNow()),
|
|
131742
|
+
externalHistory: buildExternalHistoryMeta({
|
|
131743
|
+
provider: this.provider,
|
|
131744
|
+
sourceAcpSessionId: args2.acpSessionId,
|
|
131745
|
+
sourceUpdatedAt: args2.info.updatedAt,
|
|
131746
|
+
materialized
|
|
131747
|
+
})
|
|
131748
|
+
});
|
|
131749
|
+
const synced = await sessionDoc.waitUntilSynced();
|
|
131750
|
+
if (!synced) {
|
|
131751
|
+
this.logger.debug(`[${this.provider}-history-sync] Appended history for ${args2.existing.sessionId} did not confirm sync before unload; other clients may see the previous state until next sync.`);
|
|
131752
|
+
}
|
|
131753
|
+
await this.manager.cleanSessionDoc(args2.existing.sessionId, {
|
|
131754
|
+
preserveStatus: true
|
|
131755
|
+
});
|
|
131756
|
+
return suffix.length > 0 ? "refreshed" : "skipped";
|
|
131757
|
+
}
|
|
131758
|
+
async markConflict(sessionId, info, materialized, reason) {
|
|
131759
|
+
await this.manager.repo.upsertDocMeta(getSessionRoomId(sessionId), {
|
|
131760
|
+
origin: this.provider,
|
|
131761
|
+
externalHistory: buildExternalHistoryMeta({
|
|
131762
|
+
provider: this.provider,
|
|
131763
|
+
sourceAcpSessionId: info.sessionId,
|
|
131764
|
+
sourceUpdatedAt: info.updatedAt,
|
|
131765
|
+
materialized,
|
|
131766
|
+
status: "sync_conflict",
|
|
131767
|
+
conflictReason: reason
|
|
131768
|
+
})
|
|
131769
|
+
});
|
|
131770
|
+
}
|
|
131771
|
+
}
|
|
131772
|
+
const HISTORY_REQUEST_TYPES = /* @__PURE__ */ new Set([
|
|
131773
|
+
"local-project/sync-history",
|
|
131774
|
+
"local-project/import-history"
|
|
131775
|
+
]);
|
|
131776
|
+
function isHistoryRequestType(value) {
|
|
131777
|
+
return HISTORY_REQUEST_TYPES.has(value);
|
|
131778
|
+
}
|
|
131779
|
+
function precheckLocalProjectHistoryRequest(args2) {
|
|
131780
|
+
const { request, expectedMachineId, expectedWorkspaceId } = args2;
|
|
131781
|
+
if (request.machineId !== expectedMachineId) {
|
|
131782
|
+
return {
|
|
131783
|
+
ok: false,
|
|
131784
|
+
error: "machine_mismatch",
|
|
131785
|
+
message: `Machine mismatch: expected ${expectedMachineId}`
|
|
131786
|
+
};
|
|
131787
|
+
}
|
|
131788
|
+
if (!isHistoryRequestType(request.type)) {
|
|
131789
|
+
return {
|
|
131790
|
+
ok: false,
|
|
131791
|
+
error: "invalid_request",
|
|
131792
|
+
message: `Unsupported remote local project control request: ${request.type}`
|
|
131793
|
+
};
|
|
131794
|
+
}
|
|
131795
|
+
const historyRequest = request;
|
|
131796
|
+
const requesterUserId = historyRequest.requestedByUserId?.trim();
|
|
131797
|
+
if (!requesterUserId) {
|
|
131798
|
+
return {
|
|
131799
|
+
ok: false,
|
|
131800
|
+
error: "invalid_request",
|
|
131801
|
+
message: "Local project history requests require requestedByUserId"
|
|
131802
|
+
};
|
|
131803
|
+
}
|
|
131804
|
+
if (historyRequest.workspaceId !== expectedWorkspaceId) {
|
|
131805
|
+
return {
|
|
131806
|
+
ok: false,
|
|
131807
|
+
error: "workspace_not_found",
|
|
131808
|
+
message: `Workspace mismatch: expected ${expectedWorkspaceId}`
|
|
131809
|
+
};
|
|
131810
|
+
}
|
|
131811
|
+
return {
|
|
131812
|
+
ok: true,
|
|
131813
|
+
request: historyRequest,
|
|
131814
|
+
requesterUserId
|
|
131815
|
+
};
|
|
131816
|
+
}
|
|
130549
131817
|
const SESSION_IMAGE_MIME_TYPE_BY_EXTENSION = {
|
|
130550
131818
|
png: "image/png",
|
|
130551
131819
|
jpg: "image/jpeg",
|
|
@@ -130555,9 +131823,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
130555
131823
|
};
|
|
130556
131824
|
const CODEX_IMAGE_GENERATION_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
130557
131825
|
"completed",
|
|
130558
|
-
"failed"
|
|
130559
|
-
"cancelled",
|
|
130560
|
-
"incomplete"
|
|
131826
|
+
"failed"
|
|
130561
131827
|
]);
|
|
130562
131828
|
function isCodexImageGenerationTerminalStatus(status) {
|
|
130563
131829
|
return CODEX_IMAGE_GENERATION_TERMINAL_STATUSES.has(status.trim().toLowerCase());
|
|
@@ -130714,6 +131980,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
130714
131980
|
requestedByUserId,
|
|
130715
131981
|
reason
|
|
130716
131982
|
}),
|
|
131983
|
+
dispatchLocalProjectControl: async (request) => await this.dispatchLocalProjectControlViaRpc(request),
|
|
130717
131984
|
onFatalAuthFailure: (error2) => this.onFatalAuthFailure?.(error2)
|
|
130718
131985
|
});
|
|
130719
131986
|
} else {
|
|
@@ -131007,11 +132274,44 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
131007
132274
|
}
|
|
131008
132275
|
handleCodexImageGenerationBegin(sessionId, event) {
|
|
131009
132276
|
const turnId = this.store.getTurnId(sessionId) ?? null;
|
|
131010
|
-
this.store.get(sessionId)
|
|
132277
|
+
const state2 = this.store.get(sessionId);
|
|
132278
|
+
state2.codexImageGenerationTurnIds.set(event.callId, turnId);
|
|
132279
|
+
state2.codexImageGenerationActiveCallIds.add(event.callId);
|
|
132280
|
+
this.enqueueCodexImageGenerationActivityStatusSync(sessionId);
|
|
131011
132281
|
this.logger.debug(`[${sessionId}] Codex image generation started (callId=${event.callId} turnId=${turnId ?? "none"})`);
|
|
131012
132282
|
}
|
|
132283
|
+
enqueueCodexImageGenerationActivityStatusSync(sessionId) {
|
|
132284
|
+
const state2 = this.store.get(sessionId);
|
|
132285
|
+
const task = state2.codexImageGenerationActivityStatusChain.catch(() => void 0).then(async () => {
|
|
132286
|
+
const currentState = this.store.get(sessionId);
|
|
132287
|
+
const hasActiveImageGeneration = currentState.codexImageGenerationActiveCallIds.size > 0;
|
|
132288
|
+
const sessionDoc = await this.workspaceDocument.getOrCreateSessionDoc(sessionId);
|
|
132289
|
+
const status = (await sessionDoc.getMetaState())?.status;
|
|
132290
|
+
if (hasActiveImageGeneration) {
|
|
132291
|
+
if (status?.type !== "requestPermission") {
|
|
132292
|
+
await sessionDoc.setStatus(SessionStatusFactory.running("image_generation"));
|
|
132293
|
+
}
|
|
132294
|
+
return;
|
|
132295
|
+
}
|
|
132296
|
+
if (status?.type === "running" && status.activity === "image_generation") {
|
|
132297
|
+
await sessionDoc.setStatus(SessionStatusFactory.running());
|
|
132298
|
+
}
|
|
132299
|
+
});
|
|
132300
|
+
state2.codexImageGenerationActivityStatusChain = task;
|
|
132301
|
+
void task.catch((error2) => {
|
|
132302
|
+
try {
|
|
132303
|
+
this.logger.debug(`[${sessionId}] Failed to sync Codex image generation activity: ${formatErrorMessage(error2)}`);
|
|
132304
|
+
} catch {
|
|
132305
|
+
}
|
|
132306
|
+
});
|
|
132307
|
+
}
|
|
131013
132308
|
handleCodexImageGenerationEnd(sessionId, event) {
|
|
131014
132309
|
const state2 = this.store.get(sessionId);
|
|
132310
|
+
const isTerminal2 = isCodexImageGenerationTerminalStatus(event.status);
|
|
132311
|
+
if (isTerminal2) {
|
|
132312
|
+
state2.codexImageGenerationActiveCallIds.delete(event.callId);
|
|
132313
|
+
this.enqueueCodexImageGenerationActivityStatusSync(sessionId);
|
|
132314
|
+
}
|
|
131015
132315
|
if (state2.codexImageGenerationUploadedCallIds.has(event.callId)) {
|
|
131016
132316
|
this.logger.debug(`[${sessionId}] Ignoring duplicate Codex image generation upload (callId=${event.callId} status=${event.status})`);
|
|
131017
132317
|
return;
|
|
@@ -131022,7 +132322,6 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
131022
132322
|
}
|
|
131023
132323
|
const cachedTurnId = state2.codexImageGenerationTurnIds.get(event.callId);
|
|
131024
132324
|
const capturedTurnId = cachedTurnId !== void 0 ? cachedTurnId : this.store.getTurnId(sessionId) ?? null;
|
|
131025
|
-
const isTerminal2 = isCodexImageGenerationTerminalStatus(event.status);
|
|
131026
132325
|
const savedPath = this.resolveCodexGeneratedImagePath(sessionId, event.savedPath);
|
|
131027
132326
|
if (!savedPath) {
|
|
131028
132327
|
if (isTerminal2) {
|
|
@@ -131567,6 +132866,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
131567
132866
|
cliVersion: this.cliVersion,
|
|
131568
132867
|
os: process.platform,
|
|
131569
132868
|
rpcVersion: supportsStreamsRpc ? LORO_STREAMS_RPC_VERSION : void 0,
|
|
132869
|
+
supportsLocalProjectHistoryRpc: supportsStreamsRpc,
|
|
131570
132870
|
supportRegistryAgentTypes: this.supportRegistryAgentTypes,
|
|
131571
132871
|
sessions: [],
|
|
131572
132872
|
needToArchiveSessions: {},
|
|
@@ -132404,6 +133704,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
132404
133704
|
cliVersion: this.cliVersion,
|
|
132405
133705
|
os: process.platform,
|
|
132406
133706
|
rpcVersion: supportsStreamsRpc ? LORO_STREAMS_RPC_VERSION : machineMeta?.rpcVersion,
|
|
133707
|
+
supportsLocalProjectHistoryRpc: supportsStreamsRpc,
|
|
132407
133708
|
supportRegistryAgentTypes: this.supportRegistryAgentTypes,
|
|
132408
133709
|
acpCapabilities: machineMeta?.acpCapabilities,
|
|
132409
133710
|
sessions: machineMeta?.sessions ?? [],
|
|
@@ -133044,8 +134345,74 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
133044
134345
|
}
|
|
133045
134346
|
await this.workspaceDocument.registerMachine(this.machineId, {
|
|
133046
134347
|
...existingMeta,
|
|
133047
|
-
rpcVersion: LORO_STREAMS_RPC_VERSION
|
|
134348
|
+
rpcVersion: LORO_STREAMS_RPC_VERSION,
|
|
134349
|
+
supportsLocalProjectHistoryRpc: true
|
|
134350
|
+
});
|
|
134351
|
+
}
|
|
134352
|
+
toLocalProjectControlError(type2, error2, message, data) {
|
|
134353
|
+
return {
|
|
134354
|
+
ok: false,
|
|
134355
|
+
type: type2,
|
|
134356
|
+
error: error2,
|
|
134357
|
+
message,
|
|
134358
|
+
data
|
|
134359
|
+
};
|
|
134360
|
+
}
|
|
134361
|
+
async dispatchLocalProjectControlViaRpc(message) {
|
|
134362
|
+
const requestType = message.type;
|
|
134363
|
+
const precheck = precheckLocalProjectHistoryRequest({
|
|
134364
|
+
request: message,
|
|
134365
|
+
expectedMachineId: this.machineId,
|
|
134366
|
+
expectedWorkspaceId: this.workspaceId
|
|
133048
134367
|
});
|
|
134368
|
+
if (!precheck.ok) {
|
|
134369
|
+
return this.toLocalProjectControlError(requestType, precheck.error, precheck.message);
|
|
134370
|
+
}
|
|
134371
|
+
const { requesterUserId, request } = precheck;
|
|
134372
|
+
try {
|
|
134373
|
+
const access = await canUseMachineForCliToken({
|
|
134374
|
+
token: this.token,
|
|
134375
|
+
workspaceId: this.workspaceId,
|
|
134376
|
+
machineId: this.machineId,
|
|
134377
|
+
requesterUserId,
|
|
134378
|
+
localProjectId: request.localProjectId
|
|
134379
|
+
});
|
|
134380
|
+
if (!access.allowed) {
|
|
134381
|
+
return this.toLocalProjectControlError(requestType, "access_denied", `Machine access denied: ${access.reason}`);
|
|
134382
|
+
}
|
|
134383
|
+
const rootPath = await resolveWorkspaceLocalProjectRootPath(this.workspaceDocument.repo, this.machineId, request.localProjectId);
|
|
134384
|
+
if (!rootPath) {
|
|
134385
|
+
return this.toLocalProjectControlError(requestType, "local_project_not_found", `Local project not found in workspace: ${request.localProjectId}`);
|
|
134386
|
+
}
|
|
134387
|
+
const service = new LocalProjectHistorySyncService(this.workspaceDocument, this.logger, {
|
|
134388
|
+
workspaceId: this.workspaceId,
|
|
134389
|
+
machineId: this.machineId,
|
|
134390
|
+
userId: this.userId
|
|
134391
|
+
}, request.provider);
|
|
134392
|
+
if (request.type === "local-project/sync-history") {
|
|
134393
|
+
const result2 = await service.syncLocalProject({
|
|
134394
|
+
localProjectId: request.localProjectId,
|
|
134395
|
+
rootPath
|
|
134396
|
+
});
|
|
134397
|
+
return {
|
|
134398
|
+
ok: true,
|
|
134399
|
+
type: "local-project/sync-history",
|
|
134400
|
+
result: result2
|
|
134401
|
+
};
|
|
134402
|
+
}
|
|
134403
|
+
const result = await service.importLocalProjectSessions({
|
|
134404
|
+
localProjectId: request.localProjectId,
|
|
134405
|
+
rootPath,
|
|
134406
|
+
acpSessionIds: request.acpSessionIds
|
|
134407
|
+
});
|
|
134408
|
+
return {
|
|
134409
|
+
ok: true,
|
|
134410
|
+
type: "local-project/import-history",
|
|
134411
|
+
result
|
|
134412
|
+
};
|
|
134413
|
+
} catch (error2) {
|
|
134414
|
+
return this.toLocalProjectControlError(requestType, "execution_failed", formatErrorMessage(error2));
|
|
134415
|
+
}
|
|
133049
134416
|
}
|
|
133050
134417
|
cancelPendingPermissionRequests() {
|
|
133051
134418
|
this.permissionRequestStartTimes.clear();
|
|
@@ -141893,6 +143260,18 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
141893
143260
|
}
|
|
141894
143261
|
return typeof value.error === "string";
|
|
141895
143262
|
}
|
|
143263
|
+
function isLocalProjectHistorySyncSummary(value) {
|
|
143264
|
+
return isObjectRecord(value) && typeof value.listed === "number" && Number.isInteger(value.listed) && value.listed >= 0 && typeof value.imported === "number" && Number.isInteger(value.imported) && value.imported >= 0 && typeof value.refreshed === "number" && Number.isInteger(value.refreshed) && value.refreshed >= 0 && typeof value.skipped === "number" && Number.isInteger(value.skipped) && value.skipped >= 0 && typeof value.conflicted === "number" && Number.isInteger(value.conflicted) && value.conflicted >= 0 && typeof value.failed === "number" && Number.isInteger(value.failed) && value.failed >= 0 && Array.isArray(value.failures) && value.failures.every((failure) => isObjectRecord(failure) && typeof failure.acpSessionId === "string" && typeof failure.message === "string");
|
|
143265
|
+
}
|
|
143266
|
+
function isLocalProjectHistoryCatalogItem(value) {
|
|
143267
|
+
return isObjectRecord(value) && typeof value.acpSessionId === "string" && typeof value.title === "string" && (typeof value.updatedAt === "undefined" || typeof value.updatedAt === "string") && (typeof value.importedSessionId === "undefined" || typeof value.importedSessionId === "string") && (typeof value.status === "undefined" || value.status === "available" || value.status === "imported" || value.status === "sync_conflict");
|
|
143268
|
+
}
|
|
143269
|
+
function isLocalProjectHistoryCatalogResult(value) {
|
|
143270
|
+
return isObjectRecord(value) && typeof value.listed === "number" && Number.isInteger(value.listed) && value.listed >= 0 && typeof value.lastListedAt === "number" && Number.isInteger(value.lastListedAt) && value.lastListedAt >= 0 && Array.isArray(value.sessions) && value.sessions.every(isLocalProjectHistoryCatalogItem);
|
|
143271
|
+
}
|
|
143272
|
+
function isLocalProjectHistoryImportResult(value) {
|
|
143273
|
+
return isObjectRecord(value) && isLocalProjectHistorySyncSummary(value.summary) && isLocalProjectHistoryCatalogResult(value.catalog);
|
|
143274
|
+
}
|
|
141896
143275
|
function isWorkspaceIds(value) {
|
|
141897
143276
|
return isStringArray(value);
|
|
141898
143277
|
}
|
|
@@ -141924,6 +143303,12 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
141924
143303
|
if (value.type === "local-project/checkout-branch") {
|
|
141925
143304
|
return isLocalProjectCheckoutBranchResult(value.result);
|
|
141926
143305
|
}
|
|
143306
|
+
if (value.type === "local-project/sync-history") {
|
|
143307
|
+
return isLocalProjectHistoryCatalogResult(value.result);
|
|
143308
|
+
}
|
|
143309
|
+
if (value.type === "local-project/import-history") {
|
|
143310
|
+
return isLocalProjectHistoryImportResult(value.result);
|
|
143311
|
+
}
|
|
141927
143312
|
return false;
|
|
141928
143313
|
}
|
|
141929
143314
|
const SESSION_CONTROL_PATH$2 = "/session-control";
|
|
@@ -141938,6 +143323,8 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
141938
143323
|
"local-project/list-files",
|
|
141939
143324
|
"local-project/read-file",
|
|
141940
143325
|
"local-project/checkout-branch",
|
|
143326
|
+
"local-project/sync-history",
|
|
143327
|
+
"local-project/import-history",
|
|
141941
143328
|
"worktree/list-files",
|
|
141942
143329
|
"worktree/read-file"
|
|
141943
143330
|
];
|
|
@@ -143215,6 +144602,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
143215
144602
|
localProjects: {
|
|
143216
144603
|
...existing,
|
|
143217
144604
|
[entry2.localProjectId]: {
|
|
144605
|
+
...previous ?? {},
|
|
143218
144606
|
id: entry2.localProjectId,
|
|
143219
144607
|
name: entry2.name,
|
|
143220
144608
|
rootPath: entry2.rootPath,
|
|
@@ -143396,6 +144784,43 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
143396
144784
|
result: this.localProjectControlService.checkoutProjectBranch(rootPath, message.branchName)
|
|
143397
144785
|
};
|
|
143398
144786
|
}
|
|
144787
|
+
if (message.type === "local-project/sync-history") {
|
|
144788
|
+
const runtime = await this.resolveWorkspaceRuntime(message.workspaceId);
|
|
144789
|
+
const rootPath = await this.resolveWorkspaceProjectRootPath(runtime, message.localProjectId);
|
|
144790
|
+
const service = new LocalProjectHistorySyncService(runtime.lody.documentManager, this.logger, {
|
|
144791
|
+
workspaceId: message.workspaceId,
|
|
144792
|
+
machineId: this.machineId,
|
|
144793
|
+
userId: this.userId
|
|
144794
|
+
}, message.provider);
|
|
144795
|
+
const result = await service.syncLocalProject({
|
|
144796
|
+
localProjectId: message.localProjectId,
|
|
144797
|
+
rootPath
|
|
144798
|
+
});
|
|
144799
|
+
return {
|
|
144800
|
+
ok: true,
|
|
144801
|
+
type: "local-project/sync-history",
|
|
144802
|
+
result
|
|
144803
|
+
};
|
|
144804
|
+
}
|
|
144805
|
+
if (message.type === "local-project/import-history") {
|
|
144806
|
+
const runtime = await this.resolveWorkspaceRuntime(message.workspaceId);
|
|
144807
|
+
const rootPath = await this.resolveWorkspaceProjectRootPath(runtime, message.localProjectId);
|
|
144808
|
+
const service = new LocalProjectHistorySyncService(runtime.lody.documentManager, this.logger, {
|
|
144809
|
+
workspaceId: message.workspaceId,
|
|
144810
|
+
machineId: this.machineId,
|
|
144811
|
+
userId: this.userId
|
|
144812
|
+
}, message.provider);
|
|
144813
|
+
const result = await service.importLocalProjectSessions({
|
|
144814
|
+
localProjectId: message.localProjectId,
|
|
144815
|
+
rootPath,
|
|
144816
|
+
acpSessionIds: message.acpSessionIds
|
|
144817
|
+
});
|
|
144818
|
+
return {
|
|
144819
|
+
ok: true,
|
|
144820
|
+
type: "local-project/import-history",
|
|
144821
|
+
result
|
|
144822
|
+
};
|
|
144823
|
+
}
|
|
143399
144824
|
if (message.type === "worktree/list-files") {
|
|
143400
144825
|
return {
|
|
143401
144826
|
ok: true,
|
|
@@ -143737,13 +145162,14 @@ Received ${signal}, shutting down gracefully...` : "\nShutting down gracefully..
|
|
|
143737
145162
|
runtimeStateReporter.setStartupStage("bootstrap");
|
|
143738
145163
|
const electronBootstrapEnabled = process.env[ELECTRON_BOOTSTRAP_ENV] === "1";
|
|
143739
145164
|
const electronSessionToken = process.env[ELECTRON_SESSION_TOKEN_ENV]?.trim();
|
|
143740
|
-
const electronSessionUserId = process.env[ELECTRON_SESSION_USER_ID_ENV]?.trim() || null;
|
|
143741
145165
|
const providedAuth = options.auth?.trim();
|
|
143742
145166
|
const cliAvailability = {
|
|
143743
145167
|
claude: checkClaude(),
|
|
143744
145168
|
codex: checkCodex()
|
|
143745
145169
|
};
|
|
143746
145170
|
logCliDetectionResults(logger2, cliAvailability);
|
|
145171
|
+
const electronSessionUser = electronSessionToken && !process.env[ELECTRON_SESSION_USER_ID_ENV]?.trim() ? await authClient.getSessionUserFromSessionToken(electronSessionToken) : null;
|
|
145172
|
+
const electronSessionUserId = process.env[ELECTRON_SESSION_USER_ID_ENV]?.trim() || electronSessionUser?.id || null;
|
|
143747
145173
|
const cliSelection = resolveCliTypesSelection({
|
|
143748
145174
|
requestedCliTypes: options.cliTypes,
|
|
143749
145175
|
availability: cliAvailability
|
|
@@ -175606,6 +177032,7 @@ ${result.stderr}`;
|
|
|
175606
177032
|
this.lastExitCode = result.code;
|
|
175607
177033
|
this.lastExitAtMs = Date.now();
|
|
175608
177034
|
this.publishState();
|
|
177035
|
+
if (!this.triggered) return;
|
|
175609
177036
|
if (this.restartPending) return;
|
|
175610
177037
|
if (isAlreadyRunningOutcome(result)) {
|
|
175611
177038
|
if (this.alreadyRunningIsFatal) {
|